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