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
38 char krb5_tkfile
[MAXPATHLEN
];
41 static int version_flag
;
42 static char *port_str
;
43 char *service
= KF_SERVICE
;
45 static char *regpag_str
=NULL
;
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
}
56 static int num_args
= sizeof(args
) / sizeof(args
[0]);
59 usage(int code
, struct getargs
*args
, int num_args
)
61 arg_printusage(args
, num_args
, NULL
, "");
66 server_setup(krb5_context
*context
, int argc
, char **argv
)
71 local_argc
= krb5_program_setup(context
, argc
, argv
, args
, num_args
, usage
);
74 (*usage
)(0, args
, num_args
);
81 struct servent
*s
= roken_getservbyname(port_str
, "tcp");
87 port
= strtol (port_str
, &ptr
, 10);
88 if (port
== 0 && ptr
== port_str
)
89 errx (1, "Bad port `%s'", port_str
);
95 port
= krb5_getportbyname (*context
, KF_PORT_NAME
, "tcp", KF_PORT_NUM
);
97 if(argv
[local_argc
] != NULL
)
98 usage(1, args
, num_args
);
103 static int protocol_version
;
106 kfd_match_version(const void *arg
, const char *version
)
108 if(strcmp(version
, KF_VERSION_1
) == 0) {
109 protocol_version
= 1;
111 } else if (strlen(version
) == 4 &&
114 (version
[2] == '4' || version
[2] == '3') &&
115 islower((unsigned char)version
[3])) {
116 protocol_version
= 0;
123 proto (int sock
, const char *service
)
125 krb5_auth_context auth_context
;
126 krb5_error_code status
;
127 krb5_principal server
;
131 char hostname
[MAXHOSTNAMELEN
];
133 krb5_data remotename
;
136 char ccname
[MAXPATHLEN
];
139 status
= krb5_auth_con_init (context
, &auth_context
);
141 krb5_err(context
, 1, status
, "krb5_auth_con_init");
143 status
= krb5_auth_con_setaddrs_from_fd (context
,
147 krb5_err(context
, 1, status
, "krb5_auth_con_setaddr");
149 if(gethostname (hostname
, sizeof(hostname
)) < 0)
150 krb5_err(context
, 1, errno
, "gethostname");
152 status
= krb5_sname_to_principal (context
,
158 krb5_err(context
, 1, status
, "krb5_sname_to_principal");
160 status
= krb5_recvauth_match_version (context
,
170 krb5_err(context
, 1, status
, "krb5_recvauth");
172 status
= krb5_unparse_name (context
,
176 krb5_err(context
, 1, status
, "krb5_unparse_name");
178 if(protocol_version
== 0) {
179 data
.data
= "old clnt"; /* XXX old clients only had room for
180 10 bytes of message, and also
181 didn't show it to the user */
182 data
.length
= strlen(data
.data
) + 1;
183 krb5_write_message(context
, &sock
, &data
);
184 sleep(2); /* XXX give client time to finish */
185 krb5_errx(context
, 1, "old client; exiting");
188 status
=krb5_read_priv_message (context
, auth_context
,
191 krb5_err(context
, 1, status
, "krb5_read_message");
192 status
=krb5_read_priv_message (context
, auth_context
,
195 krb5_err(context
, 1, status
, "krb5_read_message");
197 krb5_data_zero (&data
);
199 if(((char*)remotename
.data
)[remotename
.length
-1] != '\0')
200 krb5_errx(context
, 1, "unterminated received");
201 if(((char*)tk_file
.data
)[tk_file
.length
-1] != '\0')
202 krb5_errx(context
, 1, "unterminated received");
204 status
= krb5_read_priv_message(context
, auth_context
, &sock
, &data
);
207 krb5_err(context
, 1, errno
, "krb5_read_priv_message");
211 pwd
= getpwnam ((char *)(remotename
.data
));
214 krb5_warnx(context
, "getpwnam: %s failed",(char *)(remotename
.data
));
218 if(!krb5_kuserok (context
,
220 (char *)(remotename
.data
))) {
222 krb5_warnx(context
, "krb5_kuserok: permission denied");
226 if (setgid(pwd
->pw_gid
) < 0) {
227 krb5_warn(context
, errno
, "setgid");
230 if (setuid(pwd
->pw_uid
) < 0) {
231 krb5_warn(context
, errno
, "setuid");
235 if (tk_file
.length
!= 1)
236 snprintf (ccname
, sizeof(ccname
), "%s", (char *)(tk_file
.data
));
238 snprintf (ccname
, sizeof(ccname
), "FILE:/tmp/krb5cc_%lu",
239 (unsigned long)pwd
->pw_uid
);
241 status
= krb5_cc_resolve (context
, ccname
, &ccache
);
243 krb5_warn(context
, status
, "krb5_cc_resolve");
246 status
= krb5_cc_initialize (context
, ccache
, ticket
->client
);
248 krb5_warn(context
, status
, "krb5_cc_initialize");
251 status
= krb5_rd_cred2 (context
, auth_context
, ccache
, &data
);
252 krb5_cc_close (context
, ccache
);
254 krb5_warn(context
, status
, "krb5_rd_cred");
258 strlcpy(krb5_tkfile
,ccname
,sizeof(krb5_tkfile
));
259 krb5_warnx(context
, "%s forwarded ticket to %s,%s",
261 (char *)(remotename
.data
),ccname
);
264 strlcpy(ret_string
, "no", sizeof(ret_string
));
265 krb5_warnx(context
, "failed");
267 strlcpy(ret_string
, "ok", sizeof(ret_string
));
270 krb5_data_free (&tk_file
);
271 krb5_data_free (&remotename
);
272 krb5_data_free (&data
);
275 data
.data
= ret_string
;
276 data
.length
= strlen(ret_string
) + 1;
277 return krb5_write_priv_message(context
, auth_context
, &sock
, &data
);
281 doit (int port
, const char *service
)
285 return proto (STDIN_FILENO
, service
);
289 main(int argc
, char **argv
)
293 krb5_log_facility
*fac
;
295 setprogname (argv
[0]);
296 roken_openlog (argv
[0], LOG_ODELAY
| LOG_PID
,LOG_AUTH
);
297 port
= server_setup(&context
, argc
, argv
);
298 ret
= krb5_openlog(context
, "kfd", &fac
);
299 if(ret
) krb5_err(context
, 1, ret
, "krb5_openlog");
300 ret
= krb5_set_warn_dest(context
, fac
);
301 if(ret
) krb5_err(context
, 1, ret
, "krb5_set_warn_dest");
303 ret
= doit (port
, service
);
305 if (ret
== 0 && regpag_str
!= NULL
)
306 ret
= execl(regpag_str
, "regpag", "-t", krb5_tkfile
, "-r", NULL
);