1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains functions for dealing with Kerberos functions in the server.
4 * Created by: John T Kohl
6 * Copyright (c) 1988 by the Massachusetts Institute of Technology.
7 * For copying and distribution information, see the file
11 * $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/kstuff.c,v $
12 * $Header: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/kstuff.c,v 1.27 2004/02/29 06:34:04 zacheiss Exp $
19 static const char rcsid_kstuff_c[] = "$Id: kstuff.c,v 1.27 2004/02/29 06:34:04 zacheiss Exp $";
25 /* Keep a hash table mapping tickets to session keys, so we can do a fast
26 * check of the cryptographic checksum without doing and DES decryptions.
27 * Also remember the expiry time of the ticket, so that we can sweep the
28 * table periodically. */
30 #define HASHTAB_SIZE 4091
32 typedef struct hash_entry Hash_entry;
34 /* The ticket comes at the end, in a variable-length array. */
38 char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
41 unsigned char ticket[1];
44 Hash_entry *hashtab[HASHTAB_SIZE];
46 static int hash_ticket __P((unsigned char *, int));
47 static void add_session_key __P((KTEXT, C_Block, char *, time_t));
48 static int find_session_key __P((KTEXT, C_Block, char *));
49 static ZChecksum_t compute_checksum __P((ZNotice_t *, C_Block));
50 static ZChecksum_t compute_rlm_checksum __P((ZNotice_t *, C_Block));
55 * get ticket from file descriptor and decode it.
56 * Return KFAILURE if we barf on reading the ticket, else return
57 * the value of rd_ap_req() applied to the ticket.
60 GetKerberosData(fd, haddr, kdata, service, srvtab)
61 int fd; /* file descr. to read from */
62 struct in_addr haddr; /* address of foreign host on fd */
63 AUTH_DAT *kdata; /* kerberos data (returned) */
64 char *service; /* service principal desired */
65 char *srvtab; /* file to get keys from */
68 KTEXT_ST ticket; /* will get Kerberos ticket from client */
70 char instance[INST_SZ];
73 * Get the Kerberos ticket. The first few characters, terminated
74 * by a blank, should give us a length; then get than many chars
75 * which will be the ticket proper.
77 for (i=0; i<20; i++) {
78 if (read(fd, &p[i], 1) != 1) {
79 syslog(LOG_WARNING,"bad read tkt len");
87 ticket.length = atoi(p);
88 if ((i==20) || (ticket.length<=0) || (ticket.length>MAX_KTXT_LEN)) {
89 syslog(LOG_WARNING,"bad tkt len %d",ticket.length);
92 for (i=0; i<ticket.length; i++) {
93 if (read(fd, (caddr_t) &(ticket.dat[i]), 1) != 1) {
94 syslog(LOG_WARNING,"bad tkt read");
99 * now have the ticket. use it to get the authenticated
100 * data from Kerberos.
102 (void) strcpy(instance,"*"); /* let Kerberos fill it in */
104 return(krb_rd_req(&ticket, service, instance, haddr.s_addr,
105 kdata, srvtab ? srvtab : ""));
111 * create and transmit a ticket over the file descriptor for service.host
112 * return failure codes if appropriate, or 0 if we
113 * get the ticket and write it to the file descriptor
117 SendKerberosData(fd, ticket, service, host)
118 int fd; /* file descriptor to write onto */
119 KTEXT ticket; /* where to put ticket (return) */
120 char *service; /* service name, foreign host */
128 rem = krb_mk_req(ticket, service, host, ZGetRealm(), (u_long) 0);
130 return rem + krb_err_base;
132 (void) sprintf(p,"%d ",ticket->length);
133 size_to_write = strlen (p);
134 if ((written = write(fd, p, size_to_write)) != size_to_write)
135 return (written < 0) ? errno : ZSRV_PKSHORT;
136 if ((written = write(fd, (caddr_t) (ticket->dat), ticket->length))
138 return (written < 0) ? errno : ZSRV_PKSHORT;
143 #endif /* HAVE_KRB4 */
146 ZCheckRealmAuthentication(notice, from, realm)
148 struct sockaddr_in *from;
153 char rlmprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
154 char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
155 KTEXT_ST authent, ticket;
157 ZChecksum_t checksum;
164 /* Check for bogus authentication data length. */
165 if (notice->z_authent_len <= 0)
168 /* Read in the authentication data. */
169 if (ZReadAscii(notice->z_ascii_authent,
170 strlen(notice->z_ascii_authent)+1,
171 (unsigned char *)authent.dat,
172 notice->z_authent_len) == ZERR_BADFIELD) {
175 authent.length = notice->z_authent_len;
177 (void) sprintf(rlmprincipal, "%s.%s@%s", SERVER_SERVICE,
178 SERVER_INSTANCE, realm);
180 result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
181 from->sin_addr.s_addr, &dat, srvtab_file);
182 if (result == RD_AP_OK) {
183 sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "",
184 dat.pinst, dat.prealm);
185 if (strcmp(rlmprincipal, srcprincipal))
188 return ZAUTH_FAILED; /* didn't decode correctly */
191 /* Check the cryptographic checksum. */
195 checksum = compute_rlm_checksum(notice, dat.session);
197 if (checksum != notice->z_checksum) {
199 checksum = compute_checksum(notice, dat.session);
200 if (checksum != notice->z_checksum)
207 #else /* !HAVE_KRB4 */
208 return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO;
213 ZCheckAuthentication(notice, from)
215 struct sockaddr_in *from;
219 char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
220 KTEXT_ST authent, ticket;
222 ZChecksum_t checksum;
228 /* Check for bogus authentication data length. */
229 if (notice->z_authent_len <= 0)
232 /* Read in the authentication data. */
233 if (ZReadAscii(notice->z_ascii_authent,
234 strlen(notice->z_ascii_authent)+1,
235 (unsigned char *)authent.dat,
236 notice->z_authent_len) == ZERR_BADFIELD) {
239 authent.length = notice->z_authent_len;
241 result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
242 from->sin_addr.s_addr, &dat, srvtab_file);
243 if (result == RD_AP_OK) {
244 memcpy(__Zephyr_session, dat.session, sizeof(C_Block));
245 sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "",
246 dat.pinst, dat.prealm);
247 if (strcmp(srcprincipal, notice->z_sender))
250 return ZAUTH_FAILED; /* didn't decode correctly */
253 /* Check the cryptographic checksum. */
257 checksum = compute_checksum(notice, dat.session);
259 if (checksum != notice->z_checksum)
264 #else /* !HAVE_KRB4 */
265 return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO;
271 static int hash_ticket(p, len)
275 unsigned long hashval = 0, g;
277 for (; len > 0; p++, len--) {
278 hashval = (hashval << 4) + *p;
279 g = hashval & 0xf0000000;
285 return hashval % HASHTAB_SIZE;
288 static void add_session_key(ticket, session_key, srcprincipal, expires)
297 /* If we can't allocate memory for the hash table entry, just forget
299 entry = (Hash_entry *) malloc(sizeof(Hash_entry) - 1 + ticket->length);
303 /* Initialize the new entry. */
304 memcpy(entry->session_key, session_key, sizeof(entry->session_key));
305 strcpy(entry->srcprincipal, srcprincipal);
306 entry->expires = expires;
307 entry->ticket_len = ticket->length;
308 memcpy(entry->ticket, ticket->dat, ticket->length * sizeof(unsigned char));
310 /* Insert the new entry in the hash table. */
311 hashval = hash_ticket(ticket->dat, ticket->length);
312 entry->next = hashtab[hashval];
313 hashtab[hashval] = entry;
316 static int find_session_key(ticket, key, srcprincipal)
326 len = ticket->length;
327 hashval = hash_ticket(dat, len);
329 for (entry = hashtab[hashval]; entry; entry = entry->next) {
330 if (entry->ticket_len == len && memcmp(entry->ticket, dat, len) == 0) {
331 memcpy(key, entry->session_key, sizeof(entry->session_key));
332 strcpy(srcprincipal, entry->srcprincipal);
339 static ZChecksum_t compute_checksum(notice, session_key)
346 ZChecksum_t checksum;
347 char *cstart, *cend, *hstart = notice->z_packet, *hend = notice->z_message;
349 cstart = notice->z_default_format + strlen(notice->z_default_format) + 1;
350 cend = cstart + strlen(cstart) + 1;
351 checksum = des_quad_cksum(hstart, NULL, cstart - hstart, 0, session_key);
352 checksum ^= des_quad_cksum(cend, NULL, hend - cend, 0, session_key);
353 checksum ^= des_quad_cksum(notice->z_message, NULL, notice->z_message_len,
359 static ZChecksum_t compute_rlm_checksum(notice, session_key)
366 ZChecksum_t checksum;
367 char *cstart, *cend, *hstart = notice->z_packet, *hend = notice->z_message;
369 cstart = notice->z_default_format + strlen(notice->z_default_format) + 1;
370 cend = cstart + strlen(cstart) + 1;
371 checksum = des_quad_cksum(hstart, NULL, cstart - hstart, 0, session_key);
376 void sweep_ticket_hash_table(arg)
380 Hash_entry **ptr, *entry;
382 for (i = 0; i < HASHTAB_SIZE; i++) {
386 if (entry->expires < NOW) {
394 timer_set_rel(SWEEP_INTERVAL, sweep_ticket_hash_table, NULL);
397 #endif /* HAVE_KRB4 */