155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 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; 3855682Smarkmchar krb5_tkfile[MAXPATHLEN]; 3955682Smarkm 4055682Smarkmstatic int help_flag; 4155682Smarkmstatic int version_flag; 4255682Smarkmstatic char *port_str; 43103423Snectarchar *service = KF_SERVICE; 4455682Smarkmint do_inetd = 0; 4555682Smarkmstatic char *regpag_str=NULL; 4655682Smarkm 4755682Smarkmstatic struct getargs args[] = { 4855682Smarkm { "port", 'p', arg_string, &port_str, "port to listen to", "port" }, 4955682Smarkm { "inetd",'i',arg_flag, &do_inetd, 5055682Smarkm "Not started from inetd", NULL }, 5155682Smarkm { "regpag",'R',arg_string,®pag_str,"path to regpag binary","regpag"}, 5255682Smarkm { "help", 'h', arg_flag, &help_flag }, 5355682Smarkm { "version", 0, arg_flag, &version_flag } 5455682Smarkm}; 5555682Smarkm 5655682Smarkmstatic int num_args = sizeof(args) / sizeof(args[0]); 5755682Smarkm 5855682Smarkmstatic void 5955682Smarkmusage(int code, struct getargs *args, int num_args) 6055682Smarkm{ 6155682Smarkm arg_printusage(args, num_args, NULL, ""); 6255682Smarkm exit(code); 6355682Smarkm} 6455682Smarkm 6555682Smarkmstatic int 6655682Smarkmserver_setup(krb5_context *context, int argc, char **argv) 6755682Smarkm{ 6855682Smarkm int port = 0; 6955682Smarkm int local_argc; 7055682Smarkm 7155682Smarkm local_argc = krb5_program_setup(context, argc, argv, args, num_args, usage); 7255682Smarkm 7355682Smarkm if(help_flag) 7455682Smarkm (*usage)(0, args, num_args); 7555682Smarkm if(version_flag) { 7655682Smarkm print_version(NULL); 7755682Smarkm exit(0); 7855682Smarkm } 79233294Sstas 8055682Smarkm if(port_str){ 8155682Smarkm struct servent *s = roken_getservbyname(port_str, "tcp"); 8255682Smarkm if(s) 8355682Smarkm port = s->s_port; 8455682Smarkm else { 8555682Smarkm char *ptr; 8655682Smarkm 8755682Smarkm port = strtol (port_str, &ptr, 10); 8855682Smarkm if (port == 0 && ptr == port_str) 8955682Smarkm errx (1, "Bad port `%s'", port_str); 9055682Smarkm port = htons(port); 9155682Smarkm } 9255682Smarkm } 9355682Smarkm 9455682Smarkm if (port == 0) 95103423Snectar port = krb5_getportbyname (*context, KF_PORT_NAME, "tcp", KF_PORT_NUM); 9655682Smarkm 9755682Smarkm if(argv[local_argc] != NULL) 9855682Smarkm usage(1, args, num_args); 99233294Sstas 10055682Smarkm return port; 10155682Smarkm} 10255682Smarkm 103103423Snectarstatic int protocol_version; 10455682Smarkm 105103423Snectarstatic krb5_boolean 106103423Snectarkfd_match_version(const void *arg, const char *version) 10755682Smarkm{ 108103423Snectar if(strcmp(version, KF_VERSION_1) == 0) { 109103423Snectar protocol_version = 1; 110103423Snectar return TRUE; 111103423Snectar } else if (strlen(version) == 4 && 112103423Snectar version[0] == '0' && 113103423Snectar version[1] == '.' && 114103423Snectar (version[2] == '4' || version[2] == '3') && 115178825Sdfr islower((unsigned char)version[3])) { 116103423Snectar protocol_version = 0; 117103423Snectar return TRUE; 118103423Snectar } 119103423Snectar return FALSE; 12055682Smarkm} 12155682Smarkm 12255682Smarkmstatic int 12355682Smarkmproto (int sock, const char *service) 12455682Smarkm{ 12555682Smarkm krb5_auth_context auth_context; 12655682Smarkm krb5_error_code status; 12755682Smarkm krb5_principal server; 12855682Smarkm krb5_ticket *ticket; 12955682Smarkm char *name; 13055682Smarkm char ret_string[10]; 13155682Smarkm char hostname[MAXHOSTNAMELEN]; 13255682Smarkm krb5_data data; 13355682Smarkm krb5_data remotename; 13455682Smarkm krb5_data tk_file; 13555682Smarkm krb5_ccache ccache; 13655682Smarkm char ccname[MAXPATHLEN]; 13755682Smarkm struct passwd *pwd; 13855682Smarkm 13955682Smarkm status = krb5_auth_con_init (context, &auth_context); 14055682Smarkm if (status) 141103423Snectar krb5_err(context, 1, status, "krb5_auth_con_init"); 14255682Smarkm 14355682Smarkm status = krb5_auth_con_setaddrs_from_fd (context, 14455682Smarkm auth_context, 14555682Smarkm &sock); 14655682Smarkm if (status) 147103423Snectar krb5_err(context, 1, status, "krb5_auth_con_setaddr"); 14855682Smarkm 14955682Smarkm if(gethostname (hostname, sizeof(hostname)) < 0) 150103423Snectar krb5_err(context, 1, errno, "gethostname"); 15155682Smarkm 15255682Smarkm status = krb5_sname_to_principal (context, 15355682Smarkm hostname, 15455682Smarkm service, 15555682Smarkm KRB5_NT_SRV_HST, 15655682Smarkm &server); 15755682Smarkm if (status) 158103423Snectar krb5_err(context, 1, status, "krb5_sname_to_principal"); 15955682Smarkm 160103423Snectar status = krb5_recvauth_match_version (context, 161103423Snectar &auth_context, 162103423Snectar &sock, 163103423Snectar kfd_match_version, 164103423Snectar NULL, 165103423Snectar server, 166103423Snectar 0, 167103423Snectar NULL, 168103423Snectar &ticket); 16955682Smarkm if (status) 170103423Snectar krb5_err(context, 1, status, "krb5_recvauth"); 17155682Smarkm 17255682Smarkm status = krb5_unparse_name (context, 17355682Smarkm ticket->client, 17455682Smarkm &name); 17555682Smarkm if (status) 176103423Snectar krb5_err(context, 1, status, "krb5_unparse_name"); 17755682Smarkm 178103423Snectar if(protocol_version == 0) { 179103423Snectar data.data = "old clnt"; /* XXX old clients only had room for 180103423Snectar 10 bytes of message, and also 181103423Snectar didn't show it to the user */ 182103423Snectar data.length = strlen(data.data) + 1; 183103423Snectar krb5_write_message(context, &sock, &data); 184103423Snectar sleep(2); /* XXX give client time to finish */ 185103423Snectar krb5_errx(context, 1, "old client; exiting"); 18655682Smarkm } 18755682Smarkm 188103423Snectar status=krb5_read_priv_message (context, auth_context, 189103423Snectar &sock, &remotename); 190103423Snectar if (status) 191103423Snectar krb5_err(context, 1, status, "krb5_read_message"); 192233294Sstas status=krb5_read_priv_message (context, auth_context, 193103423Snectar &sock, &tk_file); 194103423Snectar if (status) 195103423Snectar krb5_err(context, 1, status, "krb5_read_message"); 196103423Snectar 19755682Smarkm krb5_data_zero (&data); 19855682Smarkm 199103423Snectar if(((char*)remotename.data)[remotename.length-1] != '\0') 200103423Snectar krb5_errx(context, 1, "unterminated received"); 201103423Snectar if(((char*)tk_file.data)[tk_file.length-1] != '\0') 202103423Snectar krb5_errx(context, 1, "unterminated received"); 20355682Smarkm 204103423Snectar status = krb5_read_priv_message(context, auth_context, &sock, &data); 20555682Smarkm 20655682Smarkm if (status) { 207103423Snectar krb5_err(context, 1, errno, "krb5_read_priv_message"); 20855682Smarkm goto out; 20955682Smarkm } 21055682Smarkm 21155682Smarkm pwd = getpwnam ((char *)(remotename.data)); 21255682Smarkm if (pwd == NULL) { 21355682Smarkm status=1; 214103423Snectar krb5_warnx(context, "getpwnam: %s failed",(char *)(remotename.data)); 21555682Smarkm goto out; 21655682Smarkm } 21755682Smarkm 21855682Smarkm if(!krb5_kuserok (context, 219103423Snectar ticket->client, 220103423Snectar (char *)(remotename.data))) { 22155682Smarkm status=1; 222103423Snectar krb5_warnx(context, "krb5_kuserok: permission denied"); 22355682Smarkm goto out; 22455682Smarkm } 22555682Smarkm 22655682Smarkm if (setgid(pwd->pw_gid) < 0) { 227103423Snectar krb5_warn(context, errno, "setgid"); 22855682Smarkm goto out; 22955682Smarkm } 23055682Smarkm if (setuid(pwd->pw_uid) < 0) { 231103423Snectar krb5_warn(context, errno, "setuid"); 23255682Smarkm goto out; 23355682Smarkm } 23455682Smarkm 23555682Smarkm if (tk_file.length != 1) 23655682Smarkm snprintf (ccname, sizeof(ccname), "%s", (char *)(tk_file.data)); 23755682Smarkm else 238178825Sdfr snprintf (ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%lu", 239178825Sdfr (unsigned long)pwd->pw_uid); 24055682Smarkm 24155682Smarkm status = krb5_cc_resolve (context, ccname, &ccache); 24255682Smarkm if (status) { 243103423Snectar krb5_warn(context, status, "krb5_cc_resolve"); 24455682Smarkm goto out; 24555682Smarkm } 24655682Smarkm status = krb5_cc_initialize (context, ccache, ticket->client); 24755682Smarkm if (status) { 248103423Snectar krb5_warn(context, status, "krb5_cc_initialize"); 24955682Smarkm goto out; 25055682Smarkm } 25172445Sassar status = krb5_rd_cred2 (context, auth_context, ccache, &data); 25255682Smarkm krb5_cc_close (context, ccache); 25355682Smarkm if (status) { 254103423Snectar krb5_warn(context, status, "krb5_rd_cred"); 25555682Smarkm goto out; 25655682Smarkm 25755682Smarkm } 25855682Smarkm strlcpy(krb5_tkfile,ccname,sizeof(krb5_tkfile)); 259103423Snectar krb5_warnx(context, "%s forwarded ticket to %s,%s", 260103423Snectar name, 261103423Snectar (char *)(remotename.data),ccname); 262103423Snectar out: 26355682Smarkm if (status) { 264120945Snectar strlcpy(ret_string, "no", sizeof(ret_string)); 265103423Snectar krb5_warnx(context, "failed"); 26655682Smarkm } else { 267120945Snectar strlcpy(ret_string, "ok", sizeof(ret_string)); 26855682Smarkm } 26955682Smarkm 27055682Smarkm krb5_data_free (&tk_file); 27155682Smarkm krb5_data_free (&remotename); 27255682Smarkm krb5_data_free (&data); 27355682Smarkm free(name); 27455682Smarkm 275103423Snectar data.data = ret_string; 276103423Snectar data.length = strlen(ret_string) + 1; 277233294Sstas status = krb5_write_priv_message(context, auth_context, &sock, &data); 278233294Sstas krb5_auth_con_free(context, auth_context); 279233294Sstas 280233294Sstas return status; 28155682Smarkm} 28255682Smarkm 28355682Smarkmstatic int 28455682Smarkmdoit (int port, const char *service) 28555682Smarkm{ 28655682Smarkm if (do_inetd) 287233294Sstas mini_inetd(port, NULL); 28855682Smarkm return proto (STDIN_FILENO, service); 28955682Smarkm} 29055682Smarkm 29155682Smarkmint 29255682Smarkmmain(int argc, char **argv) 29355682Smarkm{ 29455682Smarkm int port; 29555682Smarkm int ret; 296103423Snectar krb5_log_facility *fac; 29755682Smarkm 29878527Sassar setprogname (argv[0]); 29955682Smarkm roken_openlog (argv[0], LOG_ODELAY | LOG_PID,LOG_AUTH); 30055682Smarkm port = server_setup(&context, argc, argv); 301103423Snectar ret = krb5_openlog(context, "kfd", &fac); 302103423Snectar if(ret) krb5_err(context, 1, ret, "krb5_openlog"); 303103423Snectar ret = krb5_set_warn_dest(context, fac); 304103423Snectar if(ret) krb5_err(context, 1, ret, "krb5_set_warn_dest"); 305103423Snectar 30655682Smarkm ret = doit (port, service); 30755682Smarkm closelog(); 30855682Smarkm if (ret == 0 && regpag_str != NULL) 30955682Smarkm ret = execl(regpag_str, "regpag", "-t", krb5_tkfile, "-r", NULL); 31055682Smarkm return ret; 31155682Smarkm} 312