155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2000, 2002 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "kf_locl.h" 35233294SstasRCSID("$Id$"); 3655682Smarkm 3755682Smarkmkrb5_context context; 3855682Smarkmstatic int help_flag; 3955682Smarkmstatic int version_flag; 4055682Smarkmstatic char *port_str; 41103423Snectarconst char *service = KF_SERVICE; 4255682Smarkmconst char *remote_name = NULL; 4355682Smarkmint forwardable = 0; 4455682Smarkmconst char *ccache_name = NULL; 4555682Smarkm 4655682Smarkmstatic struct getargs args[] = { 4755682Smarkm { "port", 'p', arg_string, &port_str, "port to connect to", "port" }, 4855682Smarkm { "login", 'l',arg_string, &remote_name,"remote login name","login"}, 4955682Smarkm { "ccache", 'c',arg_string, &ccache_name, "remote cred cache","ccache"}, 5055682Smarkm { "forwardable",'F',arg_flag,&forwardable, 5155682Smarkm "Forward forwardable credentials", NULL }, 5255682Smarkm { "forwardable",'G',arg_negative_flag,&forwardable, 5355682Smarkm "Don't forward forwardable credentials", NULL }, 5455682Smarkm { "help", 'h', arg_flag, &help_flag }, 5555682Smarkm { "version", 0, arg_flag, &version_flag } 5655682Smarkm}; 5755682Smarkm 5855682Smarkmstatic int num_args = sizeof(args) / sizeof(args[0]); 5955682Smarkm 6055682Smarkmstatic void 6155682Smarkmusage(int code, struct getargs *args, int num_args) 6255682Smarkm{ 6355682Smarkm arg_printusage(args, num_args, NULL, "hosts"); 6455682Smarkm exit(code); 6555682Smarkm} 6655682Smarkm 6755682Smarkmstatic int 6855682Smarkmclient_setup(krb5_context *context, int *argc, char **argv) 6955682Smarkm{ 7055682Smarkm int optind = 0; 7155682Smarkm int port = 0; 7255682Smarkm int status; 7355682Smarkm 7478527Sassar setprogname (argv[0]); 75233294Sstas 7655682Smarkm status = krb5_init_context (context); 7755682Smarkm if (status) 7872445Sassar errx(1, "krb5_init_context failed: %d", status); 79233294Sstas 8055682Smarkm forwardable = krb5_config_get_bool (*context, NULL, 8155682Smarkm "libdefaults", 8255682Smarkm "forwardable", 83233294Sstas NULL); 84233294Sstas 8555682Smarkm if (getarg (args, num_args, *argc, argv, &optind)) 8655682Smarkm usage(1, args, num_args); 8755682Smarkm 8855682Smarkm if(help_flag) 8955682Smarkm usage (0, args, num_args); 9055682Smarkm if(version_flag) { 9155682Smarkm print_version(NULL); 9255682Smarkm exit(0); 9355682Smarkm } 94233294Sstas 9555682Smarkm if(port_str) { 9655682Smarkm struct servent *s = roken_getservbyname(port_str, "tcp"); 9755682Smarkm if(s) 9855682Smarkm port = s->s_port; 9955682Smarkm else { 10055682Smarkm char *ptr; 10155682Smarkm 10255682Smarkm port = strtol (port_str, &ptr, 10); 10355682Smarkm if (port == 0 && ptr == port_str) 10455682Smarkm errx (1, "Bad port `%s'", port_str); 10555682Smarkm port = htons(port); 10655682Smarkm } 10755682Smarkm } 10855682Smarkm 10955682Smarkm if (port == 0) 110103423Snectar port = krb5_getportbyname (*context, KF_PORT_NAME, "tcp", KF_PORT_NUM); 111233294Sstas 11255682Smarkm if(*argc - optind < 1) 11355682Smarkm usage(1, args, num_args); 11455682Smarkm *argc = optind; 11555682Smarkm 11655682Smarkm return port; 11755682Smarkm} 11855682Smarkm 11955682Smarkm/* 12055682Smarkm * forward creds to `hostname'/`service' over `sock' 12155682Smarkm * return 0 iff OK 12255682Smarkm */ 12355682Smarkm 12455682Smarkmstatic int 125103423Snectarproto (int sock, const char *hostname, const char *service, 126103423Snectar char *message, size_t len) 12755682Smarkm{ 12855682Smarkm krb5_auth_context auth_context; 12955682Smarkm krb5_error_code status; 13055682Smarkm krb5_principal server; 13155682Smarkm krb5_data data; 13255682Smarkm krb5_data data_send; 13355682Smarkm 13455682Smarkm krb5_ccache ccache; 13555682Smarkm krb5_creds creds; 13655682Smarkm krb5_kdc_flags flags; 13755682Smarkm krb5_principal principal; 13855682Smarkm 13955682Smarkm status = krb5_auth_con_init (context, &auth_context); 14055682Smarkm if (status) { 14155682Smarkm krb5_warn (context, status, "krb5_auth_con_init"); 14255682Smarkm return 1; 14355682Smarkm } 14455682Smarkm 14555682Smarkm status = krb5_auth_con_setaddrs_from_fd (context, 14655682Smarkm auth_context, 14755682Smarkm &sock); 14855682Smarkm if (status) { 149233294Sstas krb5_auth_con_free(context, auth_context); 15055682Smarkm krb5_warn (context, status, "krb5_auth_con_setaddr"); 15155682Smarkm return 1; 15255682Smarkm } 15355682Smarkm 15455682Smarkm status = krb5_sname_to_principal (context, 15555682Smarkm hostname, 15655682Smarkm service, 15755682Smarkm KRB5_NT_SRV_HST, 15855682Smarkm &server); 15955682Smarkm if (status) { 160233294Sstas krb5_auth_con_free(context, auth_context); 16155682Smarkm krb5_warn (context, status, "krb5_sname_to_principal"); 16255682Smarkm return 1; 16355682Smarkm } 16455682Smarkm 16555682Smarkm status = krb5_sendauth (context, 16655682Smarkm &auth_context, 16755682Smarkm &sock, 168103423Snectar KF_VERSION_1, 16955682Smarkm NULL, 17055682Smarkm server, 171103423Snectar AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, 17255682Smarkm NULL, 17355682Smarkm NULL, 17455682Smarkm NULL, 17555682Smarkm NULL, 17655682Smarkm NULL, 17755682Smarkm NULL); 17855682Smarkm if (status) { 179233294Sstas krb5_auth_con_free(context, auth_context); 18055682Smarkm krb5_warn(context, status, "krb5_sendauth"); 18155682Smarkm return 1; 18255682Smarkm } 18355682Smarkm 184103423Snectar if (ccache_name == NULL) 185103423Snectar ccache_name = ""; 18655682Smarkm 18755682Smarkm data_send.data = (void *)remote_name; 18855682Smarkm data_send.length = strlen(remote_name) + 1; 189103423Snectar status = krb5_write_priv_message(context, auth_context, &sock, &data_send); 19055682Smarkm if (status) { 191233294Sstas krb5_auth_con_free(context, auth_context); 19255682Smarkm krb5_warn (context, status, "krb5_write_message"); 19355682Smarkm return 1; 19455682Smarkm } 19555682Smarkm data_send.data = (void *)ccache_name; 19655682Smarkm data_send.length = strlen(ccache_name)+1; 197103423Snectar status = krb5_write_priv_message(context, auth_context, &sock, &data_send); 19855682Smarkm if (status) { 199233294Sstas krb5_auth_con_free(context, auth_context); 20055682Smarkm krb5_warn (context, status, "krb5_write_message"); 20155682Smarkm return 1; 20255682Smarkm } 20355682Smarkm 20455682Smarkm memset (&creds, 0, sizeof(creds)); 20555682Smarkm 20655682Smarkm status = krb5_cc_default (context, &ccache); 20755682Smarkm if (status) { 208233294Sstas krb5_auth_con_free(context, auth_context); 20955682Smarkm krb5_warn (context, status, "krb5_cc_default"); 21055682Smarkm return 1; 21155682Smarkm } 21255682Smarkm 21355682Smarkm status = krb5_cc_get_principal (context, ccache, &principal); 21455682Smarkm if (status) { 215233294Sstas krb5_auth_con_free(context, auth_context); 21655682Smarkm krb5_warn (context, status, "krb5_cc_get_principal"); 21755682Smarkm return 1; 21855682Smarkm } 21955682Smarkm 22055682Smarkm creds.client = principal; 221233294Sstas 222103423Snectar status = krb5_make_principal (context, 223103423Snectar &creds.server, 224103423Snectar principal->realm, 225103423Snectar KRB5_TGS_NAME, 226103423Snectar principal->realm, 227103423Snectar NULL); 22855682Smarkm 22955682Smarkm if (status) { 230233294Sstas krb5_auth_con_free(context, auth_context); 231103423Snectar krb5_warn (context, status, "krb5_make_principal"); 23255682Smarkm return 1; 23355682Smarkm } 23455682Smarkm 23555682Smarkm creds.times.endtime = 0; 23655682Smarkm 23755682Smarkm flags.i = 0; 23855682Smarkm flags.b.forwarded = 1; 23955682Smarkm flags.b.forwardable = forwardable; 24055682Smarkm 24155682Smarkm status = krb5_get_forwarded_creds (context, 24255682Smarkm auth_context, 24355682Smarkm ccache, 24455682Smarkm flags.i, 24555682Smarkm hostname, 24655682Smarkm &creds, 24755682Smarkm &data); 24855682Smarkm if (status) { 249233294Sstas krb5_auth_con_free(context, auth_context); 25055682Smarkm krb5_warn (context, status, "krb5_get_forwarded_creds"); 25155682Smarkm return 1; 25255682Smarkm } 25355682Smarkm 254103423Snectar status = krb5_write_priv_message(context, auth_context, &sock, &data); 255103423Snectar 25655682Smarkm if (status) { 257233294Sstas krb5_auth_con_free(context, auth_context); 25855682Smarkm krb5_warn (context, status, "krb5_mk_priv"); 25955682Smarkm return 1; 26055682Smarkm } 261233294Sstas 262103423Snectar krb5_data_free (&data); 26355682Smarkm 264103423Snectar status = krb5_read_priv_message(context, auth_context, &sock, &data); 265233294Sstas krb5_auth_con_free(context, auth_context); 266103423Snectar if (status) { 267103423Snectar krb5_warn (context, status, "krb5_mk_priv"); 26855682Smarkm return 1; 26955682Smarkm } 270103423Snectar if(data.length >= len) { 271103423Snectar krb5_warnx (context, "returned string is too long, truncating"); 272103423Snectar memcpy(message, data.data, len); 273103423Snectar message[len - 1] = '\0'; 274103423Snectar } else { 275103423Snectar memcpy(message, data.data, data.length); 276103423Snectar message[data.length] = '\0'; 27755682Smarkm } 27855682Smarkm krb5_data_free (&data); 27955682Smarkm 280103423Snectar return(strcmp(message, "ok")); 28155682Smarkm} 28255682Smarkm 28355682Smarkmstatic int 284233294Sstasdoit (const char *hostname, int port, const char *service, 285103423Snectar char *message, size_t len) 28655682Smarkm{ 28755682Smarkm struct addrinfo *ai, *a; 28855682Smarkm struct addrinfo hints; 28955682Smarkm int error; 29055682Smarkm char portstr[NI_MAXSERV]; 29155682Smarkm 29255682Smarkm memset (&hints, 0, sizeof(hints)); 29355682Smarkm hints.ai_socktype = SOCK_STREAM; 29455682Smarkm hints.ai_protocol = IPPROTO_TCP; 29555682Smarkm 29655682Smarkm snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); 29755682Smarkm 29855682Smarkm error = getaddrinfo (hostname, portstr, &hints, &ai); 29955682Smarkm if (error) { 30055682Smarkm errx (1, "getaddrinfo(%s): %s", hostname, gai_strerror(error)); 30155682Smarkm } 30255682Smarkm 30355682Smarkm for (a = ai; a != NULL; a = a->ai_next) { 30455682Smarkm int s; 30555682Smarkm 30655682Smarkm s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 30755682Smarkm if (s < 0) 30855682Smarkm continue; 30955682Smarkm if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 31055682Smarkm warn ("connect(%s)", hostname); 31155682Smarkm close (s); 31255682Smarkm continue; 31355682Smarkm } 31455682Smarkm freeaddrinfo (ai); 315103423Snectar return proto (s, hostname, service, message, len); 31655682Smarkm } 31755682Smarkm warnx ("failed to contact %s", hostname); 31855682Smarkm freeaddrinfo (ai); 31955682Smarkm return 1; 32055682Smarkm} 32155682Smarkm 32255682Smarkmint 32355682Smarkmmain(int argc, char **argv) 32455682Smarkm{ 32555682Smarkm int argcc,port,i; 32655682Smarkm int ret=0; 327233294Sstas 32855682Smarkm argcc = argc; 32955682Smarkm port = client_setup(&context, &argcc, argv); 33055682Smarkm 331103423Snectar if (remote_name == NULL) { 332103423Snectar remote_name = get_default_username (); 333103423Snectar if (remote_name == NULL) 334103423Snectar errx (1, "who are you?"); 335103423Snectar } 336103423Snectar 33755682Smarkm for (i = argcc;i < argc; i++) { 338103423Snectar char message[128]; 339103423Snectar ret = doit (argv[i], port, service, message, sizeof(message)); 340103423Snectar if(ret == 0) 341103423Snectar warnx ("%s: ok", argv[i]); 342103423Snectar else 343103423Snectar warnx ("%s: failed: %s", argv[i], message); 34455682Smarkm } 34555682Smarkm return(ret); 34655682Smarkm} 347