1 /*-
2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3 * Authors: Doug Rabson <dfr@rabson.org>
4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #ifdef __FreeBSD__
29 #include <sys/cdefs.h>
30 #else
31 #define __unused
32 #endif
33
34 #include <ctype.h>
35 #include <err.h>
36 #include <netdb.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include <rpc/rpc.h>
43 #include <rpc/rpcsec_gss.h>
44
45 static rpc_gss_principal_t server_acl = NULL;
46
47 static void
usage(void)48 usage(void)
49 {
50 printf("rpctest client | server\n");
51 exit(1);
52 }
53
54 static void
print_principal(rpc_gss_principal_t principal)55 print_principal(rpc_gss_principal_t principal)
56 {
57 int i, len, n;
58 uint8_t *p;
59
60 len = principal->len;
61 p = (uint8_t *) principal->name;
62 while (len > 0) {
63 n = len;
64 if (n > 16)
65 n = 16;
66 for (i = 0; i < n; i++)
67 printf("%02x ", p[i]);
68 for (; i < 16; i++)
69 printf(" ");
70 printf("|");
71 for (i = 0; i < n; i++)
72 printf("%c", isprint(p[i]) ? p[i] : '.');
73 printf("|\n");
74 len -= n;
75 p += n;
76 }
77 }
78
79 static void
test_client(int argc,const char ** argv)80 test_client(int argc, const char **argv)
81 {
82 rpcproc_t prog = 123456;
83 rpcvers_t vers = 1;
84 const char *netid = "tcp";
85 char hostname[128], service[128+5];
86 CLIENT *client;
87 AUTH *auth;
88 const char **mechs;
89 rpc_gss_options_req_t options_req;
90 rpc_gss_options_ret_t options_ret;
91 rpc_gss_service_t svc;
92 struct timeval tv;
93 enum clnt_stat stat;
94
95 if (argc == 2)
96 strlcpy(hostname, argv[1], sizeof(hostname));
97 else
98 gethostname(hostname, sizeof(hostname));
99
100 client = clnt_create(hostname, prog, vers, netid);
101 if (!client) {
102 printf("rpc_createerr.cf_stat = %d\n",
103 rpc_createerr.cf_stat);
104 printf("rpc_createerr.cf_error.re_errno = %d\n",
105 rpc_createerr.cf_error.re_errno);
106 return;
107 }
108
109 strcpy(service, "host");
110 strcat(service, "@");
111 strcat(service, hostname);
112
113 mechs = rpc_gss_get_mechanisms();
114 auth = NULL;
115 while (*mechs) {
116 options_req.req_flags = GSS_C_MUTUAL_FLAG;
117 options_req.time_req = 600;
118 options_req.my_cred = GSS_C_NO_CREDENTIAL;
119 options_req.input_channel_bindings = NULL;
120 auth = rpc_gss_seccreate(client, service,
121 *mechs,
122 rpc_gss_svc_none,
123 NULL,
124 &options_req,
125 &options_ret);
126 if (auth)
127 break;
128 mechs++;
129 }
130 if (!auth) {
131 clnt_pcreateerror("rpc_gss_seccreate");
132 printf("Can't authenticate with server %s.\n",
133 hostname);
134 exit(1);
135 }
136 client->cl_auth = auth;
137
138 for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) {
139 const char *svc_names[] = {
140 "rpc_gss_svc_default",
141 "rpc_gss_svc_none",
142 "rpc_gss_svc_integrity",
143 "rpc_gss_svc_privacy"
144 };
145 int num;
146
147 rpc_gss_set_defaults(auth, svc, NULL);
148 tv.tv_sec = 5;
149 tv.tv_usec = 0;
150 num = 42;
151 stat = CLNT_CALL(client, 1,
152 (xdrproc_t) xdr_int, (char *) &num,
153 (xdrproc_t) xdr_int, (char *) &num, tv);
154 if (stat == RPC_SUCCESS) {
155 printf("succeeded with %s\n", svc_names[svc]);
156 if (num != 142)
157 printf("unexpected reply %d\n", num);
158 } else {
159 clnt_perror(client, "call failed");
160 }
161 }
162 AUTH_DESTROY(auth);
163 CLNT_DESTROY(client);
164 }
165
166 static void
server_program_1(struct svc_req * rqstp,register SVCXPRT * transp)167 server_program_1(struct svc_req *rqstp, register SVCXPRT *transp)
168 {
169 rpc_gss_rawcred_t *rcred;
170 rpc_gss_ucred_t *ucred;
171 int i, num;
172
173 if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) {
174 svcerr_weakauth(transp);
175 return;
176 }
177
178 if (!rpc_gss_getcred(rqstp, &rcred, &ucred, NULL)) {
179 svcerr_systemerr(transp);
180 return;
181 }
182
183 printf("svc=%d, mech=%s, uid=%d, gid=%d, gids={",
184 rcred->service, rcred->mechanism, ucred->uid, ucred->gid);
185 for (i = 0; i < ucred->gidlen; i++) {
186 if (i > 0) printf(",");
187 printf("%d", ucred->gidlist[i]);
188 }
189 printf("}\n");
190
191 switch (rqstp->rq_proc) {
192 case 0:
193 if (!svc_getargs(transp, (xdrproc_t) xdr_void, 0)) {
194 svcerr_decode(transp);
195 goto out;
196 }
197 if (!svc_sendreply(transp, (xdrproc_t) xdr_void, 0)) {
198 svcerr_systemerr(transp);
199 }
200 goto out;
201
202 case 1:
203 if (!svc_getargs(transp, (xdrproc_t) xdr_int,
204 (char *) &num)) {
205 svcerr_decode(transp);
206 goto out;
207 }
208 num += 100;
209 if (!svc_sendreply(transp, (xdrproc_t) xdr_int,
210 (char *) &num)) {
211 svcerr_systemerr(transp);
212 }
213 goto out;
214
215 default:
216 svcerr_noproc(transp);
217 goto out;
218 }
219
220 out:
221 return;
222 }
223
224 #if 0
225 static void
226 report_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
227 {
228 OM_uint32 maj_stat, min_stat;
229 OM_uint32 message_context;
230 gss_buffer_desc buf;
231
232 printf("major_stat=%d, minor_stat=%d\n", maj, min);
233
234 message_context = 0;
235 do {
236 maj_stat = gss_display_status(&min_stat, maj,
237 GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf);
238 printf("%.*s\n", (int)buf.length, (char *) buf.value);
239 gss_release_buffer(&min_stat, &buf);
240 } while (message_context);
241 if (mech) {
242 message_context = 0;
243 do {
244 maj_stat = gss_display_status(&min_stat, min,
245 GSS_C_MECH_CODE, mech, &message_context, &buf);
246 printf("%.*s\n", (int)buf.length, (char *) buf.value);
247 gss_release_buffer(&min_stat, &buf);
248 } while (message_context);
249 }
250 exit(1);
251 }
252 #endif
253
254 static bool_t
server_new_context(__unused struct svc_req * req,__unused gss_cred_id_t deleg,__unused gss_ctx_id_t gss_context,rpc_gss_lock_t * lock,__unused void ** cookie)255 server_new_context(__unused struct svc_req *req,
256 __unused gss_cred_id_t deleg,
257 __unused gss_ctx_id_t gss_context,
258 rpc_gss_lock_t *lock,
259 __unused void **cookie)
260 {
261 rpc_gss_rawcred_t *rcred = lock->raw_cred;
262
263 printf("new security context version=%d, mech=%s, qop=%s:\n",
264 rcred->version, rcred->mechanism, rcred->qop);
265 print_principal(rcred->client_principal);
266
267 if (!server_acl)
268 return (TRUE);
269
270 if (rcred->client_principal->len != server_acl->len
271 || memcmp(rcred->client_principal->name, server_acl->name,
272 server_acl->len)) {
273 return (FALSE);
274 }
275
276 return (TRUE);
277 }
278
279 static void
test_server(__unused int argc,__unused const char ** argv)280 test_server(__unused int argc, __unused const char **argv)
281 {
282 char hostname[128];
283 char principal[128 + 5];
284 const char **mechs;
285 static rpc_gss_callback_t cb;
286
287 if (argc == 3) {
288 if (!rpc_gss_get_principal_name(&server_acl, argv[1],
289 argv[2], NULL, NULL)) {
290 printf("Can't create %s ACL entry for %s\n",
291 argv[1], argv[2]);
292 return;
293 }
294 }
295
296 gethostname(hostname, sizeof(hostname));;
297 snprintf(principal, sizeof(principal), "host@%s", hostname);
298
299 mechs = rpc_gss_get_mechanisms();
300 while (*mechs) {
301 if (!rpc_gss_set_svc_name(principal, *mechs, GSS_C_INDEFINITE,
302 123456, 1)) {
303 rpc_gss_error_t e;
304
305 rpc_gss_get_error(&e);
306 printf("setting name for %s for %s failed: %d, %d\n",
307 principal, *mechs,
308 e.rpc_gss_error, e.system_error);
309
310 #if 0
311 gss_OID mech_oid;
312 gss_OID_set_desc oid_set;
313 gss_name_t name;
314 OM_uint32 maj_stat, min_stat;
315 gss_buffer_desc namebuf;
316 gss_cred_id_t cred;
317
318 rpc_gss_mech_to_oid(*mechs, &mech_oid);
319 oid_set.count = 1;
320 oid_set.elements = mech_oid;
321
322 namebuf.value = principal;
323 namebuf.length = strlen(principal);
324 maj_stat = gss_import_name(&min_stat, &namebuf,
325 GSS_C_NT_HOSTBASED_SERVICE, &name);
326 if (maj_stat) {
327 printf("gss_import_name failed\n");
328 report_error(mech_oid, maj_stat, min_stat);
329 }
330 maj_stat = gss_acquire_cred(&min_stat, name,
331 0, &oid_set, GSS_C_ACCEPT, &cred, NULL, NULL);
332 if (maj_stat) {
333 printf("gss_acquire_cred failed\n");
334 report_error(mech_oid, maj_stat, min_stat);
335 }
336 #endif
337 }
338 mechs++;
339 }
340
341 cb.program = 123456;
342 cb.version = 1;
343 cb.callback = server_new_context;
344 rpc_gss_set_callback(&cb);
345
346 svc_create(server_program_1, 123456, 1, 0);
347 svc_run();
348 }
349
350 static void
test_get_principal_name(int argc,const char ** argv)351 test_get_principal_name(int argc, const char **argv)
352 {
353 const char *mechname, *name, *node, *domain;
354 rpc_gss_principal_t principal;
355
356 if (argc < 3 || argc > 5) {
357 printf("usage: rpctest principal <mechname> <name> "
358 "[<node> [<domain>] ]\n");
359 exit(1);
360 }
361
362 mechname = argv[1];
363 name = argv[2];
364 node = NULL;
365 domain = NULL;
366 if (argc > 3) {
367 node = argv[3];
368 if (argc > 4)
369 domain = argv[4];
370 }
371
372 if (rpc_gss_get_principal_name(&principal, mechname, name,
373 node, domain)) {
374 printf("succeeded:\n");
375 print_principal(principal);
376 free(principal);
377 } else {
378 printf("failed\n");
379 }
380 }
381
382 int
main(int argc,const char ** argv)383 main(int argc, const char **argv)
384 {
385
386 if (argc < 2)
387 usage();
388 if (!strcmp(argv[1], "client"))
389 test_client(argc - 1, argv + 1);
390 else if (!strcmp(argv[1], "server"))
391 test_server(argc - 1, argv + 1);
392 else if (!strcmp(argv[1], "principal"))
393 test_get_principal_name(argc - 1, argv + 1);
394 else
395 usage();
396
397 return (0);
398 }
399