1 /* 2 * Copyright (c) 1997 - 2000, 2002 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 "kf_locl.h" 35 RCSID("$Id: kf.c,v 1.17 2002/09/05 15:00:03 joda Exp $"); 36 37 krb5_context context; 38 static int help_flag; 39 static int version_flag; 40 static char *port_str; 41 const char *service = KF_SERVICE; 42 const char *remote_name = NULL; 43 int forwardable = 0; 44 const char *ccache_name = NULL; 45 46 static struct getargs args[] = { 47 { "port", 'p', arg_string, &port_str, "port to connect to", "port" }, 48 { "login", 'l',arg_string, &remote_name,"remote login name","login"}, 49 { "ccache", 'c',arg_string, &ccache_name, "remote cred cache","ccache"}, 50 { "forwardable",'F',arg_flag,&forwardable, 51 "Forward forwardable credentials", NULL }, 52 { "forwardable",'G',arg_negative_flag,&forwardable, 53 "Don't forward forwardable credentials", NULL }, 54 { "help", 'h', arg_flag, &help_flag }, 55 { "version", 0, arg_flag, &version_flag } 56 }; 57 58 static int num_args = sizeof(args) / sizeof(args[0]); 59 60 static void 61 usage(int code, struct getargs *args, int num_args) 62 { 63 arg_printusage(args, num_args, NULL, "hosts"); 64 exit(code); 65 } 66 67 static int 68 client_setup(krb5_context *context, int *argc, char **argv) 69 { 70 int optind = 0; 71 int port = 0; 72 int status; 73 74 setprogname (argv[0]); 75 76 status = krb5_init_context (context); 77 if (status) 78 errx(1, "krb5_init_context failed: %d", status); 79 80 forwardable = krb5_config_get_bool (*context, NULL, 81 "libdefaults", 82 "forwardable", 83 NULL); 84 85 if (getarg (args, num_args, *argc, argv, &optind)) 86 usage(1, args, num_args); 87 88 if(help_flag) 89 usage (0, args, num_args); 90 if(version_flag) { 91 print_version(NULL); 92 exit(0); 93 } 94 95 if(port_str) { 96 struct servent *s = roken_getservbyname(port_str, "tcp"); 97 if(s) 98 port = s->s_port; 99 else { 100 char *ptr; 101 102 port = strtol (port_str, &ptr, 10); 103 if (port == 0 && ptr == port_str) 104 errx (1, "Bad port `%s'", port_str); 105 port = htons(port); 106 } 107 } 108 109 if (port == 0) 110 port = krb5_getportbyname (*context, KF_PORT_NAME, "tcp", KF_PORT_NUM); 111 112 if(*argc - optind < 1) 113 usage(1, args, num_args); 114 *argc = optind; 115 116 return port; 117 } 118 119 /* 120 * forward creds to `hostname'/`service' over `sock' 121 * return 0 iff OK 122 */ 123 124 static int 125 proto (int sock, const char *hostname, const char *service, 126 char *message, size_t len) 127 { 128 krb5_auth_context auth_context; 129 krb5_error_code status; 130 krb5_principal server; 131 krb5_data data; 132 krb5_data data_send; 133 134 krb5_ccache ccache; 135 krb5_creds creds; 136 krb5_kdc_flags flags; 137 krb5_principal principal; 138 139 status = krb5_auth_con_init (context, &auth_context); 140 if (status) { 141 krb5_warn (context, status, "krb5_auth_con_init"); 142 return 1; 143 } 144 145 status = krb5_auth_con_setaddrs_from_fd (context, 146 auth_context, 147 &sock); 148 if (status) { 149 krb5_warn (context, status, "krb5_auth_con_setaddr"); 150 return 1; 151 } 152 153 status = krb5_sname_to_principal (context, 154 hostname, 155 service, 156 KRB5_NT_SRV_HST, 157 &server); 158 if (status) { 159 krb5_warn (context, status, "krb5_sname_to_principal"); 160 return 1; 161 } 162 163 status = krb5_sendauth (context, 164 &auth_context, 165 &sock, 166 KF_VERSION_1, 167 NULL, 168 server, 169 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, 170 NULL, 171 NULL, 172 NULL, 173 NULL, 174 NULL, 175 NULL); 176 if (status) { 177 krb5_warn(context, status, "krb5_sendauth"); 178 return 1; 179 } 180 181 if (ccache_name == NULL) 182 ccache_name = ""; 183 184 data_send.data = (void *)remote_name; 185 data_send.length = strlen(remote_name) + 1; 186 status = krb5_write_priv_message(context, auth_context, &sock, &data_send); 187 if (status) { 188 krb5_warn (context, status, "krb5_write_message"); 189 return 1; 190 } 191 data_send.data = (void *)ccache_name; 192 data_send.length = strlen(ccache_name)+1; 193 status = krb5_write_priv_message(context, auth_context, &sock, &data_send); 194 if (status) { 195 krb5_warn (context, status, "krb5_write_message"); 196 return 1; 197 } 198 199 memset (&creds, 0, sizeof(creds)); 200 201 status = krb5_cc_default (context, &ccache); 202 if (status) { 203 krb5_warn (context, status, "krb5_cc_default"); 204 return 1; 205 } 206 207 status = krb5_cc_get_principal (context, ccache, &principal); 208 if (status) { 209 krb5_warn (context, status, "krb5_cc_get_principal"); 210 return 1; 211 } 212 213 creds.client = principal; 214 215 status = krb5_make_principal (context, 216 &creds.server, 217 principal->realm, 218 KRB5_TGS_NAME, 219 principal->realm, 220 NULL); 221 222 if (status) { 223 krb5_warn (context, status, "krb5_make_principal"); 224 return 1; 225 } 226 227 creds.times.endtime = 0; 228 229 flags.i = 0; 230 flags.b.forwarded = 1; 231 flags.b.forwardable = forwardable; 232 233 status = krb5_get_forwarded_creds (context, 234 auth_context, 235 ccache, 236 flags.i, 237 hostname, 238 &creds, 239 &data); 240 if (status) { 241 krb5_warn (context, status, "krb5_get_forwarded_creds"); 242 return 1; 243 } 244 245 status = krb5_write_priv_message(context, auth_context, &sock, &data); 246 247 if (status) { 248 krb5_warn (context, status, "krb5_mk_priv"); 249 return 1; 250 } 251 252 krb5_data_free (&data); 253 254 status = krb5_read_priv_message(context, auth_context, &sock, &data); 255 if (status) { 256 krb5_warn (context, status, "krb5_mk_priv"); 257 return 1; 258 } 259 if(data.length >= len) { 260 krb5_warnx (context, "returned string is too long, truncating"); 261 memcpy(message, data.data, len); 262 message[len - 1] = '\0'; 263 } else { 264 memcpy(message, data.data, data.length); 265 message[data.length] = '\0'; 266 } 267 krb5_data_free (&data); 268 269 return(strcmp(message, "ok")); 270 } 271 272 static int 273 doit (const char *hostname, int port, const char *service, 274 char *message, size_t len) 275 { 276 struct addrinfo *ai, *a; 277 struct addrinfo hints; 278 int error; 279 char portstr[NI_MAXSERV]; 280 281 memset (&hints, 0, sizeof(hints)); 282 hints.ai_socktype = SOCK_STREAM; 283 hints.ai_protocol = IPPROTO_TCP; 284 285 snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); 286 287 error = getaddrinfo (hostname, portstr, &hints, &ai); 288 if (error) { 289 errx (1, "getaddrinfo(%s): %s", hostname, gai_strerror(error)); 290 } 291 292 for (a = ai; a != NULL; a = a->ai_next) { 293 int s; 294 295 s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 296 if (s < 0) 297 continue; 298 if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 299 warn ("connect(%s)", hostname); 300 close (s); 301 continue; 302 } 303 freeaddrinfo (ai); 304 return proto (s, hostname, service, message, len); 305 } 306 warnx ("failed to contact %s", hostname); 307 freeaddrinfo (ai); 308 return 1; 309 } 310 311 int 312 main(int argc, char **argv) 313 { 314 int argcc,port,i; 315 int ret=0; 316 317 argcc = argc; 318 port = client_setup(&context, &argcc, argv); 319 320 if (remote_name == NULL) { 321 remote_name = get_default_username (); 322 if (remote_name == NULL) 323 errx (1, "who are you?"); 324 } 325 326 for (i = argcc;i < argc; i++) { 327 char message[128]; 328 ret = doit (argv[i], port, service, message, sizeof(message)); 329 if(ret == 0) 330 warnx ("%s: ok", argv[i]); 331 else 332 warnx ("%s: failed: %s", argv[i], message); 333 } 334 return(ret); 335 } 336