1 /* 2 * Copyright (c) 1997 - 1999 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: kfd.c,v 1.7 1999/12/02 17:04:55 joda Exp $"); 36 37 krb5_context context; 38 char krb5_tkfile[MAXPATHLEN]; 39 40 static int help_flag; 41 static int version_flag; 42 static char *port_str; 43 char *service = SERVICE; 44 int do_inetd = 0; 45 static char *regpag_str=NULL; 46 47 static struct getargs args[] = { 48 { "port", 'p', arg_string, &port_str, "port to listen to", "port" }, 49 { "inetd",'i',arg_flag, &do_inetd, 50 "Not started from inetd", NULL }, 51 { "regpag",'R',arg_string,®pag_str,"path to regpag binary","regpag"}, 52 { "help", 'h', arg_flag, &help_flag }, 53 { "version", 0, arg_flag, &version_flag } 54 }; 55 56 static int num_args = sizeof(args) / sizeof(args[0]); 57 58 static void 59 usage(int code, struct getargs *args, int num_args) 60 { 61 arg_printusage(args, num_args, NULL, ""); 62 exit(code); 63 } 64 65 static int 66 server_setup(krb5_context *context, int argc, char **argv) 67 { 68 int port = 0; 69 int local_argc; 70 71 local_argc = krb5_program_setup(context, argc, argv, args, num_args, usage); 72 73 if(help_flag) 74 (*usage)(0, args, num_args); 75 if(version_flag) { 76 print_version(NULL); 77 exit(0); 78 } 79 80 if(port_str){ 81 struct servent *s = roken_getservbyname(port_str, "tcp"); 82 if(s) 83 port = s->s_port; 84 else { 85 char *ptr; 86 87 port = strtol (port_str, &ptr, 10); 88 if (port == 0 && ptr == port_str) 89 errx (1, "Bad port `%s'", port_str); 90 port = htons(port); 91 } 92 } 93 94 if (port == 0) 95 port = krb5_getportbyname (*context, PORT, "tcp", PORT_NUM); 96 97 if(argv[local_argc] != NULL) 98 usage(1, args, num_args); 99 100 return port; 101 } 102 103 static void 104 syslog_and_die (const char *m, ...) 105 { 106 va_list args; 107 108 va_start(args, m); 109 vsyslog (LOG_ERR, m, args); 110 va_end(args); 111 exit (1); 112 } 113 114 static void 115 syslog_and_cont (const char *m, ...) 116 { 117 va_list args; 118 119 va_start(args, m); 120 vsyslog (LOG_ERR, m, args); 121 va_end(args); 122 return; 123 } 124 125 static int 126 proto (int sock, const char *service) 127 { 128 krb5_auth_context auth_context; 129 krb5_error_code status; 130 krb5_principal server; 131 krb5_ticket *ticket; 132 char *name; 133 char ret_string[10]; 134 char hostname[MAXHOSTNAMELEN]; 135 krb5_data packet; 136 krb5_data data; 137 krb5_data remotename; 138 krb5_data tk_file; 139 140 u_int32_t len, net_len; 141 krb5_ccache ccache; 142 char ccname[MAXPATHLEN]; 143 struct passwd *pwd; 144 ssize_t n; 145 146 status = krb5_auth_con_init (context, &auth_context); 147 if (status) 148 syslog_and_die("krb5_auth_con_init: %s", 149 krb5_get_err_text(context, status)); 150 151 status = krb5_auth_con_setaddrs_from_fd (context, 152 auth_context, 153 &sock); 154 if (status) 155 syslog_and_die("krb5_auth_con_setaddr: %s", 156 krb5_get_err_text(context, status)); 157 158 if(gethostname (hostname, sizeof(hostname)) < 0) 159 syslog_and_die("gethostname: %s",strerror(errno)); 160 161 status = krb5_sname_to_principal (context, 162 hostname, 163 service, 164 KRB5_NT_SRV_HST, 165 &server); 166 if (status) 167 syslog_and_die("krb5_sname_to_principal: %s", 168 krb5_get_err_text(context, status)); 169 170 status = krb5_recvauth (context, 171 &auth_context, 172 &sock, 173 VERSION, 174 server, 175 0, 176 NULL, 177 &ticket); 178 if (status) 179 syslog_and_die("krb5_recvauth: %s", 180 krb5_get_err_text(context, status)); 181 182 status = krb5_unparse_name (context, 183 ticket->client, 184 &name); 185 if (status) 186 syslog_and_die("krb5_unparse_name: %s", 187 krb5_get_err_text(context, status)); 188 189 status=krb5_read_message (context, &sock, &remotename); 190 if (status) { 191 syslog_and_die("krb5_read_message: %s", 192 krb5_get_err_text(context, status)); 193 } 194 status=krb5_read_message (context, &sock, &tk_file); 195 if (status) { 196 syslog_and_die("krb5_read_message: %s", 197 krb5_get_err_text(context, status)); 198 } 199 200 krb5_data_zero (&data); 201 krb5_data_zero (&packet); 202 203 n = krb5_net_read (context, &sock, &net_len, 4); 204 if (n < 0) 205 syslog_and_die("krb5_net_read: %s", strerror(errno)); 206 if (n == 0) 207 syslog_and_die("EOF in krb5_net_read"); 208 209 len = ntohl(net_len); 210 krb5_data_alloc (&packet, len); 211 n = krb5_net_read (context, &sock, packet.data, len); 212 if (n < 0) 213 syslog_and_die("krb5_net_read: %s", strerror(errno)); 214 if (n == 0) 215 syslog_and_die("EOF in krb5_net_read"); 216 217 status = krb5_rd_priv (context, 218 auth_context, 219 &packet, 220 &data, 221 NULL); 222 if (status) { 223 syslog_and_cont("krb5_rd_priv: %s", 224 krb5_get_err_text(context, status)); 225 goto out; 226 } 227 228 pwd = getpwnam ((char *)(remotename.data)); 229 if (pwd == NULL) { 230 status=1; 231 syslog_and_cont("getpwnam: %s failed",(char *)(remotename.data)); 232 goto out; 233 } 234 235 if(!krb5_kuserok (context, 236 ticket->client, 237 (char *)(remotename.data))) { 238 status=1; 239 syslog_and_cont("krb5_kuserok: permission denied"); 240 goto out; 241 } 242 243 if (setgid(pwd->pw_gid) < 0) { 244 syslog_and_cont ("setgid: %s", strerror(errno)); 245 goto out; 246 } 247 if (setuid(pwd->pw_uid) < 0) { 248 syslog_and_cont ("setuid: %s", strerror(errno)); 249 goto out; 250 } 251 252 if (tk_file.length != 1) 253 snprintf (ccname, sizeof(ccname), "%s", (char *)(tk_file.data)); 254 else 255 snprintf (ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%u",pwd->pw_uid); 256 257 status = krb5_cc_resolve (context, ccname, &ccache); 258 if (status) { 259 syslog_and_cont("krb5_cc_resolve: %s", 260 krb5_get_err_text(context, status)); 261 goto out; 262 } 263 status = krb5_cc_initialize (context, ccache, ticket->client); 264 if (status) { 265 syslog_and_cont("krb5_cc_initialize: %s", 266 krb5_get_err_text(context, status)); 267 goto out; 268 } 269 status = krb5_rd_cred (context, auth_context, ccache, &data); 270 krb5_cc_close (context, ccache); 271 if (status) { 272 syslog_and_cont("krb5_rd_cred: %s", 273 krb5_get_err_text(context, status)); 274 goto out; 275 276 } 277 strlcpy(krb5_tkfile,ccname,sizeof(krb5_tkfile)); 278 syslog_and_cont("%s forwarded ticket to %s,%s", 279 name, 280 (char *)(remotename.data),ccname); 281 out: 282 if (status) { 283 strcpy(ret_string, "no"); 284 syslog_and_cont("failed"); 285 } else { 286 strcpy(ret_string, "ok"); 287 } 288 289 krb5_data_free (&tk_file); 290 krb5_data_free (&remotename); 291 krb5_data_free (&packet); 292 krb5_data_free (&data); 293 free(name); 294 295 len = strlen(ret_string) + 1; 296 net_len = htonl(len); 297 if (krb5_net_write (context, &sock, &net_len, 4) != 4) 298 return 1; 299 if (krb5_net_write (context, &sock, ret_string, len) != len) 300 return 1; 301 return status; 302 } 303 304 static int 305 doit (int port, const char *service) 306 { 307 if (do_inetd) 308 mini_inetd(port); 309 return proto (STDIN_FILENO, service); 310 } 311 312 int 313 main(int argc, char **argv) 314 { 315 int port; 316 int ret; 317 318 set_progname (argv[0]); 319 roken_openlog (argv[0], LOG_ODELAY | LOG_PID,LOG_AUTH); 320 port = server_setup(&context, argc, argv); 321 ret = doit (port, service); 322 closelog(); 323 if (ret == 0 && regpag_str != NULL) 324 ret = execl(regpag_str, "regpag", "-t", krb5_tkfile, "-r", NULL); 325 return ret; 326 } 327