1 /* 2 * Copyright (c) 2000 - 2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 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 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "kuser_locl.h" 35 #include <parse_units.h> 36 37 static char *client_principal_str = NULL; 38 static krb5_principal client_principal; 39 static char *server_principal_str = NULL; 40 static krb5_principal server_principal; 41 42 static char *ccache_str = NULL; 43 44 static char *ticket_flags_str = NULL; 45 static TicketFlags ticket_flags; 46 static char *keytab_file = NULL; 47 static char *enctype_string = NULL; 48 static int expiration_time = 3600; 49 static struct getarg_strings client_addresses; 50 static int version_flag = 0; 51 static int help_flag = 0; 52 static int use_krb5 = 1; 53 54 static const char *enc_type = "des-cbc-md5"; 55 56 /* 57 * 58 */ 59 60 static void 61 encode_ticket (krb5_context context, 62 EncryptionKey *skey, 63 krb5_enctype etype, 64 int skvno, 65 krb5_creds *cred) 66 { 67 size_t len, size; 68 char *buf; 69 krb5_error_code ret; 70 krb5_crypto crypto; 71 EncryptedData enc_part; 72 EncTicketPart et; 73 Ticket ticket; 74 75 memset (&enc_part, 0, sizeof(enc_part)); 76 memset (&ticket, 0, sizeof(ticket)); 77 78 /* 79 * Set up `enc_part' 80 */ 81 82 et.flags = cred->flags.b; 83 et.key = cred->session; 84 et.crealm = cred->client->realm; 85 copy_PrincipalName(&cred->client->name, &et.cname); 86 { 87 krb5_data empty_string; 88 89 krb5_data_zero(&empty_string); 90 et.transited.tr_type = DOMAIN_X500_COMPRESS; 91 et.transited.contents = empty_string; 92 } 93 et.authtime = cred->times.authtime; 94 et.starttime = NULL; 95 et.endtime = cred->times.endtime; 96 et.renew_till = NULL; 97 et.caddr = &cred->addresses; 98 et.authorization_data = NULL; /* XXX allow random authorization_data */ 99 100 /* 101 * Encrypt `enc_part' of ticket with service key 102 */ 103 104 ASN1_MALLOC_ENCODE(EncTicketPart, buf, len, &et, &size, ret); 105 if (ret) 106 krb5_err(context, 1, ret, "EncTicketPart"); 107 108 ret = krb5_crypto_init(context, skey, etype, &crypto); 109 if (ret) 110 krb5_err(context, 1, ret, "krb5_crypto_init"); 111 ret = krb5_encrypt_EncryptedData (context, 112 crypto, 113 KRB5_KU_TICKET, 114 buf, 115 len, 116 skvno, 117 &ticket.enc_part); 118 if (ret) 119 krb5_err(context, 1, ret, "krb5_encrypt_EncryptedData"); 120 121 free(buf); 122 krb5_crypto_destroy(context, crypto); 123 124 /* 125 * Encode ticket 126 */ 127 128 ticket.tkt_vno = 5; 129 ticket.realm = cred->server->realm; 130 copy_PrincipalName(&cred->server->name, &ticket.sname); 131 132 ASN1_MALLOC_ENCODE(Ticket, buf, len, &ticket, &size, ret); 133 if(ret) 134 krb5_err (context, 1, ret, "encode_Ticket"); 135 136 krb5_data_copy(&cred->ticket, buf, len); 137 free(buf); 138 } 139 140 /* 141 * 142 */ 143 144 static int 145 create_krb5_tickets (krb5_context context, krb5_keytab kt) 146 { 147 krb5_error_code ret; 148 krb5_keytab_entry entry; 149 krb5_creds cred; 150 krb5_enctype etype; 151 krb5_ccache ccache; 152 153 memset (&cred, 0, sizeof(cred)); 154 155 ret = krb5_string_to_enctype (context, enc_type, &etype); 156 if (ret) 157 krb5_err (context, 1, ret, "krb5_string_to_enctype"); 158 ret = krb5_kt_get_entry (context, kt, server_principal, 159 0, etype, &entry); 160 if (ret) 161 krb5_err (context, 1, ret, "krb5_kt_get_entry"); 162 163 /* 164 * setup cred 165 */ 166 167 168 ret = krb5_copy_principal (context, client_principal, &cred.client); 169 if (ret) 170 krb5_err (context, 1, ret, "krb5_copy_principal"); 171 ret = krb5_copy_principal (context, server_principal, &cred.server); 172 if (ret) 173 krb5_err (context, 1, ret, "krb5_copy_principal"); 174 krb5_generate_random_keyblock(context, etype, &cred.session); 175 176 cred.times.authtime = time(NULL); 177 cred.times.starttime = time(NULL); 178 cred.times.endtime = time(NULL) + expiration_time; 179 cred.times.renew_till = 0; 180 krb5_data_zero(&cred.second_ticket); 181 182 ret = krb5_get_all_client_addrs (context, &cred.addresses); 183 if (ret) 184 krb5_err (context, 1, ret, "krb5_get_all_client_addrs"); 185 cred.flags.b = ticket_flags; 186 187 188 /* 189 * Encode encrypted part of ticket 190 */ 191 192 encode_ticket (context, &entry.keyblock, etype, entry.vno, &cred); 193 194 /* 195 * Write to cc 196 */ 197 198 if (ccache_str) { 199 ret = krb5_cc_resolve(context, ccache_str, &ccache); 200 if (ret) 201 krb5_err (context, 1, ret, "krb5_cc_resolve"); 202 } else { 203 ret = krb5_cc_default (context, &ccache); 204 if (ret) 205 krb5_err (context, 1, ret, "krb5_cc_default"); 206 } 207 208 ret = krb5_cc_initialize (context, ccache, cred.client); 209 if (ret) 210 krb5_err (context, 1, ret, "krb5_cc_initialize"); 211 212 ret = krb5_cc_store_cred (context, ccache, &cred); 213 if (ret) 214 krb5_err (context, 1, ret, "krb5_cc_store_cred"); 215 216 krb5_free_cred_contents (context, &cred); 217 krb5_cc_close (context, ccache); 218 219 return 0; 220 } 221 222 /* 223 * 224 */ 225 226 static void 227 setup_env (krb5_context context, krb5_keytab *kt) 228 { 229 krb5_error_code ret; 230 231 if (keytab_file) 232 ret = krb5_kt_resolve (context, keytab_file, kt); 233 else 234 ret = krb5_kt_default (context, kt); 235 if (ret) 236 krb5_err (context, 1, ret, "resolving keytab"); 237 238 if (client_principal_str == NULL) 239 krb5_errx (context, 1, "missing client principal"); 240 ret = krb5_parse_name (context, client_principal_str, &client_principal); 241 if (ret) 242 krb5_err (context, 1, ret, "resolvning client name"); 243 244 if (server_principal_str == NULL) 245 krb5_errx (context, 1, "missing server principal"); 246 ret = krb5_parse_name (context, server_principal_str, &server_principal); 247 if (ret) 248 krb5_err (context, 1, ret, "resolvning client name"); 249 250 if (ticket_flags_str) { 251 int ticket_flags_int; 252 253 ticket_flags_int = parse_flags(ticket_flags_str, 254 asn1_TicketFlags_units(), 0); 255 if (ticket_flags_int <= 0) { 256 krb5_warnx (context, "bad ticket flags: `%s'", ticket_flags_str); 257 print_flags_table (asn1_TicketFlags_units(), stderr); 258 exit (1); 259 } 260 if (ticket_flags_int) 261 ticket_flags = int2TicketFlags (ticket_flags_int); 262 } 263 } 264 265 /* 266 * 267 */ 268 269 struct getargs args[] = { 270 { "ccache", 0, arg_string, &ccache_str, 271 "name of kerberos 5 credential cache", "cache-name"}, 272 { "server", 's', arg_string, &server_principal_str, 273 "name of server principal", NULL }, 274 { "client", 'c', arg_string, &client_principal_str, 275 "name of client principal", NULL }, 276 { "keytab", 'k', arg_string, &keytab_file, 277 "name of keytab file", NULL }, 278 { "krb5", '5', arg_flag, &use_krb5, 279 "create a kerberos 5 ticket", NULL }, 280 { "expire-time", 'e', arg_integer, &expiration_time, 281 "lifetime of ticket in seconds", NULL }, 282 { "client-addresses", 'a', arg_strings, &client_addresses, 283 "addresses of client", NULL }, 284 { "enc-type", 't', arg_string, &enctype_string, 285 "encryption type", NULL }, 286 { "ticket-flags", 'f', arg_string, &ticket_flags_str, 287 "ticket flags for krb5 ticket", NULL }, 288 { "version", 0, arg_flag, &version_flag, "Print version", 289 NULL }, 290 { "help", 0, arg_flag, &help_flag, NULL, 291 NULL } 292 }; 293 294 static void 295 usage (int ret) 296 { 297 arg_printusage (args, 298 sizeof(args) / sizeof(args[0]), 299 NULL, 300 ""); 301 exit (ret); 302 } 303 304 int 305 main (int argc, char **argv) 306 { 307 int optidx = 0; 308 krb5_error_code ret; 309 krb5_context context; 310 krb5_keytab kt; 311 312 setprogname (argv[0]); 313 314 ret = krb5_init_context (&context); 315 if (ret) 316 errx(1, "krb5_init_context failed: %u", ret); 317 318 if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) 319 usage(1); 320 321 if (help_flag) 322 usage(0); 323 324 if (version_flag) { 325 print_version(NULL); 326 return 0; 327 } 328 329 if (enctype_string) 330 enc_type = enctype_string; 331 332 setup_env(context, &kt); 333 334 if (use_krb5) 335 create_krb5_tickets(context, kt); 336 337 krb5_kt_close(context, kt); 338 339 return 0; 340 } 341