2 * Copyright (c) 1995, 1996, 1997, 1998 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
34 #include "ftpd_locl.h"
36 RCSID("$Id: kauth.c,v 1.25 1999/12/02 16:58:31 joda Exp $");
39 static unsigned int lifetime
;
40 static time_t local_time
;
42 static krb_principal pr
;
44 static int do_destroy_tickets
= 1;
47 save_tkt(const char *user
,
55 memmove(&cip
, *cipp
, sizeof(cip
));
60 store_ticket(KTEXT cip
)
67 int left
= cip
->length
;
71 ptr
= (char *) cip
->dat
;
73 /* extract session key */
74 memmove(session
, ptr
, 8);
78 len
= strnlen(ptr
, left
);
82 /* extract server's name */
83 strlcpy(sp
.name
, ptr
, sizeof(sp
.name
));
87 len
= strnlen(ptr
, left
);
91 /* extract server's instance */
92 strlcpy(sp
.instance
, ptr
, sizeof(sp
.instance
));
96 len
= strnlen(ptr
, left
);
100 /* extract server's realm */
101 strlcpy(sp
.realm
, ptr
, sizeof(sp
.realm
));
107 /* extract ticket lifetime, server key version, ticket length */
108 /* be sure to avoid sign extension on lifetime! */
109 lifetime
= (unsigned char) ptr
[0];
110 kvno
= (unsigned char) ptr
[1];
111 tkt
.length
= (unsigned char) ptr
[2];
115 if (tkt
.length
> left
)
118 /* extract ticket itself */
119 memmove(tkt
.dat
, ptr
, tkt
.length
);
123 /* Here is where the time should be verified against the KDC.
124 * Unfortunately everything is sent in host byte order (receiver
125 * makes wrong) , and at this stage there is no way for us to know
126 * which byteorder the KDC has. So we simply ignore the time,
127 * there are no security risks with this, the only thing that can
128 * happen is that we might receive a replayed ticket, which could
129 * at most be useless.
133 /* check KDC time stamp */
137 memmove(&kdc_time
, ptr
, sizeof(kdc_time
));
138 if (swap_bytes
) swap_u_long(kdc_time
);
142 if (abs((int)(local_time
- kdc_time
)) > CLOCK_SKEW
) {
143 return(RD_AP_TIME
); /* XXX should probably be better
149 /* initialize ticket cache */
151 if (tf_create(TKT_FILE
) != KSUCCESS
)
154 if (tf_put_pname(pr
.name
) != KSUCCESS
||
155 tf_put_pinst(pr
.instance
) != KSUCCESS
) {
161 kerror
= tf_save_cred(sp
.name
, sp
.instance
, sp
.realm
, session
,
162 lifetime
, kvno
, &tkt
, local_time
);
169 kauth(char *principal
, char *ticket
)
174 if(get_command_prot() != prot_private
) {
175 reply(500, "Request denied (bad protection level)");
178 ret
= krb_parse_name(principal
, &pr
);
180 reply(500, "Bad principal: %s.", krb_get_err_text(ret
));
184 krb_get_lrealm(pr
.realm
, 1);
187 cip
.length
= base64_decode(ticket
, &cip
.dat
);
188 if(cip
.length
== -1){
189 reply(500, "Failed to decode data.");
192 ret
= store_ticket(&cip
);
194 reply(500, "Kerberos error: %s.", krb_get_err_text(ret
));
195 memset(&cip
, 0, sizeof(cip
));
198 do_destroy_tickets
= 1;
202 reply(200, "Tickets will be destroyed on exit.");
206 ret
= krb_get_in_tkt (pr
.name
,
209 KRB_TICKET_GRANTING_TICKET
,
212 NULL
, save_tkt
, NULL
);
213 if(ret
!= INTK_BADPW
){
214 reply(500, "Kerberos error: %s.", krb_get_err_text(ret
));
217 if(base64_encode(cip
.dat
, cip
.length
, &p
) < 0) {
218 reply(500, "Out of memory while base64-encoding.");
221 reply(300, "P=%s T=%s", krb_unparse_name(&pr
), p
);
223 memset(&cip
, 0, sizeof(cip
));
228 short_date(int32_t dp
)
231 time_t t
= (time_t)dp
;
233 if (t
== (time_t)(-1L)) return "*** Never *** ";
244 char *file
= tkt_string();
248 char buf1
[128], buf2
[128];
254 err
= tf_init(file
, R_TKT_FIL
);
256 reply(500, "%s", krb_get_err_text(err
));
262 * We must find the realm of the ticket file here before calling
263 * tf_init because since the realm of the ticket file is not
264 * really stored in the principal section of the file, the
265 * routine we use must itself call tf_init and tf_close.
267 err
= krb_get_tf_realm(file
, pr
.realm
);
269 reply(500, "%s", krb_get_err_text(err
));
273 err
= tf_init(file
, R_TKT_FIL
);
275 reply(500, "%s", krb_get_err_text(err
));
279 err
= tf_get_pname(pr
.name
);
281 reply(500, "%s", krb_get_err_text(err
));
284 err
= tf_get_pinst(pr
.instance
);
286 reply(500, "%s", krb_get_err_text(err
));
291 * You may think that this is the obvious place to get the
292 * realm of the ticket file, but it can't be done here as the
293 * routine to do this must open the ticket file. This is why
294 * it was done before tf_init.
297 lreply(200, "Ticket file: %s", tkt_string());
299 lreply(200, "Principal: %s", krb_unparse_name(&pr
));
300 while ((err
= tf_get_cred(&c
)) == KSUCCESS
) {
302 lreply(200, "%-15s %-15s %s",
303 " Issued", " Expires", " Principal (kvno)");
306 strlcpy(buf1
, short_date(c
.issue_date
), sizeof(buf1
));
307 c
.issue_date
= krb_life_to_time(c
.issue_date
, c
.lifetime
);
308 if (time(0) < (unsigned long) c
.issue_date
)
309 strlcpy(buf2
, short_date(c
.issue_date
), sizeof(buf2
));
311 strlcpy(buf2
, ">>> Expired <<< ", sizeof(buf2
));
312 lreply(200, "%s %s %s (%d)", buf1
, buf2
,
313 krb_unparse_name_long(c
.service
, c
.instance
, c
.realm
), c
.kvno
);
315 if (header
&& err
== EOF
) {
316 lreply(200, "No tickets in file.");
322 * Only destroy if we created the tickets
328 if (do_destroy_tickets
)
338 reply(200, "Tickets destroyed");
342 krbtkfile(const char *tkfile
)
344 do_destroy_tickets
= 0;
345 krb_set_tkt_string(tkfile
);
346 reply(200, "Using ticket file %s", tkfile
);
350 afslog(const char *cell
)
354 reply(200, "afslog done");
356 reply(200, "no AFS present");