No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / appl / kf / kfd.c
blobc6c4250f67ef7bb582c0fb151dc0044fb03de638
1 /*
2 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
31 * SUCH DAMAGE.
34 #include "kf_locl.h"
35 __RCSID("$Heimdal: kfd.c 15246 2005-05-27 13:47:20Z lha $"
36 "$NetBSD$");
38 krb5_context context;
39 char krb5_tkfile[MAXPATHLEN];
41 static int help_flag;
42 static int version_flag;
43 static char *port_str;
44 char *service = KF_SERVICE;
45 int do_inetd = 0;
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,&regpag_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]);
59 static void
60 usage(int code, struct getargs *args, int num_args)
62 arg_printusage(args, num_args, NULL, "");
63 exit(code);
66 static int
67 server_setup(krb5_context *context, int argc, char **argv)
69 int port = 0;
70 int local_argc;
72 local_argc = krb5_program_setup(context, argc, argv, args, num_args, usage);
74 if(help_flag)
75 (*usage)(0, args, num_args);
76 if(version_flag) {
77 print_version(NULL);
78 exit(0);
81 if(port_str){
82 struct servent *s = roken_getservbyname(port_str, "tcp");
83 if(s)
84 port = s->s_port;
85 else {
86 char *ptr;
88 port = strtol (port_str, &ptr, 10);
89 if (port == 0 && ptr == port_str)
90 errx (1, "Bad port `%s'", port_str);
91 port = htons(port);
95 if (port == 0)
96 port = krb5_getportbyname (*context, KF_PORT_NAME, "tcp", KF_PORT_NUM);
98 if(argv[local_argc] != NULL)
99 usage(1, args, num_args);
101 return port;
104 static int protocol_version;
106 static krb5_boolean
107 kfd_match_version(const void *arg, const char *version)
109 if(strcmp(version, KF_VERSION_1) == 0) {
110 protocol_version = 1;
111 return TRUE;
112 } else if (strlen(version) == 4 &&
113 version[0] == '0' &&
114 version[1] == '.' &&
115 (version[2] == '4' || version[2] == '3') &&
116 islower((unsigned char)version[3])) {
117 protocol_version = 0;
118 return TRUE;
120 return FALSE;
123 static int
124 proto (int sock, const char *service)
126 krb5_auth_context auth_context;
127 krb5_error_code status;
128 krb5_principal server;
129 krb5_ticket *ticket;
130 char *name;
131 char ret_string[10];
132 char hostname[MAXHOSTNAMELEN];
133 krb5_data data;
134 krb5_data remotename;
135 krb5_data tk_file;
136 krb5_ccache ccache;
137 char ccname[MAXPATHLEN];
138 struct passwd *pwd;
140 status = krb5_auth_con_init (context, &auth_context);
141 if (status)
142 krb5_err(context, 1, status, "krb5_auth_con_init");
144 status = krb5_auth_con_setaddrs_from_fd (context,
145 auth_context,
146 &sock);
147 if (status)
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,
154 hostname,
155 service,
156 KRB5_NT_SRV_HST,
157 &server);
158 if (status)
159 krb5_err(context, 1, status, "krb5_sname_to_principal");
161 status = krb5_recvauth_match_version (context,
162 &auth_context,
163 &sock,
164 kfd_match_version,
165 NULL,
166 server,
168 NULL,
169 &ticket);
170 if (status)
171 krb5_err(context, 1, status, "krb5_recvauth");
173 status = krb5_unparse_name (context,
174 ticket->client,
175 &name);
176 if (status)
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,
190 &sock, &remotename);
191 if (status)
192 krb5_err(context, 1, status, "krb5_read_message");
193 status=krb5_read_priv_message (context, auth_context,
194 &sock, &tk_file);
195 if (status)
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);
207 if (status) {
208 krb5_err(context, 1, errno, "krb5_read_priv_message");
209 goto out;
212 pwd = getpwnam ((char *)(remotename.data));
213 if (pwd == NULL) {
214 status=1;
215 krb5_warnx(context, "getpwnam: %s failed",(char *)(remotename.data));
216 goto out;
219 if(!krb5_kuserok (context,
220 ticket->client,
221 (char *)(remotename.data))) {
222 status=1;
223 krb5_warnx(context, "krb5_kuserok: permission denied");
224 goto out;
227 if (setgid(pwd->pw_gid) < 0) {
228 krb5_warn(context, errno, "setgid");
229 goto out;
231 if (setuid(pwd->pw_uid) < 0) {
232 krb5_warn(context, errno, "setuid");
233 goto out;
236 if (tk_file.length != 1)
237 snprintf (ccname, sizeof(ccname), "%s", (char *)(tk_file.data));
238 else
239 snprintf (ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%lu",
240 (unsigned long)pwd->pw_uid);
242 status = krb5_cc_resolve (context, ccname, &ccache);
243 if (status) {
244 krb5_warn(context, status, "krb5_cc_resolve");
245 goto out;
247 status = krb5_cc_initialize (context, ccache, ticket->client);
248 if (status) {
249 krb5_warn(context, status, "krb5_cc_initialize");
250 goto out;
252 status = krb5_rd_cred2 (context, auth_context, ccache, &data);
253 krb5_cc_close (context, ccache);
254 if (status) {
255 krb5_warn(context, status, "krb5_rd_cred");
256 goto out;
259 strlcpy(krb5_tkfile,ccname,sizeof(krb5_tkfile));
260 krb5_warnx(context, "%s forwarded ticket to %s,%s",
261 name,
262 (char *)(remotename.data),ccname);
263 out:
264 if (status) {
265 strlcpy(ret_string, "no", sizeof(ret_string));
266 krb5_warnx(context, "failed");
267 } else {
268 strlcpy(ret_string, "ok", sizeof(ret_string));
271 krb5_data_free (&tk_file);
272 krb5_data_free (&remotename);
273 krb5_data_free (&data);
274 free(name);
276 data.data = ret_string;
277 data.length = strlen(ret_string) + 1;
278 return krb5_write_priv_message(context, auth_context, &sock, &data);
281 static int
282 doit (int port, const char *service)
284 if (do_inetd)
285 mini_inetd(port);
286 return proto (STDIN_FILENO, service);
290 main(int argc, char **argv)
292 int port;
293 int ret;
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);
305 closelog();
306 if (ret == 0 && regpag_str != NULL)
307 ret = execl(regpag_str, "regpag", "-t", krb5_tkfile, "-r", NULL);
308 return ret;