check for innetgr
[heimdal.git] / appl / ftp / ftpd / kauth.c
blob9c1c9e26eb3b49a2c82fb793a251dedf35e46f1d
1 /*
2 * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
43 RCSID("$Id$");
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
49 #include <time.h>
50 #ifdef HAVE_SYS_TIME_H
51 #include <sys/time.h>
52 #endif
53 #ifdef HAVE_SYS_TYPES_H
54 #include <sys/types.h>
55 #endif
57 #include <roken.h>
59 #include <des.h>
60 #include <krb.h>
61 #include <kafs.h>
63 #include "extern.h"
64 #include "krb4.h"
65 #include "auth.h"
66 #include "base64.h"
68 static KTEXT_ST cip;
69 static unsigned int lifetime;
70 static time_t local_time;
72 static krb_principal pr;
74 static int do_destroy_tickets = 1;
76 static int
77 save_tkt(char *user, char *instance, char *realm, void *arg,
78 int (*key_proc)(char*, char*, char*, void*, des_cblock*), KTEXT *cipp)
80 local_time = time(0);
81 memmove(&cip, *cipp, sizeof(cip));
82 return -1;
85 static int
86 store_ticket(KTEXT cip)
88 char *ptr;
89 des_cblock session;
90 krb_principal sp;
91 unsigned char kvno;
92 KTEXT_ST tkt;
93 int left = cip->length;
95 int kerror;
97 time_t kdc_time;
99 ptr = (char *) cip->dat;
101 /* extract session key */
102 memmove(session, ptr, 8);
103 ptr += 8;
104 left -= 8;
106 if (strnlen(ptr, left) == left)
107 return(INTK_BADPW);
109 /* extract server's name */
110 strcpy(sp.name, ptr);
111 ptr += strlen(sp.name) + 1;
112 left -= strlen(sp.name) + 1;
114 if (strnlen(ptr, left) == left)
115 return(INTK_BADPW);
117 /* extract server's instance */
118 strcpy(sp.instance, ptr);
119 ptr += strlen(sp.instance) + 1;
120 left -= strlen(sp.instance) + 1;
122 if (strnlen(ptr, left) == left)
123 return(INTK_BADPW);
125 /* extract server's realm */
126 strcpy(sp.realm,ptr);
127 ptr += strlen(sp.realm) + 1;
128 left -= strlen(sp.realm) + 1;
130 if(left < 3)
131 return INTK_BADPW;
132 /* extract ticket lifetime, server key version, ticket length */
133 /* be sure to avoid sign extension on lifetime! */
134 lifetime = (unsigned char) ptr[0];
135 kvno = (unsigned char) ptr[1];
136 tkt.length = (unsigned char) ptr[2];
137 ptr += 3;
138 left -= 3;
140 if (tkt.length > left)
141 return(INTK_BADPW);
143 /* extract ticket itself */
144 memmove(tkt.dat, ptr, tkt.length);
145 ptr += tkt.length;
146 left -= tkt.length;
148 /* Here is where the time should be verified against the KDC.
149 * Unfortunately everything is sent in host byte order (receiver
150 * makes wrong) , and at this stage there is no way for us to know
151 * which byteorder the KDC has. So we simply ignore the time,
152 * there are no security risks with this, the only thing that can
153 * happen is that we might receive a replayed ticket, which could
154 * at most be useless.
157 #if 0
158 /* check KDC time stamp */
159 memmove(&kdc_time, ptr, sizeof(kdc_time));
160 if (swap_bytes) swap_u_long(kdc_time);
162 ptr += 4;
164 if (abs((int)(local_time - kdc_time)) > CLOCK_SKEW) {
165 return(RD_AP_TIME); /* XXX should probably be better
166 code */
168 #endif
170 /* initialize ticket cache */
172 if (tf_create(TKT_FILE) != KSUCCESS)
173 return(INTK_ERR);
175 if (tf_put_pname(pr.name) != KSUCCESS ||
176 tf_put_pinst(pr.instance) != KSUCCESS) {
177 tf_close();
178 return(INTK_ERR);
182 kerror = tf_save_cred(sp.name, sp.instance, sp.realm, session,
183 lifetime, kvno, &tkt, local_time);
184 tf_close();
186 return(kerror);
189 void
190 kauth(char *principal, char *ticket)
192 char *p;
193 int ret;
195 ret = krb_parse_name(principal, &pr);
196 if(ret){
197 reply(500, "Bad principal: %s.", krb_get_err_text(ret));
198 return;
200 if(pr.realm[0] == 0)
201 krb_get_lrealm(pr.realm, 1);
203 if(ticket){
204 cip.length = base64_decode(ticket, &cip.dat);
205 if(cip.length == -1){
206 reply(500, "Failed to decode data.");
207 return;
209 ret = store_ticket(&cip);
210 if(ret){
211 reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
212 memset(&cip, 0, sizeof(cip));
213 return;
215 do_destroy_tickets = 1;
217 if(k_hasafs())
218 k_afsklog(0, 0);
219 reply(200, "Tickets will be destroyed on exit.");
220 return;
223 ret = krb_get_in_tkt (pr.name,
224 pr.instance,
225 pr.realm,
226 KRB_TICKET_GRANTING_TICKET,
227 pr.realm,
228 DEFAULT_TKT_LIFE,
229 NULL, save_tkt, NULL);
230 if(ret != INTK_BADPW){
231 reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
232 return;
234 if(base64_encode(cip.dat, cip.length, &p) < 0) {
235 reply(500, "Out of memory while base64-encoding.");
236 return;
238 reply(300, "P=%s T=%s", krb_unparse_name(&pr), p);
239 free(p);
240 memset(&cip, 0, sizeof(cip));
244 static char *
245 short_date(int32_t dp)
247 char *cp;
248 time_t t = (time_t)dp;
250 if (t == (time_t)(-1L)) return "*** Never *** ";
251 cp = ctime(&t) + 4;
252 cp[15] = '\0';
253 return (cp);
256 void
257 klist(void)
259 int err;
261 char *file = tkt_string();
263 krb_principal pr;
265 char buf1[128], buf2[128];
266 int header = 1;
267 CREDENTIALS c;
271 err = tf_init(file, R_TKT_FIL);
272 if(err != KSUCCESS){
273 reply(500, "%s", krb_get_err_text(err));
274 return;
276 tf_close();
279 * We must find the realm of the ticket file here before calling
280 * tf_init because since the realm of the ticket file is not
281 * really stored in the principal section of the file, the
282 * routine we use must itself call tf_init and tf_close.
284 err = krb_get_tf_realm(file, pr.realm);
285 if(err != KSUCCESS){
286 reply(500, "%s", krb_get_err_text(err));
287 return;
290 err = tf_init(file, R_TKT_FIL);
291 if(err != KSUCCESS){
292 reply(500, "%s", krb_get_err_text(err));
293 return;
296 err = tf_get_pname(pr.name);
297 if(err != KSUCCESS){
298 reply(500, "%s", krb_get_err_text(err));
299 return;
301 err = tf_get_pinst(pr.instance);
302 if(err != KSUCCESS){
303 reply(500, "%s", krb_get_err_text(err));
304 return;
308 * You may think that this is the obvious place to get the
309 * realm of the ticket file, but it can't be done here as the
310 * routine to do this must open the ticket file. This is why
311 * it was done before tf_init.
314 lreply(200, "Ticket file: %s", tkt_string());
316 lreply(200, "Principal: %s", krb_unparse_name(&pr));
317 while ((err = tf_get_cred(&c)) == KSUCCESS) {
318 if (header) {
319 lreply(200, "%-15s %-15s %s",
320 " Issued", " Expires", " Principal (kvno)");
321 header = 0;
323 strcpy(buf1, short_date(c.issue_date));
324 c.issue_date = krb_life_to_time(c.issue_date, c.lifetime);
325 if (time(0) < (unsigned long) c.issue_date)
326 strcpy(buf2, short_date(c.issue_date));
327 else
328 strcpy(buf2, ">>> Expired <<< ");
329 lreply(200, "%s %s %s (%d)", buf1, buf2,
330 krb_unparse_name_long(c.service, c.instance, c.realm), c.kvno);
332 if (header && err == EOF) {
333 lreply(200, "No tickets in file.");
335 reply(200, "");
339 * Only destroy if we created the tickets
342 void
343 cond_kdestroy(void)
345 if (do_destroy_tickets)
346 dest_tkt();
347 afsunlog();
350 void
351 kdestroy(void)
353 dest_tkt();
354 afsunlog();
355 reply(200, "Tickets destroyed");
358 void
359 krbtkfile(const char *tkfile)
361 do_destroy_tickets = 0;
362 krb_set_tkt_string(tkfile);
363 reply(200, "Using ticket file %s", tkfile);
366 void
367 afslog(const char *cell)
369 if(k_hasafs()) {
370 k_afsklog(cell, 0);
371 reply(200, "afslog done");
372 } else {
373 reply(200, "no AFS present");
377 void
378 afsunlog(void)
380 if(k_hasafs())
381 k_unlog();