1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/s4u2proxy.c - S4U2Proxy test harness */
3 /*
4 * Copyright (C) 2015 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Usage: s4u2proxy evccname targetname [ad-type ad-contents]
35 *
36 * evccname contains an evidence ticket. The default ccache contains a TGT for
37 * the intermediate service. The default keytab contains a key for the
38 * intermediate service. An S4U2Proxy request is made to get a ticket from
39 * evccname's default principal to the target service. The resulting cred is
40 * stored in the default ccache.
41 */
42
43 #include <k5-int.h>
44
45 static krb5_context ctx;
46
47 static void
check(krb5_error_code code)48 check(krb5_error_code code)
49 {
50 const char *errmsg;
51
52 if (code) {
53 errmsg = krb5_get_error_message(ctx, code);
54 fprintf(stderr, "%s\n", errmsg);
55 krb5_free_error_message(ctx, errmsg);
56 exit(1);
57 }
58 }
59
60 static krb5_authdata **
make_request_authdata(int type,const char * contents)61 make_request_authdata(int type, const char *contents)
62 {
63 krb5_authdata *ad;
64 krb5_authdata **req_authdata;
65
66 ad = malloc(sizeof(*ad));
67 assert(ad != NULL);
68 ad->magic = KV5M_AUTHDATA;
69 ad->ad_type = type;
70 ad->length = strlen(contents);
71 ad->contents = (unsigned char *)strdup(contents);
72 assert(ad->contents != NULL);
73
74 req_authdata = malloc(2 * sizeof(*req_authdata));
75 assert(req_authdata != NULL);
76 req_authdata[0] = ad;
77 req_authdata[1] = NULL;
78
79 return req_authdata;
80 }
81
82 int
main(int argc,char ** argv)83 main(int argc, char **argv)
84 {
85 krb5_context context;
86 krb5_ccache defcc, evcc;
87 krb5_principal client_name, int_name, target_name;
88 krb5_keytab defkt;
89 krb5_creds mcred, ev_cred, *new_cred;
90 krb5_ticket *ev_ticket;
91 krb5_authdata **req_authdata = NULL;
92
93 if (argc == 5) {
94 req_authdata = make_request_authdata(atoi(argv[3]), argv[4]);
95 argc -= 2;
96 }
97
98 assert(argc == 3);
99 check(krb5_init_context(&context));
100
101 /* Open the default ccache, evidence ticket ccache, and default keytab. */
102 check(krb5_cc_default(context, &defcc));
103 check(krb5_cc_resolve(context, argv[1], &evcc));
104 check(krb5_kt_default(context, &defkt));
105
106 /* Determine the client name, intermediate name, and target name. */
107 check(krb5_cc_get_principal(context, evcc, &client_name));
108 check(krb5_cc_get_principal(context, defcc, &int_name));
109 check(krb5_parse_name(context, argv[2], &target_name));
110
111 /* Retrieve and decrypt the evidence ticket. */
112 memset(&mcred, 0, sizeof(mcred));
113 mcred.client = client_name;
114 mcred.server = int_name;
115 check(krb5_cc_retrieve_cred(context, evcc, 0, &mcred, &ev_cred));
116 check(krb5_decode_ticket(&ev_cred.ticket, &ev_ticket));
117 check(krb5_server_decrypt_ticket_keytab(context, defkt, ev_ticket));
118
119 /* Make an S4U2Proxy request for the target service. */
120 mcred.client = client_name;
121 mcred.server = target_name;
122 mcred.authdata = req_authdata;
123 check(krb5_get_credentials_for_proxy(context, KRB5_GC_NO_STORE |
124 KRB5_GC_CANONICALIZE, defcc,
125 &mcred, ev_ticket, &new_cred));
126
127 assert(data_eq(new_cred->second_ticket, ev_cred.ticket));
128 assert(new_cred->second_ticket.length != 0);
129
130 /* Store the new cred in the default ccache. */
131 check(krb5_cc_store_cred(context, defcc, new_cred));
132
133 assert(req_authdata == NULL || new_cred->authdata != NULL);
134
135 krb5_cc_close(context, defcc);
136 krb5_cc_close(context, evcc);
137 krb5_kt_close(context, defkt);
138 krb5_free_principal(context, client_name);
139 krb5_free_principal(context, int_name);
140 krb5_free_principal(context, target_name);
141 krb5_free_cred_contents(context, &ev_cred);
142 krb5_free_ticket(context, ev_ticket);
143 krb5_free_creds(context, new_cred);
144 krb5_free_authdata(context, req_authdata);
145 krb5_free_context(context);
146 return 0;
147 }
148