2 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
35 __RCSID("$Heimdal: kfd.c 15246 2005-05-27 13:47:20Z lha $"
39 char krb5_tkfile
[MAXPATHLEN
];
42 static int version_flag
;
43 static char *port_str
;
44 char *service
= KF_SERVICE
;
46 static char *regpag_str
=NULL
;
48 static struct getargs args
[] = {
49 { "port", 'p', arg_string
, &port_str
, "port to listen to", "port" },
50 { "inetd",'i',arg_flag
, &do_inetd
,
51 "Not started from inetd", NULL
},
52 { "regpag",'R',arg_string
,®pag_str
,"path to regpag binary","regpag"},
53 { "help", 'h', arg_flag
, &help_flag
},
54 { "version", 0, arg_flag
, &version_flag
}
57 static int num_args
= sizeof(args
) / sizeof(args
[0]);
60 usage(int code
, struct getargs
*args
, int num_args
)
62 arg_printusage(args
, num_args
, NULL
, "");
67 server_setup(krb5_context
*context
, int argc
, char **argv
)
72 local_argc
= krb5_program_setup(context
, argc
, argv
, args
, num_args
, usage
);
75 (*usage
)(0, args
, num_args
);
82 struct servent
*s
= roken_getservbyname(port_str
, "tcp");
88 port
= strtol (port_str
, &ptr
, 10);
89 if (port
== 0 && ptr
== port_str
)
90 errx (1, "Bad port `%s'", port_str
);
96 port
= krb5_getportbyname (*context
, KF_PORT_NAME
, "tcp", KF_PORT_NUM
);
98 if(argv
[local_argc
] != NULL
)
99 usage(1, args
, num_args
);
104 static int protocol_version
;
107 kfd_match_version(const void *arg
, const char *version
)
109 if(strcmp(version
, KF_VERSION_1
) == 0) {
110 protocol_version
= 1;
112 } else if (strlen(version
) == 4 &&
115 (version
[2] == '4' || version
[2] == '3') &&
116 islower((unsigned char)version
[3])) {
117 protocol_version
= 0;
124 proto (int sock
, const char *service
)
126 krb5_auth_context auth_context
;
127 krb5_error_code status
;
128 krb5_principal server
;
132 char hostname
[MAXHOSTNAMELEN
];
134 krb5_data remotename
;
137 char ccname
[MAXPATHLEN
];
140 status
= krb5_auth_con_init (context
, &auth_context
);
142 krb5_err(context
, 1, status
, "krb5_auth_con_init");
144 status
= krb5_auth_con_setaddrs_from_fd (context
,
148 krb5_err(context
, 1, status
, "krb5_auth_con_setaddr");
150 if(gethostname (hostname
, sizeof(hostname
)) < 0)
151 krb5_err(context
, 1, errno
, "gethostname");
153 status
= krb5_sname_to_principal (context
,
159 krb5_err(context
, 1, status
, "krb5_sname_to_principal");
161 status
= krb5_recvauth_match_version (context
,
171 krb5_err(context
, 1, status
, "krb5_recvauth");
173 status
= krb5_unparse_name (context
,
177 krb5_err(context
, 1, status
, "krb5_unparse_name");
179 if(protocol_version
== 0) {
180 data
.data
= "old clnt"; /* XXX old clients only had room for
181 10 bytes of message, and also
182 didn't show it to the user */
183 data
.length
= strlen(data
.data
) + 1;
184 krb5_write_message(context
, &sock
, &data
);
185 sleep(2); /* XXX give client time to finish */
186 krb5_errx(context
, 1, "old client; exiting");
189 status
=krb5_read_priv_message (context
, auth_context
,
192 krb5_err(context
, 1, status
, "krb5_read_message");
193 status
=krb5_read_priv_message (context
, auth_context
,
196 krb5_err(context
, 1, status
, "krb5_read_message");
198 krb5_data_zero (&data
);
200 if(((char*)remotename
.data
)[remotename
.length
-1] != '\0')
201 krb5_errx(context
, 1, "unterminated received");
202 if(((char*)tk_file
.data
)[tk_file
.length
-1] != '\0')
203 krb5_errx(context
, 1, "unterminated received");
205 status
= krb5_read_priv_message(context
, auth_context
, &sock
, &data
);
208 krb5_err(context
, 1, errno
, "krb5_read_priv_message");
212 pwd
= getpwnam ((char *)(remotename
.data
));
215 krb5_warnx(context
, "getpwnam: %s failed",(char *)(remotename
.data
));
219 if(!krb5_kuserok (context
,
221 (char *)(remotename
.data
))) {
223 krb5_warnx(context
, "krb5_kuserok: permission denied");
227 if (setgid(pwd
->pw_gid
) < 0) {
228 krb5_warn(context
, errno
, "setgid");
231 if (setuid(pwd
->pw_uid
) < 0) {
232 krb5_warn(context
, errno
, "setuid");
236 if (tk_file
.length
!= 1)
237 snprintf (ccname
, sizeof(ccname
), "%s", (char *)(tk_file
.data
));
239 snprintf (ccname
, sizeof(ccname
), "FILE:/tmp/krb5cc_%lu",
240 (unsigned long)pwd
->pw_uid
);
242 status
= krb5_cc_resolve (context
, ccname
, &ccache
);
244 krb5_warn(context
, status
, "krb5_cc_resolve");
247 status
= krb5_cc_initialize (context
, ccache
, ticket
->client
);
249 krb5_warn(context
, status
, "krb5_cc_initialize");
252 status
= krb5_rd_cred2 (context
, auth_context
, ccache
, &data
);
253 krb5_cc_close (context
, ccache
);
255 krb5_warn(context
, status
, "krb5_rd_cred");
259 strlcpy(krb5_tkfile
,ccname
,sizeof(krb5_tkfile
));
260 krb5_warnx(context
, "%s forwarded ticket to %s,%s",
262 (char *)(remotename
.data
),ccname
);
265 strlcpy(ret_string
, "no", sizeof(ret_string
));
266 krb5_warnx(context
, "failed");
268 strlcpy(ret_string
, "ok", sizeof(ret_string
));
271 krb5_data_free (&tk_file
);
272 krb5_data_free (&remotename
);
273 krb5_data_free (&data
);
276 data
.data
= ret_string
;
277 data
.length
= strlen(ret_string
) + 1;
278 return krb5_write_priv_message(context
, auth_context
, &sock
, &data
);
282 doit (int port
, const char *service
)
286 return proto (STDIN_FILENO
, service
);
290 main(int argc
, char **argv
)
294 krb5_log_facility
*fac
;
296 setprogname (argv
[0]);
297 roken_openlog (argv
[0], LOG_ODELAY
| LOG_PID
,LOG_AUTH
);
298 port
= server_setup(&context
, argc
, argv
);
299 ret
= krb5_openlog(context
, "kfd", &fac
);
300 if(ret
) krb5_err(context
, 1, ret
, "krb5_openlog");
301 ret
= krb5_set_warn_dest(context
, fac
);
302 if(ret
) krb5_err(context
, 1, ret
, "krb5_set_warn_dest");
304 ret
= doit (port
, service
);
306 if (ret
== 0 && regpag_str
!= NULL
)
307 ret
= execl(regpag_str
, "regpag", "-t", krb5_tkfile
, "-r", NULL
);