xref: /freebsd/crypto/heimdal/appl/ftp/ftpd/kauth.c (revision b528cefc6b8f9670b31a865051741d946cb37085)
1b528cefcSMark Murray /*
2b528cefcSMark Murray  * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska H�gskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "ftpd_locl.h"
35b528cefcSMark Murray 
36b528cefcSMark Murray RCSID("$Id: kauth.c,v 1.25 1999/12/02 16:58:31 joda Exp $");
37b528cefcSMark Murray 
38b528cefcSMark Murray static KTEXT_ST cip;
39b528cefcSMark Murray static unsigned int lifetime;
40b528cefcSMark Murray static time_t local_time;
41b528cefcSMark Murray 
42b528cefcSMark Murray static krb_principal pr;
43b528cefcSMark Murray 
44b528cefcSMark Murray static int do_destroy_tickets = 1;
45b528cefcSMark Murray 
46b528cefcSMark Murray static int
47b528cefcSMark Murray save_tkt(const char *user,
48b528cefcSMark Murray 	 const char *instance,
49b528cefcSMark Murray 	 const char *realm,
50b528cefcSMark Murray 	 const void *arg,
51b528cefcSMark Murray 	 key_proc_t key_proc,
52b528cefcSMark Murray 	 KTEXT *cipp)
53b528cefcSMark Murray {
54b528cefcSMark Murray     local_time = time(0);
55b528cefcSMark Murray     memmove(&cip, *cipp, sizeof(cip));
56b528cefcSMark Murray     return -1;
57b528cefcSMark Murray }
58b528cefcSMark Murray 
59b528cefcSMark Murray static int
60b528cefcSMark Murray store_ticket(KTEXT cip)
61b528cefcSMark Murray {
62b528cefcSMark Murray     char *ptr;
63b528cefcSMark Murray     des_cblock session;
64b528cefcSMark Murray     krb_principal sp;
65b528cefcSMark Murray     unsigned char kvno;
66b528cefcSMark Murray     KTEXT_ST tkt;
67b528cefcSMark Murray     int left = cip->length;
68b528cefcSMark Murray     int len;
69b528cefcSMark Murray     int kerror;
70b528cefcSMark Murray 
71b528cefcSMark Murray     ptr = (char *) cip->dat;
72b528cefcSMark Murray 
73b528cefcSMark Murray     /* extract session key */
74b528cefcSMark Murray     memmove(session, ptr, 8);
75b528cefcSMark Murray     ptr += 8;
76b528cefcSMark Murray     left -= 8;
77b528cefcSMark Murray 
78b528cefcSMark Murray     len = strnlen(ptr, left);
79b528cefcSMark Murray     if (len == left)
80b528cefcSMark Murray 	return(INTK_BADPW);
81b528cefcSMark Murray 
82b528cefcSMark Murray     /* extract server's name */
83b528cefcSMark Murray     strlcpy(sp.name, ptr, sizeof(sp.name));
84b528cefcSMark Murray     ptr += len + 1;
85b528cefcSMark Murray     left -= len + 1;
86b528cefcSMark Murray 
87b528cefcSMark Murray     len = strnlen(ptr, left);
88b528cefcSMark Murray     if (len == left)
89b528cefcSMark Murray 	return(INTK_BADPW);
90b528cefcSMark Murray 
91b528cefcSMark Murray     /* extract server's instance */
92b528cefcSMark Murray     strlcpy(sp.instance, ptr, sizeof(sp.instance));
93b528cefcSMark Murray     ptr += len + 1;
94b528cefcSMark Murray     left -= len + 1;
95b528cefcSMark Murray 
96b528cefcSMark Murray     len = strnlen(ptr, left);
97b528cefcSMark Murray     if (len == left)
98b528cefcSMark Murray 	return(INTK_BADPW);
99b528cefcSMark Murray 
100b528cefcSMark Murray     /* extract server's realm */
101b528cefcSMark Murray     strlcpy(sp.realm, ptr, sizeof(sp.realm));
102b528cefcSMark Murray     ptr += len + 1;
103b528cefcSMark Murray     left -= len + 1;
104b528cefcSMark Murray 
105b528cefcSMark Murray     if(left < 3)
106b528cefcSMark Murray 	return INTK_BADPW;
107b528cefcSMark Murray     /* extract ticket lifetime, server key version, ticket length */
108b528cefcSMark Murray     /* be sure to avoid sign extension on lifetime! */
109b528cefcSMark Murray     lifetime = (unsigned char) ptr[0];
110b528cefcSMark Murray     kvno = (unsigned char) ptr[1];
111b528cefcSMark Murray     tkt.length = (unsigned char) ptr[2];
112b528cefcSMark Murray     ptr += 3;
113b528cefcSMark Murray     left -= 3;
114b528cefcSMark Murray 
115b528cefcSMark Murray     if (tkt.length > left)
116b528cefcSMark Murray 	return(INTK_BADPW);
117b528cefcSMark Murray 
118b528cefcSMark Murray     /* extract ticket itself */
119b528cefcSMark Murray     memmove(tkt.dat, ptr, tkt.length);
120b528cefcSMark Murray     ptr += tkt.length;
121b528cefcSMark Murray     left -= tkt.length;
122b528cefcSMark Murray 
123b528cefcSMark Murray     /* Here is where the time should be verified against the KDC.
124b528cefcSMark Murray      * Unfortunately everything is sent in host byte order (receiver
125b528cefcSMark Murray      * makes wrong) , and at this stage there is no way for us to know
126b528cefcSMark Murray      * which byteorder the KDC has. So we simply ignore the time,
127b528cefcSMark Murray      * there are no security risks with this, the only thing that can
128b528cefcSMark Murray      * happen is that we might receive a replayed ticket, which could
129b528cefcSMark Murray      * at most be useless.
130b528cefcSMark Murray      */
131b528cefcSMark Murray 
132b528cefcSMark Murray #if 0
133b528cefcSMark Murray     /* check KDC time stamp */
134b528cefcSMark Murray     {
135b528cefcSMark Murray 	time_t kdc_time;
136b528cefcSMark Murray 
137b528cefcSMark Murray 	memmove(&kdc_time, ptr, sizeof(kdc_time));
138b528cefcSMark Murray 	if (swap_bytes) swap_u_long(kdc_time);
139b528cefcSMark Murray 
140b528cefcSMark Murray 	ptr += 4;
141b528cefcSMark Murray 
142b528cefcSMark Murray 	if (abs((int)(local_time - kdc_time)) > CLOCK_SKEW) {
143b528cefcSMark Murray 	    return(RD_AP_TIME);		/* XXX should probably be better
144b528cefcSMark Murray 					   code */
145b528cefcSMark Murray 	}
146b528cefcSMark Murray     }
147b528cefcSMark Murray #endif
148b528cefcSMark Murray 
149b528cefcSMark Murray     /* initialize ticket cache */
150b528cefcSMark Murray 
151b528cefcSMark Murray     if (tf_create(TKT_FILE) != KSUCCESS)
152b528cefcSMark Murray 	return(INTK_ERR);
153b528cefcSMark Murray 
154b528cefcSMark Murray     if (tf_put_pname(pr.name) != KSUCCESS ||
155b528cefcSMark Murray 	tf_put_pinst(pr.instance) != KSUCCESS) {
156b528cefcSMark Murray 	tf_close();
157b528cefcSMark Murray 	return(INTK_ERR);
158b528cefcSMark Murray     }
159b528cefcSMark Murray 
160b528cefcSMark Murray 
161b528cefcSMark Murray     kerror = tf_save_cred(sp.name, sp.instance, sp.realm, session,
162b528cefcSMark Murray 			  lifetime, kvno, &tkt, local_time);
163b528cefcSMark Murray     tf_close();
164b528cefcSMark Murray 
165b528cefcSMark Murray     return(kerror);
166b528cefcSMark Murray }
167b528cefcSMark Murray 
168b528cefcSMark Murray void
169b528cefcSMark Murray kauth(char *principal, char *ticket)
170b528cefcSMark Murray {
171b528cefcSMark Murray     char *p;
172b528cefcSMark Murray     int ret;
173b528cefcSMark Murray 
174b528cefcSMark Murray     if(get_command_prot() != prot_private) {
175b528cefcSMark Murray 	reply(500, "Request denied (bad protection level)");
176b528cefcSMark Murray 	return;
177b528cefcSMark Murray     }
178b528cefcSMark Murray     ret = krb_parse_name(principal, &pr);
179b528cefcSMark Murray     if(ret){
180b528cefcSMark Murray 	reply(500, "Bad principal: %s.", krb_get_err_text(ret));
181b528cefcSMark Murray 	return;
182b528cefcSMark Murray     }
183b528cefcSMark Murray     if(pr.realm[0] == 0)
184b528cefcSMark Murray 	krb_get_lrealm(pr.realm, 1);
185b528cefcSMark Murray 
186b528cefcSMark Murray     if(ticket){
187b528cefcSMark Murray 	cip.length = base64_decode(ticket, &cip.dat);
188b528cefcSMark Murray 	if(cip.length == -1){
189b528cefcSMark Murray 	    reply(500, "Failed to decode data.");
190b528cefcSMark Murray 	    return;
191b528cefcSMark Murray 	}
192b528cefcSMark Murray 	ret = store_ticket(&cip);
193b528cefcSMark Murray 	if(ret){
194b528cefcSMark Murray 	    reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
195b528cefcSMark Murray 	    memset(&cip, 0, sizeof(cip));
196b528cefcSMark Murray 	    return;
197b528cefcSMark Murray 	}
198b528cefcSMark Murray 	do_destroy_tickets = 1;
199b528cefcSMark Murray 
200b528cefcSMark Murray 	if(k_hasafs())
201b528cefcSMark Murray 	    krb_afslog(0, 0);
202b528cefcSMark Murray 	reply(200, "Tickets will be destroyed on exit.");
203b528cefcSMark Murray 	return;
204b528cefcSMark Murray     }
205b528cefcSMark Murray 
206b528cefcSMark Murray     ret = krb_get_in_tkt (pr.name,
207b528cefcSMark Murray 			  pr.instance,
208b528cefcSMark Murray 			  pr.realm,
209b528cefcSMark Murray 			  KRB_TICKET_GRANTING_TICKET,
210b528cefcSMark Murray 			  pr.realm,
211b528cefcSMark Murray 			  DEFAULT_TKT_LIFE,
212b528cefcSMark Murray 			  NULL, save_tkt, NULL);
213b528cefcSMark Murray     if(ret != INTK_BADPW){
214b528cefcSMark Murray 	reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
215b528cefcSMark Murray 	return;
216b528cefcSMark Murray     }
217b528cefcSMark Murray     if(base64_encode(cip.dat, cip.length, &p) < 0) {
218b528cefcSMark Murray 	reply(500, "Out of memory while base64-encoding.");
219b528cefcSMark Murray 	return;
220b528cefcSMark Murray     }
221b528cefcSMark Murray     reply(300, "P=%s T=%s", krb_unparse_name(&pr), p);
222b528cefcSMark Murray     free(p);
223b528cefcSMark Murray     memset(&cip, 0, sizeof(cip));
224b528cefcSMark Murray }
225b528cefcSMark Murray 
226b528cefcSMark Murray 
227b528cefcSMark Murray static char *
228b528cefcSMark Murray short_date(int32_t dp)
229b528cefcSMark Murray {
230b528cefcSMark Murray     char *cp;
231b528cefcSMark Murray     time_t t = (time_t)dp;
232b528cefcSMark Murray 
233b528cefcSMark Murray     if (t == (time_t)(-1L)) return "***  Never  *** ";
234b528cefcSMark Murray     cp = ctime(&t) + 4;
235b528cefcSMark Murray     cp[15] = '\0';
236b528cefcSMark Murray     return (cp);
237b528cefcSMark Murray }
238b528cefcSMark Murray 
239b528cefcSMark Murray void
240b528cefcSMark Murray klist(void)
241b528cefcSMark Murray {
242b528cefcSMark Murray     int err;
243b528cefcSMark Murray 
244b528cefcSMark Murray     char *file = tkt_string();
245b528cefcSMark Murray 
246b528cefcSMark Murray     krb_principal pr;
247b528cefcSMark Murray 
248b528cefcSMark Murray     char buf1[128], buf2[128];
249b528cefcSMark Murray     int header = 1;
250b528cefcSMark Murray     CREDENTIALS c;
251b528cefcSMark Murray 
252b528cefcSMark Murray 
253b528cefcSMark Murray 
254b528cefcSMark Murray     err = tf_init(file, R_TKT_FIL);
255b528cefcSMark Murray     if(err != KSUCCESS){
256b528cefcSMark Murray 	reply(500, "%s", krb_get_err_text(err));
257b528cefcSMark Murray 	return;
258b528cefcSMark Murray     }
259b528cefcSMark Murray     tf_close();
260b528cefcSMark Murray 
261b528cefcSMark Murray     /*
262b528cefcSMark Murray      * We must find the realm of the ticket file here before calling
263b528cefcSMark Murray      * tf_init because since the realm of the ticket file is not
264b528cefcSMark Murray      * really stored in the principal section of the file, the
265b528cefcSMark Murray      * routine we use must itself call tf_init and tf_close.
266b528cefcSMark Murray      */
267b528cefcSMark Murray     err = krb_get_tf_realm(file, pr.realm);
268b528cefcSMark Murray     if(err != KSUCCESS){
269b528cefcSMark Murray 	reply(500, "%s", krb_get_err_text(err));
270b528cefcSMark Murray 	return;
271b528cefcSMark Murray     }
272b528cefcSMark Murray 
273b528cefcSMark Murray     err = tf_init(file, R_TKT_FIL);
274b528cefcSMark Murray     if(err != KSUCCESS){
275b528cefcSMark Murray 	reply(500, "%s", krb_get_err_text(err));
276b528cefcSMark Murray 	return;
277b528cefcSMark Murray     }
278b528cefcSMark Murray 
279b528cefcSMark Murray     err = tf_get_pname(pr.name);
280b528cefcSMark Murray     if(err != KSUCCESS){
281b528cefcSMark Murray 	reply(500, "%s", krb_get_err_text(err));
282b528cefcSMark Murray 	return;
283b528cefcSMark Murray     }
284b528cefcSMark Murray     err = tf_get_pinst(pr.instance);
285b528cefcSMark Murray     if(err != KSUCCESS){
286b528cefcSMark Murray 	reply(500, "%s", krb_get_err_text(err));
287b528cefcSMark Murray 	return;
288b528cefcSMark Murray     }
289b528cefcSMark Murray 
290b528cefcSMark Murray     /*
291b528cefcSMark Murray      * You may think that this is the obvious place to get the
292b528cefcSMark Murray      * realm of the ticket file, but it can't be done here as the
293b528cefcSMark Murray      * routine to do this must open the ticket file.  This is why
294b528cefcSMark Murray      * it was done before tf_init.
295b528cefcSMark Murray      */
296b528cefcSMark Murray 
297b528cefcSMark Murray     lreply(200, "Ticket file: %s", tkt_string());
298b528cefcSMark Murray 
299b528cefcSMark Murray     lreply(200, "Principal: %s", krb_unparse_name(&pr));
300b528cefcSMark Murray     while ((err = tf_get_cred(&c)) == KSUCCESS) {
301b528cefcSMark Murray 	if (header) {
302b528cefcSMark Murray 	    lreply(200, "%-15s  %-15s  %s",
303b528cefcSMark Murray 		   "  Issued", "  Expires", "  Principal (kvno)");
304b528cefcSMark Murray 	    header = 0;
305b528cefcSMark Murray 	}
306b528cefcSMark Murray 	strlcpy(buf1, short_date(c.issue_date), sizeof(buf1));
307b528cefcSMark Murray 	c.issue_date = krb_life_to_time(c.issue_date, c.lifetime);
308b528cefcSMark Murray 	if (time(0) < (unsigned long) c.issue_date)
309b528cefcSMark Murray 	    strlcpy(buf2, short_date(c.issue_date), sizeof(buf2));
310b528cefcSMark Murray 	else
311b528cefcSMark Murray 	    strlcpy(buf2, ">>> Expired <<< ", sizeof(buf2));
312b528cefcSMark Murray 	lreply(200, "%s  %s  %s (%d)", buf1, buf2,
313b528cefcSMark Murray 	       krb_unparse_name_long(c.service, c.instance, c.realm), c.kvno);
314b528cefcSMark Murray     }
315b528cefcSMark Murray     if (header && err == EOF) {
316b528cefcSMark Murray 	lreply(200, "No tickets in file.");
317b528cefcSMark Murray     }
318b528cefcSMark Murray     reply(200, " ");
319b528cefcSMark Murray }
320b528cefcSMark Murray 
321b528cefcSMark Murray /*
322b528cefcSMark Murray  * Only destroy if we created the tickets
323b528cefcSMark Murray  */
324b528cefcSMark Murray 
325b528cefcSMark Murray void
326b528cefcSMark Murray cond_kdestroy(void)
327b528cefcSMark Murray {
328b528cefcSMark Murray     if (do_destroy_tickets)
329b528cefcSMark Murray 	dest_tkt();
330b528cefcSMark Murray     afsunlog();
331b528cefcSMark Murray }
332b528cefcSMark Murray 
333b528cefcSMark Murray void
334b528cefcSMark Murray kdestroy(void)
335b528cefcSMark Murray {
336b528cefcSMark Murray     dest_tkt();
337b528cefcSMark Murray     afsunlog();
338b528cefcSMark Murray     reply(200, "Tickets destroyed");
339b528cefcSMark Murray }
340b528cefcSMark Murray 
341b528cefcSMark Murray void
342b528cefcSMark Murray krbtkfile(const char *tkfile)
343b528cefcSMark Murray {
344b528cefcSMark Murray     do_destroy_tickets = 0;
345b528cefcSMark Murray     krb_set_tkt_string(tkfile);
346b528cefcSMark Murray     reply(200, "Using ticket file %s", tkfile);
347b528cefcSMark Murray }
348b528cefcSMark Murray 
349b528cefcSMark Murray void
350b528cefcSMark Murray afslog(const char *cell)
351b528cefcSMark Murray {
352b528cefcSMark Murray     if(k_hasafs()) {
353b528cefcSMark Murray 	krb_afslog(cell, 0);
354b528cefcSMark Murray 	reply(200, "afslog done");
355b528cefcSMark Murray     } else {
356b528cefcSMark Murray 	reply(200, "no AFS present");
357b528cefcSMark Murray     }
358b528cefcSMark Murray }
359b528cefcSMark Murray 
360b528cefcSMark Murray void
361b528cefcSMark Murray afsunlog(void)
362b528cefcSMark Murray {
363b528cefcSMark Murray     if(k_hasafs())
364b528cefcSMark Murray 	k_unlog();
365b528cefcSMark Murray }
366