+Wed Sep 23 15:24:44 1998 Tom Yu <tlyu@mit.edu>
+
+ * aclocal.m4 (KRB5_LIB_AUX): Do what Sam originally meant to do by
+ moving the explicit resetting of DEPLIB=$SHLIBEXT and forcing
+ SHLIBEXT=.so-nobuild to avoid duplicate rules on AIX and such.
+
1998-08-24 Theodore Ts'o <tytso@rsts-11.mit.edu>
* Makefile.in: Add support to build the lib/krb5/ccache api
directory and include it in the Windows kerbsrc-nt.zip
file.
+Wed Aug 19 20:14:31 1998 Tom Yu <tlyu@mit.edu>
+
+ * aclocal.m4 (KRB5_LIB_AUX): Back out Sam's change to reorder the
+ "force_static" logic, as it would cause problems where a
+ forced-static library is built in the same directory as a
+ program, due to explicit setting of CC_LINK, etc.
+
+Mon Aug 17 18:10:29 1998 Tom Yu <tlyu@mit.edu>
+
+ * aclocal.m4: Fix Sam's fixes (variable capitalization).
+
Wed Jul 8 01:10:44 1998 Matthew D Hancher <mdh@mit.edu>
* aclocal.m4: Allow shared libraries to build properly under Irix
LIBLIST=
OBJLISTS=
else
- LIBLIST="lib\$(LIB)$STLIBEXT"
- LIBLINKS="\$(TOPLIBD)/lib\$(LIB)$STLIBEXT"
+ LIBLIST='lib$(LIB)$(STLIBEXT)'
+ LIBLINKS='$(TOPLIBD)/lib$(LIB)$(STLIBEXT)'
OBJLISTS=OBJS.ST
LIBINSTLIST=install-static
DEPLIBEXT=$STLIBEXT
CC_LINK="$CC_LINK_STATIC"
;;
*)
+ # set this now because some logic below may reset SHLIBEXT
+ DEPLIBEXT=$SHLIBEXT
if test "$krb5_force_static" = "yes"; then
AC_MSG_RESULT([Forcing static libraries.])
+ # avoid duplicate rules generation for AIX and such
+ SHLIBEXT=.so-nobuild
else
AC_MSG_RESULT([Enabling shared libraries.])
LIBLIST="$LIBLIST "'lib$(LIB)$(SHLIBEXT)'
esac
OBJLISTS="$OBJLISTS OBJS.SH"
fi
- DEPLIBEXT=$SHLIBEXT
CC_LINK="$CC_LINK_SHARED"
if test "$STLIBEXT" = "$SHLIBEXT" ; then
STLIBEXT=".a-no-build"
SHLIBEXT=.so
SHOBJEXT=.o
# Kludge follows: (gcc makes n32 object files but ld expects o32, so we reeducate ld)
- if test "$GCC" = yes; then
+ if test "$krb5_cv_prog_gcc" = yes; then
LDCOMBINE='ld -n32 -shared -ignore_unresolved -update_registry $(BUILDTOP)/so_locations -soname lib$(LIB)$(SHLIBSEXT)'
else
LDCOMBINE='ld -shared -ignore_unresolved -update_registry $(BUILDTOP)/so_locations -soname lib$(LIB)$(SHLIBSEXT)'
# untested...
mips-sni-sysv4)
- if test "$GCC" = yes; then
+ if test "$krb5_cv_prog_gcc" = yes; then
PICFLAGS=-fpic
LDCOMBINE='$(CC) -G -Wl,-h -Wl,lib$(LIB)$(SHLIBSEXT)'
else
;;
*-*-solaris*)
- if test "$GCC" = yes; then
+ if test "$krb5_cv_prog_gcc" = yes; then
PICFLAGS=-fpic
LDCOMBINE='$(CC) -shared -h lib$(LIB)$(SHLIBSEXT)'
else
LDCOMBINE='$(BUILDTOP)/util/makeshlib $(LIBMAJOR).$(LIBMINOR)'
SHLIB_EXPFLAGS=' $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
PROFFLAGS=-pg
- if test "$gcc" = "yes" ; then
+ if test "$krb5_cv_prog_gcc" = "yes" ; then
CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) -Xlinker -bex4:$(BUILDTOP)/util/aix.bincmds '
else
CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) -bex4:$(BUILDTOP)/util/aix.bincmds '
+1998-10-24 Marc Horowitz <marc@mit.edu>
+
+ * login.c: update to new get_creds API
+
+ * krlogin.c (main, oob, server_message, control), krlogind.c
+ (sendoob, protocol, recvauth): If the enctype is not
+ similar to DES, use an inband signalling protocol instead
+ of MSG_OOB data to indicate status changes.
+
+ * kcmd.c (rcmd_stream_init_krb5, v5_des_read, v5_des_write):
+ update to new crypto API. Add ivec chaining to
+ encryption when the enctype is not similar to DES as part
+ of the new protocol.
+
1998-10-06 Theodore Ts'o <tytso@rsts-11.mit.edu>
* krshd.c (doit): Apply ghudson's patch so that rshd passes the
the foreign and local ports so that encrypted rcp for the
same machine. [krb5-appl/638]
+Tue Aug 18 16:48:02 1998 Tom Yu <tlyu@mit.edu>
+
+ * krlogin.c: Add <sys/filio.h> for FIONREAD.
+
Sat Aug 15 00:01:15 1998 Geoffrey King <gjking@mit.edu>
* krcp.c (error): Don't call rcmd_stream_write if iamremote is not
* krlogin.c (main): Apply ghudson's patch so that rlogin -a
no longer dumps core. [krb5-appl/612]
+Sun Jul 26 23:46:36 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * login.c (main): Allow krb524 conversion for forwarded tickets
+ (try_convert524): Don't check to see if we have tickets here; caller does that and actually gets it right.
+
1998-05-26 Theodore Ts'o <tytso@rsts-11.mit.edu>
* login.c (dolastlog): BSD 4.4 systems don't have lastlog.h, but
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
/* derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88 */
#ifdef HAVE_UNISTD_H
#define START_PORT 5120 /* arbitrary */
char *default_service = "host";
+#define KCMD_KEYUSAGE 1026
+
/*
* Note that the encrypted rlogin packets take the form of a four-byte
* length followed by encrypted data. On writing the data out, a significant
static char des_outpkt[2*RCMD_BUFSIZ+4]; /* needs to be > largest write size */
static krb5_data desinbuf;
static krb5_data desoutbuf;
-static krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */
+static krb5_data encivec;
+static krb5_keyblock *keyblock; /* key for encrypt/decrypt */
static int (*input)();
static int (*output)();
static char storage[2*RCMD_BUFSIZ]; /* storage for the decryption */
output = twrite;
}
-void rcmd_stream_init_krb5(keyblock, encrypt_flag, lencheck)
- krb5_keyblock *keyblock;
+void rcmd_stream_init_krb5(in_keyblock, encrypt_flag, lencheck)
+ krb5_keyblock *in_keyblock;
int encrypt_flag;
int lencheck;
{
krb5_error_code status;
+ size_t blocksize;
+ krb5_boolean similar;
if (!encrypt_flag) {
rcmd_stream_init_normal();
}
desinbuf.data = des_inbuf;
desoutbuf.data = des_outpkt+4; /* Set up des buffers */
- krb5_use_enctype(bsd_context, &eblock, keyblock->enctype);
- if ( status = krb5_process_key(bsd_context, &eblock, keyblock)) {
- fprintf(stderr, "rcmd: Cannot process session key: %s\n",
- error_message(status));
- exit(1);
- }
+ keyblock = in_keyblock;
+
do_lencheck = lencheck;
input = v5_des_read;
output = v5_des_write;
+
+ if (status = krb5_c_enctype_compare(bsd_context, ENCTYPE_DES_CBC_CRC,
+ keyblock->enctype,
+ &similar)) {
+ /* XXX what do I do? */
+ abort();
+ }
+
+ if (similar) {
+ encivec.length = 0;
+ return;
+ }
+
+ if (status = krb5_c_block_size(bsd_context, keyblock->enctype,
+ &blocksize)) {
+ /* XXX what do I do? */
+ abort();
+ }
+
+ encivec.length = blocksize;
+
+ if ((encivec.data = malloc(encivec.length)) == NULL) {
+ /* XXX what do I do? */
+ abort();
+ }
+
+ /* is there a better way to initialize this? */
+ memset(encivec.data, '\0', blocksize);
}
#ifdef KRB5_KRB4_COMPAT
int len;
{
int nreturned = 0;
- long net_len,rd_len;
+ size_t net_len,rd_len;
int cc;
unsigned char c;
+ krb5_error_code ret;
+ krb5_data plain;
+ krb5_enc_data cipher;
if (nstored >= len) {
memcpy(buf, store_ptr, len);
if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
rd_len = (rd_len << 8) | c;
- net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
+ if (ret = krb5_c_encrypt_length(bsd_context, keyblock->enctype,
+ rd_len, &net_len)) {
+ errno = ret;
+ return(-1);
+ }
+
if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) {
/* preposterous length, probably out of sync */
errno = EIO;
errno = EIO;
return(-1);
}
+
+ cipher.enctype = ENCTYPE_UNKNOWN;
+ cipher.ciphertext.length = net_len;
+ cipher.ciphertext.data = desinbuf.data;
+ plain.length = sizeof(storage);
+ plain.data = storage;
+
/* decrypt info */
- if ((krb5_decrypt(bsd_context, desinbuf.data,
- (krb5_pointer) storage,
- net_len,
- &eblock, 0))) {
+ if (krb5_c_decrypt(bsd_context, keyblock, KCMD_KEYUSAGE,
+ encivec.length?&encivec:0,
+ &cipher, &plain)) {
/* probably out of sync */
errno = EIO;
return(-1);
int len;
{
unsigned char *len_buf = (unsigned char *) des_outpkt;
-
- desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry);
- if (desoutbuf.length > sizeof(des_outpkt)-4){
- errno = EIO;
- return(-1);
- }
- if ((krb5_encrypt(bsd_context, (krb5_pointer)buf,
- desoutbuf.data,
- len,
- &eblock,
- 0))){
+ krb5_data plain;
+ krb5_enc_data cipher;
+
+ plain.data = buf;
+ plain.length = len;
+
+ cipher.ciphertext.length = sizeof(des_outpkt)-4;
+ cipher.ciphertext.data = desoutbuf.data;
+
+ if (krb5_c_encrypt(bsd_context, keyblock, KCMD_KEYUSAGE,
+ encivec.length?&encivec:0,
+ &plain, &cipher)) {
errno = EIO;
return(-1);
}
+ desoutbuf.length = cipher.ciphertext.length;
+
len_buf[0] = (len & 0xff000000) >> 24;
len_buf[1] = (len & 0xff0000) >> 16;
len_buf[2] = (len & 0xff00) >> 8;
errno = EIO;
return(-1);
}
+
else return(len);
}
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
#include <setjmp.h>
#include <netdb.h>
+#ifdef HAVE_SYS_FILIO_H
+/* Solaris needs <sys/filio.h> for FIONREAD */
+#include <sys/filio.h>
+#endif
+
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
char *name;
int rem = -1; /* Remote socket fd */
+int do_inband = 0;
char cmdchar = '~';
int eight = 1; /* Default to 8 bit transmission */
int no_local_escape = 0;
reached from confirm_death() */
krb5_sigtype sigwinch KRB5_PROTOTYPE((int));
+int server_message KRB5_PROTOTYPE((int));
void oob KRB5_PROTOTYPE((void));
krb5_sigtype lostpeer KRB5_PROTOTYPE((int));
#if __STDC__
#else
try_normal(orig_argv);
#endif
- } else
+ } else {
+ krb5_boolean similar;
+
rcmd_stream_init_krb5(&cred->keyblock, encrypt_flag, 1);
+
+ if (status = krb5_c_enctype_compare(bsd_context, ENCTYPE_DES_CBC_CRC,
+ cred->keyblock.enctype, &similar))
+ try_normal(orig_argv); /* doesn't return */
+
+ if (!similar) {
+ do_inband = 1;
+ if (debug_port)
+ fprintf(stderr, "DEBUG: setting do_inband\n");
+ }
+ }
+
rem = sock;
#else
int rcvstate;
int ppid;
+/* returns 1 if flush, 0 otherwise */
-void oob()
+int server_message(mark)
+ int mark;
{
#ifndef POSIX_TERMIOS
int out = FWRITE;
#endif
- int atmark, n;
+ int n;
int rcvd = 0;
- char waste[RLOGIN_BUFSIZ], mark;
#ifdef POSIX_TERMIOS
struct termios tty;
#else
struct sgttyb sb;
#endif
#endif
- mark = 0;
-
- recv(rem, &mark, 1, MSG_OOB);
+
if (mark & TIOCPKT_WINDOW) {
/*
* Let server know about window size changes
(void) ioctl(1, TCFLSH, 1);
#endif
#endif
- for (;;) {
- if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
- perror("ioctl");
- break;
- }
- if (atmark)
- break;
- n = read(rem, waste, sizeof (waste));
- if (n <= 0)
- break;
-return;
- }
+ return(1);
}
+
+ return(0);
+}
+
+void oob()
+{
+ char mark;
+ char waste[RLOGIN_BUFSIZ];
+ int atmark;
+
+ mark = 0;
-
+ recv(rem, &mark, 1, MSG_OOB);
+
+ if (server_message(mark)) {
+ if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
+ perror("ioctl");
+ return;
+ }
+ if (!atmark)
+ read(rem, waste, sizeof (waste));
+ }
}
+/* two control messages are defined:
+ a double flag byte of 'o' indicates a one-byte message which is
+ identical to what was once carried out of band.
+
+ a double flag byte of 'q' indicates a zero-byte message. This
+ message is interpreted as two \377 data bytes. This is just a
+ quote rule so that binary data from the server does not confuse the
+ client. */
+
+int control(cp, n)
+ unsigned char *cp;
+ int n;
+{
+ if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
+ if (server_message(cp[4]))
+ return(-5);
+ return(5);
+ } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
+ /* this is somewhat of a hack */
+ cp[2] = '\377';
+ cp[3] = '\377';
+ return(2);
+ }
+
+ return(0);
+}
/*
- * reader: read from remote: line -> 1
+ * reader: read from remote: line -> 1
*/
reader(oldmask)
#ifdef POSIX_SIGNALS
int pid = -getpid();
#endif
fd_set readset, excset, writeset;
- int n, remaining;
+ int n, remaining, left;
char *bufp = rcvbuf;
+ char *cp;
#ifdef POSIX_SIGNALS
struct sigaction sa;
#endif /* POSIX_SIGNALS */
for (;;) {
- if ((remaining = rcvcnt - (bufp - rcvbuf)) > 0)
- {
+ if ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
FD_SET(1,&writeset);
rcvstate = WRITING;
FD_CLR(rem, &readset);
+ } else {
+ bufp = rcvbuf;
+ rcvcnt = 0;
+ rcvstate = READING;
+ FD_SET(rem,&readset);
+ FD_CLR(1,&writeset);
}
- else {
-
- bufp = rcvbuf;
- rcvcnt = 0;
- rcvstate = READING;
- FD_SET(rem,&readset);
- FD_CLR(1,&writeset);
- }
- FD_SET(rem,&excset);
+ if (!do_inband)
+ FD_SET(rem,&excset);
if (select(rem+1, &readset, &writeset, &excset, 0) > 0 ) {
- if (FD_ISSET(rem, &excset))
- oob();
+ if (!do_inband)
+ if (FD_ISSET(rem, &excset))
+ oob();
if (FD_ISSET(1,&writeset)) {
n = write(1, bufp, remaining);
if (n < 0) {
return (0);
if (rcvcnt < 0)
goto error;
+
+ if (do_inband) {
+ for (cp = rcvbuf; cp < rcvbuf+rcvcnt-1; cp++) {
+ if (cp[0] == '\377' &&
+ cp[1] == '\377') {
+ left = (rcvbuf+rcvcnt) - cp;
+ n = control(cp, left);
+ if (n < 0) {
+ left -= (-n);
+ rcvcnt = 0;
+ /* flush before, and (-n) bytes */
+ if (left > 0)
+ memmove(rcvbuf, cp+(-n), left);
+ cp = rcvbuf-1;
+ } else if (n) {
+ left -= n;
+ rcvcnt -= n;
+ if (left > 0)
+ memmove(cp, cp+n, left);
+ cp--;
+ }
+ }
+ }
+ }
}
} else
error:
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
char term[64];
char rhost_name[128];
krb5_principal client;
+int do_inband = 0;
int reapchild();
char *progname;
char oobdata[] = {0};
#endif
+int sendoob(fd, byte)
+ int fd;
+ char *byte;
+{
+ char message[5];
+ int cc;
+
+ if (do_inband) {
+ message[0] = '\377';
+ message[1] = '\377';
+ message[2] = 'o';
+ message[3] = 'o';
+ message[4] = *byte;
+
+ cc = rcmd_stream_write(fd, message, sizeof(message));
+ while (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ /* also shouldn't happen */
+ sleep(5);
+ cc = rcmd_stream_write(fd, message, sizeof(message));
+ }
+ } else {
+ send(fd, byte, 1, MSG_OOB);
+ }
+}
+
/*
* Handle a "control" request (signaled by magic being present)
* in the data stream. For now, we are only willing to handle
void protocol(f, p)
int f, p;
{
- unsigned char pibuf[BUFSIZ], fibuf[BUFSIZ], *pbp, *fbp;
+ unsigned char pibuf[BUFSIZ], qpibuf[BUFSIZ*2], fibuf[BUFSIZ], *pbp, *fbp;
register pcc = 0, fcc = 0;
int cc;
char cntl;
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef TIOCSWINSZ
- send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
+ sendoob(f, oobdata);
#endif
for (;;) {
fd_set ibits, obits, ebits;
FD_SET(f, &obits);
else
FD_SET(p, &ibits);
- FD_SET(p, &ebits);
if (select(8*sizeof(ibits), &ibits, &obits, &ebits, 0) < 0) {
if (errno == EINTR)
fatalperror(f, "select");
}
#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
- if (FD_ISSET(p, &ebits)) {
- cc = read(p, &cntl, 1);
- if (cc == 1 && pkcontrol(cntl)) {
- cntl |= oobdata[0];
- send(f, &cntl, 1, MSG_OOB);
- if (cntl & TIOCPKT_FLUSHWRITE) {
- pcc = 0;
- FD_CLR(p, &ibits);
- }
- }
- }
if (FD_ISSET(f, &ibits)) {
fcc = rcmd_stream_read(f, fibuf, sizeof (fibuf));
- if (fcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
- fcc = 0;
- else {
+ if (fcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ fcc = 0;
+ } else {
register unsigned char *cp;
int left, n;
if (fcc <= 0)
- break;
+ break;
fbp = fibuf;
- top:
- for (cp = fibuf; cp < fibuf+fcc-1; cp++)
- if (cp[0] == magic[0] &&
- cp[1] == magic[1]) {
- left = fcc - (cp-fibuf);
- n = control(p, cp, left);
- if (n) {
- left -= n;
- if (left > 0)
- memmove(cp, cp+n, left);
- fcc -= n;
- goto top; /* n^2 */
- }
- }
+ for (cp = fibuf; cp < fibuf+fcc-1; cp++) {
+ if (cp[0] == magic[0] &&
+ cp[1] == magic[1]) {
+ left = (fibuf+fcc) - cp;
+ n = control(p, cp, left);
+ if (n) {
+ left -= n;
+ fcc -= n;
+ if (left > 0)
+ memmove(cp, cp+n, left);
+ cp--;
+ }
+ }
+ }
}
}
if (FD_ISSET(p, &ibits)) {
pcc = read(p, pibuf, sizeof (pibuf));
pbp = pibuf;
- if (pcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
- pcc = 0;
- else if (pcc <= 0)
- break;
+ if (pcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ pcc = 0;
+ } else if (pcc <= 0) {
+ break;
+ }
#ifdef TIOCPKT
else if (tiocpkt_on) {
- if (pibuf[0] == 0)
- pbp++, pcc--;
- else {
- if (pkcontrol(pibuf[0])) {
- pibuf[0] |= oobdata[0];
- send(f, &pibuf[0], 1, MSG_OOB);
- }
- pcc = 0;
- }
+ if (pibuf[0] == 0) {
+ pbp++, pcc--;
+ } else {
+ if (pkcontrol(pibuf[0])) {
+ pibuf[0] |= oobdata[0];
+ sendoob(f, pibuf);
+ }
+ pcc = 0;
+ }
}
#endif
+
+ /* quote any double-\377's if necessary */
+
+ if (do_inband) {
+ unsigned char *qpbp;
+ int qpcc, i;
+
+ qpbp = qpibuf;
+ qpcc = 0;
+
+ for (i=0; i<pcc;) {
+ if (pbp[i] == 0377u && (i+1)<pcc && pbp[i+1] == 0377u) {
+ qpbp[qpcc] = '\377';
+ qpbp[qpcc+1] = '\377';
+ qpbp[qpcc+2] = 'q';
+ qpbp[qpcc+3] = 'q';
+ i += 2;
+ qpcc += 4;
+ } else {
+ qpbp[qpcc] = pbp[i];
+ i++;
+ qpcc++;
+ }
+ }
+
+ pbp = qpbp;
+ pcc = qpcc;
+ }
}
+
if (FD_ISSET(f, &obits) && pcc > 0) {
cc = rcmd_stream_write(f, pbp, pcc);
if (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
rcmd_stream_init_krb5(ticket->enc_part2->session, do_encrypt, 1);
+ {
+ krb5_boolean similar;
+
+ if (status = krb5_c_enctype_compare(bsd_context, ENCTYPE_DES_CBC_CRC,
+ ticket->enc_part2->session->enctype,
+ &similar))
+ return(status);
+
+ if (!similar) {
+ do_inband = 1;
+ syslog(LOG_DEBUG, "setting do_inband");
+ }
+ }
+
+
getstr(netf, rusername, sizeof(rusername), "remuser");
if ((status = krb5_unparse_name(bsd_context, client, &krusername)))
*/
#define KRB5_GET_TICKETS
int login_krb5_get_tickets = 1;
+
#ifdef KRB5_KRB4_COMPAT
#define KRB4_GET_TICKETS
int login_krb4_get_tickets = 0;
#define KRB_RUN_AKLOG
int login_krb_run_aklog = 0;
#endif /* KRB5_KRB4_COMPAT */
+
int login_accept_passwd = 0;
/*
#ifndef HAVE_KRB_GET_ERR_TEXT
-static const char * krb_get_err_text(kerror)
- int kerror;
+static const char *krb_get_err_text(kerror)
+ int kerror;
{
- return krb_err_txt[kerror];
+ return krb_err_txt[kerror];
}
#endif /*HAVE_KRB_GET_ERR_TEXT*/
#ifndef HAVE_INITGROUPS
static int initgroups(char* name, gid_t basegid) {
- gid_t others[NGROUPS_MAX+1];
- int ngrps;
+ gid_t others[NGROUPS_MAX+1];
+ int ngrps;
- others[0] = basegid;
- ngrps = getgroups(NGROUPS_MAX, others+1);
- return setgroups(ngrps+1, others);
+ others[0] = basegid;
+ ngrps = getgroups(NGROUPS_MAX, others+1);
+ return setgroups(ngrps+1, others);
}
#endif
-#ifdef KRB5_GET_TICKETS
static struct login_confs {
- char *flagname;
- int *flag;
+ char *flagname;
+ int *flag;
} login_conf_set[] = {
- "krb5_get_tickets", &login_krb5_get_tickets,
+#ifdef KRB5_GET_TICKETS
+ "krb5_get_tickets", &login_krb5_get_tickets,
+#endif
#ifdef KRB5_KRB4_COMPAT
- "krb4_get_tickets", &login_krb4_get_tickets,
- "krb4_convert", &login_krb4_convert,
- "krb4_run_aklog", &login_krb_run_aklog,
+ "krb4_get_tickets", &login_krb4_get_tickets,
+ "krb4_convert", &login_krb4_convert,
+ "krb4_run_aklog", &login_krb_run_aklog,
#endif /* KRB5_KRB4_COMPAT */
};
+
static char *conf_yes[] = {
- "y", "yes", "true", "t", "1", "on",
- 0
+ "y", "yes", "true", "t", "1", "on",
+ 0
};
+
static char *conf_no[] = {
- "n", "no", "false", "nil", "0", "off",
- 0
+ "n", "no", "false", "nil", "0", "off",
+ 0
};
+
/* 1 = true, 0 = false, -1 = ambiguous */
static int conf_affirmative(s)
- char *s;
+ char *s;
{
- char **p;
- for(p=conf_yes; *p; p++) {
- if (!strcasecmp(*p,s))
- return 1;
- }
- for(p=conf_no; *p; p++) {
- if (!strcasecmp(*p,s))
- return 0;
- }
- /* ambiguous */
- return -1;
+ char **p;
+
+ for(p=conf_yes; *p; p++) {
+ if (!strcasecmp(*p,s))
+ return 1;
+ }
+
+ for(p=conf_no; *p; p++) {
+ if (!strcasecmp(*p,s))
+ return 0;
+ }
+
+ /* ambiguous */
+ return -1;
}
-#endif /* KRB5_GET_TICKETS */
#ifdef KRB5_GET_TICKETS
krb5_data tgtname = {
};
#endif
-#ifdef KRB5_GET_TICKETS
/* get flags (listed above) from the profile */
void login_get_kconf(k)
- krb5_context k;
+ krb5_context k;
{
- int i, max_i;
- const char* kconf_names[3];
- char **kconf_val;
- int retval;
-
- max_i = sizeof(login_conf_set)/sizeof(struct login_confs);
- for (i = 0; i<max_i; i++) {
- kconf_names[0] = "login";
- kconf_names[1] = login_conf_set[i].flagname;
- kconf_names[2] = 0;
- retval = profile_get_values(k->profile,
- kconf_names, &kconf_val);
- if (retval) {
- /* ignore most (all?) errors */
- } else if (kconf_val) {
- switch(conf_affirmative(*kconf_val)) {
- case 1:
- *login_conf_set[i].flag = 1;
- break;
- case 0:
- *login_conf_set[i].flag = 0;
- break;
- default:
- case -1:
- com_err("login/kconf", 0,
- "invalid flag value %s for flag %s",
- *kconf_val, kconf_names[1]);
- break;
- }
- }
+ int i, max_i;
+ const char* kconf_names[3];
+ char **kconf_val;
+ int retval;
+
+ max_i = sizeof(login_conf_set)/sizeof(struct login_confs);
+ for (i = 0; i<max_i; i++) {
+ kconf_names[0] = "login";
+ kconf_names[1] = login_conf_set[i].flagname;
+ kconf_names[2] = 0;
+ retval = profile_get_values(k->profile,
+ kconf_names, &kconf_val);
+ if (retval) {
+ /* ignore most (all?) errors */
+ } else if (kconf_val) {
+ switch(conf_affirmative(*kconf_val)) {
+ case 1:
+ *login_conf_set[i].flag = 1;
+ break;
+ case 0:
+ *login_conf_set[i].flag = 0;
+ break;
+ default:
+ case -1:
+ com_err("login/kconf", 0,
+ "invalid flag value %s for flag %s",
+ *kconf_val, kconf_names[1]);
+ break;
+ }
}
+ }
}
-#endif /* KRB5_GET_TICKETS */
-\f
/* UNIX password support */
struct passwd *pwd;
#endif
return !strcmp (namep, pwd->pw_passwd);
}
-\f
+
/* Kerberos support */
#ifdef KRB5_GET_TICKETS
krb5_context kcontext;
krb5_ccache ccache;
-static int got_v5_tickets, got_v4_tickets;
+krb5_creds my_creds;
+static int got_v5_tickets, forwarded_v5_tickets;
char ccfile[MAXPATHLEN+6]; /* FILE:path+\0 */
int krbflag; /* set if tickets have been obtained */
+#endif /* KRB5_GET_TICKETS */
#ifdef KRB4_GET_TICKETS
+static int got_v4_tickets;
AUTH_DAT *kdata = (AUTH_DAT *) NULL;
KTEXT ticket = (KTEXT) NULL;
char tkfile[MAXPATHLEN];
void k_init (ttyn)
char *ttyn;
{
+#ifdef KRB5_GET_TICKETS
krb5_error_code retval;
retval = krb5_init_context(&kcontext);
com_err("login", retval, "while initializing krb5");
exit(1);
}
+
krb5_secure_config_files (kcontext);
login_get_kconf(kcontext);
strncpy(ccfile, getenv(KRB5_ENV_CCNAME), sizeof(ccfile));
ccfile[sizeof(ccfile) - 1] = '\0';
}
+#endif
#ifdef KRB4_GET_TICKETS
if (krb_get_lrealm(realm, 1) != KSUCCESS) {
#endif /* BIND_HACK */
}
+#ifdef KRB5_GET_TICKETS
int k5_get_password (user_pwstring, pwsize)
char *user_pwstring;
{
return 1;
}
-#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
-int krb5_options = 0;
-krb5_deltat krb5_ticket_lifetime = KRB5_DEFAULT_LIFE;
-
int try_krb5 (me_p, pass)
krb5_principal *me_p;
char *pass;
{
krb5_error_code code;
- krb5_principal server, me;
- krb5_creds my_creds;
- krb5_timestamp now;
- krb5_deltat lifetime = krb5_ticket_lifetime;
-
- /* set up credential cache -- obeying KRB5_ENV_CCNAME
- set earlier */
- /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */
- if ((code = krb5_cc_default(kcontext, &ccache))) {
- com_err("login", code, "while getting default ccache");
- return 0;
- }
- /* setup code from v5 kinit */
- memset((char *)&my_creds, 0, sizeof(my_creds));
+ krb5_principal me;
- code = krb5_parse_name (kcontext, username, &me);
- if (code) {
+ if (code = krb5_parse_name(kcontext, username, &me)) {
com_err ("login", code, "when parsing name %s",username);
return 0;
}
- *me_p = my_creds.client = me;
- code = krb5_cc_initialize (kcontext, ccache, me);
- if (code) {
- com_err ("login", code,
- "when initializing cache");
- return 0;
- }
+ *me_p = me;
- code = krb5_build_principal_ext(kcontext, &server,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- tgtname.length, tgtname.data,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- 0);
- if (code) {
- com_err("login", code,
- "while building server name");
- goto nuke_ccache;
- }
-
- my_creds.server = server;
- code = krb5_timeofday(kcontext, &now);
- if (code) {
- com_err("login", code,
- "while getting time of day");
- goto nuke_ccache;
- }
- my_creds.times.starttime = 0; /* start timer when
- request gets to KDC */
- my_creds.times.endtime = now + lifetime;
- my_creds.times.renew_till = 0;
-
- code = krb5_get_in_tkt_with_password(kcontext, krb5_options,
- 0, NULL, 0 /*preauth*/,
- pass,
- ccache,
- &my_creds, 0);
-
- if (code) {
+ if (code = krb5_get_init_creds_password(kcontext, &my_creds, me, pass,
+ krb5_prompter_posix, NULL,
+ 0, NULL, NULL)) {
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
fprintf (stderr,
"%s: Kerberos password incorrect\n",
else
com_err ("login", code,
"while getting initial credentials");
- nuke_ccache:
- krb5_cc_destroy (kcontext, ccache);
return 0;
- } else {
- /* get_name pulls out just the name not the
- type */
- strncpy(ccfile, krb5_cc_get_name(kcontext, ccache), sizeof(ccfile));
- ccfile[sizeof(ccfile) - 1] = '\0';
- krbflag = got_v5_tickets = 1;
- return 1;
}
+
+ krbflag = got_v5_tickets = 1;
+
+ return 1;
}
int have_v5_tickets (me)
krbflag = 1;
return 1;
}
+#endif /* KRB5_GET_TICKETS */
#ifdef KRB4_CONVERT
try_convert524 (kcontext, me)
krb5_creds increds, *v5creds;
CREDENTIALS v4creds;
- if (!got_v5_tickets)
- return 0;
/* or do this directly with krb524_convert_creds_kdc */
krb524_init_ets(kcontext);
}
#endif /* KRB4_GET_TICKETS */
-/* call already conditionalized on login_krb5_get_tickets */
-/*
- * Verify the Kerberos ticket-granting ticket just retrieved for the
- * user. If the Kerberos server doesn't respond, assume the user is
- * trying to fake us out (since we DID just get a TGT from what is
- * supposedly our KDC). If the host/<host> service is unknown (i.e.,
- * the local keytab doesn't have it), let her in.
- *
- * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
- */
-int verify_krb_v5_tgt (c)
- krb5_context c;
+void destroy_tickets()
{
- char phost[BUFSIZ];
- krb5_ccache ccdef;
- int retval, have_keys;
- krb5_principal princ;
- krb5_keyblock *kb = 0;
- krb5_error_code krbval;
- krb5_data packet;
- krb5_auth_context auth_context = NULL;
- krb5_ticket *ticket = NULL;
-
- /* XXX This is to work around a library bug. I'm not sure if it's
- been fixed for beta-7, so leave this in for now. Remove it (and
- fix the bug if necessary) after beta-7 ships.
-
- Whoever wrote that comment didn't mention what the bug is! Ted
- says it is something about the starttime of the ticket and
- "now" being equal. He thinks it is fixed, but isn't sure.
- */
- sleep(2);
-
- /* get the server principal for the local host */
- /* (use defaults of "host" and canonicalized local name) */
- krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ);
- if (krbval) {
- com_err ("login", krbval, "constructing local service name");
- return -1;
- }
+#ifdef KRB5_GET_TICKETS
+ krb5_ccache cache;
+ krb5_error_code retval;
- /* since krb5_sname_to_principal has done the work for us, just
- extract the name directly */
- strncpy(phost, krb5_princ_component(c, princ, 1)->data, sizeof(phost));
- phost[sizeof(phost) - 1] = '\0';
-
- /* Do we have host/<host> keys? */
- /* (use default keytab, kvno IGNORE_VNO to get the first match,
- and enctype is currently ignored anyhow.) */
- krbval = krb5_kt_read_service_key (c, NULL, princ, 0, ENCTYPE_DES_CBC_CRC, &kb);
- if (kb)
- krb5_free_keyblock (c, kb);
- /* any failure means we don't have keys at all. */
- have_keys = krbval ? 0 : 1;
-
- /* set up credential cache -- obeying KRB5_ENV_CCNAME set earlier */
- /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */
- if (krbval = krb5_cc_default(c, &ccdef)) {
- com_err("login", krbval, "while getting default ccache");
- return -1;
- }
- /* talk to the kdc and construct the ticket */
- krbval = krb5_mk_req(c, &auth_context, 0, "host", phost,
- 0, ccdef, &packet);
- /* wipe the auth context for mk_req */
- if (auth_context) {
- krb5_auth_con_free(c, auth_context);
- auth_context = NULL;
- }
- if (krbval == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
- /* we have a service key, so something should be
- in the database, therefore this error packet could
- have come from an attacker. */
- if (have_keys) { retval = -1; goto EGRESS; }
- /* but if it is unknown and we've got no key, we don't
- have any security anyhow, so it is ok. */
- else { retval = 0; goto EGRESS; }
- }
- else if (krbval) {
- com_err("login", krbval,
- "Unable to verify Kerberos V5 TGT: %s", phost);
-#ifndef SYSLOG42
- syslog (LOG_NOTICE|LOG_AUTH, "Kerberos V5 TGT bad: %s",
- error_message(krbval));
-#endif
- retval = -1;
- goto EGRESS;
- }
- /* got ticket, try to use it */
- krbval = krb5_rd_req(c, &auth_context, &packet,
- princ, NULL, NULL, &ticket);
- if (krbval) {
- if (!have_keys)
- /* The krb5 errors aren't specified well, but I think
- these values cover the cases we expect. */
- switch (krbval) {
- /* no keytab */
- case ENOENT:
- /* keytab found, missing entry */
-#if 0 /* Don't depend on the nameserver for security. Assume that if
- we have a keytab, it must contain the right host/FQDN key. */
- case KRB5_KT_NOTFOUND:
-#endif
- retval = 0;
- break;
- default:
- /* unexpected error: fail */
- retval = -1;
- break;
- }
- else
- /* Any error here is bad. */
- retval = -1;
- com_err("login", krbval, "Unable to verify host ticket");
-#ifndef SYSLOG42
- syslog (LOG_NOTICE|LOG_AUTH, "can't verify v5 ticket: %s; %s\n",
- error_message(krbval),
- retval
- ? "keytab found, assuming failure"
- : "no keytab found, assuming success");
-#endif
- goto EGRESS;
+ if (login_krb5_get_tickets) {
+ if(!krb5_cc_default(kcontext, &cache))
+ krb5_cc_destroy (kcontext, cache);
}
- /*
- * The host/<host> ticket has been received _and_ verified.
- */
- retval = 1;
- /* do cleanup and return */
-EGRESS:
- if (auth_context) krb5_auth_con_free(c, auth_context);
- krb5_free_principal(c, princ);
- /* possibly ticket and packet need freeing here as well */
- /* memset (&ticket, 0, sizeof (ticket)); */
- return retval;
-}
-
-destroy_tickets()
-{
- krb5_context c;
- krb5_ccache cache;
- krb5_error_code retval;
-
-#ifdef KRB5_GET_TICKETS
- if (login_krb5_get_tickets) {
- if(!krb5_cc_default(kcontext, &cache))
- krb5_cc_destroy (kcontext, cache);
- }
#endif
#ifdef KRB4_GET_TICKETS
- if (login_krb4_get_tickets||login_krb4_convert)
+ if (login_krb4_get_tickets || login_krb4_convert)
dest_tkt();
#endif /* KRB4_GET_TICKETS */
}
-#endif /* KRB5_GET_TICKETS */
-\f
/* AFS support routines */
#ifdef SETPAG
void
afs_login ()
{
-#ifdef KRB4_GET_TICKETS
-#ifdef SETPAG
+#if defined(KRB4_GET_TICKETS) && defined(SETPAG)
if (login_krb4_get_tickets && pwd->pw_uid) {
/* Only reset the pag for non-root users. */
/* This allows root to become anything. */
pagflag = try_setpag ();
}
#endif
-#endif /* KRB4_GET_TICKETS */
#ifdef KRB_RUN_AKLOG
if (got_v4_tickets && login_krb_run_aklog) {
/* KPROGDIR is $(prefix)/bin */
try_unlog ();
#endif
}
-\f
+
/* Main routines */
#define EXCL_AUTH_TEST if (rflag || kflag || Kflag || eflag || fflag ) { \
- fprintf(stderr, \
- "login: only one of -r, -k, -K, -e, -F, and -f allowed.\n"); \
- exit(1);\
- }
+ fprintf(stderr, \
+ "login: only one of -r, -k, -K, -e, -F, and -f allowed.\n"); \
+ exit(1); \
+}
#define EXCL_HOST_TEST if (rflag || kflag || Kflag || hflag) { \
- fprintf(stderr, \
- "login: only one of -r, -k, -K, and -h allowed.\n"); \
- exit(1);\
- }
+ fprintf(stderr, \
+ "login: only one of -r, -k, -K, and -h allowed.\n"); \
+ exit(1); \
+}
static void
read_env_vars_from_file (filename)
char *p, *eq;
char tbuf[MAXPATHLEN+2];
- if ((fp = fopen("/etc/environment", "r")) != NULL) {
+ if ((fp = fopen(filename, "r")) != NULL) {
while (fgets(tbuf, sizeof(tbuf), fp)) {
if (tbuf[0] == '#')
continue;
tty, hostname, UT_NAMESIZE,
username);
#endif
- }
- else
+ } else {
syslog(LOG_ERR,
"REPEATED LOGIN FAILURES ON %s, %.*s",
tty, UT_NAMESIZE, username);
+ }
}
int main(argc, argv)
- int argc;
- char **argv;
+ int argc;
+ char **argv;
{
- extern int optind;
- extern char *optarg, **environ;
- struct group *gr;
- int ch;
- char *p;
- int fflag, hflag, pflag, rflag, cnt;
- int kflag, Kflag, eflag;
- int quietlog, passwd_req, ioctlval;
- sigtype timedout();
- char *domain, **envinit, *ttyn, *tty;
- char tbuf[MAXPATHLEN + 2];
- char *ttyname(), *stypeof(), *crypt(), *getpass();
- time_t login_time;
- int retval;
-int rewrite_ccache = 1; /*try to write out ccache*/
+ extern int optind;
+ extern char *optarg, **environ;
+ struct group *gr;
+ int ch;
+ char *p;
+ int fflag, hflag, pflag, rflag, cnt;
+ int kflag, Kflag, eflag;
+ int quietlog, passwd_req, ioctlval;
+ sigtype timedout();
+ char *domain, **envinit, *ttyn, *tty;
+ char tbuf[MAXPATHLEN + 2];
+ char *ttyname(), *stypeof(), *crypt(), *getpass();
+ time_t login_time;
+ int retval;
+ int rewrite_ccache = 1; /*try to write out ccache*/
#ifdef KRB5_GET_TICKETS
- krb5_principal me;
- krb5_creds save_v5creds;
+ krb5_principal me;
+ krb5_creds save_v5creds;
+ krb5_ccache xtra_creds = NULL;
#endif
#ifdef KRB4_GET_TICKETS
- CREDENTIALS save_v4creds;
+ CREDENTIALS save_v4creds;
#endif
- char *ccname = 0; /* name of forwarded cache */
- char *tz = 0;
+ char *ccname = 0; /* name of forwarded cache */
+ char *tz = 0;
- off_t lseek();
- handler sa;
+ off_t lseek();
+ handler sa;
- handler_init (sa, timedout);
- handler_set (SIGALRM, sa);
- (void)alarm((u_int)timeout);
+ handler_init (sa, timedout);
+ handler_set (SIGALRM, sa);
+ (void)alarm((u_int)timeout);
- handler_init (sa, SIG_IGN);
- handler_set (SIGQUIT, sa);
- handler_set (SIGINT, sa);
- setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+ handler_init (sa, SIG_IGN);
+ handler_set (SIGQUIT, sa);
+ handler_set (SIGINT, sa);
+ setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
#ifdef OQUOTA
- (void)quota(Q_SETUID, 0, 0, 0);
+ (void)quota(Q_SETUID, 0, 0, 0);
#endif
- /*
- * -p is used by getty to tell login not to destroy the environment
- * -r is used by rlogind to cause the autologin protocol;
- * -f is used to skip a second login authentication
- * -F is used to skip a second login authentication, allows login as root
- * -e is used to skip a second login authentication, but allows
- * login as root.
- * -h is used by other servers to pass the name of the
- * remote host to login so that it may be placed in utmp and wtmp
- * -k is used by klogind to cause the Kerberos V4 autologin protocol;
- * -K is used by klogind to cause the Kerberos V4 autologin
- * protocol with restricted access.
- */
- (void)gethostname(tbuf, sizeof(tbuf));
- domain = strchr(tbuf, '.');
-
- fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
- passwd_req = 1;
- while ((ch = getopt(argc, argv, "Ffeh:pr:k:K:")) != -1)
- switch (ch) {
- case 'f':
- EXCL_AUTH_TEST;
- fflag = 1;
- break;
- case 'F':
- EXCL_AUTH_TEST;
- fflag = 1;
- break;
- case 'h':
- EXCL_HOST_TEST;
- if (getuid()) {
- fprintf(stderr,
- "login: -h for super-user only.\n");
- exit(1);
- }
- hflag = 1;
- if (domain && (p = strchr(optarg, '.')) &&
- strcmp(p, domain) == 0)
- *p = 0;
- hostname = optarg;
- break;
- case 'p':
- pflag = 1;
- break;
- case 'r':
- EXCL_AUTH_TEST;
- EXCL_HOST_TEST;
- if (getuid()) {
- fprintf(stderr,
- "login: -r for super-user only.\n");
- exit(1);
- }
- /* "-r hostname" must be last args */
- if (optind != argc) {
- fprintf(stderr, "Syntax error.\n");
- exit(1);
- }
- rflag = 1;
- passwd_req = (doremotelogin(optarg) == -1);
- if (domain && (p = strchr(optarg, '.')) &&
- !strcmp(p, domain))
- *p = '\0';
- hostname = optarg;
- break;
+ /*
+ * -p is used by getty to tell login not to destroy the environment
+ * -r is used by rlogind to cause the autologin protocol;
+ * -f is used to skip a second login authentication
+ * -F is used to skip a second login authentication, allows login as root
+ * -e is used to skip a second login authentication, but allows
+ * login as root.
+ * -h is used by other servers to pass the name of the
+ * remote host to login so that it may be placed in utmp and wtmp
+ * -k is used by klogind to cause the Kerberos V4 autologin protocol;
+ * -K is used by klogind to cause the Kerberos V4 autologin
+ * protocol with restricted access.
+ */
+ (void)gethostname(tbuf, sizeof(tbuf));
+ domain = strchr(tbuf, '.');
+
+ fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
+ passwd_req = 1;
+ while ((ch = getopt(argc, argv, "Ffeh:pr:k:K:")) != -1)
+ switch (ch) {
+ case 'f':
+ EXCL_AUTH_TEST;
+ fflag = 1;
+ break;
+ case 'F':
+ EXCL_AUTH_TEST;
+ fflag = 1;
+ break;
+ case 'h':
+ EXCL_HOST_TEST;
+ if (getuid()) {
+ fprintf(stderr,
+ "login: -h for super-user only.\n");
+ exit(1);
+ }
+ hflag = 1;
+ if (domain && (p = strchr(optarg, '.')) && strcmp(p, domain) == 0)
+ *p = 0;
+ hostname = optarg;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ EXCL_AUTH_TEST;
+ EXCL_HOST_TEST;
+ if (getuid()) {
+ fprintf(stderr,
+ "login: -r for super-user only.\n");
+ exit(1);
+ }
+ /* "-r hostname" must be last args */
+ if (optind != argc) {
+ fprintf(stderr, "Syntax error.\n");
+ exit(1);
+ }
+ rflag = 1;
+ passwd_req = (doremotelogin(optarg) == -1);
+ if (domain && (p = strchr(optarg, '.')) && !strcmp(p, domain))
+ *p = '\0';
+ hostname = optarg;
+ break;
#ifdef KRB4_KLOGIN
- case 'k':
- case 'K':
- EXCL_AUTH_TEST;
- EXCL_HOST_TEST;
- if (getuid()) {
- fprintf(stderr,
- "login: -%c for super-user only.\n", ch);
- exit(1);
- }
- /* "-k hostname" must be last args */
- if (optind != argc) {
- fprintf(stderr, "Syntax error.\n");
- exit(1);
- }
- if (ch == 'K')
- Kflag = 1;
- else
- kflag = 1;
- passwd_req = (do_krb_login(optarg,
- Kflag ? 1 : 0) == -1);
- if (domain && (p = strchr(optarg, '.')) &&
- !strcmp(p, domain))
- *p = '\0';
- hostname = optarg;
- break;
+ case 'k':
+ case 'K':
+ EXCL_AUTH_TEST;
+ EXCL_HOST_TEST;
+ if (getuid()) {
+ fprintf(stderr,
+ "login: -%c for super-user only.\n", ch);
+ exit(1);
+ }
+ /* "-k hostname" must be last args */
+ if (optind != argc) {
+ fprintf(stderr, "Syntax error.\n");
+ exit(1);
+ }
+ if (ch == 'K')
+ Kflag = 1;
+ else
+ kflag = 1;
+ passwd_req = (do_krb_login(optarg, Kflag ? 1 : 0) == -1);
+ if (domain &&
+ (p = strchr(optarg, '.')) &&
+ (!strcmp(p, domain)))
+ *p = '\0';
+ hostname = optarg;
+ break;
#endif /* KRB4_KLOGIN */
- case 'e':
- EXCL_AUTH_TEST;
- if (getuid()) {
- fprintf(stderr,
- "login: -e for super-user only.\n");
- exit(1);
- }
- eflag = 1;
- passwd_req = 0;
- break;
- case '?':
- default:
- fprintf(stderr, "usage: login [-fp] [username]\n");
- exit(1);
- }
- argc -= optind;
- argv += optind;
- if (*argv)
- username = *argv;
+ case 'e':
+ EXCL_AUTH_TEST;
+ if (getuid()) {
+ fprintf(stderr,
+ "login: -e for super-user only.\n");
+ exit(1);
+ }
+ eflag = 1;
+ passwd_req = 0;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "usage: login [-fp] [username]\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+ if (*argv)
+ username = *argv;
#if !defined(POSIX_TERMIOS) && defined(TIOCLSET)
- ioctlval = 0;
- /* Only do this we we're not using POSIX_TERMIOS */
- (void)ioctl(0, TIOCLSET, (char *)&ioctlval);
+ ioctlval = 0;
+ /* Only do this we we're not using POSIX_TERMIOS */
+ (void)ioctl(0, TIOCLSET, (char *)&ioctlval);
#endif
#ifdef TIOCNXCL
- (void)ioctl(0, TIOCNXCL, (char *)0);
+ (void)ioctl(0, TIOCNXCL, (char *)0);
#endif
- ioctlval = fcntl(0, F_GETFL);
+ ioctlval = fcntl(0, F_GETFL);
#ifdef O_NONBLOCK
- ioctlval &= ~O_NONBLOCK;
+ ioctlval &= ~O_NONBLOCK;
#endif
#ifdef O_NDELAY
- ioctlval &= ~O_NDELAY;
+ ioctlval &= ~O_NDELAY;
#endif
- (void)fcntl(0, F_SETFL, ioctlval);
+ (void)fcntl(0, F_SETFL, ioctlval);
/*
* If talking to an rlogin process, propagate the terminal type and
* baud rate across the network.
*/
- if (eflag)
- lgetstr(term, sizeof(term), "Terminal type");
- else if (!(kflag || Kflag )) /*Preserve terminal if not read over net */
- {
- if (getenv("TERM")) {
- strncpy(term, getenv("TERM"), sizeof(term));
- term[sizeof(term) - 1] = '\0';
- }
- }
+ if (eflag) {
+ lgetstr(term, sizeof(term), "Terminal type");
+ } else if (!(kflag || Kflag)) {/* Preserve terminal if not read over net */
+ if (getenv("TERM")) {
+ strncpy(term, getenv("TERM"), sizeof(term));
+ term[sizeof(term) - 1] = '\0';
+ }
+ }
- term_init (rflag || kflag || Kflag || eflag);
+ term_init (rflag || kflag || Kflag || eflag);
- for (cnt = getdtablesize(); cnt > 2; cnt--)
- (void) close(cnt);
+ for (cnt = getdtablesize(); cnt > 2; cnt--)
+ (void) close(cnt);
- ttyn = ttyname(0);
- if (ttyn == NULL || *ttyn == '\0')
- ttyn = "/dev/tty??";
+ ttyn = ttyname(0);
+ if (ttyn == NULL || *ttyn == '\0')
+ ttyn = "/dev/tty??";
- /* This allows for tty names of the form /dev/pts/4 as well */
- if ((tty = strchr(ttyn, '/')) && (tty = strchr(tty+1, '/')))
- ++tty;
- else
- tty = ttyn;
+ /* This allows for tty names of the form /dev/pts/4 as well */
+ if ((tty = strchr(ttyn, '/')) && (tty = strchr(tty+1, '/')))
+ ++tty;
+ else
+ tty = ttyn;
#ifndef LOG_ODELAY /* 4.2 syslog ... */
- openlog("login", 0);
+ openlog("login", 0);
#else
- openlog("login", LOG_ODELAY, LOG_AUTH);
+ openlog("login", LOG_ODELAY, LOG_AUTH);
#endif /* 4.2 syslog */
/******* begin askpw *******/
- /* overall:
- ask for username if we don't have it already
- look it up in local pw or shadow file (to get crypt string)
- ask for password
- try and get v4, v5 tickets with it
- try and use the tickets against the local srvtab
- if the password matches, always let them in
- if the ticket decrypts, let them in.
- v5 needs to work, does v4?
- */
-
+ /* overall:
+ ask for username if we don't have it already
+ look it up in local pw or shadow file (to get crypt string)
+ ask for password
+ try and get v4, v5 tickets with it
+ try and use the tickets against the local srvtab
+ if the password matches, always let them in
+ if the ticket decrypts, let them in.
+ v5 needs to work, does v4?
+ */
+
+ k_init (ttyn);
+
+ for (cnt = 0;; username = NULL) {
#ifdef KRB5_GET_TICKETS
- k_init (ttyn);
-#endif
-
- for (cnt = 0;; username = NULL) {
-#ifdef KRB5_GET_TICKETS
- int kpass_ok,lpass_ok;
- char user_pwstring[MAXPWSIZE];
- /* variables from v5 kinit */
+ int kpass_ok, lpass_ok;
+ char user_pwstring[MAXPWSIZE];
#endif /* KRB5_GET_TICKETS */
- if (username == NULL) {
- fflag = 0;
- getloginname();
- }
-
- lookup_user (username); /* sets pwd */
-
- /* if user not super-user, check for disabled logins */
- if (pwd == NULL || pwd->pw_uid)
- checknologin();
+ if (username == NULL) {
+ fflag = 0;
+ getloginname();
+ }
- /*
- * Allows automatic login by root.
- * If not invoked by root, disallow if the uid's differ.
- */
+ lookup_user(username); /* sets pwd */
- if (fflag && pwd) {
- int uid = (int) getuid();
- passwd_req = (uid && uid != pwd->pw_uid);
- }
+ /* if user not super-user, check for disabled logins */
+ if (pwd == NULL || pwd->pw_uid)
+ checknologin();
- /*
- * If no remote login authentication and a password exists
- * for this user, prompt for one and verify it.
- */
- if (!passwd_req)
- break;
+ /*
+ * Allows automatic login by root.
+ * If not invoked by root, disallow if the uid's differ.
+ */
- if (! unix_needs_passwd ())
- break;
+ if (fflag && pwd) {
+ int uid = (int) getuid();
+ passwd_req = (uid && uid != pwd->pw_uid);
+ }
- /* we have several sets of code:
- 1) get v5 tickets alone -DKRB5_GET_TICKETS
- 2) get v4 tickets alone [** don't! only get them *with* v5 **]
- 3) get both tickets -DKRB5_GET_TICKETS -DKRB4_GET_TICKETS
- 3a) use krb524 calls to get the v4 tickets -DKRB4_CONVERT plus (3).
- 4) get no tickets and use the password file (none of thes defined.)
+ /*
+ * If no remote login authentication and a password exists
+ * for this user, prompt for one and verify it.
+ */
+ if (!passwd_req)
+ break;
+
+ if (!unix_needs_passwd())
+ break;
+
+ /* we have several sets of code:
+ 1) get v5 tickets alone -DKRB5_GET_TICKETS
+ 2) get v4 tickets alone [** don't! only get them *with* v5 **]
+ 3) get both tickets -DKRB5_GET_TICKETS -DKRB4_GET_TICKETS
+ 3a) use krb524 calls to get the v4 tickets -DKRB4_CONVERT plus (3).
+ 4) get no tickets and use the password file (none of thes defined.)
- Likewise we need to (optionally?) test these tickets against local srvtabs.
- */
+ Likewise we need to (optionally?) test these tickets against
+ local srvtabs.
+ */
+
#ifdef KRB5_GET_TICKETS
- if (login_krb5_get_tickets) {
- /* rename these to something more verbose */
- kpass_ok = 0;
- lpass_ok = 0;
-
- setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
- if (! k5_get_password (user_pwstring, sizeof (user_pwstring))) {
- goto bad_login;
- }
+ if (login_krb5_get_tickets) {
+ /* rename these to something more verbose */
+ kpass_ok = 0;
+ lpass_ok = 0;
- /* now that we have the password, we've obscured things
- sufficiently, and can avoid trying tickets */
- if (!pwd)
- goto bad_login;
+ setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
+ if (! k5_get_password(user_pwstring, sizeof (user_pwstring))) {
+ goto bad_login;
+ }
+
+ /* now that we have the password, we've obscured things
+ sufficiently, and can avoid trying tickets */
+ if (!pwd)
+ goto bad_login;
- lpass_ok = unix_passwd_okay (user_pwstring);
+ lpass_ok = unix_passwd_okay(user_pwstring);
- if (pwd->pw_uid != 0) { /* Don't get tickets for root */
- try_krb5 (&me, user_pwstring);
+ if (pwd->pw_uid != 0) { /* Don't get tickets for root */
+ try_krb5(&me, user_pwstring);
#ifdef KRB4_GET_TICKETS
- if (login_krb4_get_tickets
- && (!got_v5_tickets
- || !login_krb4_convert))
- try_krb4 (me, user_pwstring);
+ if (login_krb4_get_tickets &&
+ !(got_v5_tickets && login_krb4_convert))
+ try_krb4(me, user_pwstring);
+#endif
+ krbflag = (got_v5_tickets
+#ifdef KRB4_GET_TICKETS
+ || got_v4_tickets
#endif
- krbflag = got_v5_tickets || got_v4_tickets;
- memset (user_pwstring, 0, sizeof(user_pwstring));
- /* password wiped, so we can relax */
- setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+ );
+ memset (user_pwstring, 0, sizeof(user_pwstring));
+ /* password wiped, so we can relax */
+ setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+ } else {
+ memset(user_pwstring, 0, sizeof(user_pwstring));
+ setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+ }
+
+ /* Policy: If local password is good, user is good.
+ We really can't trust the Kerberos password,
+ because somebody on the net could spoof the
+ Kerberos server (not easy, but possible).
+ Some sites might want to use it anyways, in
+ which case they should change this line
+ to:
+ if (kpass_ok)
+ */
+
+ if (lpass_ok)
+ break;
+ if (got_v5_tickets) {
+ if (retval = krb5_verify_init_creds(kcontext, &my_creds, NULL,
+ NULL, &xtra_creds,
+ NULL)) {
+ com_err("login", retval, "while verifying initial ticket");
+#ifndef SYSLOG42
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "can't verify v5 ticket: %s\n",
+ error_message(retval));
+#endif
} else {
- memset (user_pwstring, 0, sizeof(user_pwstring));
- setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+ break; /* we're ok */
}
-
- /* Policy: If local password is good, user is good.
- We really can't trust the Kerberos password,
- because somebody on the net could spoof the
- Kerberos server (not easy, but possible).
- Some sites might want to use it anyways, in
- which case they should change this line
- to:
- if (kpass_ok)
- */
- if (lpass_ok)
- break;
- if (got_v5_tickets
- && verify_krb_v5_tgt(kcontext) != -1)
- break; /* we're ok */
+ }
#ifdef KRB4_GET_TICKETS
- if (login_krb4_get_tickets) {
- if (got_v4_tickets
- && ! got_v5_tickets
- && verify_krb_v4_tgt(realm) != -1)
- break; /* we're ok */
- }
+ else if (got_v4_tickets) {
+ if (login_krb4_get_tickets &&
+ (verify_krb_v4_tgt(realm) != -1))
+ break; /* we're ok */
+ }
#endif /* KRB4_GET_TICKETS */
+
bad_login:
- setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
- if (krbflag)
- destroy_tickets(); /* clean up tickets if login fails */
+ setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
- }
+ if (krbflag)
+ destroy_tickets(); /* clean up tickets if login fails */
+ }
#endif /* KRB5_GET_TICKETS */
+
#ifdef OLD_PASSWD
- p = getpass ("Password:");
- /* conventional password only */
- if (unix_passwd_okay (p))
- break;
+ p = getpass ("Password:");
+ /* conventional password only */
+ if (unix_passwd_okay (p))
+ break;
#endif /* OLD_PASSWD */
- printf("Login incorrect\n");
- if (++cnt >= 5) {
- log_repeated_failures (tty, hostname);
-/* irix has no tichpcl */
+ printf("Login incorrect\n");
+ if (++cnt >= 5) {
+ log_repeated_failures (tty, hostname);
+ /* irix has no tichpcl */
#ifdef TIOCHPCL
- (void)ioctl(0, TIOCHPCL, (char *)0);
+ (void)ioctl(0, TIOCHPCL, (char *)0);
#endif
- sleepexit(1);
- }
- } /* end of password retry loop */
+ sleepexit(1);
+ }
+ } /* end of password retry loop */
- /* committed to login -- turn off timeout */
- (void)alarm((u_int)0);
+ /* committed to login -- turn off timeout */
+ (void) alarm((u_int) 0);
- /*
- * If valid so far and root is logging in, see if root logins on
- * this terminal are permitted.
- *
- * We allow authenticated remote root logins (except -r style)
- */
- if (pwd->pw_uid == 0 && !rootterm(tty) && (passwd_req || rflag)) {
- if (hostname)
+ /*
+ * If valid so far and root is logging in, see if root logins on
+ * this terminal are permitted.
+ *
+ * We allow authenticated remote root logins (except -r style)
+ */
+
+ if (pwd->pw_uid == 0 && !rootterm(tty) && (passwd_req || rflag)) {
+ if (hostname) {
#ifdef UT_HOSTSIZE
- syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
- tty, UT_HOSTSIZE, hostname);
+ syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
+ tty, UT_HOSTSIZE, hostname);
#else
- syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %s",
- tty, hostname);
+ syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %s",
+ tty, hostname);
#endif
- else
- syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty);
- printf("Login incorrect\n");
- sleepexit(1);
+ } else {
+ syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty);
}
+ printf("Login incorrect\n");
+ sleepexit(1);
+ }
#ifdef OQUOTA
- if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
- switch(errno) {
- case EUSERS:
- fprintf(stderr,
- "Too many users logged on already.\nTry again later.\n");
- break;
- case EPROCLIM:
- fprintf(stderr,
- "You have too many processes running.\n");
- break;
- default:
- perror("quota (Q_SETUID)");
- }
- sleepexit(0);
+ if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
+ switch(errno) {
+ case EUSERS:
+ fprintf(stderr,
+ "Too many users logged on already.\nTry again later.\n");
+ break;
+ case EPROCLIM:
+ fprintf(stderr,
+ "You have too many processes running.\n");
+ break;
+ default:
+ perror("quota (Q_SETUID)");
}
+ sleepexit(0);
+ }
#endif
- if (chdir(pwd->pw_dir) < 0) {
- printf("No directory %s!\n", pwd->pw_dir);
- if (chdir("/"))
- exit(0);
- pwd->pw_dir = "/";
- printf("Logging in with home = \"/\".\n");
- }
- /* nothing else left to fail -- really log in */
- {
- struct utmp utmp;
-
- login_time = time(&utmp.ut_time);
- if ( (retval = pty_update_utmp(PTY_USER_PROCESS, getpid(), username, ttyn, hostname, PTY_TTYSLOT_USABLE)) < 0 )
- com_err (argv[0], retval, "while updating utmp");
- }
+ if (chdir(pwd->pw_dir) < 0) {
+ printf("No directory %s!\n", pwd->pw_dir);
+ if (chdir("/"))
+ exit(0);
+ pwd->pw_dir = "/";
+ printf("Logging in with home = \"/\".\n");
+ }
- quietlog = access(HUSHLOGIN, F_OK) == 0;
- dolastlog(quietlog, tty);
+ /* nothing else left to fail -- really log in */
+ {
+ struct utmp utmp;
- if (!hflag && !rflag && !kflag && !Kflag && !eflag) { /* XXX */
- static struct winsize win = { 0, 0, 0, 0 };
+ login_time = time(&utmp.ut_time);
+ if ((retval = pty_update_utmp(PTY_USER_PROCESS, getpid(), username,
+ ttyn, hostname,
+ PTY_TTYSLOT_USABLE)) < 0)
+ com_err (argv[0], retval, "while updating utmp");
+ }
- (void)ioctl(0, TIOCSWINSZ, (char *)&win);
- }
+ quietlog = access(HUSHLOGIN, F_OK) == 0;
+ dolastlog(quietlog, tty);
- (void)chown(ttyn, pwd->pw_uid,
- (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+ if (!hflag && !rflag && !kflag && !Kflag && !eflag) { /* XXX */
+ static struct winsize win = { 0, 0, 0, 0 };
- (void)chmod(ttyn, 0620);
-#ifdef KRB5_GET_TICKETS
- /* Maybe telnetd got tickets for us? */
- if (!got_v5_tickets && have_v5_tickets (&me))
- got_v5_tickets = 1;
-#endif /* GET_KRB_TICKETS */
+ (void)ioctl(0, TIOCSWINSZ, (char *)&win);
+ }
-#ifdef KRB4_GET_TICKETS
- if ( login_krb4_convert && !got_v4_tickets) {
+ (void)chown(ttyn, pwd->pw_uid,
+ (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+ (void)chmod(ttyn, 0620);
- if (got_v5_tickets)
- try_convert524 (kcontext, me);
+#ifdef KRB5_GET_TICKETS
+ /* Maybe telnetd got tickets for us? */
+ if (!got_v5_tickets && have_v5_tickets (&me))
+ forwarded_v5_tickets = 1;
+#endif /* KRB5_GET_TICKETS */
- }
+#if defined(KRB5_GET_TICKETS) && defined(KRB4_CONVERT)
+ if (login_krb4_convert && !got_v4_tickets) {
+ if (got_v5_tickets||forwarded_v5_tickets)
+ try_convert524 (kcontext, me);
+ }
#endif
-#if defined(KRB5_GET_TICKETS) || defined(KRB4_GET_TICKETS)
-#if defined(KRB5_GET_TICKETS) && defined(KRB4_GET_TICKETS)
- if (login_krb4_get_tickets || login_krb5_get_tickets) {
-#elif defined(KRB4_GET_TICKETS)
- if (login_krb4_get_tickets) {
-#else
- if (login_krb5_get_tickets) {
+#ifdef KRB5_GET_TICKETS
+ if (login_krb5_get_tickets)
+ dofork();
+ else
#endif
- /* Fork so that we can call kdestroy */
+#ifdef KRB4_GET_TICKETS
+ if (login_krb4_get_tickets)
dofork();
- }
-#endif /* KRB4_GET_TICKETS */
+#endif
/* If the user's shell does not do job control we should put it in a
different process group than than us, and set the tty process group
telnetd or rlogind if they don't properly detach from their
controlling tty, which is the case (under SunOS at least.) */
- {
- int p = getpid();
- struct sigaction sa, osa;
+ {
+ int p = getpid();
+ struct sigaction sa, osa;
- /* this will set the PGID to the PID. */
+ /* this will set the PGID to the PID. */
#ifdef HAVE_SETPGID
- if (setpgid(p,p) < 0) perror("login.krb5: setpgid");
+ if (setpgid(p,p) < 0)
+ perror("login.krb5: setpgid");
+#elif defined(SETPGRP_TWOARG)
+ if (setpgrp(p,p) < 0)
+ perror("login.krb5: setpgrp");
#else
-#ifdef SETPGRP_TWOARG
- if (setpgrp(p,p) < 0) perror("login.krb5: setpgrp");
-#else
- if (setpgrp() < 0) perror("login.krb5: setpgrp");
-#endif
+ if (setpgrp() < 0)
+ perror("login.krb5: setpgrp");
#endif
- /* This will cause SIGTTOU to be ignored for the duration
- of the TIOCSPGRP. If this is not done, and the parent's
- process group is the foreground pgrp of the tty, then
- this will suspend the child, which is bad. */
+ /* This will cause SIGTTOU to be ignored for the duration
+ of the TIOCSPGRP. If this is not done, and the parent's
+ process group is the foreground pgrp of the tty, then
+ this will suspend the child, which is bad. */
- sa.sa_flags = 0;
- sa.sa_handler = SIG_IGN;
- sigemptyset(&(sa.sa_mask));
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&(sa.sa_mask));
- if (sigaction(SIGTTOU, &sa, &osa))
- perror("login.krb5: sigaction(SIGTTOU, SIG_IGN)");
+ if (sigaction(SIGTTOU, &sa, &osa))
+ perror("login.krb5: sigaction(SIGTTOU, SIG_IGN)");
- /* This will set the foreground process group of the
- controlling terminal to this process group (containing
- only this process). */
+ /* This will set the foreground process group of the
+ controlling terminal to this process group (containing
+ only this process). */
#ifdef HAVE_TCSETPGRP
- if (tcsetpgrp(0, p) < 0) perror("login.krb5: tcsetpgrp");
+ if (tcsetpgrp(0, p) < 0)
+ perror("login.krb5: tcsetpgrp");
#else
- if (ioctl(0, TIOCSPGRP, &p) < 0) perror("login.krb5: tiocspgrp");
+ if (ioctl(0, TIOCSPGRP, &p) < 0)
+ perror("login.krb5: tiocspgrp");
#endif
- /* This will reset the SIGTTOU handler */
+ /* This will reset the SIGTTOU handler */
- if (sigaction(SIGTTOU, &osa, NULL))
- perror("login.krb5: sigaction(SIGTTOU, [old handler])");
- }
+ if (sigaction(SIGTTOU, &osa, NULL))
+ perror("login.krb5: sigaction(SIGTTOU, [old handler])");
+ }
- (void)setgid((gid_t) pwd->pw_gid);
- (void) initgroups(username, pwd->pw_gid);
+ (void) setgid((gid_t) pwd->pw_gid);
+ (void) initgroups(username, pwd->pw_gid);
- /*
- * The V5 ccache and V4 ticket file are both created as root.
- * They need to be owned by the user, and chown (a) assumes
- * they are stored in a file and (b) allows a race condition
- * in which a user can delete the file (if the directory
- * sticky bit is not set) and make it a symlink to somewhere
- * else; on some platforms, chown() on a symlink actually
- * changes the owner of the pointed-to file. This is Bad.
- *
- * So, we suck the V5 and V4 krbtgts into memory here, destroy
- * the ccache/ticket file, and recreate them later after the
- * setuid.
- */
+ /*
+ * The V5 ccache and V4 ticket file are both created as root.
+ * They need to be owned by the user, and chown (a) assumes
+ * they are stored in a file and (b) allows a race condition
+ * in which a user can delete the file (if the directory
+ * sticky bit is not set) and make it a symlink to somewhere
+ * else; on some platforms, chown() on a symlink actually
+ * changes the owner of the pointed-to file. This is Bad.
+ *
+ * So, we suck the V5 and V4 krbtgts into memory here, destroy
+ * the ccache/ticket file, and recreate them later after the
+ * setuid.
+ *
+ * With the new v5 api, v5 tickets are kept in memory until written
+ * out after the setuid. However, forwarded tickets still
+ * need to be read in and recreated later
+ */
#ifdef KRB5_GET_TICKETS
- if (got_v5_tickets) {
- krb5_creds mcreds;
-
- memset(&mcreds, 0, sizeof(mcreds));
- memset(&save_v5creds, 0, sizeof(save_v5creds));
-
- mcreds.client = me;
- retval = krb5_build_principal_ext(kcontext, &mcreds.server,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- tgtname.length, tgtname.data,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- 0);
- if (retval) {
- syslog(LOG_ERR,
- "%s while creating V5 krbtgt principal",
- error_message(retval));
- goto skip_ccache_rewrite;
- }
-
- mcreds.ticket_flags =0;
-
- if (retval = krb5_cc_retrieve_cred(kcontext, ccache,
- 0,
- &mcreds, &save_v5creds)) {
- syslog(LOG_ERR,
- "%s while retrieiving V5 initial ticket for copy",
- error_message(retval));
- skip_ccache_rewrite: rewrite_ccache = 0;
-
- }
- krb5_free_principal(kcontext, mcreds.server);
+ if (forwarded_v5_tickets) {
+ krb5_creds mcreds;
+
+ memset(&mcreds, 0, sizeof(mcreds));
+ memset(&save_v5creds, 0, sizeof(save_v5creds));
+
+ mcreds.client = me;
+ retval =
+ krb5_build_principal_ext(kcontext, &mcreds.server,
+ krb5_princ_realm(kcontext, me)->length,
+ krb5_princ_realm(kcontext, me)->data,
+ tgtname.length, tgtname.data,
+ krb5_princ_realm(kcontext, me)->length,
+ krb5_princ_realm(kcontext, me)->data,
+ 0);
+ if (retval) {
+ syslog(LOG_ERR,
+ "%s while creating V5 krbtgt principal",
+ error_message(retval));
+ rewrite_ccache = 0;
+ } else {
+ mcreds.ticket_flags = 0;
+
+ if (retval = krb5_cc_retrieve_cred(kcontext, ccache, 0,
+ &mcreds, &save_v5creds)) {
+ syslog(LOG_ERR,
+ "%s while retrieiving V5 initial ticket for copy",
+ error_message(retval));
+ rewrite_ccache = 0;
+ }
}
+
+ krb5_free_principal(kcontext, mcreds.server);
+ }
#endif /* KRB5_GET_TICKETS */
+
#ifdef KRB4_GET_TICKETS
- if (got_v4_tickets) {
- memset(&save_v4creds, 0, sizeof(save_v4creds));
-
- retval = krb_get_cred("krbtgt", realm, realm, &save_v4creds);
- if (retval != KSUCCESS) {
- syslog(LOG_ERR,
- "%s while retrieving V4 initial ticket for copy",
- error_message(retval));
- rewrite_ccache = 0;
+ if (got_v4_tickets) {
+ memset(&save_v4creds, 0, sizeof(save_v4creds));
- }
+ retval = krb_get_cred("krbtgt", realm, realm, &save_v4creds);
+ if (retval != KSUCCESS) {
+ syslog(LOG_ERR,
+ "%s while retrieving V4 initial ticket for copy",
+ error_message(retval));
+ rewrite_ccache = 0;
}
+ }
#endif /* KRB4_GET_TICKETS */
-#if defined(KRB5_GET_TICKETS) || defined(KRB4_GET_TICKETS)
- if (got_v5_tickets || got_v4_tickets)
- destroy_tickets();
+
+#ifdef KRB5_GET_TICKETS
+ if (forwarded_v5_tickets)
+ destroy_tickets();
+ else
+#endif
+#ifdef KRB4_GET_TICKETS
+ if (got_v4_tickets)
+ destroy_tickets();
#endif
#ifdef OQUOTA
- quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
+ quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
#endif
#ifdef HAVE_SETLOGIN
- if (setlogin(pwd->pw_name) < 0)
- syslog(LOG_ERR, "setlogin() failure %d",errno);
+ if (setlogin(pwd->pw_name) < 0)
+ syslog(LOG_ERR, "setlogin() failure %d",errno);
#endif
#ifdef HAVE_SETLUID
- /*
- * If we're on a system which keeps track of login uids, then
- * attempt to set the login uid, but don't get too unhappy when/if
- * it doesn't succeed.
- */
- if ((uid_t) getluid() < (uid_t) 0) {
- setluid((uid_t) pwd->pw_uid);
- }
+ /*
+ * If we're on a system which keeps track of login uids, then
+ * attempt to set the login uid, but don't get too unhappy when/if
+ * it doesn't succeed.
+ */
+ if ((uid_t) getluid() < (uid_t) 0) {
+ setluid((uid_t) pwd->pw_uid);
+ }
#endif /* HAVE_SETLUID */
#ifdef _IBMR2
- setuidx(ID_LOGIN, pwd->pw_uid);
+ setuidx(ID_LOGIN, pwd->pw_uid);
#endif
- /* This call MUST succeed */
- if(setuid((uid_t) pwd->pw_uid) < 0) {
- perror("setuid");
- sleepexit(1);
- }
+ /* This call MUST succeed */
+ if (setuid((uid_t) pwd->pw_uid) < 0) {
+ perror("setuid");
+ sleepexit(1);
+ }
+
+ /*
+ * We are the user now. Re-create the destroyed ccache and
+ * ticket file.
+ */
- /*
- * We are the user now. Re-create the destroyed ccache and
- * ticket file.
- */
#ifdef KRB5_GET_TICKETS
- if (got_v5_tickets && rewrite_ccache) {
- retval = krb5_cc_initialize (kcontext, ccache, me);
- if (retval) {
- syslog(LOG_ERR,
- "%s while re-initializing V5 ccache as user",
- error_message(retval));
- goto skip_ccache_output;
- }
- if (retval = krb5_cc_store_cred(kcontext, ccache, &save_v5creds)) {
- syslog(LOG_ERR,
- "%s while re-storing V5 credentials as user",
- error_message(retval));
-
- }
- skip_ccache_output: krb5_free_cred_contents(kcontext, &save_v5creds);
+ if (got_v5_tickets) {
+ /* set up credential cache -- obeying KRB5_ENV_CCNAME
+ set earlier */
+ /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */
+ if (retval = krb5_cc_default(kcontext, &ccache)) {
+ com_err(argv[0], retval, "while getting default ccache");
+ } else if (retval = krb5_cc_initialize(kcontext, ccache, me)) {
+ com_err(argv[0], retval, "when initializing cache");
+ } else if (retval = krb5_cc_store_cred(kcontext, ccache, &my_creds)) {
+ com_err(argv[0], retval, "while storing credentials");
+ } else if (xtra_creds &&
+ (retval = krb5_cc_copy_creds(kcontext, xtra_creds,
+ ccache))) {
+ com_err(argv[0], retval, "while storing credentials");
}
+
+ krb5_cc_destroy(kcontext, xtra_creds);
+ } else if (forwarded_v5_tickets && rewrite_ccache) {
+ if ((retval = krb5_cc_initialize (kcontext, ccache, me))) {
+ syslog(LOG_ERR,
+ "%s while re-initializing V5 ccache as user",
+ error_message(retval));
+ } else if (retval = krb5_cc_store_cred(kcontext, ccache,
+ &save_v5creds)) {
+ syslog(LOG_ERR,
+ "%s while re-storing V5 credentials as user",
+ error_message(retval));
+
+ }
+ krb5_free_cred_contents(kcontext, &save_v5creds);
+ }
#endif /* KRB5_GET_TICKETS */
+
#ifdef KRB4_GET_TICKETS
- if (got_v4_tickets&&rewrite_ccache) {
- retval = in_tkt(save_v4creds.pname, save_v4creds.pinst);
- if (retval != KSUCCESS) {
- syslog(LOG_ERR,
- "%s while re-initializing V4 ticket cache as user",
- error_message((retval == -1)?errno:retval));
- goto skip_output_tkfile;
- }
- retval = krb_save_credentials(save_v4creds.service,
- save_v4creds.instance,
- save_v4creds.realm,
- save_v4creds.session,
- save_v4creds.lifetime,
- save_v4creds.kvno,
- &(save_v4creds.ticket_st),
- save_v4creds.issue_date);
- if (retval != KSUCCESS) {
- syslog(LOG_ERR,
- "%s while re-storing V4 tickets as user",
- error_message(retval));
-
- }
+ if (got_v4_tickets && rewrite_ccache) {
+ if ((retval = in_tkt(save_v4creds.pname, save_v4creds.pinst))
+ != KSUCCESS) {
+ syslog(LOG_ERR,
+ "%s while re-initializing V4 ticket cache as user",
+ error_message((retval == -1)?errno:retval));
+ } else if ((retval = krb_save_credentials(save_v4creds.service,
+ save_v4creds.instance,
+ save_v4creds.realm,
+ save_v4creds.session,
+ save_v4creds.lifetime,
+ save_v4creds.kvno,
+ &(save_v4creds.ticket_st),
+ save_v4creds.issue_date))
+ != KSUCCESS) {
+ syslog(LOG_ERR,
+ "%s while re-storing V4 tickets as user",
+ error_message(retval));
}
+ }
#endif /* KRB4_GET_TICKETS */
- skip_output_tkfile: /*null*/;
+ if (*pwd->pw_shell == '\0')
+ pwd->pw_shell = BSHELL;
- if (*pwd->pw_shell == '\0')
- pwd->pw_shell = BSHELL;
#if defined(NTTYDISC) && defined(TIOCSETD)
- /* turn on new line discipline for all shells */
- ioctlval = NTTYDISC;
- (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+ /* turn on new line discipline for all shells */
+ ioctlval = NTTYDISC;
+ (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
#endif
- ccname = getenv("KRB5CCNAME"); /* save cache */
- tz = getenv("TZ"); /* and time zone */
+ ccname = getenv("KRB5CCNAME"); /* save cache */
+ tz = getenv("TZ"); /* and time zone */
- /* destroy environment unless user has requested preservation */
- if (!pflag) {
- envinit = (char **)malloc(MAXENVIRON * sizeof(char *));
- if (envinit == 0) {
- fprintf(stderr, "Can't malloc empty environment.\n");
- sleepexit(1);
- }
- envinit[0] = NULL;
- environ = envinit;
+ /* destroy environment unless user has requested preservation */
+ if (!pflag) {
+ envinit = (char **) malloc(MAXENVIRON * sizeof(char *));
+ if (envinit == 0) {
+ fprintf(stderr, "Can't malloc empty environment.\n");
+ sleepexit(1);
}
+ envinit[0] = NULL;
+ environ = envinit;
+ }
- setenv ("LOGNAME", pwd->pw_name, 1);
- setenv ("LOGIN", pwd->pw_name, 1);
+ setenv ("LOGNAME", pwd->pw_name, 1);
+ setenv ("LOGIN", pwd->pw_name, 1);
- /* read the /etc/environment file on AIX */
+ /* read the /etc/environment file on AIX */
#ifdef HAVE_ETC_ENVIRONMENT
- read_env_vars_from_file ("/etc/environment");
+ read_env_vars_from_file ("/etc/environment");
#endif
- /* Set login timezone for date information (sgi PDG) */
+ /* Set login timezone for date information (sgi PDG) */
#ifdef HAVE_ETC_TIMEZONE
- read_env_vars_from_file ("/etc/TIMEZONE");
+ read_env_vars_from_file ("/etc/TIMEZONE");
#else
- if (tz)
- setenv ("TZ", tz, 1);
+ if (tz)
+ setenv ("TZ", tz, 1);
#endif
- if (ccname)
- setenv("KRB5CCNAME", ccname, 1);
+ if (ccname)
+ setenv("KRB5CCNAME", ccname, 1);
- setenv("HOME", pwd->pw_dir, 1);
- setenv("PATH", LPATH, 1);
- setenv("USER", pwd->pw_name, 1);
- setenv("SHELL", pwd->pw_shell, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ setenv("PATH", LPATH, 1);
+ setenv("USER", pwd->pw_name, 1);
+ setenv("SHELL", pwd->pw_shell, 1);
+
+ if (term[0] == '\0') {
+ (void) strncpy(term, stypeof(tty), sizeof(term));
+ term[sizeof(term) - 1] = '\0';
+ }
+ if (term[0])
+ (void)setenv("TERM", term, 0);
- if (term[0] == '\0') {
- (void) strncpy(term, stypeof(tty), sizeof(term));
- term[sizeof(term) - 1] = '\0';
- }
- if (term[0])
- (void)setenv("TERM", term, 0);
#ifdef KRB4_GET_TICKETS
- /* tkfile[0] is only set if we got tickets above */
- if (login_krb4_get_tickets && tkfile[0])
- (void) setenv(KRB_ENVIRON, tkfile, 1);
+ /* tkfile[0] is only set if we got tickets above */
+ if (login_krb4_get_tickets && tkfile[0])
+ (void) setenv(KRB_ENVIRON, tkfile, 1);
#endif /* KRB4_GET_TICKETS */
+
#ifdef KRB5_GET_TICKETS
- /* ccfile[0] is only set if we got tickets above */
- if (login_krb5_get_tickets && ccfile[0])
- (void) setenv(KRB5_ENV_CCNAME, ccfile, 1);
+ /* ccfile[0] is only set if we got tickets above */
+ if (login_krb5_get_tickets && ccfile[0])
+ (void) setenv(KRB5_ENV_CCNAME, ccfile, 1);
#endif /* KRB5_GET_TICKETS */
- if (tty[sizeof("tty")-1] == 'd')
- syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
- if (pwd->pw_uid == 0)
- if (hostname)
+ if (tty[sizeof("tty")-1] == 'd')
+ syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
+ if (pwd->pw_uid == 0)
#ifdef KRB4_KLOGIN
- if (kdata) {
- /* @*$&@#*($)#@$ syslog doesn't handle very
- many arguments */
- char buf[BUFSIZ];
+ if (kdata) {
+ if (hostname) {
+ char buf[BUFSIZ];
#ifdef UT_HOSTSIZE
- (void) sprintf(buf,
- "ROOT LOGIN (krb) %s from %.*s, %s.%s@%s",
- tty, UT_HOSTSIZE, hostname,
- kdata->pname, kdata->pinst,
- kdata->prealm);
+ (void) sprintf(buf,
+ "ROOT LOGIN (krb) %s from %.*s, %s.%s@%s",
+ tty, UT_HOSTSIZE, hostname,
+ kdata->pname, kdata->pinst,
+ kdata->prealm);
#else
- (void) sprintf(buf,
- "ROOT LOGIN (krb) %s from %s, %s.%s@%s",
- tty, hostname,
- kdata->pname, kdata->pinst,
- kdata->prealm);
-#endif
- syslog(LOG_NOTICE, "%s", buf);
- } else {
+ (void) sprintf(buf,
+ "ROOT LOGIN (krb) %s from %s, %s.%s@%s",
+ tty, hostname,
+ kdata->pname, kdata->pinst,
+ kdata->prealm);
+#endif
+ syslog(LOG_NOTICE, "%s", buf);
+ } else {
+ syslog(LOG_NOTICE,
+ "ROOT LOGIN (krb) %s, %s.%s@%s",
+ tty,
+ kdata->pname, kdata->pinst,
+ kdata->prealm);
+ }
+ } else
#endif /* KRB4_KLOGIN */
+ {
+ if (hostname) {
#ifdef UT_HOSTSIZE
- syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
- tty, UT_HOSTSIZE, hostname);
+ syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
+ tty, UT_HOSTSIZE, hostname);
#else
- syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %s",
- tty, hostname);
+ syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %s",
+ tty, hostname);
#endif
-#ifdef KRB4_KLOGIN
- }
- else
- if (kdata) {
- syslog(LOG_NOTICE,
- "ROOT LOGIN (krb) %s, %s.%s@%s",
- tty,
- kdata->pname, kdata->pinst,
- kdata->prealm);
- }
-#endif /* KRB4_KLOGIN */
- else
- syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
+ } else {
+ syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
+ }
+ }
- afs_login ();
+ afs_login();
- if (!quietlog) {
+ if (!quietlog) {
#ifdef KRB4_KLOGIN
- if (!krbflag && !fflag && !eflag )
- printf("\nWarning: No Kerberos tickets obtained.\n\n");
+ if (!krbflag && !fflag && !eflag )
+ printf("\nWarning: No Kerberos tickets obtained.\n\n");
#endif /* KRB4_KLOGIN */
- motd ();
- check_mail ();
- }
+ motd();
+ check_mail();
+ }
#ifndef OQUOTA
- if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN);
-#endif
- handler_init (sa, SIG_DFL);
- handler_set (SIGALRM, sa);
- handler_set (SIGQUIT, sa);
- handler_set (SIGINT, sa);
- handler_init (sa, SIG_IGN);
- handler_set (SIGTSTP, sa);
-
- tbuf[0] = '-';
- (void) strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
- p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);
- tbuf[sizeof(tbuf) - 1] = '\0';
- execlp(pwd->pw_shell, tbuf, 0);
- fprintf(stderr, "login: no shell: ");
- perror(pwd->pw_shell);
- exit(0);
+ if (! access( QUOTAWARN, X_OK))
+ (void) system(QUOTAWARN);
+#endif
+
+ handler_init (sa, SIG_DFL);
+ handler_set (SIGALRM, sa);
+ handler_set (SIGQUIT, sa);
+ handler_set (SIGINT, sa);
+ handler_init (sa, SIG_IGN);
+ handler_set (SIGTSTP, sa);
+
+ tbuf[0] = '-';
+ p = strrchr(pwd->pw_shell, '/');
+ (void) strncpy(tbuf+1, p?(p+1):pwd->pw_shell, sizeof(tbuf-1));
+ tbuf[sizeof(tbuf) - 1] = '\0';
+
+ execlp(pwd->pw_shell, tbuf, 0);
+ fprintf(stderr, "login: no shell: ");
+ perror(pwd->pw_shell);
+ exit(0);
}
char *speeds[] = {
term_init (do_rlogin)
{
- int line_speed = -1;
+ int line_speed = -1;
- if (do_rlogin) {
- register char *cp = strchr(term, '/'), **cpp;
- char *speed;
+ if (do_rlogin) {
+ register char *cp = strchr(term, '/'), **cpp;
+ char *speed;
- if (cp) {
+ if (cp) {
+ *cp++ = '\0';
+ speed = cp;
+ cp = strchr(speed, '/');
+ if (cp)
*cp++ = '\0';
- speed = cp;
- cp = strchr(speed, '/');
- if (cp)
- *cp++ = '\0';
- for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
- if (strcmp(*cpp, speed) == 0) {
- line_speed = cpp-speeds;
- break;
- }
- }
+ for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
+ if (strcmp(*cpp, speed) == 0) {
+ line_speed = cpp-speeds;
+ break;
+ }
}
+ }
#ifdef POSIX_TERMIOS
- {
- struct termios tc;
+ {
+ struct termios tc;
- (void)tcgetattr(0, &tc);
- if (line_speed != -1) {
- cfsetispeed(&tc, b_speeds[line_speed]);
- cfsetospeed(&tc, b_speeds[line_speed]);
- }
- tc.c_cc[VMIN] = 1;
- tc.c_cc[VTIME] = 0;
+ (void)tcgetattr(0, &tc);
+ if (line_speed != -1) {
+ cfsetispeed(&tc, b_speeds[line_speed]);
+ cfsetospeed(&tc, b_speeds[line_speed]);
+ }
+ tc.c_cc[VMIN] = 1;
+ tc.c_cc[VTIME] = 0;
#ifndef NO_INIT_CC
- tc.c_cc[VERASE] = CERASE;
- tc.c_cc[VKILL] = CKILL;
- tc.c_cc[VEOF] = CEOF;
- tc.c_cc[VINTR] = CINTR;
- tc.c_cc[VQUIT] = CQUIT;
- tc.c_cc[VSTART] = CSTART;
- tc.c_cc[VSTOP] = CSTOP;
+ tc.c_cc[VERASE] = CERASE;
+ tc.c_cc[VKILL] = CKILL;
+ tc.c_cc[VEOF] = CEOF;
+ tc.c_cc[VINTR] = CINTR;
+ tc.c_cc[VQUIT] = CQUIT;
+ tc.c_cc[VSTART] = CSTART;
+ tc.c_cc[VSTOP] = CSTOP;
#ifndef CNUL
#define CNUL CEOL
#endif
- tc.c_cc[VEOL] = CNUL;
- /* The following are common extensions to POSIX */
+ tc.c_cc[VEOL] = CNUL;
+ /* The following are common extensions to POSIX */
#ifdef VEOL2
- tc.c_cc[VEOL2] = CNUL;
+ tc.c_cc[VEOL2] = CNUL;
#endif
#ifdef VSUSP
#if !defined(CSUSP) && defined(CSWTCH)
#define CSUSP CSWTCH
#endif
- tc.c_cc[VSUSP] = CSUSP;
+ tc.c_cc[VSUSP] = CSUSP;
#endif
#ifdef VDSUSP
- tc.c_cc[VDSUSP] = CDSUSP;
+ tc.c_cc[VDSUSP] = CDSUSP;
#endif
#ifdef VLNEXT
- tc.c_cc[VLNEXT] = CLNEXT;
+ tc.c_cc[VLNEXT] = CLNEXT;
#endif
#ifdef VREPRINT
- tc.c_cc[VREPRINT] = CRPRNT;
+ tc.c_cc[VREPRINT] = CRPRNT;
#endif
#ifdef VDISCRD
- tc.c_cc[VDISCRD] = CFLUSH;
+ tc.c_cc[VDISCRD] = CFLUSH;
#endif
#ifdef VDISCARD
#ifndef CDISCARD
#define CDISCARD CFLUSH
#endif
- tc.c_cc[VDISCARD] = CDISCARD;
+ tc.c_cc[VDISCARD] = CDISCARD;
#endif
#ifdef VWERSE
- tc.c_cc[VWERSE] = CWERASE;
+ tc.c_cc[VWERSE] = CWERASE;
#endif
#ifdef VWERASE
- tc.c_cc[VWERASE] = CWERASE;
+ tc.c_cc[VWERASE] = CWERASE;
#endif
#if defined (VSTATUS) && defined (CSTATUS)
- tc.c_cc[VSTATUS] = CSTATUS;
+ tc.c_cc[VSTATUS] = CSTATUS;
#endif /* VSTATUS && CSTATUS */
#endif /* NO_INIT_CC */
- /* set all standard echo, edit, and job control options */
- /* but leave any extensions */
- tc.c_lflag |= ECHO|ECHOE|ECHOK|ICANON|ISIG|IEXTEN;
- tc.c_lflag &= ~(NOFLSH|TOSTOP);
+ /* set all standard echo, edit, and job control options */
+ /* but leave any extensions */
+ tc.c_lflag |= ECHO|ECHOE|ECHOK|ICANON|ISIG|IEXTEN;
+ tc.c_lflag &= ~(NOFLSH|TOSTOP);
#ifdef ECHOCTL
- /* Not POSIX, but if we have it, we probably want it */
- tc.c_lflag |= ECHOCTL;
+ /* Not POSIX, but if we have it, we probably want it */
+ tc.c_lflag |= ECHOCTL;
#endif
#ifdef ECHOKE
- /* Not POSIX, but if we have it, we probably want it */
- tc.c_lflag |= ECHOKE;
+ /* Not POSIX, but if we have it, we probably want it */
+ tc.c_lflag |= ECHOKE;
#endif
- tc.c_iflag |= ICRNL|BRKINT;
- tc.c_oflag |= ONLCR|OPOST|TAB3;
- tcsetattr(0, TCSANOW, &tc);
- }
+ tc.c_iflag |= ICRNL|BRKINT;
+ tc.c_oflag |= ONLCR|OPOST|TAB3;
+ tcsetattr(0, TCSANOW, &tc);
+ }
#else /* not POSIX_TERMIOS */
- {
- struct sgttyb sgttyb;
- static struct tchars tc = {
- CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
- };
- static struct ltchars ltc = {
- CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
- };
-
- (void) ioctl(0, TIOCGETP, (char *)&sgttyb);
- if (line_speed != -1)
- sgttyb.sg_ispeed = sgttyb.sg_ospeed = line_speed;
- sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS;
- sgttyb.sg_erase = CERASE;
- sgttyb.sg_kill = CKILL;
- (void)ioctl(0, TIOCSLTC, (char *)<c);
- (void)ioctl(0, TIOCSETC, (char *)&tc);
- (void)ioctl(0, TIOCSETP, (char *)&sgttyb);
+ {
+ struct sgttyb sgttyb;
+ static struct tchars tc = {
+ CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
+ };
+ static struct ltchars ltc = {
+ CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
+ };
+
+ (void) ioctl(0, TIOCGETP, (char *)&sgttyb);
+ if (line_speed != -1)
+ sgttyb.sg_ispeed = sgttyb.sg_ospeed = line_speed;
+ sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS;
+ sgttyb.sg_erase = CERASE;
+ sgttyb.sg_kill = CKILL;
+ (void)ioctl(0, TIOCSLTC, (char *)<c);
+ (void)ioctl(0, TIOCSETC, (char *)&tc);
+ (void)ioctl(0, TIOCSETP, (char *)&sgttyb);
#if defined(TIOCSETD)
- {
- int ioctlval;
- ioctlval = 0;
- (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
- }
-#endif
+ {
+ int ioctlval;
+ ioctlval = 0;
+ (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
}
+#endif
+ }
#endif
}
void getloginname()
{
- register int ch;
- register char *p;
- static char nbuf[UT_NAMESIZE + 1];
-
- for (;;) {
- printf("login: ");
- for (p = nbuf; (ch = getchar()) != '\n'; ) {
- if (ch == EOF)
- exit(0);
- if (p < nbuf + UT_NAMESIZE)
- *p++ = ch;
- }
- if (p > nbuf)
- if (nbuf[0] == '-')
- fprintf(stderr,
- "login names may not start with '-'.\n");
- else {
- *p = '\0';
- username = nbuf;
- break;
- }
+ register int ch;
+ register char *p;
+ static char nbuf[UT_NAMESIZE + 1];
+
+ for (;;) {
+ printf("login: ");
+ for (p = nbuf; (ch = getchar()) != '\n'; ) {
+ if (ch == EOF)
+ exit(0);
+ if (p < nbuf + UT_NAMESIZE)
+ *p++ = ch;
}
+ if (p > nbuf)
+ if (nbuf[0] == '-')
+ fprintf(stderr,
+ "login names may not start with '-'.\n");
+ else {
+ *p = '\0';
+ username = nbuf;
+ break;
+ }
+ }
}
sigtype
timedout()
{
- fprintf(stderr, "Login timed out after %d seconds\n", timeout);
- exit(0);
+ fprintf(stderr, "Login timed out after %d seconds\n", timeout);
+ exit(0);
}
#ifndef HAVE_TTYENT_H
int root_tty_security = 1;
#endif
+
int rootterm(tty)
char *tty;
{
#ifndef HAVE_TTYENT_H
- return(root_tty_security);
+ return(root_tty_security);
#else
- struct ttyent *t;
+ struct ttyent *t;
- return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
+ return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
#endif /* HAVE_TTYENT_H */
}
#ifndef NO_MOTD
sigjmp_buf motdinterrupt;
+
sigtype
sigint()
{
- siglongjmp(motdinterrupt, 1);
+ siglongjmp(motdinterrupt, 1);
}
void motd()
{
- register int fd, nchars;
- char tbuf[8192];
- handler sa, osa;
-
- if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
- return;
- handler_init (sa, sigint);
- handler_swap (SIGINT, sa, osa);
- if (sigsetjmp(motdinterrupt, 1) == 0)
- while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
- (void)write(fileno(stdout), tbuf, nchars);
- handler_set (SIGINT, osa);
- (void)close(fd);
+ register int fd, nchars;
+ char tbuf[8192];
+ handler sa, osa;
+
+ if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
+ return;
+ handler_init (sa, sigint);
+ handler_swap (SIGINT, sa, osa);
+ if (sigsetjmp(motdinterrupt, 1) == 0)
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ (void)write(fileno(stdout), tbuf, nchars);
+ handler_set (SIGINT, osa);
+ (void)close(fd);
}
#else
-void motd () { }
+void motd()
+{
+}
#endif
#ifndef NO_MAILCHECK
-void check_mail ()
+void check_mail()
{
char tbuf[MAXPATHLEN+2];
struct stat st;
(st.st_mtime > st.st_atime) ? "new " : "");
}
#else
-void check_mail () { }
+void check_mail()
+{
+}
#endif
void checknologin()
{
- register int fd, nchars;
- char tbuf[8192];
+ register int fd, nchars;
+ char tbuf[8192];
- if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
- while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
- (void)write(fileno(stdout), tbuf, nchars);
- sleepexit(0);
- }
+ if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ (void)write(fileno(stdout), tbuf, nchars);
+ sleepexit(0);
+ }
}
void dolastlog(quiet, tty)
- int quiet;
- char *tty;
+ int quiet;
+ char *tty;
{
#if defined(HAVE_LASTLOG_H) || (defined(BSD) && (BSD >= 199103))
- struct lastlog ll;
- int fd;
+ struct lastlog ll;
+ int fd;
- if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) {
- (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
- if (!quiet) {
- if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
- ll.ll_time != 0) {
- printf("Last login: %.*s ",
- 24-5, (char *)ctime(&ll.ll_time));
- if (*ll.ll_host != '\0')
- printf("from %.*s\n",
- sizeof(ll.ll_host), ll.ll_host);
- else
- printf("on %.*s\n",
- sizeof(ll.ll_line), ll.ll_line);
- }
- (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
- }
- (void)time(&ll.ll_time);
- (void) strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
- ll.ll_line[sizeof(ll.ll_line) - 1] = '\0';
- if (hostname) {
- (void) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
- ll.ll_host[sizeof(ll.ll_host) - 1] = '\0';
- } else
- (void) memset(ll.ll_host, 0, sizeof(ll.ll_host));
- (void)write(fd, (char *)&ll, sizeof(ll));
- (void)close(fd);
+ if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) {
+ (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
+ if (!quiet) {
+ if ((read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll)) &&
+ (ll.ll_time != 0)) {
+
+ printf("Last login: %.*s ", 24-5, (char *)ctime(&ll.ll_time));
+
+ if (*ll.ll_host != '\0')
+ printf("from %.*s\n", sizeof(ll.ll_host), ll.ll_host);
+ else
+ printf("on %.*s\n", sizeof(ll.ll_line), ll.ll_line);
+ }
+ (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
+ }
+ (void) time(&ll.ll_time);
+
+ (void) strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+ ll.ll_line[sizeof(ll.ll_line) - 1] = '\0';
+
+ if (hostname) {
+ (void) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+ ll.ll_host[sizeof(ll.ll_host) - 1] = '\0';
+ } else {
+ (void) memset(ll.ll_host, 0, sizeof(ll.ll_host));
}
+
+ (void)write(fd, (char *)&ll, sizeof(ll));
+ (void)close(fd);
+ }
#endif
}
char *
stypeof(ttyid)
- char *ttyid;
+ char *ttyid;
{
-char *cp = getenv("term");
+ char *cp = getenv("term");
#ifndef HAVE_TTYENT_H
-if (cp)
- return cp;
-else return(UNKNOWN);
+ if (cp)
+ return cp;
+ else
+ return(UNKNOWN);
#else
- struct ttyent *t;
- if (cp)
- return cp;
- else return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
+ struct ttyent *t;
+ if (cp)
+ return cp;
+ else
+ return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
#endif
}
int doremotelogin(host)
- char *host;
+ char *host;
{
- static char lusername[UT_NAMESIZE+1];
- char rusername[UT_NAMESIZE+1];
-
- lgetstr(rusername, sizeof(rusername), "Remote user");
- lgetstr(lusername, sizeof(lusername), "Local user");
- lgetstr(term, sizeof(term), "Terminal type");
- username = lusername;
- pwd = getpwnam(username);
- if (pwd == NULL)
- return(-1);
- return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
+ static char lusername[UT_NAMESIZE+1];
+ char rusername[UT_NAMESIZE+1];
+
+ lgetstr(rusername, sizeof(rusername), "Remote user");
+ lgetstr(lusername, sizeof(lusername), "Local user");
+ lgetstr(term, sizeof(term), "Terminal type");
+ username = lusername;
+ pwd = getpwnam(username);
+ if (pwd == NULL)
+ return(-1);
+ return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
}
#ifdef KRB4_KLOGIN
int do_krb_login(host, strict)
- char *host;
- int strict;
+ char *host;
+ int strict;
{
- int rc;
- struct sockaddr_in sin;
- char instance[INST_SZ], version[9];
- long authoptions = 0L;
- struct hostent *hp = gethostbyname(host);
- static char lusername[UT_NAMESIZE+1];
+ int rc;
+ struct sockaddr_in sin;
+ char instance[INST_SZ], version[9];
+ long authoptions = 0L;
+ struct hostent *hp = gethostbyname(host);
+ static char lusername[UT_NAMESIZE+1];
+
+ /*
+ * Kerberos autologin protocol.
+ */
+ (void) memset((char *) &sin, 0, (int) sizeof(sin));
+
+ if (hp)
+ (void) memcpy ((char *)&sin.sin_addr, hp->h_addr,
+ sizeof(sin.sin_addr));
+ else
+ sin.sin_addr.s_addr = inet_addr(host);
+
+ if ((hp == NULL) && (sin.sin_addr.s_addr == -1)) {
+ printf("Hostname did not resolve to an address, so Kerberos authentication failed\r\n");
/*
- * Kerberos autologin protocol.
+ * No host addr prevents auth, so
+ * punt krb and require password
*/
-
- (void) memset((char *) &sin, 0, (int) sizeof(sin));
-
- if (hp)
- (void) memcpy ((char *)&sin.sin_addr, hp->h_addr,
- sizeof(sin.sin_addr));
- else
- sin.sin_addr.s_addr = inet_addr(host);
-
- if ((hp == NULL) && (sin.sin_addr.s_addr == -1)) {
- printf("Hostname did not resolve to an address, so Kerberos authentication failed\r\n");
- /*
- * No host addr prevents auth, so
- * punt krb and require password
- */
- if (strict) {
- goto paranoid;
- } else {
- pwd = NULL;
- return(-1);
- }
+ if (strict) {
+ goto paranoid;
+ } else {
+ pwd = NULL;
+ return(-1);
}
+ }
- kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) );
- ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
+ kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) );
+ ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
- (void) strcpy(instance, "*");
- if ((rc=krb_recvauth(authoptions, 0, ticket, "rcmd",
- instance, &sin,
- (struct sockaddr_in *)0,
- kdata, "", (bit_64 *) 0, version))) {
- printf("Kerberos rlogin failed: %s\r\n",krb_get_err_text(rc));
- if (strict) {
+ (void) strcpy(instance, "*");
+ if ((rc=krb_recvauth(authoptions, 0, ticket, "rcmd",
+ instance, &sin,
+ (struct sockaddr_in *)0,
+ kdata, "", (bit_64 *) 0, version))) {
+ printf("Kerberos rlogin failed: %s\r\n",krb_get_err_text(rc));
+ if (strict) {
paranoid:
- /*
- * Paranoid hosts, such as a Kerberos server,
- * specify the Klogind daemon to disallow
- * even password access here.
- */
- printf("Sorry, you must have Kerberos authentication to access this host.\r\n");
- exit(1);
- }
- }
- (void) lgetstr(lusername, sizeof (lusername), "Local user");
- (void) lgetstr(term, sizeof(term), "Terminal type");
- username = lusername;
- if (getuid()) {
- pwd = NULL;
- return(-1);
- }
- pwd = getpwnam(lusername);
- if (pwd == NULL) {
- pwd = NULL;
- return(-1);
+ /*
+ * Paranoid hosts, such as a Kerberos server,
+ * specify the Klogind daemon to disallow
+ * even password access here.
+ */
+ printf("Sorry, you must have Kerberos authentication to access this host.\r\n");
+ exit(1);
}
+ }
+ (void) lgetstr(lusername, sizeof (lusername), "Local user");
+ (void) lgetstr(term, sizeof(term), "Terminal type");
+ username = lusername;
+ if (getuid()) {
+ pwd = NULL;
+ return(-1);
+ }
+ pwd = getpwnam(lusername);
+ if (pwd == NULL) {
+ pwd = NULL;
+ return(-1);
+ }
- /*
- * if Kerberos login failed because of an error in krb_recvauth,
- * return the indication of a bad attempt. User will be prompted
- * for a password. We CAN'T check the .rhost file, because we need
- * the remote username to do that, and the remote username is in the
- * Kerberos ticket. This affects ONLY the case where there is
- * Kerberos on both ends, but Kerberos fails on the server end.
- */
- if (rc) {
- return(-1);
- }
+ /*
+ * if Kerberos login failed because of an error in krb_recvauth,
+ * return the indication of a bad attempt. User will be prompted
+ * for a password. We CAN'T check the .rhost file, because we need
+ * the remote username to do that, and the remote username is in the
+ * Kerberos ticket. This affects ONLY the case where there is
+ * Kerberos on both ends, but Kerberos fails on the server end.
+ */
+ if (rc) {
+ return(-1);
+ }
- if ((rc=kuserok(kdata,lusername))) {
- printf("login: %s has not given you permission to login without a password.\r\n",lusername);
- if (strict) {
- exit(1);
- }
- return(-1);
+ if ((rc=kuserok(kdata,lusername))) {
+ printf("login: %s has not given you permission to login without a password.\r\n",lusername);
+ if (strict) {
+ exit(1);
}
- return(0);
+ return(-1);
+ }
+ return(0);
}
#endif /* KRB4_KLOGIN */
void lgetstr(buf, cnt, err)
- char *buf, *err;
- int cnt;
+ char *buf, *err;
+ int cnt;
{
- int ocnt = cnt;
- char *obuf = buf;
- char ch;
-
- do {
- if (read(0, &ch, sizeof(ch)) != sizeof(ch))
- exit(1);
- if (--cnt < 0) {
- fprintf(stderr,"%s '%.*s' too long, %d characters maximum.\r\n",
- err, ocnt, obuf, ocnt-1);
- sleepexit(1);
- }
- *buf++ = ch;
- } while (ch);
+ int ocnt = cnt;
+ char *obuf = buf;
+ char ch;
+
+ do {
+ if (read(0, &ch, sizeof(ch)) != sizeof(ch))
+ exit(1);
+ if (--cnt < 0) {
+ fprintf(stderr,"%s '%.*s' too long, %d characters maximum.\r\n",
+ err, ocnt, obuf, ocnt-1);
+ sleepexit(1);
+ }
+ *buf++ = ch;
+ } while (ch);
}
void sleepexit(eval)
- int eval;
+ int eval;
{
#ifdef KRB4_GET_TICKETS
- if (login_krb4_get_tickets && krbflag)
- (void) destroy_tickets();
+ if (login_krb4_get_tickets && krbflag)
+ (void) destroy_tickets();
#endif /* KRB4_GET_TICKETS */
- sleep((u_int)5);
- exit(eval);
+ sleep((u_int)5);
+ exit(eval);
}
#if defined(KRB4_GET_TICKETS) || defined(KRB5_GET_TICKETS)
-
static int hungup = 0;
+
static sigtype
sighup() {
hungup = 1;
#ifdef _IBMR2
update_ref_count(1);
#endif
- if(!(child=fork()))
- return; /* Child process returns */
+ if (!(child=fork()))
+ return; /* Child process returns */
/* The parent continues here */
- { /* Try and get rid of our controlling tty. On SunOS, this may or may
- not work depending on if our parent did a setsid before exec-ing us. */
+ /* Try and get rid of our controlling tty. On SunOS, this may or may
+ not work depending on if our parent did a setsid before exec-ing
+ us. */
#ifndef __linux__
- /* On linux, TIOCNOTTY causes us to die on a
- SIGHUP, so don't even try it. */
+ /* On linux, TIOCNOTTY causes us to die on a
+ SIGHUP, so don't even try it. */
#ifdef TIOCNOTTY
- { int fd;
- if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
- ioctl(fd, TIOCNOTTY, 0);
- close(fd);
- }
- }
+ {
+ int fd;
+
+ if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
+ ioctl(fd, TIOCNOTTY, 0);
+ close(fd);
+ }
+ }
#endif
#endif /* __linux__ */
+
#ifdef HAVE_SETSID
- (void)setsid();
+ (void)setsid();
#endif
+
#ifdef SETPGRP_TWOARG
- (void)setpgrp(0, 0);
+ (void)setpgrp(0, 0);
#else
- (void)setpgrp();
+ (void)setpgrp();
#endif
- }
/* Setup stuff? This would be things we could do in parallel with login */
(void) chdir("/"); /* Let's not keep the fs busy... */
while (1) {
#ifdef HAVE_WAITPID
pid = waitpid(child, 0, 0);
-#else
-#ifdef WAIT_USES_INT
+#elif defined(WAIT_USES_INT)
pid = wait((int *)0);
#else
pid = wait((union wait *)0);
#endif
-#endif
- if (hungup)
+
+ if (hungup) {
#ifdef HAVE_KILLPG
killpg(child, SIGHUP);
#else
kill(-child, SIGHUP);
#endif
+ }
+
if (pid == child)
- break;
+ break;
}
/* Cleanup stuff */
for compatablilty with version 5 krb library, since kcmd.o is linked
into all programs. */
-char *
- strsave(sp)
-char *sp;
+char *strsave(sp)
+ char *sp;
{
register char *ret;
- if((ret = (char *) malloc((unsigned) strlen(sp)+1)) == NULL) {
+ if ((ret = (char *) malloc((unsigned) strlen(sp)+1)) == NULL) {
fprintf(stderr, "no memory for saving args\n");
exit(1);
}
(void) strcpy(ret,sp);
return(ret);
}
-
#endif
#ifdef _IBMR2
+1998-10-24 Marc Horowitz <marc@mit.edu>
+
+ * gss-server.c (sign_server): fix the text heuristic to recognize
+ whitespace as text.
+ (main): clean up file descriptors properly after each
+ connection.
+
+ * gss-client.c (read_file): properly handle empty files
+
+ * gss-client.c: (call_server): NUL-terminate the contents
+ of non-empty files on the wire.
+
Wed Feb 18 15:27:32 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in: Remove trailing slash from BUILDTOP. Fix up
exit(1);
}
in_buf->length = stat_buf.st_size;
- in_buf->value = malloc(in_buf->length);
- if (in_buf->value == 0) {
+
+ if (in_buf->length == 0) {
+ in_buf->value = NULL;
+ return;
+ }
+
+ if ((in_buf->value = malloc(in_buf->length)) == 0) {
fprintf(stderr, "Couldn't allocate %d byte buffer for reading file\n",
in_buf->length);
exit(1);
}
- memset(in_buf->value, 0, in_buf->length);
- for (bytes_in = 0; bytes_in < in_buf->length; bytes_in += count) {
- count = read(fd, in_buf->value, in_buf->length);
- if (count < 0) {
- perror("read");
- exit(1);
- }
- if (count == 0)
- break;
+
+ /* this code used to check for incomplete reads, but you can't get
+ an incomplete read on any file for which fstat() is meaningful */
+
+ count = read(fd, in_buf->value, in_buf->length);
+ if (count < 0) {
+ perror("read");
+ exit(1);
}
- if (bytes_in != count)
+ if (count < in_buf->length)
fprintf(stderr, "Warning, only read in %d bytes, expected %d\n",
- bytes_in, count);
+ count, in_buf->length);
}
/*
* seals msg in a GSS-API token with gss_seal, sends it to the server,
* reads back a GSS-API signature block for msg from the server, and
* verifies it with gss_verify. -1 is returned if any step fails,
- * otherwise 0 is returned.
- */
+ * otherwise 0 is returned. */
int call_server(host, port, oid, service_name, deleg_flag, msg, use_file)
char *host;
u_short port;
} else {
/* Seal the message */
in_buf.value = msg;
- in_buf.length = strlen(msg) + 1;
+ in_buf.length = strlen(msg);
}
maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
fprintf(log, "Received message: ");
cp = msg_buf.value;
- if (isprint(cp[0]) && isprint(cp[1]))
- fprintf(log, "\"%s\"\n", cp);
- else {
+ if ((isprint(cp[0]) || isspace(cp[0])) &&
+ (isprint(cp[1]) || isspace(cp[1]))) {
+ fprintf(log, "\"%.*s\"\n", msg_buf.length, msg_buf.value);
+ } else {
printf("\n");
print_token(&msg_buf);
}
} else {
int stmp;
- if ((stmp = create_socket(port))) {
+ if ((stmp = create_socket(port)) >= 0) {
do {
/* Accept a TCP connection */
if ((s = accept(stmp, NULL, 0)) < 0) {
perror("accepting connection");
- } else {
- /* this return value is not checked, because there's
- not really anything to do if it fails */
- sign_server(s, server_creds);
+ continue;
}
+ /* this return value is not checked, because there's
+ not really anything to do if it fails */
+ sign_server(s, server_creds);
+ close(s);
} while (!once);
- }
- close(stmp);
+ close(stmp);
+ }
}
(void) gss_release_cred(&min_stat, &server_creds);
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * ftp.c (login): *always* encrypt the password, regardless
+ of the default command mode.
+ (do_auth): Try the new krb5 mech, and if that fails, try the
+ old one.
+
1998-10-26 Geoffrey King <gjking@mit.edu>
* ftp.M: Add documentation for new ccc and cprotect commands.
* SUCH DAMAGE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef lint
static char sccsid[] = "@(#)ftp.c 5.38 (Berkeley) 4/22/91";
#endif /* not lint */
#endif /* KRB5_KRB4_COMPAT */
#ifdef GSSAPI
#include <gssapi/gssapi.h>
-#include <gssapi/gssapi_generic.h>
+/* need to include the krb5 file, because we're doing manual fallback
+ from the v2 mech to the v2 mech. Once there's real negotiation,
+ we can be generic again. */
+#include <gssapi/gssapi_krb5.h>
gss_ctx_id_t gcontext;
#endif /* GSSAPI */
-
static int kerror; /* XXX needed for all auth types */
char *auth_type; /* Authentication succeeded? If so, what type? */
if (pass == NULL)
pass = mygetpass("Password:");
#ifndef NOENCRYPTION
- if ((oldclevel = clevel) == PROT_S) clevel = PROT_P;
+ oldclevel = clevel;
+ clevel = PROT_P;
#endif
n = command("PASS %s", pass);
#ifndef NOENCRYPTION
#endif /* KRB5_KRB4_COMPAT */
#ifdef GSSAPI
-/* for testing, we don't have an ftp key yet */
-char* gss_services[] = { "ftp", "host", 0 };
+struct {
+ const gss_OID_desc * const * mech_type;
+ char *service_name;
+} gss_trials[] = {
+ { &gss_mech_krb5_v2, "ftp" },
+ { &gss_mech_krb5, "ftp" },
+ { &gss_mech_krb5_v2, "host" },
+ { &gss_mech_krb5, "host" },
+};
+int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
#endif /* GSSAPI */
do_auth()
gss_name_t target_name;
gss_buffer_desc send_tok, recv_tok, *token_ptr;
char stbuf[FTP_BUFSIZ];
- char **service_name, **end_service_name;
- int comcode;
+ int comcode, trial;
struct gss_channel_bindings_struct chan;
chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
chan.initiator_address.length = 4;
chan.application_data.length = 0;
chan.application_data.value = 0;
- for (end_service_name = gss_services; *end_service_name; )
- end_service_name++;
- end_service_name--;
-
if (verbose)
- printf("%s accepted as authentication type\n", "GSSAPI");
+ printf("GSSAPI accepted as authentication type\n");
/* blob from gss-client */
-
- for (service_name = gss_services; *service_name; service_name++) {
-
+ for (trial = 0; trial < n_gss_trials; trial++) {
/* ftp@hostname first, the host@hostname */
/* the V5 GSSAPI binding canonicalizes this for us... */
- sprintf(stbuf, "%s@%s", *service_name, hostname);
+ sprintf(stbuf, "%s@%s", gss_trials[trial].service_name, hostname);
if (debug)
fprintf(stderr, "Trying to authenticate to <%s>\n", stbuf);
GSS_C_NO_CREDENTIAL,
&gcontext,
target_name,
- GSS_C_NULL_OID,
+ *gss_trials[trial].mech_type,
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
(forward ? GSS_C_DELEG_FLAG : 0),
0,
if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED){
- if (service_name == end_service_name)
+ if (trial == n_gss_trials-1)
user_gss_error(maj_stat, min_stat, "initializing context");
(void) gss_release_name(&min_stat, &target_name);
/* could just be that we missed on the service name */
int len = send_tok.length;
reply_parse = "ADAT="; /* for command() later */
oldverbose = verbose;
- verbose = 0;
+ verbose = (trial == n_gss_trials-1)?0:-1;
kerror = radix_encode(send_tok.value, out_buf, &len, 0);
if (kerror) {
fprintf(stderr, "Base 64 encoding failed: %s\n",
radix_error(kerror));
} else if ((comcode = command("ADAT %s", out_buf))!=COMPLETE
/* && comcode != 3 (335)*/) {
- fprintf(stderr, "GSSAPI ADAT failed\n");
- /* force out of loop */
- maj_stat = GSS_S_FAILURE;
+ if (trial == n_gss_trials-1) {
+ fprintf(stderr, "GSSAPI ADAT failed\n");
+ /* force out of loop */
+ maj_stat = GSS_S_FAILURE;
+ }
+ /* backoff to the v1 gssapi is still possible. Send
+ a new AUTH command. If that fails, terminate the
+ loop */
+ if (command("AUTH %s", "GSSAPI") != CONTINUE) {
+ fprintf(stderr,
+ "GSSAPI ADAT failed, AUTH restart failed\n");
+ /* force out of loop */
+ maj_stat = GSS_S_FAILURE;
+ }
+ goto outer_loop;
} else if (!reply_parse) {
fprintf(stderr,
"No authentication data received from server\n");
/* get out of loop clean */
gss_complete_loop:
- service_name = end_service_name;
+ trial = n_gss_trials-1;
gss_release_buffer(&min_stat, &send_tok);
gss_release_name(&min_stat, &target_name);
goto outer_loop;
}
verbose = oldverbose;
if (maj_stat == GSS_S_COMPLETE) {
- if (verbose)
- printf("GSSAPI authentication succeeded\n");
+ printf("GSSAPI authentication succeeded\n");
reply_parse = NULL;
auth_type = "GSSAPI";
return(1);
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * enc_des.c, kerberos.c: the ECB des functions don't exist
+ anymore, but telnet always encrypted/decrypted one block. Convert
+ to calls to the new crypto api, with des-cbc-raw, using a single
+ block.
+
Tue Mar 3 14:43:30 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
* configure.in: Change test for cgetent to use HAVE_ instead
* SUCH DAMAGE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
/* based on @(#)enc_des.c 8.1 (Berkeley) 6/4/93 */
#ifdef ENCRYPTION
# ifdef AUTHENTICATION
# ifdef DES_ENCRYPTION
+#include <krb5.h>
#include <arpa/telnet.h>
#include <stdio.h>
#ifdef __STDC__
extern encrypt_debug_mode;
+extern krb5_context telnet_context;
+
#define CFB 0
#define OFB 1
struct fb {
- Block krbdes_key;
- Schedule krbdes_sched;
Block temp_feed;
unsigned char fb_feed[64];
int need_start;
int state[2];
int keyid[2];
int once;
+ int validkey;
struct stinfo {
Block str_output;
Block str_feed;
Block str_iv;
- Block str_ikey;
- Schedule str_sched;
+ unsigned char str_keybytes[8]; /* yuck */
+ krb5_keyblock str_key;
int str_index;
int str_flagshift;
} streams[2];
void fb64_stream_key P((Block, struct stinfo *));
int fb64_keyid P((int, unsigned char *, int *, struct fb *));
+static void ecb_encrypt(stp, in, out)
+ struct stinfo *stp;
+ Block in;
+ Block out;
+{
+ krb5_error_code code;
+ krb5_data din;
+ krb5_enc_data dout;
+
+ din.length = 8;
+ din.data = in;
+
+ dout.ciphertext.length = 8;
+ dout.ciphertext.data = out;
+ dout.enctype = ENCTYPE_UNKNOWN;
+
+ code = krb5_c_encrypt(telnet_context, &stp->str_key, 0, 0,
+ &din, &dout);
+ /* XXX I'm not sure what to do if this fails */
+ if (code)
+ com_err("libtelnet", code, "encrypting stream data");
+}
+
void
cfb64_init(server)
int server;
else if ((state & NO_SEND_IV) == 0)
break;
- if (!VALIDKEY(fbp->krbdes_key)) {
+ if (!fbp->validkey) {
fbp->need_start = 1;
break;
}
/*
* Create a random feed and send it over.
*/
- des_new_random_key(fbp->temp_feed);
- des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
- fbp->krbdes_sched, 1);
+ {
+ krb5_data d;
+ krb5_error_code code;
+
+ d.data = fbp->temp_feed;
+ d.length = sizeof(fbp->temp_feed);
+
+ if (code = krb5_c_random_make_octets(telnet_context,
+ &d))
+ return(FAILED);
+ }
+
p = fbp->fb_feed + 3;
*p++ = ENCRYPT_IS;
p++;
int server;
struct fb *fbp;
{
-
if (!key || key->type != SK_DES) {
if (encrypt_debug_mode)
printf("Can't set krbdes's session key (%d != %d)\r\n",
key ? key->type : -1, SK_DES);
return;
}
- memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
- fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
- fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
+ fbp->validkey = 1;
+
+ fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1]);
+ fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1]);
- if (fbp->once == 0) {
- des_set_random_generator_seed(fbp->krbdes_key);
- fbp->once = 1;
- }
- des_key_sched(fbp->krbdes_key, fbp->krbdes_sched);
/*
* Now look to see if krbdes_start() was was waiting for
* the key to show up. If so, go ahead an call it now
Block seed;
register struct stinfo *stp;
{
-
memcpy((void *)stp->str_iv, (void *)seed, sizeof(Block));
memcpy((void *)stp->str_output, (void *)seed, sizeof(Block));
- des_key_sched(stp->str_ikey, stp->str_sched);
-
stp->str_index = sizeof(Block);
}
Block key;
register struct stinfo *stp;
{
- memcpy((void *)stp->str_ikey, (void *)key, sizeof(Block));
- des_key_sched(key, stp->str_sched);
+ memcpy((void *)stp->str_keybytes, (void *)key, sizeof(Block));
+ stp->str_key.length = 8;
+ stp->str_key.contents = stp->str_keybytes;
+ /* the original version of this code uses des ecb mode, but
+ it only ever does one block at a time. cbc with a zero iv
+ is identical */
+ stp->str_key.enctype = ENCTYPE_DES_CBC_RAW;
memcpy((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
while (c-- > 0) {
if (index == sizeof(Block)) {
Block b;
- des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+ ecb_encrypt(stp, stp->str_output, b);
memcpy((void *)stp->str_feed,(void *)b,sizeof(Block));
index = 0;
}
index = stp->str_index++;
if (index == sizeof(Block)) {
Block b;
- des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+ ecb_encrypt(stp, stp->str_output, b);
memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
stp->str_index = 1; /* Next time will be 1 */
index = 0; /* But now use 0 */
while (c-- > 0) {
if (index == sizeof(Block)) {
Block b;
- des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+ ecb_encrypt(stp, stp->str_feed, b);
memcpy((void *)stp->str_feed,(void *)b,sizeof(Block));
index = 0;
}
index = stp->str_index++;
if (index == sizeof(Block)) {
Block b;
- des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+ ecb_encrypt(stp, stp->str_feed, b);
memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
stp->str_index = 1; /* Next time will be 1 */
index = 0; /* But now use 0 */
* or implied warranty.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifdef KRB4
+/* this code must be compiled in the krb5 tree. disgustingly, there
+ is code in here which declares structures which happen to mirror
+ the krb4 des structures. I didn't want to rototill this *completely*
+ so this is how it's going to work. --marc */
+#include <krb5.h>
#include <sys/types.h>
#include <arpa/telnet.h>
#include <stdio.h>
#include "misc.h"
extern auth_debug_mode;
+extern krb5_context telnet_context;
static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
AUTHTYPE_KERBEROS_V4, };
#ifdef ENCRYPTION
static Block session_key = { 0 };
static Schedule sched;
+static krb5_keyblock krbkey;
static Block challenge = { 0 };
#endif /* ENCRYPTION */
} else {
str_data[3] = TELQUAL_IS;
}
+
+ kerberos5_init(NULL, server);
+
return(1);
}
Authenticator *ap;
{
KTEXT_ST auth;
-#ifdef ENCRYPTION
- Block enckey;
-#endif /* ENCRYPTION */
char instance[INST_SZ];
char *realm;
char *krb_realmofhost();
char *krb_get_phost();
CREDENTIALS cred;
int r;
+#ifdef ENCRYPTION
+ krb5_data data;
+ krb5_enc_data encdata;
+ krb5_error_code code;
+ krb5_keyblock random_key;
+#endif
printf("[ Trying KERBEROS4 ... ]\r\n");
if (!UserNameRequested) {
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
register int i;
- des_key_sched(cred.session, sched);
- des_init_random_number_generator(cred.session);
- des_new_random_key(session_key);
- des_ecb_encrypt(session_key, session_key, sched, 0);
- des_ecb_encrypt(session_key, challenge, sched, 0);
+ data.data = cred.session;
+ data.length = 8; /* sizeof(cred.session) */;
+
+ if (code = krb5_c_random_seed(telnet_context, &data)) {
+ com_err("libtelnet", code,
+ "while seeding random number generator");
+ return(0);
+ }
+
+ if (code = krb5_c_make_random_key(telnet_context,
+ ENCTYPE_DES_CBC_RAW,
+ &random_key)) {
+ com_err("libtelnet", code,
+ "while creating random session key");
+ return(0);
+ }
+
+ /* the krb4 code uses ecb mode, but on a single block
+ with a zero ivec, ecb and cbc are the same */
+ krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+ krbkey.length = 8;
+ krbkey.contents = cred.session;
+
+ encdata.ciphertext.data = random_key.contents;
+ encdata.ciphertext.length = random_key.length;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ data.data = session_key;
+ data.length = 8;
+
+ code = krb5_c_decrypt(telnet_context, &krbkey, 0, 0,
+ &encdata, &data);
+
+ krb5_free_keyblock_contents(telnet_context, &random_key);
+
+ if (code) {
+ com_err("libtelnet", code, "while encrypting random key");
+ return(0);
+ }
+
+ encdata.ciphertext.data = session_key;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ data.data = challenge;
+ data.length = 8;
+
+ code = krb5_c_decrypt(telnet_context, &krbkey, 0, 0,
+ &encdata, &data);
+
/*
* Increment the challenge by 1, and encrypt it for
* later comparison.
if (x < 256) /* if no overflow, all done */
break;
}
- des_ecb_encrypt(challenge, challenge, sched, 1);
+
+ data.data = challenge;
+ data.length = 8;
+
+ encdata.ciphertext.data = challenge;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(telnet_context, &krbkey, 0, 0, &data,
+ &encdata)) {
+ com_err("libtelnet", code, "while encrypting random key");
+ return(0);
+ }
}
#endif /* ENCRYPTION */
{
#ifdef ENCRYPTION
Session_Key skey;
- Block datablock;
+ Block datablock, tmpkey;
+ krb5_data kdata;
+ krb5_enc_data encdata;
+ krb5_error_code code;
#endif /* ENCRYPTION */
char realm[REALM_SZ];
char instance[INST_SZ];
* Initialize the random number generator since it's
* used later on by the encryption routine.
*/
- des_init_random_number_generator(session_key);
- des_key_sched(session_key, sched);
+
+ kdata.data = session_key;
+ kdata.length = 8;
+
+ if (code = krb5_c_random_seed(telnet_context, &kdata)) {
+ com_err("libtelnet", code,
+ "while seeding random number generator");
+ return;
+ }
+
memcpy((void *)datablock, (void *)data, sizeof(Block));
/*
* Take the received encrypted challenge, and encrypt
* it again to get a unique session_key for the
* ENCRYPT option.
*/
- des_ecb_encrypt(datablock, session_key, sched, 1);
+ krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+ krbkey.length = 8;
+ krbkey.contents = session_key;
+
+ kdata.data = datablock;
+ kdata.length = 8;
+
+ encdata.ciphertext.data = tmpkey;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(telnet_context, &krbkey, 0, 0,
+ &kdata, &encdata)) {
+ com_err("libtelnet", code, "while encrypting random key");
+ return;
+ }
+
skey.type = SK_DES;
skey.length = 8;
- skey.data = session_key;
+ skey.data = tmpkey;
encrypt_session_key(&skey, 1);
/*
* Now decrypt the received encrypted challenge,
* increment by one, re-encrypt it and send it back.
*/
- des_ecb_encrypt(datablock, challenge, sched, 0);
+ encdata.ciphertext.data = datablock;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ kdata.data = challenge;
+ kdata.length = 8;
+
+ if (code = krb5_c_decrypt(telnet_context, &krbkey, 0, 0,
+ &encdata, &kdata)) {
+ com_err("libtelnet", code, "while decrypting challenge");
+ return;
+ }
+
for (r = 7; r >= 0; r--) {
register int t;
t = (unsigned int)challenge[r] + 1;
if (t < 256) /* if no overflow, all done */
break;
}
- des_ecb_encrypt(challenge, challenge, sched, 1);
+
+ kdata.data = challenge;
+ kdata.length = 8;
+
+ encdata.ciphertext.data = challenge;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(telnet_context, &krbkey, 0, 0,
+ &kdata, &encdata)) {
+ com_err("libtelnet", code, "while decrypting challenge");
+ return;
+ }
+
Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge));
#endif /* ENCRYPTION */
break;
{
#ifdef ENCRYPTION
Session_Key skey;
+ krb5_data kdata;
+ krb5_enc_data encdata;
+ krb5_error_code code;
+
#endif /* ENCRYPTION */
if (cnt-- < 1)
#else /* ENCRYPTION */
Data(ap, KRB_CHALLENGE, (void *)session_key,
sizeof(session_key));
- des_ecb_encrypt(session_key, session_key, sched, 1);
+
+ kdata.data = session_key;
+ kdata.length = 8;
+
+ encdata.ciphertext.data = session_key;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(telnet_context, &krbkey,
+ 0, 0, &kdata, &encdata)) {
+ com_err("libtelnet", code,
+ "while encrypting session_key");
+ return;
+ }
+
skey.type = SK_DES;
skey.length = 8;
skey.data = session_key;
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * commands.c: remove calls to setuid(getuid()). This looks like
+ it was once an attempt to make it safe to run setuid, but it's not
+ safe for a number of other reasons, so there's no reason to
+ pretend.
+
Sat Oct 10 06:24:55 1998 Geoffrey King <gjking@mit.edu>
* telnet.c (telnet): Cosmetic change: Put a newline after "Waiting
if (connected) {
printf("?Already connected to %s\r\n", hostname);
- setuid(getuid());
return 0;
}
if (argc < 2) {
}
usage:
printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd);
- setuid(getuid());
return 0;
}
if (hostp == 0)
temp = sourceroute(hostp, &srp, &srlen);
if (temp == 0) {
herror(srp);
- setuid(getuid());
return 0;
} else if (temp == -1) {
printf("Bad source route option: %s\r\n", hostp);
- setuid(getuid());
return 0;
} else {
sin.sin_addr.s_addr = temp;
hostname = _hostname;
} else {
herror(hostp);
- setuid(getuid());
return 0;
}
}
sin.sin_port = sp->s_port;
else {
printf("%s: bad port number\r\n", portp);
- setuid(getuid());
return 0;
}
} else {
sp = getservbyname("telnet", "tcp");
if (sp == 0) {
fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
- setuid(getuid());
return 0;
}
sin.sin_port = sp->s_port;
printf("Trying %s...\r\n", inet_ntoa(sin.sin_addr));
do {
net = socket(AF_INET, SOCK_STREAM, 0);
- setuid(getuid());
if (net < 0) {
perror("telnet: socket");
return 0;
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: add kvno
+
+Sat Jul 25 15:00:26 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (LOCAL_SUBDIRS): add kvno
+
Wed Feb 18 15:40:02 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in: Remove trailing slash from thisconfigdir.
thisconfigdir=.
BUILDTOP=$(REL)$(U)
-LOCAL_SUBDIRS= klist kinit kdestroy kpasswd ksu
+LOCAL_SUBDIRS= klist kinit kdestroy kpasswd ksu kvno
##WIN32##all-windows::
##WIN32## @echo Making all in clients\klist
K5_GEN_MAKEFILE(.)
K5_GEN_MAKEFILE(klist)
K5_GEN_MAKEFILE(kinit)
+K5_GEN_MAKEFILE(kvno)
K5_GEN_MAKEFILE(kdestroy)
K5_GEN_MAKEFILE(kpasswd)
K5_GEN_MAKEFILE(ksu)
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * kinit.c: convert to new init_creds api
+
1998-05-06 Theodore Ts'o <tytso@rsts-11.mit.edu>
* kinit.c (main): POSIX states that getopt returns -1 when it
* Initialize a credentials cache.
*/
-#include "k5-int.h"
+#include <krb5.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef GETOPT_LONG
+#include "getopt.h"
+#else
+#include <unistd.h>
+#endif
#include "com_err.h"
-#include "adm_proto.h"
-#include <stdio.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
-#endif
-#define KRB5_DEFAULT_OPTIONS 0
-#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
-
-extern int optind;
-extern char *optarg;
+void get_name_from_passwd_file(program_name, kcontext, me)
+ char * program_name;
+ krb5_context kcontext;
+ krb5_principal * me;
+{
+ struct passwd *pw;
+ krb5_error_code code;
+ if (pw = getpwuid((int) getuid())) {
+ if ((code = krb5_parse_name(kcontext, pw->pw_name, me))) {
+ com_err (program_name, code, "when parsing name %s", pw->pw_name);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "Unable to identify user from password file\n");
+ exit(1);
+ }
+}
+#else /* HAVE_PWD_H */
+void get_name_from_passwd_file(kcontext, me)
+ krb5_context kcontext;
+ krb5_principal * me;
+{
+ fprintf(stderr, "Unable to identify user\n");
+ exit(1);
+}
+#endif /* HAVE_PWD_H */
-krb5_data tgtname = {
- 0,
- KRB5_TGS_NAME_SIZE,
- KRB5_TGS_NAME
+#ifdef GETOPT_LONG
+/* if struct[2] == NULL, then long_getopt acts as if the short flag
+ struct[3] was specified. If struct[2] != NULL, then struct[3] is
+ stored in *(struct[2]), the array index which was specified is
+ stored in *index, and long_getopt() returns 0. */
+
+struct option long_options[] = {
+ { "noforwardable", 0, NULL, 'f'+0200 },
+ { "noproxiable", 0, NULL, 'p'+0200 },
+ { "addresses", 0, NULL, 'A'+0200},
+ { "forwardable", 0, NULL, 'f' },
+ { "proxiable", 0, NULL, 'p' },
+ { "noaddresses", 0, NULL, 'A'},
+ { "version", 0, NULL, 0x01 },
+ { NULL, 0, NULL, 0 }
};
-
-/* Internal prototypes */
-static krb5_error_code krb5_validate_tgt
- KRB5_PROTOTYPE((krb5_context, krb5_ccache,
- krb5_principal, krb5_data *));
-static krb5_error_code krb5_renew_tgt
- KRB5_PROTOTYPE((krb5_context, krb5_ccache,
- krb5_principal, krb5_data *));
-static krb5_error_code krb5_tgt_gen
- KRB5_PROTOTYPE((krb5_context, krb5_ccache,
- krb5_principal, krb5_data *, int opt));
-
-/*
- * Try no preauthentication first; then try the encrypted timestamp
- */
-krb5_preauthtype * preauth = NULL;
-krb5_preauthtype preauth_list[2] = { 0, -1 };
+#endif
int
main(argc, argv)
char **argv;
{
krb5_context kcontext;
+ krb5_principal me = NULL;
+ krb5_deltat start_time = 0;
+ krb5_address **addresses = NULL;
+ krb5_get_init_creds_opt opts;
+ char *service_name = NULL;
+ krb5_keytab keytab = NULL;
+ char *cache_name;
krb5_ccache ccache = NULL;
- char *cache_name = NULL; /* -f option */
- char *keytab_name = NULL; /* -t option */
- char *service_name = NULL; /* -s option */
- krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */
- krb5_timestamp starttime = 0;
- krb5_deltat rlife = 0;
- int options = KRB5_DEFAULT_OPTIONS;
- int option;
- int errflg = 0;
- krb5_error_code code;
- krb5_principal me;
- krb5_principal server;
+ enum { INIT_PW, INIT_KT, RENEW, VALIDATE} action;
+ int errflg = 0, idx, i;
krb5_creds my_creds;
- krb5_timestamp now;
- krb5_address *null_addr = (krb5_address *)0;
- krb5_address **addrs = (krb5_address **)0;
- int use_keytab = 0; /* -k option */
- krb5_keytab keytab = NULL;
- struct passwd *pw = 0;
- int pwsize;
- char password[255], *client_name, prompt[1024];
+ krb5_error_code code;
- code = krb5_init_context(&kcontext);
- if (code) {
- com_err(argv[0], code, "while initializing krb5");
- exit(1);
- }
+ /* Ensure we can be driven from a pipe */
+ if(!isatty(fileno(stdin)))
+ setvbuf(stdin, 0, _IONBF, 0);
+ if(!isatty(fileno(stdout)))
+ setvbuf(stdout, 0, _IONBF, 0);
+ if(!isatty(fileno(stderr)))
+ setvbuf(stderr, 0, _IONBF, 0);
- if ((code = krb5_timeofday(kcontext, &now))) {
- com_err(argv[0], code, "while getting time of day");
+ if (code = krb5_init_context(&kcontext)) {
+ com_err(argv[0], code, "while initializing kerberos library");
exit(1);
}
+ krb5_get_init_creds_opt_init(&opts);
+
+ action = INIT_PW;
+
if (strrchr(argv[0], '/'))
argv[0] = strrchr(argv[0], '/')+1;
- while ((option = getopt(argc, argv, "r:Rfpl:s:c:kt:vS:")) != -1) {
- switch (option) {
- case 'r':
- options |= KDC_OPT_RENEWABLE;
- code = krb5_string_to_deltat(optarg, &rlife);
- if (code != 0 || rlife == 0) {
- fprintf(stderr, "Bad lifetime value %s\n", optarg);
- errflg++;
+ while (
+#ifdef GETOPT_LONG
+ (i = getopt_long(argc, argv, "r:fpAl:s:c:kt:RS:v",
+ long_options, &idx)) != -1
+#else
+ (i = getopt(argc, argv, "r:fpAl:s:c:kt:RS:v")) != -1
+#endif
+ ) {
+ switch (i) {
+#ifdef GETOPT_LONG
+ case 1: /* Print the version */
+ printf("%s\n", krb5_version);
+ exit(0);
+#endif
+ case 'l':
+ {
+ krb5_deltat lifetime;
+ code = krb5_string_to_deltat(optarg, &lifetime);
+ if (code != 0 || lifetime == 0) {
+ fprintf(stderr, "Bad lifetime value %s\n", optarg);
+ errflg++;
+ }
+ krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime);
}
break;
- case 'R':
- /* renew the ticket */
- options |= KDC_OPT_RENEW;
+ case 'r':
+ {
+ krb5_deltat rlife;
+
+ code = krb5_string_to_deltat(optarg, &rlife);
+ if (code != 0 || rlife == 0) {
+ fprintf(stderr, "Bad lifetime value %s\n", optarg);
+ errflg++;
+ }
+ krb5_get_init_creds_opt_set_renew_life(&opts, rlife);
+ }
break;
- case 'v':
- /* validate the ticket */
- options |= KDC_OPT_VALIDATE;
+ case 'f':
+ krb5_get_init_creds_opt_set_forwardable(&opts, 1);
break;
- case 'S':
- service_name = optarg;
+#ifdef GETOPT_LONG
+ case 'f'+0200:
+ krb5_get_init_creds_opt_set_forwardable(&opts, 0);
break;
+#endif
case 'p':
- options |= KDC_OPT_PROXIABLE;
+ krb5_get_init_creds_opt_set_proxiable(&opts, 1);
break;
- case 'f':
- options |= KDC_OPT_FORWARDABLE;
+#ifdef GETOPT_LONG
+ case 'p'+0200:
+ krb5_get_init_creds_opt_set_proxiable(&opts, 0);
break;
-#ifndef NO_KEYTAB
- case 'k':
- use_keytab = 1;
+#endif
+ case 'A':
+ krb5_get_init_creds_opt_set_address_list(&opts, NULL);
break;
- case 't':
- if (keytab == NULL) {
- keytab_name = optarg;
+#ifdef GETOPT_LONG
+ case 'A'+0200:
+ krb5_os_localaddr(kcontext, &addresses);
+ krb5_get_init_creds_opt_set_address_list(&opts, addresses);
+ break;
+#endif
+ case 's':
+ code = krb5_string_to_deltat(optarg, &start_time);
+ if (code != 0 || start_time == 0) {
+ krb5_timestamp abs_starttime;
+ krb5_timestamp now;
+
+ code = krb5_string_to_timestamp(optarg, &abs_starttime);
+ if (code != 0 || abs_starttime == 0) {
+ fprintf(stderr, "Bad start time value %s\n", optarg);
+ errflg++;
+ } else {
+ if ((code = krb5_timeofday(kcontext, &now))) {
+ com_err(argv[0], code,
+ "while getting time of day");
+ exit(1);
+ }
- code = krb5_kt_resolve(kcontext, keytab_name, &keytab);
+ start_time = abs_starttime - now;
+ }
+ }
+ break;
+ case 'S':
+ service_name = optarg;
+ break;
+ case 'k':
+ action = INIT_KT;
+ break;
+ case 't':
+ if (keytab == NULL) {
+ code = krb5_kt_resolve(kcontext, optarg, &keytab);
if (code != 0) {
- com_err(argv[0], code, "resolving keytab %s",
- keytab_name);
- errflg++;
+ com_err(argv[0], code, "resolving keytab %s", optarg);
+ errflg++;
}
} else {
fprintf(stderr, "Only one -t option allowed.\n");
errflg++;
}
break;
-#endif
- case 'l':
- code = krb5_string_to_deltat(optarg, &lifetime);
- if (code != 0 || lifetime == 0) {
- fprintf(stderr, "Bad lifetime value %s\n", optarg);
- errflg++;
- }
+ case 'R':
+ action = RENEW;
break;
- case 's':
- code = krb5_string_to_timestamp(optarg, &starttime);
- if (code != 0 || starttime == 0) {
- krb5_deltat ktmp;
- code = krb5_string_to_deltat(optarg, &ktmp);
- if (code == 0 && ktmp != 0) {
- starttime = now + ktmp;
- options |= KDC_OPT_POSTDATED;
- } else {
- fprintf(stderr, "Bad postdate start time value %s\n", optarg);
- errflg++;
- }
- } else {
- options |= KDC_OPT_POSTDATED;
- }
+ case 'v':
+ action = VALIDATE;
break;
- case 'c':
+ case 'c':
if (ccache == NULL) {
cache_name = optarg;
errflg++;
}
break;
- case '?':
default:
errflg++;
break;
}
if (errflg) {
- fprintf(stderr, "Usage: %s [-r time] [-R] [-s time] [-v] [-puf] [-l lifetime] [-c cachename] [-k] [-t keytab] [-S target_service] [principal]\n", argv[0]);
+#ifdef GETOPT_LONG
+ fprintf(stderr, "Usage: %s [--version] [-l lifetime] [-r renewable_life] [-f | --forwardable | --noforwardable] [-p | --proxiable | --noproxiable] [-A | --noaddresses | --addresses] [-s start_time] [-S target_service] [-k [-t keytab_file]] [-R] [-v] [-c cachename] [principal]\n", argv[0]);
+#else
+ fprintf(stderr, "Usage: %s [-l lifetime] [-r renewable_life] [-f] [-p] [-A] [-s start_time] [-S target_service] [-k [-t keytab_file]] [-R] [-v] [-c cachename] [principal]\n", argv[0]);
+#endif
exit(2);
}
}
}
- if (optind != argc-1) { /* No principal name specified */
-#ifndef NO_KEYTAB
- if (use_keytab) {
- /* Use the default host/service name */
- code = krb5_sname_to_principal(kcontext, NULL, NULL,
- KRB5_NT_SRV_HST, &me);
- if (code) {
- com_err(argv[0], code,
- "when creating default server principal name");
- exit(1);
- }
- } else
-#endif
- {
- /* Get default principal from cache if one exists */
- code = krb5_cc_get_principal(kcontext, ccache, &me);
- if (code) {
-#ifdef HAVE_PWD_H
- /* Else search passwd file for client */
- pw = getpwuid((int) getuid());
- if (pw) {
- if ((code = krb5_parse_name(kcontext,pw->pw_name,
- &me))) {
- com_err (argv[0], code, "when parsing name %s",
- pw->pw_name);
- exit(1);
- }
- } else {
- fprintf(stderr,
- "Unable to identify user from password file\n");
- exit(1);
- }
-#else /* HAVE_PWD_H */
- fprintf(stderr, "Unable to identify user\n");
- exit(1);
-#endif /* HAVE_PWD_H */
- }
- }
- } /* Use specified name */
- else if ((code = krb5_parse_name (kcontext, argv[optind], &me))) {
- com_err (argv[0], code, "when parsing name %s",argv[optind]);
- exit(1);
- }
-
- if ((code = krb5_unparse_name(kcontext, me, &client_name))) {
- com_err (argv[0], code, "when unparsing name");
- exit(1);
- }
-
- memset((char *)&my_creds, 0, sizeof(my_creds));
-
- my_creds.client = me;
-
- if (service_name == NULL) {
- if((code = krb5_build_principal_ext(kcontext, &server,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- tgtname.length, tgtname.data,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- 0))) {
- com_err(argv[0], code, "while building server name");
- exit(1);
- }
- } else {
- if ((code = krb5_parse_name(kcontext, service_name, &server))) {
- com_err(argv[0], code, "while parsing service name %s",
- service_name);
- exit(1);
- }
- }
-
- my_creds.server = server;
-
- if (options & KDC_OPT_POSTDATED) {
- my_creds.times.starttime = starttime;
- my_creds.times.endtime = starttime + lifetime;
+ if (optind == argc-1) {
+ /* Use specified name */
+ if ((code = krb5_parse_name (kcontext, argv[optind], &me))) {
+ com_err (argv[0], code, "when parsing name %s",argv[optind]);
+ exit(1);
+ }
} else {
- my_creds.times.starttime = 0; /* start timer when request
- gets to KDC */
- my_creds.times.endtime = now + lifetime;
- }
- if (options & KDC_OPT_RENEWABLE) {
- my_creds.times.renew_till = now + rlife;
- } else
- my_creds.times.renew_till = 0;
-
- if (options & KDC_OPT_VALIDATE) {
- /* don't use get_in_tkt, just use mk_req... */
- krb5_data outbuf;
-
- code = krb5_validate_tgt(kcontext, ccache, server, &outbuf);
- if (code) {
- com_err (argv[0], code, "validating tgt");
- exit(1);
+ /* No principal name specified */
+ if (action == INIT_KT) {
+ /* Use the default host/service name */
+ if (code = krb5_sname_to_principal(kcontext, NULL, NULL,
+ KRB5_NT_SRV_HST, &me)) {
+ com_err(argv[0], code,
+ "when creating default server principal name");
+ exit(1);
+ }
+ } else {
+ /* Get default principal from cache if one exists */
+ if (code = krb5_cc_get_principal(kcontext, ccache, &me))
+ get_name_from_passwd_file(argv[0], kcontext, &me);
}
- /* should be done... */
- exit(0);
}
-
- if (options & KDC_OPT_RENEW) {
- /* don't use get_in_tkt, just use mk_req... */
- krb5_data outbuf;
-
- code = krb5_renew_tgt(kcontext, ccache, server, &outbuf);
- if (code) {
- com_err (argv[0], code, "renewing tgt");
- exit(1);
- }
- /* should be done... */
- exit(0);
+
+ switch (action) {
+ case INIT_PW:
+ code = krb5_get_init_creds_password(kcontext, &my_creds, me, NULL,
+ krb5_prompter_posix, NULL,
+ start_time, service_name,
+ &opts);
+ break;
+ case INIT_KT:
+ code = krb5_get_init_creds_keytab(kcontext, &my_creds, me, keytab,
+ start_time, service_name,
+ &opts);
+ break;
+ case VALIDATE:
+ code = krb5_get_validated_creds(kcontext, &my_creds, me, ccache,
+ service_name);
+ break;
+ case RENEW:
+ code = krb5_get_renewed_creds(kcontext, &my_creds, me, ccache,
+ service_name);
+ break;
}
-#ifndef NO_KEYTAB
- if (!use_keytab)
-#endif
- {
- (void) sprintf(prompt, "Password for %.*s: ",
- sizeof(prompt)-32, (char *) client_name);
-
- pwsize = sizeof(password);
- code = krb5_read_password(kcontext, prompt, 0, password, &pwsize);
- if (code || pwsize == 0) {
- fprintf(stderr, "Error while reading password for '%s'\n",
- client_name);
- memset(password, 0, sizeof(password));
- exit(1);
- }
-
- code = krb5_get_in_tkt_with_password(kcontext, options, addrs,
- NULL, preauth, password, 0,
- &my_creds, 0);
- memset(password, 0, sizeof(password));
-#ifndef NO_KEYTAB
- } else {
- code = krb5_get_in_tkt_with_keytab(kcontext, options, addrs,
- NULL, preauth, keytab, 0,
- &my_creds, 0);
-#endif
- }
-
if (code) {
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
fprintf (stderr, "%s: Password incorrect\n", argv[0]);
exit(1);
}
- code = krb5_cc_initialize (kcontext, ccache, me);
- if (code != 0) {
+ if (code = krb5_cc_initialize(kcontext, ccache, me)) {
com_err (argv[0], code, "when initializing cache %s",
cache_name?cache_name:"");
exit(1);
}
- code = krb5_cc_store_cred(kcontext, ccache, &my_creds);
- if (code) {
+ if (code = krb5_cc_store_cred(kcontext, ccache, &my_creds)) {
com_err (argv[0], code, "while storing credentials");
exit(1);
}
- /* my_creds is pointing at server */
- krb5_free_principal(kcontext, server);
+ if (me)
+ krb5_free_principal(kcontext, me);
+ if (keytab)
+ krb5_kt_close(kcontext, keytab);
+ if (ccache)
+ krb5_cc_close(kcontext, ccache);
+ if (addresses)
+ krb5_free_addresses(kcontext, addresses);
krb5_free_context(kcontext);
-
+
exit(0);
}
-
-#define VALIDATE 0
-#define RENEW 1
-
-/* stripped down version of krb5_mk_req */
-static krb5_error_code krb5_validate_tgt(context, ccache, server, outbuf)
- krb5_context context;
- krb5_ccache ccache;
- krb5_principal server; /* tgtname */
- krb5_data *outbuf;
-{
- return krb5_tgt_gen(context, ccache, server, outbuf, VALIDATE);
-}
-
-/* stripped down version of krb5_mk_req */
-static krb5_error_code krb5_renew_tgt(context, ccache, server, outbuf)
- krb5_context context;
- krb5_ccache ccache;
- krb5_principal server; /* tgtname */
- krb5_data *outbuf;
-{
- return krb5_tgt_gen(context, ccache, server, outbuf, RENEW);
-}
-
-
-/* stripped down version of krb5_mk_req */
-static krb5_error_code krb5_tgt_gen(context, ccache, server, outbuf, opt)
- krb5_context context;
- krb5_ccache ccache;
- krb5_principal server; /* tgtname */
- krb5_data *outbuf;
- int opt;
-{
- krb5_error_code retval;
- krb5_creds * credsp;
- krb5_creds creds;
-
- /* obtain ticket & session key */
- memset((char *)&creds, 0, sizeof(creds));
- if ((retval = krb5_copy_principal(context, server, &creds.server)))
- goto cleanup;
-
- if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)))
- goto cleanup_creds;
-
- if(opt == VALIDATE) {
- if ((retval = krb5_get_credentials_validate(context, 0,
- ccache, &creds, &credsp)))
- goto cleanup_creds;
- } else {
- if ((retval = krb5_get_credentials_renew(context, 0,
- ccache, &creds, &credsp)))
- goto cleanup_creds;
- }
-
- /* we don't actually need to do the mk_req, just get the creds. */
-cleanup_creds:
- krb5_free_cred_contents(context, &creds);
-
-cleanup:
-
- return retval;
-}
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * klist.c: add -a flag to print the ticket address, and -n flag to
+ do so without attempting resolution. Make klist use the new api
+ for stringifying enctypes.
+
Tue Aug 11 23:38:53 1998 Matthew D Hancher <mdh@mit.edu>
* klist.c (do_ccache): Properly check the return value of
#include <string.h>
#include <stdio.h>
#include <time.h>
+#include <sys/socket.h>
+#include <netdb.h>
extern int optind;
extern char *optarg;
int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;
-int show_etype = 0;
+int show_etype = 0, show_addresses = 0, no_resolve = 0;
char *defname;
char *progname;
krb5_int32 now;
void do_ccache KRB5_PROTOTYPE((char *));
void do_keytab KRB5_PROTOTYPE((char *));
void printtime KRB5_PROTOTYPE((time_t));
+void one_addr KRB5_PROTOTYPE((krb5_address *));
void fillit KRB5_PROTOTYPE((FILE *, int, int));
#define DEFAULT 0
void usage()
{
- fprintf(stderr, "Usage: %s [[-c] [-f] [-e] [-s]] [-k [-t] [-K]] [name]\n",
+ fprintf(stderr, "Usage: %s [[-c] [-f] [-e] [-s] [-a] [-n]] [-k [-t] [-K]] [name]\n",
progname);
fprintf(stderr, "\t-c specifies credentials cache, -k specifies keytab");
fprintf(stderr, ", -c is default\n");
fprintf(stderr, "\t\t-f shows credentials flags\n");
fprintf(stderr, "\t\t-e shows the encryption type\n");
fprintf(stderr, "\t\t-s sets exit status based on valid tgt existence\n");
+ fprintf(stderr, "\t\t-a displays the address list\n");
+ fprintf(stderr, "\t\t\t-n do not reverse-resolve\n");
fprintf(stderr, "\toptions for keytabs:\n");
fprintf(stderr, "\t\t-t shows keytab entry timestamps\n");
fprintf(stderr, "\t\t-K shows keytab entry DES keys\n");
case 's':
status_only = 1;
break;
+ case 'n':
+ no_resolve = 1;
+ break;
+ case 'a':
+ show_addresses = 1;
+ break;
case 'c':
if (mode != DEFAULT) usage();
mode = CCACHE;
printf(" ");
}
printf("%s", pname);
-if (show_etype)
- printf(" (%s) " , etype_string(entry.key.enctype));
+ if (show_etype)
+ printf(" (%s) " , etype_string(entry.key.enctype));
if (show_keys) {
printf(" (0x");
{
etype_string(enctype)
krb5_enctype enctype;
{
- static char buf[12];
+ static char buf[100];
+ krb5_error_code retval;
- switch (enctype) {
- case ENCTYPE_DES_CBC_CRC:
- return "DES-CBC-CRC";
- break;
- case ENCTYPE_DES_CBC_MD4:
- return "DES-CBC-MD4";
- break;
- case ENCTYPE_DES_CBC_MD5:
- return "DES-CBC-MD5";
- break;
- case ENCTYPE_DES3_CBC_SHA:
- return "DES3-CBC-SHA";
- break;
- default:
+ if ((retval = krb5_enctype_to_string(enctype, buf, sizeof(buf)))) {
+ /* XXX if there's an error != EINVAL, I should probably report it */
sprintf(buf, "etype %d", enctype);
- return buf;
- break;
}
+
+ return buf;
}
char *
fputs("\t",stdout);
else
fputs(", ",stdout);
- printf("Etype (skey, tkt): %s, %s ",
- etype_string(cred->keyblock.enctype),
+ printf("Etype (skey, tkt): %s, ",
+ etype_string(cred->keyblock.enctype));
+ printf("%s ",
etype_string(tkt->enc_part.enctype));
krb5_free_ticket(kcontext, tkt);
extra_field++;
/* if any additional info was printed, extra_field is non-zero */
if (extra_field)
putchar('\n');
+
+
+ if (show_addresses) {
+ if (!cred->addresses || !cred->addresses[0]) {
+ printf("\tAddresses: (none)\n");
+ } else {
+ int i;
+
+ printf("\tAddresses: ");
+ one_addr(cred->addresses[0]);
+
+ for (i=1; cred->addresses[i]; i++) {
+ printf(", ");
+ one_addr(cred->addresses[1]);
+ }
+
+ printf("\n");
+ }
+ }
+
free(name);
free(sname);
}
+void one_addr(a)
+ krb5_address *a;
+{
+ struct hostent *h;
+
+ if ((a->addrtype == ADDRTYPE_INET) &&
+ (a->length == 4)) {
+ if (!no_resolve) {
+ h = gethostbyaddr(a->contents, 4, AF_INET);
+ if (h) {
+ printf("%s", h->h_name);
+ }
+ }
+ if (no_resolve || !h) {
+ printf("%d.%d.%d.%d", a->contents[0], a->contents[1],
+ a->contents[2], a->contents[3]);
+ }
+ } else {
+ printf("unknown addr type %d", a->addrtype);
+ }
+}
+
void
fillit(f, num, c)
FILE *f;
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * krb5.hin: add new interfaces for new crypto API and key
+ derivation/key usage. Add new (krb5_get_permitted_enctypes,
+ krb5_is_permitted_enctype) api for querying permitted etypes from
+ krb5.conf, and new auth_context flag
+ (KRB5_AUTH_CONTEXT_PERMIT_ALL) to override this. Fix bug in
+ krb5_kt_get_type.
+
+ * k5-int.h: make changes related to new crypto API and key
+ derivation/key usage
+
+Tue Sep 1 19:32:33 1998 Tom Yu <tlyu@mit.edu>
+
+ * krb5.hin: Add ENCTYPE_LOCAL_DES3_HMAC_SHA1, in order to deal
+ with marc's current des3 cryptosystem until we figure out what
+ we're actually going to use for a standardized cryptosystem.
+
Wed Jul 1 19:14:25 1998 Theodore Y. Ts'o <tytso@mit.edu>
* win-mac.h: Make size_t to be an unsigned long instead of
* documentation shall at all times remain with M.I.T., and USER agrees to
* preserve same.
*/
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
/*
* This prototype for k5-int.h (Krb5 internals include file)
* includes the user-visible definitions from krb5.h and then
#define labs(x) abs(x)
#endif
+/* #define KRB5_OLD_CRYPTO is done in krb5.h */
+
#endif /* KRB5_CONFIG__ */
/*
krb5_error_code krb5_find_config_files
KRB5_PROTOTYPE(());
+#endif /* KRB5_LIBOS_PROTO__ */
+
+/* new encryption provider api */
+
+struct krb5_enc_provider {
+ void (*block_size) KRB5_NPROTOTYPE
+ ((size_t *output));
+
+ /* keybytes is the input size to make_key;
+ keylength is the output size */
+ void (*keysize) KRB5_NPROTOTYPE
+ ((size_t *keybytes, size_t *keylength));
+
+ /* ivec == 0 is an all-zeros ivec */
+ krb5_error_code (*encrypt) KRB5_NPROTOTYPE
+ ((krb5_const krb5_keyblock *key, krb5_const krb5_data *ivec,
+ krb5_const krb5_data *input, krb5_data *output));
+
+ krb5_error_code (*decrypt) KRB5_NPROTOTYPE
+ ((krb5_const krb5_keyblock *key, krb5_const krb5_data *ivec,
+ krb5_const krb5_data *input, krb5_data *output));
+
+ krb5_error_code (*make_key) KRB5_NPROTOTYPE
+ ((krb5_const krb5_data *randombits, krb5_keyblock *key));
+};
+
+struct krb5_hash_provider {
+ void (*hash_size) KRB5_NPROTOTYPE
+ ((size_t *output));
+
+ void (*block_size) KRB5_NPROTOTYPE
+ ((size_t *output));
+
+ /* this takes multiple inputs to avoid lots of copying. */
+ krb5_error_code (*hash) KRB5_NPROTOTYPE
+ ((unsigned int icount, krb5_const krb5_data *input, krb5_data *output));
+};
+
+struct krb5_keyhash_provider {
+ void (*hash_size) KRB5_NPROTOTYPE
+ ((size_t *output));
+
+ krb5_error_code (*hash) KRB5_NPROTOTYPE
+ ((krb5_const krb5_keyblock *key, krb5_const krb5_data *ivec,
+ krb5_const krb5_data *input, krb5_data *output));
+
+ krb5_error_code (*verify) KRB5_NPROTOTYPE
+ ((krb5_const krb5_keyblock *key, krb5_const krb5_data *ivec,
+ krb5_const krb5_data *input, krb5_const krb5_data *hash,
+ krb5_boolean *valid));
+};
+
+typedef void (*krb5_encrypt_length_func) KRB5_NPROTOTYPE
+((krb5_const struct krb5_enc_provider *enc,
+ krb5_const struct krb5_hash_provider *hash,
+ size_t inputlen, size_t *length));
+
+typedef krb5_error_code (*krb5_crypt_func) KRB5_NPROTOTYPE
+((krb5_const struct krb5_enc_provider *enc,
+ krb5_const struct krb5_hash_provider *hash,
+ krb5_const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_const krb5_data *ivec,
+ krb5_const krb5_data *input, krb5_data *output));
+
+typedef krb5_error_code (*krb5_str2key_func) KRB5_NPROTOTYPE
+((krb5_const struct krb5_enc_provider *enc, krb5_const krb5_data *string,
+ krb5_const krb5_data *salt, krb5_keyblock *key));
+
+struct krb5_keytypes {
+ krb5_enctype etype;
+ char *in_string;
+ char *out_string;
+ struct krb5_enc_provider *enc;
+ struct krb5_hash_provider *hash;
+ krb5_encrypt_length_func encrypt_len;
+ krb5_crypt_func encrypt;
+ krb5_crypt_func decrypt;
+ krb5_str2key_func str2key;
+};
+
+struct krb5_cksumtypes {
+ krb5_cksumtype ctype;
+ unsigned int flags;
+ char *in_string;
+ char *out_string;
+ /* if the hash is keyed, this is the etype it is keyed with.
+ Actually, it can be keyed by any etype which has the same
+ enc_provider as the specified etype. DERIVE checksums can
+ be keyed with any valid etype. */
+ krb5_enctype keyed_etype;
+ /* I can't statically initialize a union, so I'm just going to use
+ two pointers here. The keyhash is used if non-NULL. If NULL,
+ then HMAC/hash with derived keys is used if the relevant flag
+ is set. Otherwise, a non-keyed hash is computed. This is all
+ kind of messy, but so is the krb5 api. */
+ struct krb5_keyhash_provider *keyhash;
+ struct krb5_hash_provider *hash;
+};
+
+#define KRB5_CKSUMFLAG_DERIVE 0x0001
+#define KRB5_CKSUMFLAG_NOT_COLL_PROOF 0x0002
/*
- * in here to deal with stuff from lib/crypto/os
+ * in here to deal with stuff from lib/crypto
*/
+void krb5_nfold
+KRB5_PROTOTYPE((int inbits, krb5_const unsigned char *in,
+ int outbits, unsigned char *out));
+
+krb5_error_code krb5_hmac
+KRB5_PROTOTYPE((krb5_const struct krb5_hash_provider *hash,
+ krb5_const krb5_keyblock *key, unsigned int icount,
+ krb5_const krb5_data *input, krb5_data *output));
+
+
+#ifdef KRB5_OLD_CRYPTO
+/* old provider api */
+
typedef struct _krb5_cryptosystem_entry {
krb5_magic magic;
krb5_error_code (*encrypt_func) KRB5_NPROTOTYPE(( krb5_const_pointer /* in */,
unsigned int uses_key:1;
} krb5_checksum_entry;
-
-/* This array is indexed by encryption type */
-extern krb5_cs_table_entry * NEAR krb5_csarray[];
-extern int krb5_max_cryptosystem;
-
-/* This array is indexed by key type */
-extern krb5_cs_table_entry * NEAR krb5_enctype_array[];
-extern krb5_enctype krb5_max_enctype;
-
-/* This array is indexed by checksum type */
-extern krb5_checksum_entry * NEAR krb5_cksumarray[];
-extern krb5_cksumtype krb5_max_cksum;
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV krb5_random_confounder
- KRB5_PROTOTYPE((size_t,
- krb5_pointer ));
-
krb5_error_code krb5_crypto_os_localaddr
KRB5_PROTOTYPE((krb5_address ***));
time_t gmt_mktime KRB5_PROTOTYPE((struct tm *));
-#endif /* KRB5_LIBOS_PROTO__ */
+#endif /* KRB5_OLD_CRYPTO */
+
+/* this helper fct is in libkrb5, but it makes sense declared here. */
+
+krb5_error_code krb5_encrypt_helper
+KRB5_PROTOTYPE((krb5_context context, krb5_const krb5_keyblock *key,
+ krb5_keyusage usage, krb5_const krb5_data *plain,
+ krb5_enc_data *cipher));
+
/*
* End "los-proto.h"
*/
KRB5_PROTOTYPE((krb5_context,
krb5_const krb5_msgtype,
krb5_const krb5_enc_kdc_rep_part *,
+ int using_subkey,
krb5_const krb5_keyblock *,
krb5_kdc_rep *,
krb5_data ** ));
+Thu Sep 17 18:23:26 1998 Tom Yu <tlyu@mit.edu>
+
+ * krb_db.h: ifdef out the declarations for kerb_get_* and
+ kerb_db_* to avoid problems with krb4 compat code in the kdc,
+ which declares some of these static.
+
Wed Feb 18 15:51:41 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in: Remove trailing slash from thisconfigdir. Fix up
}
Dba;
+#if 0
extern int kerb_get_principal();
extern int kerb_put_principal();
extern int kerb_db_get_stat();
extern int kerb_db_put_stat();
extern int kerb_get_dba();
extern int kerb_db_get_dba();
+#endif
#endif /* KRB_DB_DEFS */
* General definitions for Kerberos version 5.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef KRB5_GENERAL__
#define KRB5_GENERAL__
#define THREEPARAMOPEN(x,y,z) open(x,y,z)
#endif
+#define KRB5_OLD_CRYPTO
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
typedef unsigned int krb5_msgtype;
typedef unsigned int krb5_kvno;
-typedef unsigned int krb5_addrtype;
-typedef unsigned int krb5_enctype;
-typedef unsigned int krb5_cksumtype;
-typedef unsigned int krb5_authdatatype;
+typedef krb5_int32 krb5_addrtype;
+typedef krb5_int32 krb5_enctype;
+typedef krb5_int32 krb5_cksumtype;
+typedef krb5_int32 krb5_authdatatype;
+typedef krb5_int32 krb5_keyusage;
typedef krb5_int32 krb5_preauthtype; /* This may change, later on */
typedef krb5_int32 krb5_flags;
krb5_octet FAR *contents;
} krb5_keyblock;
+#ifdef KRB5_OLD_CRYPTO
+typedef struct _krb5_encrypt_block {
+ krb5_magic magic;
+ krb5_enctype crypto_entry; /* to call krb5_encrypt_size, you need
+ this. it was a pointer, but it
+ doesn't have to be. gross. */
+ krb5_keyblock FAR *key;
+ krb5_int32 priv_size; /* Size of private data */
+} krb5_encrypt_block;
+#endif
+
typedef struct _krb5_checksum {
krb5_magic magic;
krb5_cksumtype checksum_type; /* checksum type */
krb5_octet FAR *contents;
} krb5_checksum;
-typedef struct _krb5_encrypt_block {
- krb5_magic magic;
- struct _krb5_cryptosystem_entry FAR * crypto_entry;
- krb5_keyblock FAR *key;
- krb5_pointer priv; /* for private use, e.g. DES
- key schedules */
- krb5_int32 priv_size; /* Size of private data */
-} krb5_encrypt_block;
-
typedef struct _krb5_enc_data {
krb5_magic magic;
krb5_enctype enctype;
#define ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */
#define ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */
#define ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */
+/* XXX deprecated? */
#define ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */
#define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */
+#define ENCTYPE_DES3_HMAC_SHA1 0x0007
+#define ENCTYPE_DES_HMAC_SHA1 0x0008
#define ENCTYPE_UNKNOWN 0x01ff
+/* local crud */
+/* marc's DES-3 with 32-bit length */
+#define ENCTYPE_LOCAL_DES3_HMAC_SHA1 0x7007
#define CKSUMTYPE_CRC32 0x0001
#define CKSUMTYPE_RSA_MD4 0x0002
#define CKSUMTYPE_RSA_MD5 0x0007
#define CKSUMTYPE_RSA_MD5_DES 0x0008
#define CKSUMTYPE_NIST_SHA 0x0009
-#define CKSUMTYPE_HMAC_SHA 0x000a
+#define CKSUMTYPE_HMAC_SHA1 0x000a
#ifndef krb5_roundup
/* round x up to nearest multiple of y */
extern "C" {
#endif
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_encrypt
+ KRB5_PROTOTYPE((krb5_context context, krb5_const krb5_keyblock *key,
+ krb5_keyusage usage, krb5_const krb5_data *ivec,
+ krb5_const krb5_data *input, krb5_enc_data *output));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_decrypt
+ KRB5_PROTOTYPE((krb5_context context, krb5_const krb5_keyblock *key,
+ krb5_keyusage usage, krb5_const krb5_data *ivec,
+ krb5_const krb5_enc_data *input, krb5_data *output));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_encrypt_length
+ KRB5_PROTOTYPE((krb5_context context, krb5_enctype enctype,
+ size_t inputlen, size_t *length));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_block_size
+ KRB5_PROTOTYPE((krb5_context context, krb5_enctype enctype,
+ size_t *blocksize));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_make_random_key
+ KRB5_PROTOTYPE((krb5_context context, krb5_enctype enctype,
+ krb5_keyblock *random_key));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_random_make_octets
+ KRB5_PROTOTYPE((krb5_context context, krb5_data *data));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_random_seed
+ KRB5_PROTOTYPE((krb5_context context, krb5_data *data));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_string_to_key
+ KRB5_PROTOTYPE((krb5_context context, krb5_enctype enctype,
+ krb5_const krb5_data *string, krb5_const krb5_data *salt,
+ krb5_keyblock *key));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_enctype_compare
+ KRB5_PROTOTYPE((krb5_context context, krb5_enctype e1, krb5_enctype e2,
+ krb5_boolean *similar));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_make_checksum
+ KRB5_PROTOTYPE((krb5_context context, krb5_cksumtype cksumtype,
+ krb5_const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_const krb5_data *input, krb5_checksum *cksum));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_verify_checksum
+ KRB5_PROTOTYPE((krb5_context context,
+ krb5_const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_const krb5_data *data,
+ krb5_const krb5_checksum *cksum,
+ krb5_boolean *valid));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_checksum_length
+ KRB5_PROTOTYPE((krb5_context context, krb5_cksumtype cksumtype,
+ size_t *length));
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+ krb5_c_keyed_checksum_types
+ KRB5_PROTOTYPE((krb5_context context, krb5_enctype enctype,
+ unsigned int *count, krb5_cksumtype **cksumtypes));
+
+#define KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS 1
+#define KRB5_KEYUSAGE_KDC_REP_TICKET 2
+#define KRB5_KEYUSAGE_AS_REP_ENCPART 3
+#define KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY 4
+#define KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY 5
+#define KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM 6
+#define KRB5_KEYUSAGE_TGS_REQ_AUTH 7
+#define KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY 8
+#define KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY 9
+#define KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM 10
+#define KRB5_KEYUSAGE_AP_REQ_AUTH 11
+#define KRB5_KEYUSAGE_AP_REP_ENCPART 12
+#define KRB5_KEYUSAGE_KRB_PRIV_ENCPART 13
+#define KRB5_KEYUSAGE_KRB_CRED_ENCPART 14
+#define KRB5_KEYUSAGE_KRB_SAFE_CKSUM 15
+#define KRB5_KEYUSAGE_APP_DATA_ENCRYPT 16
+#define KRB5_KEYUSAGE_APP_DATA_CKSUM 17
+#define KRB5_KEYUSAGE_KRB_ERROR_CKSUM 18
+#define KRB5_KEYUSAGE_AD_KDCISSUED_CKSUM 19
+#define KRB5_KEYUSAGE_AD_MTE 20
+#define KRB5_KEYUSAGE_AD_ITE 21
+
+/* XXX need to register these */
+
+#define KRB5_KEYUSAGE_GSS_TOK_MIC 22
+#define KRB5_KEYUSAGE_GSS_TOK_WRAP_INTEG 23
+#define KRB5_KEYUSAGE_GSS_TOK_WRAP_PRIV 24
+
+
+krb5_boolean KRB5_CALLCONV valid_enctype
+ KRB5_PROTOTYPE((krb5_const krb5_enctype ktype));
+krb5_boolean KRB5_CALLCONV valid_cksumtype
+ KRB5_PROTOTYPE((krb5_const krb5_cksumtype ctype));
+krb5_boolean KRB5_CALLCONV is_coll_proof_cksum
+ KRB5_PROTOTYPE((krb5_const krb5_cksumtype ctype));
+krb5_boolean KRB5_CALLCONV is_keyed_cksum
+ KRB5_PROTOTYPE((krb5_const krb5_cksumtype ctype));
+
+#ifdef KRB5_OLD_CRYPTO
/*
- * cryptosystem routine prototypes
+ * old cryptosystem routine prototypes. These are now layered
+ * on top of the functions above.
*/
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV krb5_encrypt
KRB5_PROTOTYPE((krb5_context context,
krb5_const krb5_enctype enctype));
KRB5_DLLIMP size_t KRB5_CALLCONV krb5_encrypt_size
KRB5_PROTOTYPE((krb5_const size_t length,
- krb5_const struct _krb5_cryptosystem_entry FAR * crypto));
+ krb5_enctype crypto));
KRB5_DLLIMP size_t KRB5_CALLCONV krb5_checksum_size
KRB5_PROTOTYPE((krb5_context context,
krb5_const krb5_cksumtype ctype));
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV krb5_random_confounder
KRB5_PROTOTYPE((size_t, krb5_pointer));
-krb5_boolean KRB5_CALLCONV valid_enctype
- KRB5_PROTOTYPE((krb5_const krb5_enctype ktype));
-krb5_boolean KRB5_CALLCONV valid_cksumtype
- KRB5_PROTOTYPE((krb5_const krb5_cksumtype ctype));
-krb5_boolean KRB5_CALLCONV is_coll_proof_cksum
- KRB5_PROTOTYPE((krb5_const krb5_cksumtype ctype));
-krb5_boolean KRB5_CALLCONV is_keyed_cksum
- KRB5_PROTOTYPE((krb5_const krb5_cksumtype ctype));
-
krb5_error_code krb5_encrypt_data
KRB5_PROTOTYPE((krb5_context context, krb5_keyblock *key,
krb5_pointer ivec, krb5_data *data,
KRB5_PROTOTYPE((krb5_context context, krb5_keyblock *key,
krb5_pointer ivec, krb5_enc_data *data,
krb5_data *enc_data));
+
+#endif /* KRB5_OLD_CRYPTO */
+
#ifdef __cplusplus
}
#endif
#define KRB5_AUTH_CONTEXT_RET_TIME 0x00000002
#define KRB5_AUTH_CONTEXT_DO_SEQUENCE 0x00000004
#define KRB5_AUTH_CONTEXT_RET_SEQUENCE 0x00000008
+#define KRB5_AUTH_CONTEXT_PERMIT_ALL 0x00000010
typedef struct krb5_replay_data {
krb5_timestamp timestamp;
void * serializer;
} krb5_kt_ops;
-#define krb5_kt_get_type(context, keytab) (*(keytab)->ops->prefix)
+#define krb5_kt_get_type(context, keytab) ((keytab)->ops->prefix)
#define krb5_kt_get_name(context, keytab, name, namelen) krb5_x((keytab)->ops->get_name,(context, keytab,name,namelen))
#define krb5_kt_close(context, keytab) krb5_x((keytab)->ops->close,(context, keytab))
#define krb5_kt_get_entry(context, keytab, principal, vno, enctype, entry) krb5_x((keytab)->ops->get,(context, keytab, principal, vno, enctype, entry))
krb5_const_principal,
krb5_enctype **));
+krb5_error_code krb5_get_permitted_enctypes
+ KRB5_PROTOTYPE((krb5_context, krb5_enctype **));
+
+krb5_boolean krb5_is_permitted_enctype
+ KRB5_PROTOTYPE((krb5_context, krb5_enctype));
+
/* libkrb.spec */
krb5_error_code krb5_kdc_rep_decrypt_proc
KRB5_PROTOTYPE((krb5_context,
KRB5_PROTOTYPE((krb5_context, krb5_cred_enc_part FAR *));
KRB5_DLLIMP void KRB5_CALLCONV krb5_free_checksum
KRB5_PROTOTYPE((krb5_context, krb5_checksum FAR *));
+KRB5_DLLIMP void KRB5_CALLCONV krb5_free_checksum_contents
+ KRB5_PROTOTYPE((krb5_context, krb5_checksum FAR *));
KRB5_DLLIMP void KRB5_CALLCONV krb5_free_keyblock
KRB5_PROTOTYPE((krb5_context, krb5_keyblock FAR *));
KRB5_DLLIMP void KRB5_CALLCONV krb5_free_keyblock_contents
KRB5_PROTOTYPE((krb5_context, krb5_data FAR *));
KRB5_DLLIMP void KRB5_CALLCONV krb5_free_unparsed_name
KRB5_PROTOTYPE((krb5_context, char FAR *));
+KRB5_DLLIMP void KRB5_CALLCONV krb5_free_cksumtypes
+ KRB5_PROTOTYPE((krb5_context, krb5_cksumtype FAR *));
/* From krb5/os but needed but by the outside world */
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV krb5_us_timeofday
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * kdb_dbc.h, kdb.h: update kdb api to be compatible with the new
+ crypto api.
+
Wed Jul 8 04:30:22 1998 Geoffrey King <gjking@mit.edu>
* adm_proto.h: Added prototype for new function krb5_klog_reopen()
* KDC Database interface definitions.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
#ifndef KRB5_KDB5__
#define KRB5_KDB5__
krb5_error_code krb5_db_verify_master_key
KRB5_PROTOTYPE((krb5_context,
krb5_principal,
- krb5_keyblock *,
- krb5_encrypt_block *));
+ krb5_keyblock *));
krb5_error_code krb5_db_store_mkey
KRB5_PROTOTYPE((krb5_context,
char *,
krb5_principal *));
krb5_error_code krb5_db_set_mkey
- KRB5_PROTOTYPE((krb5_context, krb5_encrypt_block *));
+ KRB5_PROTOTYPE((krb5_context, krb5_keyblock *));
krb5_error_code krb5_db_get_mkey
- KRB5_PROTOTYPE((krb5_context, krb5_encrypt_block **));
+ KRB5_PROTOTYPE((krb5_context, krb5_keyblock **));
krb5_error_code krb5_db_destroy
KRB5_PROTOTYPE((krb5_context,
char * ));
krb5_error_code krb5_db_fetch_mkey
KRB5_PROTOTYPE((krb5_context,
krb5_principal,
- krb5_encrypt_block *,
+ krb5_enctype,
krb5_boolean,
krb5_boolean,
char *,
krb5_error_code krb5_dbekd_encrypt_key_data
KRB5_PROTOTYPE((krb5_context,
- krb5_encrypt_block *,
+ const krb5_keyblock *,
const krb5_keyblock *,
const krb5_keysalt *,
int,
krb5_key_data *));
krb5_error_code krb5_dbekd_decrypt_key_data
KRB5_PROTOTYPE((krb5_context,
- krb5_encrypt_block *,
+ const krb5_keyblock *,
const krb5_key_data *,
krb5_keyblock *,
krb5_keysalt *));
krb5_error_code krb5_dbe_cpw
KRB5_PROTOTYPE((krb5_context,
- krb5_encrypt_block *,
+ krb5_keyblock *,
struct __krb5_key_salt_tuple *,
int,
char *,
krb5_db_entry *));
krb5_error_code krb5_dbe_apw
KRB5_PROTOTYPE((krb5_context,
- krb5_encrypt_block *,
+ krb5_keyblock *,
struct __krb5_key_salt_tuple *,
int,
char *,
krb5_db_entry *));
krb5_error_code krb5_dbe_crk
KRB5_PROTOTYPE((krb5_context,
- krb5_encrypt_block *,
+ krb5_keyblock *,
struct __krb5_key_salt_tuple *,
int,
krb5_db_entry *));
krb5_error_code krb5_dbe_ark
KRB5_PROTOTYPE((krb5_context,
- krb5_encrypt_block *,
+ krb5_keyblock *,
struct __krb5_key_salt_tuple *,
int,
krb5_db_entry *));
* KDC Database context definitions.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef KRB5_KDB5_DBC__
#define KRB5_KDB5_DBC__
int db_locks_held; /* Number of times locked */
int db_lock_mode; /* Last lock mode, e.g. greatest*/
krb5_boolean db_nb_locks; /* [Non]Blocking lock modes */
- krb5_encrypt_block *db_master_key; /* Master key of database */
+ krb5_keyblock *db_master_key; /* Master key of database */
kdb5_dispatch_table *db_dispatch; /* Dispatch table */
} krb5_db_context;
+1998-10-26 Marc Horowitz <marc@mit.edu>
+
+ * keytab.c (etype_string): replace the hardwired table with a call
+ to krb5_enctype_to_string()
+
Fri Feb 27 23:32:38 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
* Makefile.in: Changed thisconfigdir to point at the kadmin
* $Source$
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header$";
#endif
static char *etype_string(enctype)
krb5_enctype enctype;
{
- static char buf[12];
-
- switch (enctype) {
- case ENCTYPE_DES_CBC_CRC:
- return "DES-CBC-CRC";
- break;
- case ENCTYPE_DES_CBC_MD4:
- return "DES-CBC-MD4";
- break;
- case ENCTYPE_DES_CBC_MD5:
- return "DES-CBC-MD5";
- break;
-#if 0
- case ENCTYPE_DES3_CBC_MD5:
- return "DES3-CBC-MD5";
- break;
-#endif
- default:
+ static char buf[100];
+ krb5_error_code ret;
+
+ if (ret = krb5_enctype_to_string(enctype, buf, sizeof(buf)))
sprintf(buf, "etype %d", enctype);
- return buf;
- break;
- }
+
+ return buf;
}
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * dumpv4, loadv4.c, kdb5_create.c, kdb5_stash.c, kdb5_util.c,
+ kadm5_create.c: convert to new crypto api
+
Wed Sep 30 00:02:01 1998 Theodore Y. Ts'o <tytso@mit.edu>
* dump.c: Add support for changing the master key for a database
as part of creating a dump of the database.
+Thu Aug 20 16:50:00 1998 Tom Yu <tlyu@mit.edu>
+
+ * kdb5_util.c (add_random_key): Fixes to deal with absence of "-e"
+ flag.
+
+Wed Aug 19 14:52:40 1998 Tom Yu <tlyu@mit.edu>
+
+ * kdb5_util.c (add_random_key): New function to create a new
+ random key for a principal while retaining the previous kvno's
+ keys. This is only temporary until a reasonable kadm5 interface
+ is made.
+
1998-05-06 Theodore Ts'o <tytso@rsts-11.mit.edu>
* kdb5_stash.c (argv):
* Dump a KDC database into a V4 slave dump.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifdef KRB5_KRB4_COMPAT
#include "k5-int.h"
struct dump_record {
char *comerr_name;
FILE *f;
- krb5_encrypt_block *v5master;
+ krb5_keyblock *v5mkey;
C_Block v4_master_key;
Key_schedule v4_master_key_schedule;
long master_key_version;
char *realm;
};
-extern krb5_encrypt_block master_encblock;
extern krb5_keyblock master_keyblock;
extern krb5_principal master_princ;
extern krb5_boolean dbactive;
principal->key_version,
principal->attributes);
- handle_one_key(arg, arg->v5master, &entry->key_data[ok_key], v4key);
+ handle_one_key(arg, arg->v5mkey, &entry->key_data[ok_key], v4key);
for (i = 0; i < 8; i++) {
fprintf(arg->f, "%02x", ((unsigned char*)v4key)[i]);
exit(1);
}
- krb5_use_enctype(util_context, &master_encblock, DEFAULT_KDC_ENCTYPE);
if (retval = krb5_db_fetch_mkey(util_context, master_princ,
- &master_encblock, 0,
+ master_keyblock.enctype, 0,
0, global_params.stash_file, 0,
&master_keyblock)) {
com_err(arg->comerr_name, retval, "while reading master key");
exit(1);
}
- if (retval = krb5_process_key(util_context, &master_encblock,
- &master_keyblock)) {
- com_err(arg->comerr_name, retval, "while processing master key");
- exit(1);
- }
- arg->v5master = &master_encblock;
+ arg->v5mkey = &master_keyblock;
return(0);
}
-handle_one_key(arg, v5master, v5key, v4key)
+handle_one_key(arg, v5mkey, v5key, v4key)
struct dump_record *arg;
- krb5_encrypt_block *v5master;
+ krb5_keyblock *v5mkey;
krb5_key_data *v5key;
des_cblock v4key;
{
krb5_keyblock v5plainkey;
/* v4key is the actual v4 key from the file. */
- if (retval = krb5_dbekd_decrypt_key_data(util_context, v5master, v5key,
+ if (retval = krb5_dbekd_decrypt_key_data(util_context, v5mkey, v5key,
&v5plainkey, NULL))
return retval;
* $Source$
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header$";
#endif
extern char *progname;
-extern krb5_encrypt_block master_encblock;
extern krb5_keyblock master_keyblock;
extern krb5_db_entry master_db;
* Generate (from scratch) a Kerberos KDC database.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include <stdio.h>
#include <k5-int.h>
#include <kadm5/admin.h>
krb5_deltat max_rlife;
krb5_timestamp expiration;
krb5_flags flags;
- krb5_encrypt_block *eblock;
- krb5_pointer rseed;
+ krb5_keyblock *key;
krb5_int32 nkslist;
krb5_key_salt_tuple *kslist;
} rblock = { /* XXX */
KRB5_KDB_MAX_RLIFE,
KRB5_KDB_EXPIRATION,
KRB5_KDB_DEF_FLAGS,
- (krb5_encrypt_block *) NULL,
- (krb5_pointer) NULL,
+ (krb5_keyblock *) NULL,
1,
&def_kslist
};
extern krb5_keyblock master_keyblock;
extern krb5_principal master_princ;
-extern krb5_encrypt_block master_encblock;
krb5_data master_salt;
krb5_data tgt_princ_entries[] = {
int pw_size = 0;
int do_stash = 0;
krb5_int32 crflags = KRB5_KDB_CREATE_BTREE;
- krb5_data pwd;
+ krb5_data pwd, seed;
if (strrchr(argv[0], '/'))
argv[0] = strrchr(argv[0], '/')+1;
rblock.nkslist = global_params.num_keysalts;
rblock.kslist = global_params.keysalts;
- krb5_use_enctype(util_context, &master_encblock, master_keyblock.enctype);
-
retval = krb5_db_set_name(util_context, global_params.dbname);
if (!retval) retval = EEXIST;
com_err(argv[0], retval, "while calculated master key salt");
exit_status++; return;
}
- if (retval = krb5_string_to_key(util_context, &master_encblock,
- &master_keyblock, &pwd, &master_salt)) {
+ if (retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,
+ &pwd, &master_salt, &master_keyblock)) {
com_err(argv[0], retval, "while transforming master key from password");
exit_status++; return;
}
- if ((retval = krb5_process_key(util_context, &master_encblock,
- &master_keyblock))) {
- com_err(argv[0], retval, "while processing master key");
- exit_status++; return;
- }
+ rblock.key = &master_keyblock;
+
+ seed.length = master_keyblock.length;
+ seed.data = master_keyblock.contents;
- rblock.eblock = &master_encblock;
- if ((retval = krb5_init_random_key(util_context, &master_encblock,
- &master_keyblock, &rblock.rseed))) {
+ if ((retval = krb5_c_random_seed(util_context, &seed))) {
com_err(argv[0], retval, "while initializing random key generator");
- (void) krb5_finish_key(util_context, &master_encblock);
exit_status++; return;
}
if ((retval = krb5_db_create(util_context,
global_params.dbname, crflags))) {
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
com_err(argv[0], retval, "while creating database '%s'",
global_params.dbname);
exit_status++; return;
}
if (retval = krb5_db_fini(util_context)) {
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock,
- &rblock.rseed);
com_err(argv[0], retval, "while closing current database");
exit_status++; return;
}
if ((retval = krb5_db_set_name(util_context, global_params.dbname))) {
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
com_err(argv[0], retval, "while setting active database to '%s'",
global_params.dbname);
exit_status++; return;
}
if ((retval = krb5_db_init(util_context))) {
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
com_err(argv[0], retval, "while initializing the database '%s'",
global_params.dbname);
exit_status++; return;
if ((retval = add_principal(util_context, master_princ, MASTER_KEY, &rblock)) ||
(retval = add_principal(util_context, &tgt_princ, TGT_KEY, &rblock))) {
(void) krb5_db_fini(util_context);
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
com_err(argv[0], retval, "while adding entries to the database");
exit_status++; return;
}
}
/* clean up */
(void) krb5_db_fini(util_context);
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock, &rblock.rseed);
memset((char *)master_keyblock.contents, 0, master_keyblock.length);
free(master_keyblock.contents);
if (pw_str) {
krb5_context context;
krb5_error_code kret;
struct iterate_args *iargs;
- krb5_keyblock random_keyblock, *key;
+ krb5_keyblock key;
krb5_int32 ind;
- krb5_encrypt_block random_encblock;
krb5_pointer rseed;
krb5_data pwd;
* Convert the master key password into a key for this particular
* encryption system.
*/
- krb5_use_enctype(context, &random_encblock, ksent->ks_enctype);
pwd.data = mkey_password;
pwd.length = strlen(mkey_password);
- if (kret = krb5_string_to_key(context, &random_encblock, &random_keyblock,
- &pwd, &master_salt))
- return kret;
- if ((kret = krb5_init_random_key(context, &random_encblock,
- &random_keyblock, &rseed)))
+ if (kret = krb5_c_random_seed(context, &pwd))
return kret;
-
+
if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
ind = iargs->dbentp->n_key_data-1;
- if (!(kret = krb5_random_key(context,
- &random_encblock, rseed,
- &key))) {
+ if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype,
+ &key))) {
kret = krb5_dbekd_encrypt_key_data(context,
- iargs->rblock->eblock,
- key,
+ iargs->rblock->key,
+ &key,
NULL,
1,
&iargs->dbentp->key_data[ind]);
- krb5_free_keyblock(context, key);
+ krb5_free_keyblock_contents(context, &key);
}
}
- memset((char *)random_keyblock.contents, 0, random_keyblock.length);
- free(random_keyblock.contents);
- (void) krb5_finish_random_key(context, &random_encblock, &rseed);
+
return(kret);
}
entry.n_key_data = 1;
entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
- if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
+ if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
&master_keyblock, NULL,
1, entry.key_data)))
return retval;
* Store the master database key in a file.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "com_err.h"
#include <kadm5/admin.h>
extern krb5_keyblock master_keyblock;
extern krb5_principal master_princ;
-extern krb5_encrypt_block master_encblock;
extern kadm5_config_params global_params;
extern int exit_status;
exit_status++; return;
}
- krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
-
if (retval = krb5_db_set_name(context, dbname)) {
com_err(argv[0], retval, "while setting active database to '%s'",
dbname);
}
/* TRUE here means read the keyboard, but only once */
- if (retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
+ if (retval = krb5_db_fetch_mkey(context, master_princ,
+ master_keyblock.enctype,
TRUE, FALSE, (char *) NULL,
0, &master_keyblock)) {
com_err(argv[0], retval, "while reading master key");
exit_status++; return;
}
if (retval = krb5_db_verify_master_key(context, master_princ,
- &master_keyblock,&master_encblock)) {
+ &master_keyblock)) {
com_err(argv[0], retval, "while verifying master key");
(void) krb5_db_fini(context);
exit_status++; return;
* Edit a KDC database.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include <stdio.h>
#include <k5-int.h>
#include <kadm5/admin.h>
"\tdump [-old] [-ov] [-b6] [-verbose] [filename [princs...]]\n"
"\tload [-old] [-ov] [-b6] [-verbose] [-update] filename\n"
"\tdump_v4 [filename]\n"
- "\tload_v4 [-t] [-n] [-v] [-K] [-s stashfile] inputfile\n");
+ "\tload_v4 [-t] [-n] [-v] [-K] [-s stashfile] inputfile\n"
+ "\tark [-e etype_list] principal\n");
exit(1);
}
extern krb5_keyblock master_keyblock;
extern krb5_principal master_princ;
-extern krb5_encrypt_block master_encblock;
krb5_db_entry master_entry;
-krb5_pointer master_random;
int valid_master_key = 0;
int close_policy_db = 0;
int dump_v4db(int, char **);
int load_v4db(int, char **);
int open_db_and_mkey();
+int add_random_key(int, char **);
typedef int (*cmd_func)(int, char **);
"load", load_db, 0,
"dump_v4", dump_v4db, 1,
"load_v4", load_v4db, 0,
+ "ark", add_random_key, 1,
NULL, NULL, 0,
};
(void) umask(077);
master_keyblock.enctype = global_params.enctype;
- if (master_keyblock.enctype != ENCTYPE_UNKNOWN) {
- if (!valid_enctype(master_keyblock.enctype)) {
- char tmp[32];
- if (krb5_enctype_to_string(master_keyblock.enctype,
- tmp, sizeof(tmp)))
- com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP,
- "while setting up enctype %d", master_keyblock.enctype);
- else
- com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP, tmp);
- exit(1);
- }
- krb5_use_enctype(util_context, &master_encblock,
- master_keyblock.enctype);
+ if ((master_keyblock.enctype != ENCTYPE_UNKNOWN) &&
+ (!valid_enctype(master_keyblock.enctype))) {
+ com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d", master_keyblock.enctype);
}
cmd = cmd_lookup(cmd_argv[0]);
return;
}
if (valid_master_key) {
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock,
- &master_random);
- krb5_free_keyblock_contents(util_context, &master_keyblock);
- master_keyblock.contents = NULL;
- valid_master_key = 0;
+ krb5_free_keyblock_contents(util_context, &master_keyblock);
+ master_keyblock.contents = NULL;
+ valid_master_key = 0;
}
krb5_free_principal(util_context, master_princ);
dbactive = FALSE;
krb5_error_code retval;
int nentries;
krb5_boolean more;
- krb5_data scratch, pwd;
+ krb5_data scratch, pwd, seed;
dbactive = FALSE;
valid_master_key = 0;
/* If no encryption type is set, use the default */
if (master_keyblock.enctype == ENCTYPE_UNKNOWN) {
- master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
- if (!valid_enctype(master_keyblock.enctype)) {
- char tmp[32];
- if (krb5_enctype_to_string(master_keyblock.enctype,
- tmp, sizeof(tmp)))
- com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
- "while setting up enctype %d", master_keyblock.enctype);
- else
- com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP, tmp);
- exit(1);
- }
- krb5_use_enctype(util_context, &master_encblock,
- master_keyblock.enctype);
+ master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+ if (!valid_enctype(master_keyblock.enctype))
+ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
+ "while setting up enctype %d",
+ master_keyblock.enctype);
}
- retval = krb5_string_to_key(util_context, &master_encblock,
- &master_keyblock, &pwd, &scratch);
+ retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,
+ &pwd, &scratch, &master_keyblock);
if (retval) {
com_err(progname, retval,
"while transforming master key from password");
free(scratch.data);
mkey_password = 0;
} else if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
- &master_encblock, manual_mkey,
- FALSE, global_params.stash_file,
+ master_keyblock.enctype,
+ manual_mkey, FALSE,
+ global_params.stash_file,
0, &master_keyblock))) {
com_err(progname, retval, "while reading master key");
com_err(progname, 0, "Warning: proceeding without master key");
return(0);
}
if ((retval = krb5_db_verify_master_key(util_context, master_princ,
- &master_keyblock,&master_encblock))
- ) {
+ &master_keyblock))) {
com_err(progname, retval, "while verifying master key");
exit_status++;
krb5_free_keyblock_contents(util_context, &master_keyblock);
return(1);
}
- if ((retval = krb5_process_key(util_context, &master_encblock,
- &master_keyblock))) {
- com_err(progname, retval, "while processing master key");
- exit_status++;
- memset((char *)master_keyblock.contents, 0, master_keyblock.length);
- krb5_free_keyblock_contents(util_context, &master_keyblock);
- return(1);
- }
- if ((retval = krb5_init_random_key(util_context, &master_encblock,
- &master_keyblock,
- &master_random))) {
- com_err(progname, retval, "while initializing random key generator");
+
+ seed.length = master_keyblock.length;
+ seed.data = master_keyblock.contents;
+
+ if ((retval = krb5_c_random_seed(util_context, &seed))) {
+ com_err(progname, retval, "while seeding random number generator");
exit_status++;
- (void) krb5_finish_key(util_context, &master_encblock);
memset((char *)master_keyblock.contents, 0, master_keyblock.length);
krb5_free_keyblock_contents(util_context, &master_keyblock);
return(1);
if (finished)
return 0;
- if (valid_master_key) {
- (void) krb5_finish_key(util_context, &master_encblock);
- (void) krb5_finish_random_key(util_context, &master_encblock,
- &master_random);
- }
retval = krb5_db_fini(util_context);
memset((char *)master_keyblock.contents, 0, master_keyblock.length);
finished = TRUE;
}
return 0;
}
+
+int
+add_random_key(argc, argv)
+ int argc;
+ char **argv;
+{
+ krb5_error_code ret;
+ krb5_principal princ;
+ krb5_db_entry dbent;
+ int n, i;
+ krb5_boolean more;
+ krb5_timestamp now;
+
+ krb5_key_salt_tuple *keysalts = NULL;
+ krb5_int32 num_keysalts = 0;
+
+ int free_keysalts;
+ char *me = argv[0];
+ char *ks_str = NULL;
+ char *pr_str;
+
+ if (argc < 2)
+ usage();
+ for (argv++, argc--; *argv; argv++, argc--) {
+ if (!strcmp(*argv, "-e")) {
+ argv++; argc--;
+ ks_str = *argv;
+ continue;
+ } else
+ break;
+ }
+ if (argc < 1)
+ usage();
+ pr_str = *argv;
+ ret = krb5_parse_name(util_context, pr_str, &princ);
+ if (ret) {
+ com_err(me, ret, "while parsing principal name %s", pr_str);
+ return 1;
+ }
+ n = 1;
+ ret = krb5_db_get_principal(util_context, princ, &dbent,
+ &n, &more);
+ if (ret) {
+ com_err(me, ret, "while fetching principal %s", pr_str);
+ return 1;
+ }
+ if (n != 1) {
+ fprintf(stderr, "principal %s not found\n", pr_str);
+ return 1;
+ }
+ if (more) {
+ fprintf(stderr, "principal %s not unique\n", pr_str);
+ krb5_dbe_free_contents(util_context, &dbent);
+ return 1;
+ }
+ ret = krb5_string_to_keysalts(ks_str,
+ ", \t", ":.-", 0,
+ &keysalts,
+ &num_keysalts);
+ if (ret) {
+ com_err(me, ret, "while parsing keysalts %s", ks_str);
+ return 1;
+ }
+ if (!num_keysalts || keysalts == NULL) {
+ num_keysalts = global_params.num_keysalts;
+ keysalts = global_params.keysalts;
+ free_keysalts = 0;
+ } else
+ free_keysalts = 1;
+ ret = krb5_dbe_ark(util_context, &master_keyblock,
+ keysalts, num_keysalts,
+ &dbent);
+ if (free_keysalts)
+ free(keysalts);
+ if (ret) {
+ com_err(me, ret, "while randomizing principal %s", pr_str);
+ krb5_dbe_free_contents(util_context, &dbent);
+ return 1;
+ }
+ dbent.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+ ret = krb5_timeofday(util_context, &now);
+ if (ret) {
+ com_err(me, ret, "while getting time");
+ krb5_dbe_free_contents(util_context, &dbent);
+ return 1;
+ }
+ ret = krb5_dbe_update_last_pwd_change(util_context, &dbent, now);
+ if (ret) {
+ com_err(me, ret, "while setting changetime");
+ krb5_dbe_free_contents(util_context, &dbent);
+ return 1;
+ }
+ ret = krb5_db_put_principal(util_context, &dbent, &n);
+ krb5_dbe_free_contents(util_context, &dbent);
+ if (ret) {
+ com_err(me, ret, "while saving principal %s", pr_str);
+ return 1;
+ }
+ printf("%s changed\n", pr_str);
+ return 0;
+}
* entries from a V4 database.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifdef KRB5_KRB4_COMPAT
#include <des.h>
krb5_deltat max_rlife;
krb5_timestamp expiration;
krb5_flags flags;
- krb5_encrypt_block *eblock;
- krb5_pointer rseed;
+ krb5_keyblock *key;
};
static struct realm_info rblock = { /* XXX */
static krb5_keyblock master_keyblock;
static krb5_principal master_princ;
-static krb5_encrypt_block master_encblock;
static krb5_data tgt_princ_entries[] = {
{0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
extern kadm5_config_params global_params;
long exp_time = 0;
krb5_int32 crflags = KRB5_KDB_CREATE_BTREE;
+ krb5_data seed;
retval = krb5_init_context(&context);
if (retval) {
return;
}
- krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
-
/* If the user has not requested locking, don't modify an existing database. */
if (! tempdb) {
retval = krb5_db_set_name(context, dbname);
fflush(stdout);
}
- if (retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
+ if (retval = krb5_db_fetch_mkey(context, master_princ,
+ master_keyblock.enctype,
read_mkey, read_mkey, stash_file, 0,
&master_keyblock)) {
com_err(PROGNAME, retval, "while reading master key");
krb5_free_context(context);
return;
}
- if (retval = krb5_process_key(context, &master_encblock, &master_keyblock)) {
- com_err(PROGNAME, retval, "while processing master key");
- krb5_free_context(context);
- return;
- }
- rblock.eblock = &master_encblock;
- if (retval = krb5_init_random_key(context, &master_encblock,
- &master_keyblock, &rblock.rseed)) {
+ rblock.key = &master_keyblock;
+
+ seed.length = master_keyblock.length;
+ seed.data = master_keyblock.contents;
+
+ if (retval = krb5_c_random_seed(context, &seed)) {
com_err(PROGNAME, retval, "while initializing random key generator");
- (void) krb5_finish_key(context, &master_encblock);
krb5_free_context(context);
return;
}
if (retval = krb5_db_create(context, tempdbname, crflags)) {
- (void) krb5_finish_key(context, &master_encblock);
- (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
- (void) krb5_db_destroy(context, tempdbname);
com_err(PROGNAME, retval, "while creating %sdatabase '%s'",
tempdb ? "temporary " : "", tempdbname);
krb5_free_context(context);
return;
}
if (retval = krb5_db_set_name(context, tempdbname)) {
- (void) krb5_finish_key(context, &master_encblock);
- (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
(void) krb5_db_destroy(context, tempdbname);
com_err(PROGNAME, retval, "while setting active database to '%s'",
tempdbname);
return;
}
if (v4init(PROGNAME, v4manual, v4dumpfile)) {
- (void) krb5_finish_key(context, &master_encblock);
- (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
(void) krb5_db_destroy(context, tempdbname);
krb5_free_context(context);
return;
}
if ((retval = krb5_db_init(context)) ||
(retval = krb5_db_open_database(context))) {
- (void) krb5_finish_key(context, &master_encblock);
- (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
(void) krb5_db_destroy(context, tempdbname);
com_err(PROGNAME, retval, "while initializing the database '%s'",
tempdbname);
if (retval = add_principal(context, master_princ, MASTER_KEY, &rblock)) {
(void) krb5_db_fini(context);
- (void) krb5_finish_key(context, &master_encblock);
- (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
(void) krb5_db_destroy(context, tempdbname);
com_err(PROGNAME, retval, "while adding K/M to the database");
krb5_free_context(context);
if (create_local_tgt &&
(retval = add_principal(context, &tgt_princ, RANDOM_KEY, &rblock))) {
(void) krb5_db_fini(context);
- (void) krb5_finish_key(context, &master_encblock);
- (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
(void) krb5_db_destroy(context, tempdbname);
com_err(PROGNAME, retval, "while adding TGT service to the database");
krb5_free_context(context);
if (tempdb)
(void) krb5_db_destroy (context, tempdbname);
}
- (void) krb5_finish_key(context, &master_encblock);
- (void) krb5_finish_random_key(context, &master_encblock, &rblock.rseed);
memset((char *)master_keyblock.contents, 0, master_keyblock.length);
/*
keysalt.type = KRB5_KDB_SALTTYPE_V4;
keysalt.data.length = 0;
keysalt.data.data = (char *) NULL;
- retval = krb5_dbekd_encrypt_key_data(context, rblock.eblock,
+ retval = krb5_dbekd_encrypt_key_data(context, rblock.key,
&v4v5key, &keysalt,
princ->key_version,
&entry.key_data[0]);
{
krb5_db_entry entry;
krb5_error_code retval;
- krb5_keyblock *rkey;
+ krb5_keyblock rkey;
int nentries = 1;
krb5_timestamp mod_time;
krb5_principal mod_princ;
switch (op) {
case MASTER_KEY:
entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
- if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
+ if (retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
&master_keyblock,
(krb5_keysalt *) NULL, 1,
&entry.key_data[0])) {
}
break;
case RANDOM_KEY:
- if (retval = krb5_random_key(context, pblock->eblock, pblock->rseed,
- &rkey)) {
+ if (retval = krb5_c_make_random_key(context, pblock->key->enctype,
+ &rkey)) {
krb5_db_free_principal(context, &entry, 1);
return retval;
}
- if (retval = krb5_dbekd_encrypt_key_data(context, pblock->eblock,
- rkey,
+ if (retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
+ &rkey,
(krb5_keysalt *) NULL, 1,
&entry.key_data[0])) {
krb5_db_free_principal(context, &entry, 1);
return(retval);
}
- krb5_free_keyblock(context, rkey);
+ krb5_free_keyblock_contents(context, &rkey);
break;
case NULL_KEY:
return EOPNOTSUPP;
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * ovsec_kadmd.c: add calls to a new function
+ _svcauth_gssapi_unset_names() to clean up memory when shutting
+ down. Use krb5_overridekeyname instead of krb5_defkeyname, so the
+ command line takes precedence over the environment.
+
Wed Jul 22 00:28:57 1998 Geoffrey King <gjking@mit.edu>
* ovsec_kadmd.c (main): Cast gss_nt_krb5_name to
*
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include <stdio.h>
#include <signal.h>
#include <syslog.h>
* it also restricts us to linking against the Kv5 GSS-API library.
* Since this is *k*admind, that shouldn't be a problem.
*/
-extern char *krb5_defkeyname;
+extern char *krb5_overridekeyname;
char *build_princ_name(char *name, char *realm);
void log_badauth(OM_uint32 major, OM_uint32 minor,
htons(addr.sin_port));
}
kadm5_destroy(global_server_handle);
- krb5_klog_close();
+ krb5_klog_close();
exit(1);
}
memset(&addr, 0, sizeof(addr));
exit(1);
}
- /* XXX krb5_defkeyname is an internal library global and should
- go away */
- krb5_defkeyname = params.admin_keytab;
+ /* XXX krb5_overridekeyname is an internal library global and should
+ go away. This is an awful hack. */
+
+ krb5_overridekeyname = params.admin_keytab;
/*
* Try to acquire creds for the old OV services as well as the
"failing.");
fprintf(stderr, "%s: Cannot set GSS-API authentication names.\n",
whoami);
+ _svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close();
exit(1);
error_message(ret));
fprintf(stderr, "%s: Cannot initialize acl file: %s\n",
whoami, error_message(ret));
+ _svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close();
exit(1);
krb5_klog_syslog(LOG_ERR, "Cannot detach from tty: %s", error_message(ret));
fprintf(stderr, "%s: Cannot detach from tty: %s\n",
whoami, error_message(ret));
+ _svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close();
exit(1);
krb5_klog_syslog(LOG_INFO, "finished, exiting");
/* Clean up memory, etc */
+ _svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
close(s);
acl_finish(context, 0);
error_message(errno));
fprintf(stderr, "Cannot create connecting socket: %s",
error_message(errno));
+ _svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close();
exit(1);
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * admin_server.c, kadm_funcs.c, kadm_ser_wrap.c, kadm_server.h:
+ convert to new crypto api
+
+Fri Jul 31 18:17:16 1998 Tom Yu <tlyu@mit.edu>
+
+ * kadm_ser_wrap.c (kadm_ser_init): Remove references to
+ master_encblock, as it's no longer needed in the new crypto API,
+ adjusting kdb calls accordingly. Also punt calls to use_enctype,
+ process_key, etc.
+
+ * admin_server.c (clear_secrets): Remove references to
+ master_encblock, due to new crypto API.
+
Mon Jul 20 11:20:32 1998 Ezra Peisach <epeisach@mit.edu>
* acl_files.c: Include stdlib.h if present.
hv = hashval(el) % h->size;
while(h->tbl[hv] != NULL && strcmp(h->tbl[hv], el)) hv = (hv+1) % h->size;
- s = malloc(strlen(el)+1);
+ s = (char *) malloc(strlen(el)+1);
strcpy(s, el);
h->tbl[hv] = s;
h->entries++;
static void clear_secrets()
{
- krb5_finish_key(kadm_context, &server_parm.master_encblock);
- memset((char *)&server_parm.master_encblock, 0,
- sizeof (server_parm.master_encblock));
memset((char *)server_parm.master_keyblock.contents, 0,
server_parm.master_keyblock.length);
server_parm.mkvno = 0L;
}
status = krb5_dbekd_decrypt_key_data(kadm_context,
- &server_parm.master_encblock,
+ &server_parm.master_keyblock,
kdatap,
&cpw_skey,
(krb5_keysalt *) NULL);
sblock.data.length = 0;
sblock.data.data = (char *) NULL;
retval = krb5_dbekd_encrypt_key_data(kadm_context,
+ /* XXX but I'm ifdef'd out here,
+ so I can't really test this. */
&server_parm.master_encblock,
&localpw,
&sblock,
/* setting up the database */
mkey_name = KRB5_KDB_M_NAME;
-#ifdef KADM5
server_parm.master_keyblock.enctype = params->enctype;
- krb5_use_enctype(kadm_context, &server_parm.master_encblock,
- server_parm.master_keyblock.enctype);
-#else
- if (inter == 1) {
- server_parm.master_keyblock.enctype = ENCTYPE_DES_CBC_MD5;
- krb5_use_enctype(kadm_context, &server_parm.master_encblock,
- server_parm.master_keyblock.enctype);
- } else
- server_parm.master_keyblock.enctype = ENCTYPE_UNKNOWN;
-#endif
retval = krb5_db_setup_mkey_name(kadm_context, mkey_name, realm,
(char **) 0,
if (retval)
return KADM_NO_MAST;
krb5_db_fetch_mkey(kadm_context, server_parm.master_princ,
- &server_parm.master_encblock,
+ server_parm.master_keyblock.enctype,
(inter == 1), FALSE,
-#ifdef KADM5
params->stash_file,
-#else
- (char *) NULL,
-#endif
NULL,
&server_parm.master_keyblock);
if (retval)
return KADM_NO_MAST;
retval = krb5_db_verify_master_key(kadm_context, server_parm.master_princ,
- &server_parm.master_keyblock,
- &server_parm.master_encblock);
- if (retval)
- return KADM_NO_VERI;
- retval = krb5_process_key(kadm_context, &server_parm.master_encblock,
- &server_parm.master_keyblock);
+ &server_parm.master_keyblock);
if (retval)
return KADM_NO_VERI;
retval = krb5_db_get_principal(kadm_context, server_parm.master_princ,
char sinst[INST_SZ];
char krbrlm[REALM_SZ];
krb5_principal sprinc;
- krb5_encrypt_block master_encblock;
krb5_principal master_princ;
krb5_keyblock master_keyblock;
krb5_deltat max_life;
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * do_as_req.c, do_tgs_req.c, extern.h, kdc_preauth.c, kdc_util.c,
+ kerberos_v4.c, main.c: conver to new crypto api.
+
+Fri Sep 25 19:47:26 1998 Tom Yu <tlyu@mit.edu>
+
+ * kerberos_v4.c (check_princ): Re-order if statements that check
+ for null keys to make Purify shut up.
+
+Thu Sep 17 18:21:51 1998 Tom Yu <tlyu@mit.edu>
+
+ * kdc_util.c (kdc_get_server_key): Fix to not use cached tgs key
+ to prevent lossage when it might be out of date by always fetching
+ the correct kvno for the ticket out of the database.
+
+Tue Sep 1 19:34:30 1998 Tom Yu <tlyu@mit.edu>
+
+ * kerberos_v4.c (compat_decrypt_key): Add
+ ENCTYPE_LOCAL_DES3_HMAC_SHA1 to the list of keytypes to bash.
+ (kerb_get_principal): Add ENCTYPE_LOCAL_DES3_HMAC_SHA1 to the list
+ of searched enctypes.
+
+Wed Aug 19 13:37:00 1998 Tom Yu <tlyu@mit.edu>
+
+ * kerberos_v4.c (set_tgtkey): Add kvno arg to fetch an explicit
+ kvno. Also compare kvno as well as realm when caching the TGT
+ key. Declare as static.
+ (kerb_get_principal): Add kvno argument to permit searching for
+ an explicit kvno.
+ (kerberos_v4): Extract the kvno directly out of the krb_req, since
+ we know what the format is.
+
+Wed Aug 12 18:40:08 1998 Tom Yu <tlyu@mit.edu>
+
+ * kerberos_v4.c: Add macro K4KDC_ENCTYPE_OK to determine whether a
+ given enctype is compatible with single-DES krb4.
+ (compat_decrypt_key): Declare as static. Change call signature to
+ include an output krb5_keyblock as well as an input to determine
+ whether the principal should be treated as a service principal.
+ Bash the enctype of the keyblock to raw des3 if it's full-blown
+ des3.
+ (kerb_get_principal): Add k5key and issrv arguments as in
+ compat_decrypt_key, mostly to pass them on there. Hardcode a
+ search order that includes des3 for looking up service keys.
+ (kerberos_v4): Call krb_create_ticket or krb_cr_tkt_krb5 as
+ appropriate to the key type. While we're at it, s/ktbtgt/krbtgt/
+ just to avoid confusing people.
+ (check_princ): Add k5key and issrv args for as in
+ compat_decrypt_key. Fix up null key detection to only operate if
+ it's a single-des key.
+ (set_tgtkey): Call krb_set_key_krb5 if appropriate.
+
Tue Jul 21 20:29:38 1998 Tom Yu <tlyu@mit.edu>
* replay.c (kdc_check_lookaside):
int c_nprincs = 0, s_nprincs = 0;
krb5_boolean more;
krb5_timestamp kdc_time, authtime;
- krb5_keyblock *session_key = 0;
+ krb5_keyblock session_key;
krb5_keyblock encrypting_key;
const char *status;
- krb5_encrypt_block eblock;
krb5_key_data *server_key, *client_key;
krb5_enctype useenctype;
#ifdef KRBCONF_KDC_MODIFIES_KDB
ticket_reply.enc_part.ciphertext.data = 0;
e_data.data = 0;
encrypting_key.contents = 0;
+ session_key.contents = 0;
#ifdef HAVE_NETINET_IN_H
if (from->address->addrtype == ADDRTYPE_INET)
errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
goto errout;
}
- krb5_use_enctype(kdc_context, &eblock, useenctype);
-
- if ((errcode = krb5_random_key(kdc_context, &eblock,
- krb5_enctype_array[useenctype]->random_sequence,
- &session_key))) {
- /* random key failed */
+
+ if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
+ &session_key))) {
status = "RANDOM_KEY_FAILED";
goto errout;
}
if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
- enc_tkt_reply.session = session_key;
+ enc_tkt_reply.session = &session_key;
enc_tkt_reply.client = request->client;
enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
/* convert server.key into a real key (it may be encrypted
in the database) */
- if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock,
+ if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock,
server_key, &encrypting_key,
NULL))) {
status = "DECRYPT_SERVER_KEY";
}
/* convert client.key_data into a real key */
- if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock,
+ if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock,
client_key, &encrypting_key,
NULL))) {
status = "DECRYPT_CLIENT_KEY";
reply.padata = 0;
reply.client = request->client;
reply.ticket = &ticket_reply;
- reply_encpart.session = session_key;
+ reply_encpart.session = &session_key;
if ((errcode = fetch_last_req_info(&client, &reply_encpart.last_req))) {
status = "FETCH_LAST_REQ";
goto errout;
reply.enc_part.enctype = encrypting_key.enctype;
errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart,
- &encrypting_key, &reply, response);
+ 0, &encrypting_key, &reply, response);
krb5_free_keyblock_contents(kdc_context, &encrypting_key);
encrypting_key.contents = 0;
}
if (s_nprincs)
krb5_db_free_principal(kdc_context, &server, s_nprincs);
- if (session_key)
- krb5_free_keyblock(kdc_context, session_key);
+ if (session_key.contents)
+ krb5_free_keyblock_contents(kdc_context, &session_key);
if (ticket_reply.enc_part.ciphertext.data) {
memset(ticket_reply.enc_part.ciphertext.data , 0,
ticket_reply.enc_part.ciphertext.length);
krb5_data **response; /* filled in with a response packet */
{
krb5_keyblock * subkey;
- krb5_encrypt_block eblock;
krb5_kdc_req *request = 0;
krb5_db_entry server;
krb5_kdc_rep reply;
int nprincs = 0;
krb5_boolean more;
krb5_timestamp kdc_time, authtime=0;
- krb5_keyblock *session_key = 0;
+ krb5_keyblock session_key;
krb5_timestamp until, rtime;
krb5_keyblock encrypting_key;
krb5_key_data *server_key;
register int i;
int firstpass = 1;
const char *status = 0;
+
+ session_key.contents = 0;
retval = decode_krb5_tgs_req(pkt, &request);
if (retval)
goto cleanup;
}
- krb5_use_enctype(kdc_context, &eblock, useenctype);
- errcode = krb5_random_key(kdc_context, &eblock,
- krb5_enctype_array[useenctype]->random_sequence,
- &session_key);
+ errcode = krb5_c_make_random_key(kdc_context, useenctype, &session_key);
+
if (errcode) {
/* random key failed */
status = "RANDOM_KEY_FAILED";
/* assemble any authorization data */
if (request->authorization_data.ciphertext.data) {
- krb5_encrypt_block eblock;
krb5_data scratch;
- /* decrypt the authdata in the request */
- if (!valid_enctype(request->authorization_data.enctype)) {
- status = "BAD_AUTH_ETYPE";
- errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
- goto cleanup;
- }
- /* put together an eblock for this encryption */
-
- krb5_use_enctype(kdc_context, &eblock,
- request->authorization_data.enctype);
-
scratch.length = request->authorization_data.ciphertext.length;
if (!(scratch.data =
malloc(request->authorization_data.ciphertext.length))) {
errcode = ENOMEM;
goto cleanup;
}
- /* do any necessary key pre-processing */
- if ((errcode = krb5_process_key(kdc_context, &eblock,
- header_ticket->enc_part2->session))) {
- status = "AUTH_PROCESS_KEY";
- free(scratch.data);
- goto cleanup;
- }
- /* call the encryption routine */
- if ((errcode = krb5_decrypt(kdc_context, (krb5_pointer) request->authorization_data.ciphertext.data,
- (krb5_pointer) scratch.data,
- scratch.length, &eblock, 0))) {
+ if ((errcode = krb5_c_decrypt(kdc_context,
+ header_ticket->enc_part2->session,
+ KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
+ 0, &request->authorization_data,
+ &scratch))) {
status = "AUTH_ENCRYPT_FAIL";
- (void) krb5_finish_key(kdc_context, &eblock);
- free(scratch.data);
- goto cleanup;
- }
- if ((errcode = krb5_finish_key(kdc_context, &eblock))) {
- status = "AUTH_FINISH_KEY";
free(scratch.data);
goto cleanup;
}
+
/* scratch now has the authorization data, so we decode it */
errcode = decode_krb5_authdata(&scratch, &(request->unenc_authdata));
free(scratch.data);
enc_tkt_reply.authorization_data =
header_ticket->enc_part2->authorization_data;
- enc_tkt_reply.session = session_key;
+ enc_tkt_reply.session = &session_key;
enc_tkt_reply.client = header_ticket->enc_part2->client;
enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
/* convert server.key into a real key (it may be encrypted
* in the database) */
if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context,
- &master_encblock,
+ &master_keyblock,
server_key, &encrypting_key,
NULL))) {
status = "DECRYPT_SERVER_KEY";
if ((encrypting_key.enctype == ENCTYPE_DES_CBC_CRC) &&
(isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5)))
encrypting_key.enctype = ENCTYPE_DES_CBC_MD5;
- ticket_reply.enc_part.kvno = server_key->key_data_kvno;
errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key,
&ticket_reply);
krb5_free_keyblock_contents(kdc_context, &encrypting_key);
status = "TKT_ENCRYPT";
goto cleanup;
}
+ ticket_reply.enc_part.kvno = server_key->key_data_kvno;
}
/* Start assembling the response */
reply.enc_part.kvno = 0; /* We are using the session key */
reply.ticket = &ticket_reply;
- reply_encpart.session = session_key;
+ reply_encpart.session = &session_key;
reply_encpart.nonce = request->nonce;
/* copy the time fields EXCEPT for authtime; its location
reply.enc_part.enctype = subkey ? subkey->enctype :
header_ticket->enc_part2->session->enctype;
errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart,
+ subkey ? 1 : 0,
subkey ? subkey :
header_ticket->enc_part2->session,
&reply, response);
free(sname);
if (nprincs)
krb5_db_free_principal(kdc_context, &server, 1);
- if (session_key)
- krb5_free_keyblock(kdc_context, session_key);
+ if (session_key.contents)
+ krb5_free_keyblock_contents(kdc_context, &session_key);
if (newtransited)
free(enc_tkt_reply.transited.tr_contents.data);
/*
* Other per-realm data.
*/
- krb5_encrypt_block realm_encblock; /* Per-realm master encryption block*/
char *realm_ports; /* Per-realm KDC port */
/*
* Per-realm parameters.
#define kdc_context kdc_active_realm->realm_context
#define max_life_for_realm kdc_active_realm->realm_maxlife
#define max_renewable_life_for_realm kdc_active_realm->realm_maxrlife
-#define master_encblock kdc_active_realm->realm_encblock
#define master_keyblock kdc_active_realm->realm_mkey
#define master_princ kdc_active_realm->realm_mprinc
#define tgs_key kdc_active_realm->realm_tgskey
* Preauthentication routines for the KDC.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "kdc_util.h"
#include "extern.h"
krb5_int32 start;
krb5_timestamp timenow;
- enc_ts_data.data = 0;
scratch.data = pa->contents;
scratch.length = pa->length;
+
+ enc_ts_data.data = 0;
if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0)
goto cleanup;
+ enc_ts_data.length = enc_data->ciphertext.length;
+ if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL)
+ goto cleanup;
+
start = 0;
while (1) {
if ((retval = krb5_dbe_search_enctype(context, client,
-1, 0, &client_key)))
goto cleanup;
- if ((retval = krb5_dbekd_decrypt_key_data(context, &master_encblock,
+ if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
client_key, &key, NULL)))
goto cleanup;
+
key.enctype = enc_data->enctype;
- retval = krb5_decrypt_data(context, &key, 0, enc_data, &enc_ts_data);
+ retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
+ 0, enc_data, &enc_ts_data);
krb5_free_keyblock_contents(context, &key);
if (retval == 0)
break;
goto cleanup;
pa_data->contents = scratch->data;
pa_data->length = scratch->length;
+ free(scratch);
retval = 0;
krb5_predicted_sam_response psr;
krb5_data * scratch;
int i = 0;
- krb5_encrypt_block eblock;
krb5_keyblock encrypting_key;
char response[9];
char inputblock[8];
break;
}
}
+
+ krb5_princ_component(kdc_context,newp,probeslot)->data = 0;
+ krb5_princ_component(kdc_context,newp,probeslot)->length = 0;
+ krb5_princ_size(context, newp)--;
+
+ krb5_free_principal(kdc_context, newp);
+
/* if sc.sam_type is set, it worked */
if (sc.sam_type) {
/* so use assoc to get the key out! */
&assoc_key);
if (retval) {
char *sname;
- krb5_unparse_name(kdc_context, newp, &sname);
+ krb5_unparse_name(kdc_context, request->client, &sname);
com_err("krb5kdc", retval,
"snk4 finding the enctype and key <%s>", sname);
+ free(sname);
return retval;
}
/* convert server.key into a real key */
retval = krb5_dbekd_decrypt_key_data(kdc_context,
- &master_encblock,
+ &master_keyblock,
assoc_key, &encrypting_key,
NULL);
if (retval) {
}
/* now we can use encrypting_key... */
}
- } else
+ } else {
/* SAM is not an option - so don't return as hint */
return KRB5_PREAUTH_BAD_TYPE;
-
- krb5_princ_component(kdc_context,newp,probeslot)->data = 0;
- krb5_princ_component(kdc_context,newp,probeslot)->length = 0;
- krb5_princ_size(context, newp)--;
- krb5_free_principal(kdc_context, newp);
+ }
}
sc.magic = KV5M_SAM_CHALLENGE;
sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY;
/* eblock is just to set the enctype */
{
const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
- if (!valid_enctype(type)) return KRB5_PROG_ETYPE_NOSUPP;
- krb5_use_enctype(context, &eblock, type);
- retval = krb5_string_to_key(context, &eblock,
- &psr.sam_key, &sc.sam_challenge,
- 0 /* salt */);
- retval = encode_krb5_predicted_sam_response(&psr, &scratch);
- if (retval) goto cleanup;
+
+ if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge,
+ 0 /* salt */, &psr.sam_key)))
+ goto cleanup;
+
+ if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch)))
+ goto cleanup;
{
- krb5_enc_data tmpdata;
- retval = krb5_encrypt_data(context, master_encblock.key, 0,
- scratch, &tmpdata);
- sc.sam_track_id = tmpdata.ciphertext;
+ size_t enclen;
+ krb5_enc_data tmpdata;
+
+ if ((retval = krb5_c_encrypt_length(context,
+ master_keyblock.enctype,
+ scratch->length, &enclen)))
+ goto cleanup;
+
+ if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ tmpdata.ciphertext.length = enclen;
+
+ if ((retval = krb5_c_encrypt(context, &master_keyblock,
+ /* XXX */ 0, 0, scratch, &tmpdata)))
+ goto cleanup;
+
+ sc.sam_track_id = tmpdata.ciphertext;
}
- if (retval) goto cleanup;
}
sc.sam_response_prompt.data = "response prompt";
/* generate digit string, take it mod 1000000 (six digits.) */
{
int j;
- krb5_encrypt_block eblock;
- krb5_keyblock *session_key = 0;
+ krb5_keyblock session_key;
char outputblock[8];
int i;
+
+ session_key.contents = 0;
+
memset(inputblock, 0, 8);
- krb5_use_enctype(kdc_context, &eblock, ENCTYPE_DES_CBC_CRC);
- retval = krb5_random_key(kdc_context, &eblock,
- krb5_enctype_array[ENCTYPE_DES_CBC_CRC]->random_sequence,
- &session_key);
+
+ retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC,
+ &session_key);
+
if (retval) {
/* random key failed */
com_err("krb5kdc", retval,"generating random challenge for preauth");
}
/* now session_key has a key which we can pick bits out of */
/* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */
- if (session_key->length != 8) {
+ if (session_key.length != 8) {
com_err("krb5kdc", retval = KRB5KDC_ERR_ETYPE_NOSUPP,
"keytype didn't match code expectations");
return retval;
}
for(i = 0; i<6; i++) {
- inputblock[i] = '0' + ((session_key->contents[i]/2) % 10);
+ inputblock[i] = '0' + ((session_key.contents[i]/2) % 10);
}
- if (session_key)
- krb5_free_keyblock(kdc_context, session_key);
+ if (session_key.contents)
+ krb5_free_keyblock_contents(kdc_context, &session_key);
/* retval = krb5_finish_key(kdc_context, &eblock); */
/* now we have inputblock containing the 8 byte input to DES... */
sc.sam_challenge.data = inputblock;
sc.sam_challenge.length = 6;
- krb5_use_enctype(kdc_context, &eblock, ENCTYPE_DES_CBC_RAW);
encrypting_key.enctype = ENCTYPE_DES_CBC_RAW;
- /* do any necessary key pre-processing */
- retval= krb5_process_key(kdc_context, &eblock, &encrypting_key);
if (retval) {
com_err("krb5kdc", retval, "snk4 processing key");
}
{
- char ivec[8];
- memset(ivec,0,8);
- retval = krb5_encrypt(kdc_context, inputblock, outputblock, 8,
- &eblock, ivec);
- }
- if (retval) {
- com_err("krb5kdc", retval, "snk4 response generation failed");
- return retval;
+ krb5_data plain;
+ krb5_enc_data cipher;
+
+ plain.length = 8;
+ plain.data = inputblock;
+
+ /* XXX I know this is enough because of the fixed raw enctype.
+ if it's not, the underlying code will return a reasonable
+ error, which should never happen */
+ cipher.ciphertext.length = 8;
+ cipher.ciphertext.data = outputblock;
+
+ if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key,
+ /* XXX */ 0, 0, &plain, &cipher))) {
+ com_err("krb5kdc", retval, "snk4 response generation failed");
+ return retval;
+ }
}
+
/* now output block is the raw bits of the response; convert it
to display form */
for (j=0; j<4; j++) {
/* string2key on sc.sam_challenge goes in here */
/* eblock is just to set the enctype */
{
- const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
- if (!valid_enctype(type)) return KRB5_PROG_ETYPE_NOSUPP;
- krb5_use_enctype(context, &eblock, type);
- retval = krb5_string_to_key(context, &eblock,
- &psr.sam_key, &predict_response,
- 0 /* salt */);
+ retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
+ &predict_response, 0 /* salt */,
+ &psr.sam_key);
+ if (retval) goto cleanup;
+
retval = encode_krb5_predicted_sam_response(&psr, &scratch);
if (retval) goto cleanup;
{
- krb5_enc_data tmpdata;
- retval = krb5_encrypt_data(context, master_encblock.key, 0,
- scratch, &tmpdata);
- sc.sam_track_id = tmpdata.ciphertext;
+ size_t enclen;
+ krb5_enc_data tmpdata;
+
+ if ((retval = krb5_c_encrypt_length(context,
+ master_keyblock.enctype,
+ scratch->length, &enclen)))
+ goto cleanup;
+
+ if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ tmpdata.ciphertext.length = enclen;
+
+ if ((retval = krb5_c_encrypt(context, &master_keyblock,
+ /* XXX */ 0, 0, scratch, &tmpdata)))
+ goto cleanup;
+
+ sc.sam_track_id = tmpdata.ciphertext;
}
if (retval) goto cleanup;
}
scratch.data = pa->contents;
scratch.length = pa->length;
- retval = decode_krb5_sam_response(&scratch, &sr);
- if (retval) com_err("krb5kdc", retval, "decode_krb5_sam_response failed");
- if (retval) goto cleanup;
+ if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
+ scratch.data = 0;
+ com_err("krb5kdc", retval, "decode_krb5_sam_response failed");
+ goto cleanup;
+ }
{
krb5_enc_data tmpdata;
+
+ tmpdata.enctype = ENCTYPE_UNKNOWN;
tmpdata.ciphertext = sr->sam_track_id;
- retval = krb5_decrypt_data(context, master_encblock.key, 0,
- &tmpdata, &scratch);
- if (retval) com_err("krb5kdc", retval, "decrypt track_id failed");
+
+ scratch.length = tmpdata.ciphertext.length;
+ if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+
+ if ((retval = krb5_c_decrypt(context, &master_keyblock, /* XXX */ 0, 0,
+ &tmpdata, &scratch))) {
+ com_err("krb5kdc", retval, "decrypt track_id failed");
+ goto cleanup;
+ }
}
- if (retval) goto cleanup;
- retval = decode_krb5_predicted_sam_response(&scratch, &psr);
- if (retval) com_err("krb5kdc", retval, "decode_krb5_predicted_sam_response failed");
- if (retval) goto cleanup;
+
+ if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
+ com_err("krb5kdc", retval,
+ "decode_krb5_predicted_sam_response failed");
+ goto cleanup;
+ }
+
{
- /* now psr.sam_key is what we said to use... */
- retval = krb5_decrypt_data(context, &psr->sam_key, 0,
- &sr->sam_enc_nonce_or_ts, &scratch);
- if (retval) com_err("krb5kdc", retval, "decrypt nonce_or_ts failed");
+ free(scratch.data);
+ scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length;
+ if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+
+ if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0,
+ 0, &sr->sam_enc_nonce_or_ts, &scratch))) {
+ com_err("krb5kdc", retval, "decrypt nonce_or_ts failed");
+ goto cleanup;
+ }
+ }
+
+ if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) {
+ com_err("krb5kdc", retval, "decode_krb5_enc_sam_response_enc failed");
+ goto cleanup;
}
- if (retval) goto cleanup;
- retval = decode_krb5_enc_sam_response_enc(&scratch, &esre);
- if (retval) com_err("krb5kdc", retval, "decode_krb5_enc_sam_response_enc failed");
- if (retval) goto cleanup;
+
if (esre->sam_timestamp != sr->sam_patimestamp) {
retval = KRB5KDC_ERR_PREAUTH_FAILED;
goto cleanup;
}
- retval = krb5_timeofday(context, &timenow);
- if (retval) goto cleanup;
+
+ if ((retval = krb5_timeofday(context, &timenow)))
+ goto cleanup;
if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
retval = KRB5KRB_AP_ERR_SKEW;
}
setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
+
cleanup:
- if (retval) com_err("krb5kdc", retval, "sam verify failure");
+ if (retval)
+ com_err("krb5kdc", retval, "sam verify failure");
+ if (scratch.data) free(scratch.data);
if (sr) free(sr);
if (psr) free(psr);
if (esre) free(esre);
krb5_checksum * his_cksum;
{
krb5_error_code retval;
+ krb5_boolean valid;
if (!valid_cksumtype(his_cksum->checksum_type))
return KRB5KDC_ERR_SUMTYPE_NOSUPP;
return KRB5KRB_AP_ERR_INAPP_CKSUM;
/* verify checksum */
- if ((retval = krb5_verify_checksum(kcontext, his_cksum->checksum_type,
- his_cksum,
- source->data, source->length,
- ticket->enc_part2->session->contents,
- ticket->enc_part2->session->length))) {
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- return retval;
+ if ((retval = krb5_c_verify_checksum(kcontext, ticket->enc_part2->session,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
+ source, his_cksum, &valid)))
+ return(retval);
+
+ if (!valid)
+ return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
+
+ return(0);
}
krb5_error_code
/* XXX This function should no longer be necessary.
* The KDC should take the keytab associated with the realm and pass that to
* the krb5_rd_req_decode(). --proven
+ *
+ * It's actually still used by do_tgs_req() for u2u auth, and not too
+ * much else. -- tlyu
*/
krb5_error_code
kdc_get_server_key(ticket, key, kvno)
krb5_ticket * ticket;
krb5_keyblock ** key;
- krb5_kvno * kvno;
+ krb5_kvno * kvno; /* XXX nothing uses this */
{
krb5_error_code retval;
krb5_db_entry server;
krb5_key_data * server_key;
int i;
- if (krb5_principal_compare(kdc_context, tgs_server, ticket->server)) {
- retval = krb5_copy_keyblock(kdc_context, &tgs_key, key);
- *kvno = tgs_kvno;
- return retval;
- } else {
- nprincs = 1;
+ nprincs = 1;
- if ((retval = krb5_db_get_principal(kdc_context, ticket->server,
- &server, &nprincs,
- &more))) {
- return(retval);
- }
- if (more) {
- krb5_db_free_principal(kdc_context, &server, nprincs);
- return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
- } else if (nprincs != 1) {
- char *sname;
-
- krb5_db_free_principal(kdc_context, &server, nprincs);
- if (!krb5_unparse_name(kdc_context, ticket->server, &sname)) {
- krb5_klog_syslog(LOG_ERR,"TGS_REQ: UNKNOWN SERVER: server='%s'",
- sname);
- free(sname);
- }
- return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
- }
- /*
- * Get the latest version of the server key_data and
- * convert the key into a real key (it may be encrypted in the database)
- *
- * Search the key list in the order specified by the key/salt list.
- */
- server_key = (krb5_key_data *) NULL;
- for (i=0; i<kdc_active_realm->realm_nkstypes; i++) {
- krb5_key_salt_tuple *kslist;
-
- kslist = (krb5_key_salt_tuple *) kdc_active_realm->realm_kstypes;
- if (!krb5_dbe_find_enctype(kdc_context,
- &server,
- kslist[i].ks_enctype,
- -1,
- -1,
- &server_key))
- break;
- }
- if (!server_key)
- return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
-
- *kvno = server_key->key_data_kvno;
- if ((*key = (krb5_keyblock *)malloc(sizeof **key))) {
- retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock,
- server_key,
- *key, NULL);
- } else
- retval = ENOMEM;
+ if ((retval = krb5_db_get_principal(kdc_context, ticket->server,
+ &server, &nprincs,
+ &more))) {
+ return(retval);
+ }
+ if (more) {
krb5_db_free_principal(kdc_context, &server, nprincs);
- return retval;
+ return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
+ } else if (nprincs != 1) {
+ char *sname;
+
+ krb5_db_free_principal(kdc_context, &server, nprincs);
+ if (!krb5_unparse_name(kdc_context, ticket->server, &sname)) {
+ krb5_klog_syslog(LOG_ERR,"TGS_REQ: UNKNOWN SERVER: server='%s'",
+ sname);
+ free(sname);
+ }
+ return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
}
+ retval = krb5_dbe_find_enctype(kdc_context, &server,
+ ticket->enc_part.enctype, -1,
+ ticket->enc_part.kvno, &server_key);
+ if (retval)
+ goto errout;
+ if (!server_key) {
+ retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ goto errout;
+ }
+ *kvno = server_key->key_data_kvno;
+ if ((*key = (krb5_keyblock *)malloc(sizeof **key))) {
+ retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock,
+ server_key,
+ *key, NULL);
+ } else
+ retval = ENOMEM;
+errout:
+ krb5_db_free_principal(kdc_context, &server, nprincs);
+ return retval;
}
/* This probably wants to be updated if you support last_req stuff */
extern int errno;
-int compat_decrypt_key PROTOTYPE((krb5_key_data *, C_Block));
-int kerb_get_principal PROTOTYPE((char *, char *, Principal *, int,
- int *));
-int check_princ PROTOTYPE((char *, char *, unsigned, Principal *));
+static int compat_decrypt_key PROTOTYPE((krb5_key_data *, C_Block,
+ krb5_keyblock *, int));
+static int kerb_get_principal PROTOTYPE((char *, char *, Principal *, int,
+ int *, krb5_keyblock *, krb5_kvno, int));
+static int check_princ PROTOTYPE((char *, char *, unsigned, Principal *,
+ krb5_keyblock *, int));
#ifdef HAVE_STDARG_H
char * v4_klog KRB5_PROTOTYPE((int, const char *, ...));
void kerberos_v4 PROTOTYPE((struct sockaddr_in *, KTEXT));
void kerb_err_reply PROTOTYPE((struct sockaddr_in *, KTEXT, long, char *));
-int set_tgtkey PROTOTYPE((char *));
-
+static int set_tgtkey PROTOTYPE((char *, krb5_kvno));
+
/* Attributes converted from V5 to V4 - internal representation */
#define V4_KDB_REQUIRES_PREAUTH 0x1
#define V4_KDB_DISALLOW_ALL_TIX 0x2
}
#define kdb_encrypt_key( in, out, mk, mks, e_d_flag)
#define LONGLEN 4
+#define K4KDC_ENCTYPE_OK(e) \
+((e) == ENCTYPE_DES_CBC_CRC \
+ || (e) == ENCTYPE_DES_CBC_MD4 \
+ || (e) == ENCTYPE_DES_CBC_MD5 \
+ || (e) == ENCTYPE_DES_CBC_RAW)
/* take a v5 keyblock, masquerading as a v4 key,
* decrypt it, and convert the resulting v5 keyblock
* to a real v4 key.
* this is ugly, but it saves changing more v4 code.
+ *
+ * Also, keep old krb5_keyblock around in case we want to use it later.
*/
-int compat_decrypt_key (in5, out4)
- krb5_key_data *in5;
- C_Block out4;
+static int
+compat_decrypt_key (in5, out4, out5, issrv)
+ krb5_key_data *in5;
+ C_Block out4;
+ krb5_keyblock *out5;
+ int issrv; /* whether it's a server key */
{
- krb5_keyblock out5;
- int retval = -1;
+ krb5_error_code retval;
- out5.contents = NULL;
- if (krb5_dbekd_decrypt_key_data(kdc_context,&master_encblock,in5,&out5,NULL)){
+ out5->contents = NULL;
+ memset(out4, 0, sizeof(out4));
+ retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock,
+ in5, out5, NULL);
+ if (retval) {
lt = klog(L_DEATH_REQ, "KDC can't decrypt principal's key.");
+ out5->contents = NULL;
return(retval);
}
- if (out5.length != KRB5_MIT_DES_KEYSIZE)
- lt = klog(L_DEATH_REQ, "internal keysize error in kdc");
- else if ((out5.enctype != ENCTYPE_DES_CBC_CRC) &&
- (out5.enctype != ENCTYPE_DES_CBC_MD4) &&
- (out5.enctype != ENCTYPE_DES_CBC_MD5) &&
- (out5.enctype != ENCTYPE_DES_CBC_RAW))
- lt = klog(L_DEATH_REQ, "incompatible principal key type.");
- else {
- memcpy(out4, out5.contents, out5.length);
- retval = 0;
+ if (K4KDC_ENCTYPE_OK(out5->enctype)) {
+ if (out5->length == KRB5_MIT_DES_KEYSIZE)
+ memcpy(out4, out5->contents, out5->length);
+ else {
+ lt = klog(L_DEATH_REQ, "internal keysize error in kdc");
+ krb5_free_keyblock_contents(kdc_context, out5);
+ out5->contents = NULL;
+ retval = -1;
+ }
+ } else {
+ if (!issrv) {
+ lt = klog(L_DEATH_REQ, "incompatible principal key type.");
+ krb5_free_keyblock_contents(kdc_context, out5);
+ out5->contents = NULL;
+ retval = -1;
+ } else {
+ /* KLUDGE! If it's a non-raw des3 key, bash its enctype */
+ if (out5->enctype == ENCTYPE_DES3_HMAC_SHA1 ||
+ out5->enctype == ENCTYPE_LOCAL_DES3_HMAC_SHA1)
+ out5->enctype = ENCTYPE_DES3_CBC_RAW;
+ }
}
- krb5_free_keyblock_contents(kdc_context, &out5);
return(retval);
}
#define MIN5 300
#define HR21 255
-int
-kerb_get_principal(name, inst, principal, maxn, more)
+static int
+kerb_get_principal(name, inst, principal, maxn, more, k5key, kvno, issrv)
char *name; /* could have wild card */
char *inst; /* could have wild card */
Principal *principal;
int maxn; /* max number of name structs to return */
int *more; /* more tuples than room for */
+ krb5_keyblock *k5key;
+ krb5_kvno kvno;
+ int issrv; /* true if retrieving a service key */
{
/* Note that this structure should not be passed to the
krb5_free* functions, because the pointers within it point
return(nprinc);
}
- if (krb5_dbe_find_enctype(kdc_context,
- &entries,
- ENCTYPE_DES_CBC_CRC,
- KRB5_KDB_SALTTYPE_V4,
- -1,
- &pkey) &&
- krb5_dbe_find_enctype(kdc_context,
- &entries,
- ENCTYPE_DES_CBC_CRC,
- -1,
- -1,
- &pkey))
- {
- lt = klog(L_KRB_PERR, "KDC V4: principal %s.%s isn't V4 compatible",
- name, inst);
- krb5_db_free_principal(kdc_context, &entries, nprinc);
- return(0);
+ if (!issrv) {
+ if (krb5_dbe_find_enctype(kdc_context,
+ &entries,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ kvno,
+ &pkey) &&
+ krb5_dbe_find_enctype(kdc_context,
+ &entries,
+ ENCTYPE_DES_CBC_CRC,
+ -1,
+ kvno,
+ &pkey)) {
+ lt = klog(L_KRB_PERR,
+ "KDC V4: principal %s.%s isn't V4 compatible",
+ name, inst);
+ krb5_db_free_principal(kdc_context, &entries, nprinc);
+ return(0);
+ }
+ } else {
+ /* XXX yes I know this is a hardcoded search order */
+ if (krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES3_CBC_RAW,
+ -1, kvno, &pkey) &&
+ krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_LOCAL_DES3_HMAC_SHA1,
+ -1, kvno, &pkey) &&
+ krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES3_HMAC_SHA1,
+ -1, kvno, &pkey) &&
+ krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4, kvno, &pkey) &&
+ krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES_CBC_CRC,
+ -1, kvno, &pkey)) {
+ lt = klog(L_KRB_PERR,
+ "KDC V4: failed to find key for %s.%s",
+ name, inst);
+ krb5_db_free_principal(kdc_context, &entries, nprinc);
+ return(0);
+ }
}
- if (! compat_decrypt_key( pkey, k)) {
- memcpy( &principal->key_low, k, LONGLEN);
+ if (!compat_decrypt_key(pkey, k, k5key, issrv)) {
+ memcpy( &principal->key_low, k, LONGLEN);
memcpy( &principal->key_high, (krb5_ui_4 *) k + 1, LONGLEN);
}
/* convert v5's entries struct to v4's Principal struct:
Key_schedule key_s;
char *ptr;
+ krb5_keyblock k5key;
+ krb5_kvno kvno;
+
+ k5key.contents = NULL; /* in case we have to free it */
ciph->length = 0;
inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0);
if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
- &a_name_data))) {
+ &a_name_data, &k5key, 0))) {
kerb_err_reply(client, pkt, i, lt);
a_name_data.key_low = a_name_data.key_high = 0;
+ krb5_free_keyblock_contents(kdc_context, &k5key);
return;
}
+ /* don't use k5key for client */
+ krb5_free_keyblock_contents(kdc_context, &k5key);
tk->length = 0; /* init */
if (strcmp(service, "krbtgt"))
klog(L_NTGT_INTK,
req_inst_ptr, service, instance, 0);
/* this does all the checking */
if ((i = check_princ(service, instance, lifetime,
- &s_name_data))) {
+ &s_name_data, &k5key, 1))) {
kerb_err_reply(client, pkt, i, lt);
a_name_data.key_high = a_name_data.key_low = 0;
s_name_data.key_high = s_name_data.key_low = 0;
+ krb5_free_keyblock_contents(kdc_context, &k5key);
return;
}
/* Bound requested lifetime with service and user */
kdb_encrypt_key(key, key, master_key,
master_key_schedule, DECRYPT);
/* construct and seal the ticket */
- krb_create_ticket(tk, k_flags, a_name_data.name,
- a_name_data.instance, local_realm,
- client_host.s_addr, (char *) session_key, lifetime, kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance, key);
+ if (K4KDC_ENCTYPE_OK(k5key.enctype)) {
+ krb_create_ticket(tk, k_flags, a_name_data.name,
+ a_name_data.instance, local_realm,
+ client_host.s_addr, (char *) session_key,
+ lifetime, kerb_time.tv_sec,
+ s_name_data.name, s_name_data.instance,
+ key);
+ } else {
+ krb_cr_tkt_krb5(tk, k_flags, a_name_data.name,
+ a_name_data.instance, local_realm,
+ client_host.s_addr, (char *) session_key,
+ lifetime, kerb_time.tv_sec,
+ s_name_data.name, s_name_data.instance,
+ &k5key);
+ }
+ krb5_free_keyblock_contents(kdc_context, &k5key);
memset(key, 0, sizeof(key));
memset(key_s, 0, sizeof(key_s));
memcpy(auth->dat, pkt->dat, auth->length);
strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
- if (set_tgtkey(tktrlm)) {
+ kvno = (krb5_kvno)auth->dat[2];
+ if (set_tgtkey(tktrlm, kvno)) {
lt = klog(L_ERR_UNK,
- "FAILED realm %s unknown. Host: %s ",
- tktrlm, inet_ntoa(client_host));
+ "FAILED set_tgtkey realm %s, kvno %d. Host: %s ",
+ tktrlm, kvno, inet_ntoa(client_host));
kerb_err_reply(client, pkt, kerno, lt);
return;
}
- kerno = krb_rd_req(auth, "ktbtgt", tktrlm, client_host.s_addr,
+ kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
ad, 0);
if (kerno) {
return;
}
kerno = check_princ(service, instance, req_life,
- &s_name_data);
+ &s_name_data, &k5key, 1);
if (kerno) {
kerb_err_reply(client, pkt, kerno, lt);
+ s_name_data.key_high = s_name_data.key_low = 0;
+ krb5_free_keyblock_contents(kdc_context, &k5key);
return;
}
/* Bound requested lifetime with service and user */
return st;
}
-int check_princ(p_name, instance, lifetime, p)
+static int
+check_princ(p_name, instance, lifetime, p, k5key, issrv)
char *p_name;
char *instance;
unsigned lifetime;
Principal *p;
+ krb5_keyblock *k5key;
+ int issrv; /* whether this is a server key */
{
static int n;
static int more;
/* long trans; */
- n = kerb_get_principal(p_name, instance, p, 1, &more);
+ n = kerb_get_principal(p_name, instance, p, 1, &more, k5key, 0, issrv);
klog(L_ALL_REQ,
"Principal: \"%s\", Instance: \"%s\" Lifetime = %d n = %d",
p_name, instance, lifetime, n, 0);
}
/* If the user's key is null, we want to return an error */
- if ((p->key_low == 0) && (p->key_high == 0)) {
- /* User has a null key */
- lt = klog(L_ERR_NKY, "Null key \"%s\" \"%s\"", p_name,
- instance, 0);
- return KERB_ERR_NULL_KEY;
+ if (k5key->contents != NULL && K4KDC_ENCTYPE_OK(k5key->enctype)) {
+ if ((p->key_low == 0) && (p->key_high == 0)) {
+ /* User has a null key */
+ lt = klog(L_ERR_NKY, "Null key \"%s\" \"%s\"", p_name,
+ instance, 0);
+ return KERB_ERR_NULL_KEY;
+ }
}
/* make sure the service hasn't expired */
if (((u_long) p->exp_date != 0)&&
/* Set the key for krb_rd_req so we can check tgt */
-int set_tgtkey(r)
+static int
+set_tgtkey(r, kvno)
char *r; /* Realm for desired key */
+ krb5_kvno kvno;
{
int n;
static char lastrealm[REALM_SZ] = "";
+ static int last_kvno = 0;
Principal p_st;
Principal *p = &p_st;
C_Block key;
+ krb5_keyblock k5key;
- if (!strcmp(lastrealm, r))
+ k5key.contents = NULL;
+ if (!strcmp(lastrealm, r) && last_kvno == kvno)
return (KSUCCESS);
/* log("Getting key for %s", r); */
- n = kerb_get_principal("krbtgt", r, p, 1, &more);
+ n = kerb_get_principal("krbtgt", r, p, 1, &more, &k5key, kvno, 1);
if (n == 0)
return (KFAILURE);
- /* unseal tgt key from master key */
- memcpy(key, &p->key_low, 4);
- memcpy(((krb5_ui_4 *) key) + 1, &p->key_high, 4);
- kdb_encrypt_key(key, key, master_key,
- master_key_schedule, DECRYPT);
- krb_set_key((char *) key, 0);
- strcpy(lastrealm, r);
+ if (!K4KDC_ENCTYPE_OK(k5key.enctype)) {
+ krb_set_key_krb5(kdc_context, &k5key);
+ strcpy(lastrealm, r);
+ last_kvno = kvno;
+ } else {
+ /* unseal tgt key from master key */
+ memcpy(key, &p->key_low, 4);
+ memcpy(((krb5_ui_4 *) key) + 1, &p->key_high, 4);
+ kdb_encrypt_key(key, key, master_key,
+ master_key_schedule, DECRYPT);
+ krb_set_key((char *) key, 0);
+ strcpy(lastrealm, r);
+ last_kvno = kvno;
+ }
+ krb5_free_keyblock_contents(kdc_context, &k5key);
return (KSUCCESS);
}
memset(rdp->realm_tgskey.contents, 0, rdp->realm_tgskey.length);
free(rdp->realm_tgskey.contents);
}
- if (rdp->realm_encblock.crypto_entry)
- krb5_finish_key(rdp->realm_context, &rdp->realm_encblock);
krb5_db_fini(rdp->realm_context);
if (rdp->realm_tgsprinc)
krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
goto whoops;
}
- /* Select the specified encryption type */
- /* krb5_db_fetch_mkey will setup the encblock for stashed keys */
- if (manual)
- krb5_use_enctype(rdp->realm_context, &rdp->realm_encblock,
- rdp->realm_mkey.enctype);
-
/*
* Get the master key.
*/
if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
- &rdp->realm_encblock, manual,
+ rdp->realm_mkey.enctype, manual,
FALSE, rdp->realm_stash,
0, &rdp->realm_mkey))) {
com_err(progname, kret,
/* Verify the master key */
if ((kret = krb5_db_verify_master_key(rdp->realm_context,
rdp->realm_mprinc,
- &rdp->realm_mkey,
- &rdp->realm_encblock))) {
+ &rdp->realm_mkey))) {
com_err(progname, kret,
"while verifying master key for realm %s", realm);
goto whoops;
rdp->realm_mkvno = kdata->key_data_kvno;
krb5_db_free_principal(rdp->realm_context, &db_entry, num2get);
- /* Now preprocess the master key */
- if ((kret = krb5_process_key(rdp->realm_context,
- &rdp->realm_encblock,
- &rdp->realm_mkey))) {
- com_err(progname, kret,
- "while processing master key for realm %s", realm);
- goto whoops;
- }
-
- if ((kret = krb5_db_set_mkey(rdp->realm_context,
- &rdp->realm_encblock))) {
+ if ((kret = krb5_db_set_mkey(rdp->realm_context, &rdp->realm_mkey))) {
com_err(progname, kret,
"while setting master key for realm %s", realm);
goto whoops;
goto whoops;
}
if (!(kret = krb5_dbekd_decrypt_key_data(rdp->realm_context,
- &rdp->realm_encblock,
+ &rdp->realm_mkey,
kdata,
&rdp->realm_tgskey, NULL))){
rdp->realm_tgskvno = kdata->key_data_kvno;
}
if (!rkey_init_done) {
- krb5_enctype enctype;
- krb5_encrypt_block temp_eblock;
+ krb5_timestamp now;
+ krb5_data seed;
#ifdef KRB5_KRB4_COMPAT
- krb5_keyblock *temp_key;
+ krb5_keyblock temp_key;
#endif
/*
* If all that worked, then initialize the random key
* generators.
*/
- for (enctype = 0; enctype <= krb5_max_enctype; enctype++) {
- if (krb5_enctype_array[enctype] &&
- !krb5_enctype_array[enctype]->random_sequence) {
- krb5_use_enctype(rdp->realm_context, &temp_eblock, enctype);
- if ((kret = krb5_init_random_key(
- rdp->realm_context, &temp_eblock,
- &rdp->realm_mkey,
- &krb5_enctype_array[enctype]->random_sequence))) {
- com_err(progname, kret,
- "while setting up random key generator for enctype %d--enctype disabled",
- enctype);
- krb5_enctype_array[enctype] = 0;
- } else {
+
+ if ((kret = krb5_timeofday(rdp->realm_context, &now)))
+ goto whoops;
+ seed.length = sizeof(now);
+ seed.data = (char *) &now;
+ if ((kret = krb5_c_random_seed(rdp->realm_context, &seed)))
+ goto whoops;
+
+ seed.length = rdp->realm_mkey.length;
+ seed.data = rdp->realm_mkey.contents;
+
+ if ((kret = krb5_c_random_seed(rdp->realm_context, &seed)))
+ goto whoops;
+
#ifdef KRB5_KRB4_COMPAT
- if (enctype == ENCTYPE_DES_CBC_CRC) {
- if ((kret = krb5_random_key(
- rdp->realm_context, &temp_eblock,
- krb5_enctype_array[enctype]->random_sequence,
- &temp_key)))
- com_err(progname, kret,
- "while initializing V4 random key generator");
- else {
- (void) des_init_random_number_generator(temp_key->contents);
- krb5_free_keyblock(rdp->realm_context, temp_key);
- }
- }
-#endif
- }
- }
+ if ((kret = krb5_c_make_random_key(rdp->realm_context,
+ ENCTYPE_DES_CBC_CRC, &temp_key))) {
+ com_err(progname, kret,
+ "while initializing V4 random key generator");
+ goto whoops;
}
+
+ (void) des_init_random_number_generator(temp_key.contents);
+ krb5_free_keyblock_contents(rdp->realm_context, &temp_key);
+#endif
rkey_init_done = 1;
}
whoops:
+Tue Sep 1 19:35:44 1998 Tom Yu <tlyu@mit.edu>
+
+ * cnv_tkt_skey.c (krb524_convert_tkt_skey): Add
+ ENCTYPE_LOCAL_DES3_HMAC_SHA1 to the list of enctypes to bash.
+
+ * krb524d.c (do_connection): Add ENCTYPE_LOCAL_DES3_HMAC_SHA1 to
+ the list of enctypes to search.
+
+Wed Aug 19 13:40:28 1998 Tom Yu <tlyu@mit.edu>
+
+ * cnv_tkt_skey.c (krb524_convert_tkt_skey): Call krb_cr_tkt_krb5
+ if necessary, depending on th enctype. Force enctype to be raw
+ DES3 if it's another DES3 type.
+
+ * krb524d.c (kdc_get_server_key): Add integer kvno argument,
+ rename previous kvno arg as kvnop, to distinguish returned (found)
+ kvno from the input kvno.
+ (lookup_service_key): Add kvnop argument to allow for returned
+ kvno.
+ (do_connection): Search for DES3 keys as well as DES. Get the
+ found kvno as well, and use that instead of the kvno of the
+ incoming ticket.
+
Fri Jul 24 19:38:58 1998 Geoffrey King <gjking@mit.edu>
* krb524d.c (main): Fork into the background by default, also
(long) lifetime);
/* XXX are there V5 flags we should map to V4 equivalents? */
- ret = krb_create_ticket(v4tkt,
- 0, /* flags */
- pname,
- pinst,
- prealm,
- *((unsigned long *)kaddr.contents),
- (char *) v5etkt->session->contents,
- lifetime,
- /* issue_data */
- server_time,
- sname,
- sinst,
- v4_skey->contents);
+ if (v4_skey->enctype == ENCTYPE_DES_CBC_CRC) {
+ ret = krb_create_ticket(v4tkt,
+ 0, /* flags */
+ pname,
+ pinst,
+ prealm,
+ *((unsigned long *)kaddr.contents),
+ (char *) v5etkt->session->contents,
+ lifetime,
+ /* issue_data */
+ server_time,
+ sname,
+ sinst,
+ v4_skey->contents);
+ } else {
+ /* Force enctype to be raw if using DES3. */
+ if (v4_skey->enctype == ENCTYPE_DES3_HMAC_SHA1 ||
+ v4_skey->enctype == ENCTYPE_LOCAL_DES3_HMAC_SHA1)
+ v4_skey->enctype = ENCTYPE_DES3_CBC_RAW;
+ ret = krb_cr_tkt_krb5(v4tkt,
+ 0, /* flags */
+ pname,
+ pinst,
+ prealm,
+ *((unsigned long *)kaddr.contents),
+ (char *) v5etkt->session->contents,
+ lifetime,
+ /* issue_data */
+ server_time,
+ sname,
+ sinst,
+ v4_skey);
+ }
krb5_free_enc_tkt_part(context, v5etkt);
v5tkt->enc_part2 = NULL;
krb5_data msgdata, tktdata;
char msgbuf[MSGSIZE], tktbuf[TKT_BUFSIZ], *p;
int n, ret, saddrlen;
+ krb5_kvno v4kvno;
/* Clear out keyblock contents so we don't accidentally free the stack.*/
v5_service_key.contents = v4_service_key.contents = 0;
printf("V5 ticket decoded\n");
if ((ret = lookup_service_key(context, v5tkt->server,
- v5tkt->enc_part.enctype,
- &v5_service_key)))
+ v5tkt->enc_part.enctype,
+ v5tkt->enc_part.kvno,
+ &v5_service_key, NULL)))
goto error;
if ((ret = lookup_service_key(context, v5tkt->server,
+ ENCTYPE_DES3_CBC_RAW,
+ 0, /* highest kvno */
+ &v4_service_key, &v4kvno)) &&
+ (ret = lookup_service_key(context, v5tkt->server,
+ ENCTYPE_LOCAL_DES3_HMAC_SHA1,
+ 0,
+ &v4_service_key, &v4kvno)) &&
+ (ret = lookup_service_key(context, v5tkt->server,
+ ENCTYPE_DES3_HMAC_SHA1,
+ 0,
+ &v4_service_key, &v4kvno)) &&
+ (ret = lookup_service_key(context, v5tkt->server,
ENCTYPE_DES_CBC_CRC,
- &v4_service_key)))
- goto error;
+ 0,
+ &v4_service_key, &v4kvno)))
+ goto error;
if (debug)
printf("service key retrieved\n");
if (ret)
goto write_msg;
- n = htonl(v5tkt->enc_part.kvno);
+ n = htonl(v4kvno);
memcpy(p, (char *) &n, sizeof(int));
p += sizeof(int);
msgdata.length += sizeof(int);
return ret;
}
-krb5_error_code lookup_service_key(context, p, ktype, key)
+krb5_error_code lookup_service_key(context, p, ktype, kvno, key, kvnop)
krb5_context context;
krb5_principal p;
krb5_enctype ktype;
+ krb5_kvno kvno;
krb5_keyblock *key;
+ krb5_kvno *kvnop;
{
int ret;
krb5_keytab_entry entry;
if (use_keytab) {
- if ((ret = krb5_kt_get_entry(context, kt, p, 0, ktype, &entry)))
+ if ((ret = krb5_kt_get_entry(context, kt, p, kvno, ktype, &entry)))
return ret;
memcpy(key, (char *) &entry.key, sizeof(krb5_keyblock));
return 0;
} else if (use_master) {
- return kdc_get_server_key(context, p, key, NULL, ktype);
+ return kdc_get_server_key(context, p, key, kvnop, ktype, kvno);
}
return 0;
}
-krb5_error_code kdc_get_server_key(context, service, key, kvno, ktype)
+krb5_error_code kdc_get_server_key(context, service, key, kvnop, ktype, kvno)
krb5_context context;
krb5_principal service;
krb5_keyblock *key;
- krb5_kvno *kvno;
+ krb5_kvno *kvnop;
krb5_enctype ktype;
+ krb5_kvno kvno;
{
krb5_error_code ret;
kadm5_principal_ent_rec server;
ktype,
(ktype == ENCTYPE_DES_CBC_CRC) ?
KRB5_KDB_SALTTYPE_V4 : -1,
- -1,
- key, NULL, kvno)) &&
+ kvno,
+ key, NULL, kvnop)) &&
(ret = kadm5_decrypt_key(handle,
&server,
ktype,
-1,
- -1,
- key, NULL, kvno))) {
+ kvno,
+ key, NULL, kvnop))) {
kadm5_free_principal_ent(handle, &server);
return (KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
}
+Tue Sep 22 21:19:01 1998 Tom Yu <tlyu@mit.edu>
+
+ * prng.c (krb5_c_random_make_octets): Fix to nfold into 15 bytes,
+ not one byte.
+
+Mon Sep 21 15:23:19 1998 Tom Yu <tlyu@mit.edu>
+
+ * prng.c (krb5_c_random_seed): Fix memory leak.
+
+Mon Sep 14 23:21:17 1998 Tom Yu <tlyu@mit.edu>
+
+ * old/decrypt.c (krb5_old_decrypt): Fix memory leak.
+
+Tue Sep 1 19:33:38 1998 Tom Yu <tlyu@mit.edu>
+
+ * etypes.c: Add ETYPE_LOCAL_DES3_HMAC_SHA1 to deal with marc's
+ des3 code. ETYPE_DES3_HMAC_SHA1 remains the same for now.
+
+Mon Aug 17 23:40:11 1998 Tom Yu <tlyu@mit.edu>
+
+ * keyhash_provider/k5_md4des.c (k5_md4des_verify): Add
+ compatibility for krb5-beta5 checksums.
+
+ * keyhash_provider/k5_md5des.c (k5_md5des_verify): Add
+ compatibility for krb5-beta5 checksums. Fix typos similar to
+ those corrected in k5_md4des.c.
+
+Sun Jul 19 12:00:00 1998 Marc Horowitz <marc@mit.edu>
+
+ * *.c: replace the crypto layer.
+
Wed Apr 15 18:02:44 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in (LIB): Rename to k5crypto.
thisconfigdir=.
BUILDTOP=$(REL)$(U)$(S)$(U)
-LOCAL_SUBDIRS=des crc32 md4 md5 sha os
-CFLAGS = $(CCOPTS) $(DEFS) -I$(srcdir)/crc32 -I$(srcdir)/des -I$(srcdir)/md4 -I$(srcdir)/md5 -I$(srcdir)/sha
+LOCAL_SUBDIRS=crc32 des dk enc_provider hash_provider keyhash_provider \
+ md4 md5 old raw sha1
+CFLAGS = $(CCOPTS) $(DEFS) -I$(srcdir)/enc_provider \
+ -I$(srcdir)/hash_provider -I$(srcdir)/keyhash_provider \
+ -I$(srcdir)/old -I$(srcdir)/raw -I$(srcdir)/dk
##DOSBUILDTOP = ..\..
##DOSLIBNAME=crypto.lib
##DOSOBJFILELIST=@crypto.lst @des.lst @md4.lst @md5.lst @sha.lst @crc32.lst @os.lst
##DOSOBJFILEDEP =crypto.lst des.lst md4.lst md5.lst sha.lst crc32.lst os.lst
-MAC_SUBDIRS = des sha md4 md5 crc32 os
-
-OBJS= cryptoconf.$(OBJEXT) \
- encrypt_data.$(OBJEXT) \
- krb5_glue.$(OBJEXT) \
- decrypt_data.$(OBJEXT) \
- des_crc.$(OBJEXT) \
- des_md5.$(OBJEXT) \
- des3_sha.$(OBJEXT) \
- des3_raw.$(OBJEXT) \
- raw_des.$(OBJEXT)
-
-SRCS= $(srcdir)/cryptoconf.c \
- $(srcdir)/encrypt_data.c \
- $(srcdir)/krb5_glue.c \
- $(srcdir)/decrypt_data.c \
- $(srcdir)/des_crc.c \
- $(srcdir)/des_md5.c \
- $(srcdir)/des3_sha.c \
- $(srcdir)/des3_raw.c \
- $(srcdir)/raw_des.c
+MAC_SUBDIRS = crc32 des dk enc_provider hash_provider keyhash_provider \
+ md4 md5 old raw sha1
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+STLIBOBJS=\
+ block_size.o \
+ checksum_length.o \
+ cksumtype_to_string.o \
+ cksumtypes.o \
+ coll_proof_cksum.o \
+ decrypt.o \
+ encrypt.o \
+ encrypt_length.o \
+ enctype_compare.o \
+ enctype_to_string.o \
+ etypes.o \
+ hmac.o \
+ keyed_cksum.o \
+ keyed_checksum_types.o \
+ make_checksum.o \
+ make_random_key.o \
+ nfold.o \
+ old_api_glue.o \
+ prng.o \
+ string_to_cksumtype.o \
+ string_to_enctype.o \
+ string_to_key.o \
+ valid_cksumtype.o \
+ valid_enctype.o \
+ verify_checksum.o
+
+OBJS=\
+ block_size.$(OBJEXT) \
+ checksum_length.$(OBJEXT) \
+ cksumtype_to_string.$(OBJEXT) \
+ cksumtypes.$(OBJEXT) \
+ coll_proof_cksum.$(OBJEXT) \
+ decrypt.$(OBJEXT) \
+ encrypt.$(OBJEXT) \
+ encrypt_length.$(OBJEXT) \
+ enctype_compare.$(OBJEXT) \
+ enctype_to_string.$(OBJEXT) \
+ etypes.$(OBJEXT) \
+ hmac.$(OBJEXT) \
+ keyed_cksum.$(OBJEXT) \
+ keyed_checksum_types.$(OBJEXT) \
+ make_checksum.$(OBJEXT) \
+ make_random_key.$(OBJEXT) \
+ nfold.$(OBJEXT) \
+ old_api_glue.$(OBJEXT) \
+ prng.$(OBJEXT) \
+ string_to_cksumtype.$(OBJEXT) \
+ string_to_enctype.$(OBJEXT) \
+ string_to_key.$(OBJEXT) \
+ valid_cksumtype.$(OBJEXT) \
+ valid_enctype.$(OBJEXT) \
+ verify_checksum.$(OBJEXT)
+
+SRCS=\
+ $(subdir)/block_size.c \
+ $(subdir)/checksum_length.c \
+ $(subdir)/cksumtype_to_string.c \
+ $(subdir)/cksumtypes.c \
+ $(subdir)/coll_proof_cksum.c \
+ $(subdir)/decrypt.c \
+ $(subdir)/encrypt.c \
+ $(subdir)/encrypt_length.c \
+ $(subdir)/enctype_compare.c \
+ $(subdir)/enctype_to_string.c \
+ $(subdir)/etypes.c \
+ $(subdir)/hmac.c \
+ $(subdir)/keyed_cksum.c \
+ $(subdir)/keyed_checksum_types.c\
+ $(subdir)/make_checksum.c \
+ $(subdir)/make_random_key.c \
+ $(subdir)/nfold.c \
+ $(subdir)/old_api_glue.c \
+ $(subdir)/prng.c \
+ $(subdir)/string_to_cksumtype.c \
+ $(subdir)/string_to_enctype.c \
+ $(subdir)/string_to_key.c \
+ $(subdir)/valid_cksumtype.c \
+ $(subdir)/valid_enctype.c \
+ $(subdir)/verify_checksum.c
+
LIB=k5crypto
LIBMAJOR=2
-LIBMINOR=0
+LIBMINOR=1
RELDIR=crypto
-STLIBOBJS=cryptoconf.o encrypt_data.o decrypt_data.o \
- des_crc.o des_md5.o des3_sha.o des3_raw.o raw_des.o krb5_glue.o
-STOBJLISTS=des/OBJS.ST md4/OBJS.ST md5/OBJS.ST sha/OBJS.ST crc32/OBJS.ST \
- os/OBJS.ST OBJS.ST
+STOBJLISTS=crc32/OBJS.ST des/OBJS.ST dk/OBJS.ST enc_provider/OBJS.ST \
+ hash_provider/OBJS.ST keyhash_provider/OBJS.ST md4/OBJS.ST \
+ md5/OBJS.ST old/OBJS.ST raw/OBJS.ST sha1/OBJS.ST OBJS.ST
# No dependencies. Record places to find this shared object if the target
# link editor and loader support it.
clean-unix:: clean-liblinks clean-libs clean-libobjs
-check-unix::
+check-unix:: t_nfold
+ $(RUN_SETUP) ./t_nfold
+
+t_nfold$(EXEEXT): t_nfold.$(OBJEXT) nfold.$(OBJEXT)
+ $(CC_LINK) -o $@ t_nfold.$(OBJEXT) nfold.$(OBJEXT)
+
+clean::
+ $(RM) t_nfold.o t_nfold
all-windows::
cd crc32
cd ..\des
@echo Making in crypto\des
-$(MAKE) -$(MFLAGS)
+ cd ..\dk
+ @echo Making in crypto\dk
+ -$(MAKE) -$(MFLAGS)
+ cd ..\enc_provider
+ @echo Making in crypto\enc_provider
+ -$(MAKE) -$(MFLAGS)
+ cd ..\hash_provider
+ @echo Making in crypto\hash_provider
+ -$(MAKE) -$(MFLAGS)
+ cd ..\keyhash_provider
+ @echo Making in crypto\keyhash_provider
+ -$(MAKE) -$(MFLAGS)
cd ..\md4
@echo Making in crypto\md4
-$(MAKE) -$(MFLAGS)
- cd ..\os
- @echo Making in crypto\os
- -$(MAKE) -$(MFLAGS)
cd ..\md5
@echo Making in crypto\md5
-$(MAKE) -$(MFLAGS)
- cd ..\sha
- @echo Making in crypto\sha
+ cd ..\old
+ @echo Making in crypto\old
+ -$(MAKE) -$(MFLAGS)
+ cd ..\raw
+ @echo Making in crypto\raw
+ -$(MAKE) -$(MFLAGS)
+ cd ..\sha1
+ @echo Making in crypto\sha1
-$(MAKE) -$(MFLAGS)
- cd ..
clean-windows::
cd crc32
- @echo Making clean in crypto\crc32
+ @echo Making in clean crypto\crc32
-$(MAKE) -$(MFLAGS) clean
cd ..\des
@echo Making clean in crypto\des
-$(MAKE) -$(MFLAGS) clean
+ cd ..\dk
+ @echo Making clean in crypto\dk
+ -$(MAKE) -$(MFLAGS) clean
+ cd ..\enc_provider
+ @echo Making clean in crypto\enc_provider
+ -$(MAKE) -$(MFLAGS) clean
+ cd ..\hash_provider
+ @echo Making clean in crypto\hash_provider
+ -$(MAKE) -$(MFLAGS) clean
+ cd ..\keyhash_provider
+ @echo Making clean in crypto\keyhash_provider
+ -$(MAKE) -$(MFLAGS) clean
cd ..\md4
@echo Making clean in crypto\md4
-$(MAKE) -$(MFLAGS) clean
cd ..\md5
@echo Making clean in crypto\md5
-$(MAKE) -$(MFLAGS) clean
- cd ..\sha
- @echo Making clean in crypto\sha
+ cd ..\old
+ @echo Making clean in crypto\old
-$(MAKE) -$(MFLAGS) clean
- cd ..\os
- @echo Making clean in crypto\os
+ cd ..\raw
+ @echo Making clean in crypto\raw
+ -$(MAKE) -$(MFLAGS) clean
+ cd ..\sha1
+ @echo Making clean in crypto\sha1
-$(MAKE) -$(MFLAGS) clean
- cd ..
- @echo Making clean locally
check-windows::
cd crc32
- @echo Making check in crypto\crc32
+ @echo Making in check crypto\crc32
-$(MAKE) -$(MFLAGS) check
cd ..\des
@echo Making check in crypto\des
-$(MAKE) -$(MFLAGS) check
+ cd ..\dk
+ @echo Making check in crypto\dk
+ -$(MAKE) -$(MFLAGS) check
+ cd ..\enc_provider
+ @echo Making check in crypto\enc_provider
+ -$(MAKE) -$(MFLAGS) check
+ cd ..\hash_provider
+ @echo Making check in crypto\hash_provider
+ -$(MAKE) -$(MFLAGS) check
+ cd ..\keyhash_provider
+ @echo Making check in crypto\keyhash_provider
+ -$(MAKE) -$(MFLAGS) check
cd ..\md4
@echo Making check in crypto\md4
-$(MAKE) -$(MFLAGS) check
cd ..\md5
@echo Making check in crypto\md5
-$(MAKE) -$(MFLAGS) check
- cd ..\sha
- @echo Making check in crypto\sha
+ cd ..\old
+ @echo Making check in crypto\old
-$(MAKE) -$(MFLAGS) check
- cd ..\os
- @echo Making check in crypto\os
+ cd ..\raw
+ @echo Making check in crypto\raw
+ -$(MAKE) -$(MFLAGS) check
+ cd ..\sha1
+ @echo Making check in crypto\sha1
-$(MAKE) -$(MFLAGS) check
- cd ..
-
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_c_block_size(context, enctype, blocksize)
+ krb5_context context;
+ krb5_enctype enctype;
+ size_t *blocksize;
+{
+ int i;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ (*(krb5_enctypes_list[i].enc->block_size))(blocksize);
+
+ return(0);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_error_code
+krb5_c_checksum_length(context, cksumtype, length)
+ krb5_context context;
+ krb5_cksumtype cksumtype;
+ size_t *length;
+{
+ int i;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == cksumtype)
+ break;
+ }
+
+ if (i == krb5_cksumtypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ if (krb5_cksumtypes_list[i].keyhash)
+ (*(krb5_cksumtypes_list[i].keyhash->hash_size))(length);
+ else
+ (*(krb5_cksumtypes_list[i].hash->hash_size))(length);
+
+ return(0);
+}
+
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_cksumtype_to_string(cksumtype, buffer, buflen)
+ krb5_cksumtype cksumtype;
+ char FAR * buffer;
+ size_t buflen;
+{
+ int i;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == cksumtype) {
+ if ((strlen(krb5_cksumtypes_list[i].out_string)+1) > buflen)
+ return(ENOMEM);
+
+ strcpy(buffer, krb5_cksumtypes_list[i].out_string);
+ return(0);
+ }
+ }
+
+ return(EINVAL);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "hash_provider.h"
+#include "keyhash_provider.h"
+#include "cksumtypes.h"
+
+struct krb5_cksumtypes krb5_cksumtypes_list[] = {
+ { CKSUMTYPE_CRC32, KRB5_CKSUMFLAG_NOT_COLL_PROOF,
+ "crc32", "CRC-32",
+ 0, NULL,
+ &krb5_hash_crc32 },
+
+ { CKSUMTYPE_RSA_MD4, 0,
+ "md4", "RSA-MD4",
+ 0, NULL,
+ &krb5_hash_md4 },
+ { CKSUMTYPE_RSA_MD4_DES, 0,
+ "md4-des", "RSA-MD4 with DES cbc mode",
+ ENCTYPE_DES_CBC_CRC, &krb5_keyhash_md4des,
+ NULL },
+
+ { CKSUMTYPE_DESCBC, 0,
+ "des-cbc", "DES cbc mode",
+ ENCTYPE_DES_CBC_CRC, &krb5_keyhash_descbc,
+ NULL },
+
+ { CKSUMTYPE_RSA_MD5, 0,
+ "md5", "RSA-MD5",
+ 0, NULL,
+ &krb5_hash_md5 },
+ { CKSUMTYPE_RSA_MD5_DES, 0,
+ "md5-des", "RSA-MD5 with DES cbc mode",
+ ENCTYPE_DES_CBC_CRC, &krb5_keyhash_md5des,
+ NULL },
+
+ { CKSUMTYPE_NIST_SHA, 0,
+ "sha", "NIST-SHA",
+ 0, NULL,
+ &krb5_hash_sha1 },
+
+ { CKSUMTYPE_HMAC_SHA1, KRB5_CKSUMFLAG_DERIVE,
+ "hmac-sha1", "HMAC-SHA1",
+ 0, NULL,
+ &krb5_hash_sha1 },
+};
+
+int krb5_cksumtypes_length =
+sizeof(krb5_cksumtypes_list)/sizeof(struct krb5_cksumtypes);
+
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern struct krb5_cksumtypes krb5_cksumtypes_list[];
+extern int krb5_cksumtypes_length;
+
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_boolean is_coll_proof_cksum(ctype)
+ krb5_cksumtype ctype;
+{
+ int i;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == ctype)
+ return((krb5_cksumtypes_list[i].flags &
+ KRB5_CKSUMFLAG_NOT_COLL_PROOF)?0:1);
+ }
+
+ /* ick, but it's better than coredumping, which is what the
+ old code would have done */
+ return(0);
+}
AC_PROG_ARCHIVE_ADD
AC_PROG_RANLIB
AC_PROG_INSTALL
-dnl
-dnl Determine which cryptosystems we are enabling
-dnl
-AC_ARG_ENABLE([des-cbc-md5],
-[ --enable-des-cbc-md5 enable DES_CBC_MD5 (DEFAULT).
- --disable-des-cbc-md5 disable DES_CBC_MD5.],
-,
-enableval=yes)dnl
-if test "$enableval" = yes; then
- AC_MSG_RESULT(Enabling DES_CBC_MD5)
- AC_DEFINE(PROVIDE_DES_CBC_MD5)
-else
- AC_MSG_RESULT(Disabling DES_CBC_MD5)
-fi
-dnl AC_ARG_ENABLE([des3-cbc-sha],
-dnl [ --enable-des3-cbc-sha enable DES3_CBC_SHA (DEFAULT).
-dnl --disable-des3-cbc-sha disable DES3_CBC_SHA.],
-dnl ,
-dnl enableval=yes)dnl
-dnl if test "$enableval" = yes; then
-dnl AC_MSG_RESULT(Enabling DES3_CBC_SHA)
-dnl AC_DEFINE(PROVIDE_DES3_CBC_SHA)
-dnl else
-dnl AC_MSG_RESULT(Disabling DES3_CBC_SHA)
-dnl fi
-AC_ARG_WITH([des-cbc-crc],
-[ --enable-des-cbc-crc enable DES_CBC_CRC (DEFAULT).
- --disable-des-cbc-crc disable DES_CBC_CRC.],
-,
-enableval=yes)dnl
-if test "$enableval" = yes; then
- AC_MSG_RESULT(Enabling DES_CBC_CRC)
- AC_DEFINE(PROVIDE_DES_CBC_CRC)
-else
- AC_MSG_RESULT(Disabling DES_CBC_CRC)
-fi
-AC_ARG_WITH([des-cbc-raw],
-[ --enable-des-cbc-raw enable DES_CBC_RAW (DEFAULT).
- --disable-des-cbc-raw disable DES_CBC_RAW.],
-,
-enableval=yes)dnl
-if test "$enableval" = yes; then
- AC_MSG_RESULT(Enabling DES_CBC_RAW)
- AC_DEFINE(PROVIDE_DES_CBC_RAW)
-else
- AC_MSG_RESULT(Disabling DES_CBC_RAW)
-fi
-dnl AC_ARG_WITH([des3-cbc-raw],
-dnl [ --enable-des3-cbc-raw enable DES3_CBC_RAW (DEFAULT).
-dnl --disable-des3-cbc-raw disable DES3_CBC_RAW.],
-dnl ,
-dnl enableval=yes)dnl
-dnl if test "$enableval" = yes; then
-dnl AC_MSG_RESULT(Enabling DES3_CBC_RAW)
-dnl AC_DEFINE(PROVIDE_DES3_CBC_RAW)
-dnl else
-dnl AC_MSG_RESULT(Disabling DES3_CBC_RAW)
-dnl fi
-AC_ARG_WITH([des-cbc-cksum],
-[ --enable-des-cbc-cksum enable DES_CBC_CKSUM (DEFAULT).
- --disable-des-cbc-cksum disable DES_CBC_CKSUM.],
-,
-enableval=yes)dnl
-if test "$enableval" = yes; then
- AC_MSG_RESULT(Enabling DES_CBC_CKSUM)
- AC_DEFINE(PROVIDE_DES_CBC_CKSUM)
-else
- AC_MSG_RESULT(Disabling DES_CBC_CKSUM)
-fi
-AC_ARG_WITH([crc32],
-[ --enable-crc32 enable CRC32 (DEFAULT).
- --disable-crc32 disable CRC32.],
-,
-enableval=yes)dnl
-if test "$enableval" = yes; then
- AC_MSG_RESULT(Enabling CRC32)
- AC_DEFINE(PROVIDE_CRC32)
-else
- AC_MSG_RESULT(Disabling CRC32)
-fi
-AC_ARG_WITH([rsa-md4],
-[ --enable-rsa-md4 enable RSA_MD4 (DEFAULT).
- --disable-rsa-md4 disable RSA_MD4.],
-,
-enableval=yes)dnl
-if test "$enableval" = yes; then
- AC_MSG_RESULT(Enabling RSA_MD4)
- AC_DEFINE(PROVIDE_RSA_MD4)
-else
- AC_MSG_RESULT(Disabling RSA_MD4)
-fi
-AC_ARG_WITH([rsa-md5],
-[ --enable-rsa-md5 enable RSA_MD5 (DEFAULT).
- --disable-rsa-md5 disable RSA_MD5.],
-,
-enableval=yes)dnl
-if test "$enableval" = yes; then
- AC_MSG_RESULT(Enabling RSA_MD5)
- AC_DEFINE(PROVIDE_RSA_MD5)
-else
- AC_MSG_RESULT(Disabling RSA_MD5)
-fi
-dnl AC_ARG_WITH([nist-sha],
-dnl [ --enable-nist-sha enable NIST_SHA (DEFAULT).
-dnl --disable-nist-sha disable NIST_SHA.],
-dnl ,
-dnl enableval=yes)dnl
-dnl if test "$enableval" = yes; then
-dnl AC_MSG_RESULT(Enabling NIST_SHA)
-dnl AC_DEFINE(PROVIDE_NIST_SHA)
-dnl else
-dnl AC_MSG_RESULT(Disabling NIST_SHA)
-dnl fi
-
-AC_REPLACE_FUNCS(memmove)
-AC_HAVE_FUNCS(srand48 srand srandom getpid)
-AC_CHECK_HEADERS(sys/types.h)
-AC_PROG_LN_S
-KRB5_SOCKADDR_SA_LEN
KRB5_RUN_FLAGS
+KRB5_BUILD_PROGRAM
KRB5_BUILD_LIBOBJS
KRB5_BUILD_LIBRARY
-KRB5_BUILD_PROGRAM
K5_GEN_MAKEFILE(., lib libobj)
K5_GEN_MAKEFILE(crc32, libobj)
K5_GEN_MAKEFILE(des, libobj)
+K5_GEN_MAKEFILE(dk, libobj)
+K5_GEN_MAKEFILE(enc_provider, libobj)
+K5_GEN_MAKEFILE(hash_provider, libobj)
+K5_GEN_MAKEFILE(keyhash_provider, libobj)
K5_GEN_MAKEFILE(md4, libobj)
K5_GEN_MAKEFILE(md5, libobj)
-K5_GEN_MAKEFILE(os, libobj)
-K5_GEN_MAKEFILE(sha, libobj)
+K5_GEN_MAKEFILE(old, libobj)
+K5_GEN_MAKEFILE(raw, libobj)
+K5_GEN_MAKEFILE(sha1, libobj)
K5_AC_OUTPUT
+Sun Jul 19 12:00:00 1998 Marc Horowitz <marc@mit.edu>
+
+ * *.c: replace the crypto layer.
+
Wed Feb 18 16:05:45 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in: Remove trailing slash from thisconfigdir. Fix up
##DOS##OBJFILE=..\crc32.lst
##WIN16##LIBNAME=..\crypto.lib
-STLIBOBJS=crc.o
-OBJS= crc.$(OBJEXT)
-SRCS= $(srcdir)/crc.c
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
-##DOS##LIBOBJS = $(OBJS)
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
-all-unix:: all-libobjs
+STLIBOBJS= crc32.o
+
+OBJS= crc32.$(OBJEXT)
-crctest: crctest.$(OBJEXT) $(OBJS)
- $(RM) crctest
- $(CC) -o crctest crctest.$(OBJEXT) $(CFLAGS) $(LDFLAGS) $(OBJS)
+SRCS= $(srcdir)/crc32.c
-crctest.exe:
- $(CC) -o crctest.exe $(CFLAGS2) $(SRCS)
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
-check:: crctest$(EXEEXT)
- $(C)crctest$(EXEEXT) < $(srcdir)$(S)crc-test
+includes:: depend
-clean::
- $(RM) crctest$(EXEEXT) crctest.$(OBJEXT)
+depend:: $(SRCS)
clean-unix:: clean-libobjs
* Definitions for the CRC-32 checksum
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef KRB5_CRC32__
#define KRB5_CRC32__
-#define CRC32_CKSUM_LENGTH (4*sizeof(krb5_octet))
+#define CRC32_CKSUM_LENGTH 4
+
+void
+mit_crc32 PROTOTYPE((krb5_const krb5_pointer in, krb5_const size_t in_length,
+ unsigned long *c));
extern krb5_checksum_entry crc32_cksumtable_entry;
--- /dev/null
+/*
+ * lib/crypto/crc32/crc.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * CRC-32/AUTODIN-II routines
+ */
+
+#include "k5-int.h"
+#include "crc-32.h"
+
+/* This table and block of comments are taken from code labeled: */
+/*
+ * Copyright (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+/* First, the polynomial itself and its table of feedback terms. The */
+/* polynomial is */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in */
+/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
+/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
+/* the MSB being 1. */
+
+/* Note that the usual hardware shift register implementation, which */
+/* is what we're using (we're merely optimizing it by doing eight-bit */
+/* chunks at a time) shifts bits into the lowest-order term. In our */
+/* implementation, that means shifting towards the right. Why do we */
+/* do it this way? Because the calculated CRC must be transmitted in */
+/* order from highest-order term to lowest-order term. UARTs transmit */
+/* characters in order from LSB to MSB. By storing the CRC this way, */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part. Reception works similarly. */
+
+/* The feedback terms table consists of 256, 32-bit entries. Notes: */
+/* */
+/* 1. The table can be generated at runtime if desired; code to do so */
+/* is shown later. It might not be obvious, but the feedback */
+/* terms simply represent the results of eight shift/xor opera- */
+/* tions for all combinations of data and CRC register values. */
+/* */
+/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
+/* be they sixteen or thirty-two bits wide. You simply choose the */
+/* appropriate table. Alternatively, because the table can be */
+/* generated at runtime, you can start by generating the table for */
+/* the polynomial in question and use exactly the same "updcrc", */
+/* if your application needn't simultaneously handle two CRC */
+/* polynomials. (Note, however, that XMODEM is strange.) */
+/* */
+/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
+/* of course, 32-bit entries work OK if the high 16 bits are zero. */
+/* */
+/* 4. The values must be right-shifted by eight bits by the "updcrc" */
+/* logic; the shift must be unsigned (bring in zeroes). On some */
+/* hardware you could probably optimize the shift in assembler by */
+/* using byte-swap instructions. */
+
+static u_long const crc_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ };
+
+void
+mit_crc32(in, in_length, cksum)
+ krb5_const krb5_pointer in;
+ krb5_const size_t in_length;
+ unsigned long *cksum;
+{
+ register u_char *data;
+ register u_long c = 0;
+ register int idx;
+ size_t i;
+
+ data = (u_char *)in;
+ for (i = 0; i < in_length; i++) {
+ idx = (int) (data[i] ^ c);
+ idx &= 0xff;
+ c >>= 8;
+ c ^= crc_table[idx];
+ }
+
+ *cksum = c;
+}
+++ /dev/null
-/*
- * lib/crypto/cryptoconf.c
- *
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- *
- * Cryptosystem configurations
- */
-
-#include "k5-int.h"
-
-#if defined(PROVIDE_DES_CBC_CRC) || defined(PROVIDE_CRC32)
-#include "crc-32.h"
-#define CRC32_CKENTRY &crc32_cksumtable_entry
-#else
-#define CRC32_CKENTRY 0
-#endif
-
-#ifdef PROVIDE_RSA_MD4
-#include "rsa-md4.h"
-#define MD4_CKENTRY &rsa_md4_cksumtable_entry
-#define MD4_DES_CKENTRY &rsa_md4_des_cksumtable_entry
-#else
-#define MD4_CKENTRY 0
-#define MD4_DES_CKENTRY 0
-#endif
-
-#ifdef PROVIDE_RSA_MD5
-#include "rsa-md5.h"
-#define MD5_CKENTRY &rsa_md5_cksumtable_entry
-#define MD5_DES_CKENTRY &rsa_md5_des_cksumtable_entry
-#else
-#define MD5_CKENTRY 0
-#define MD5_DES_CKENTRY 0
-#endif
-
-#ifdef PROVIDE_NIST_SHA
-#include "shs.h"
-/* #define SHA_CKENTRY &nist_sha_cksumtable_entry */
-/* #define HMAC_SHA_CKENTRY &hmac_sha_cksumtable_entry */
-#define SHA_CKENTRY 0
-#define HMAC_SHA_CKENTRY 0
-#else
-#define SHA_CKENTRY 0
-#define HMAC_SHA_CKENTRY 0
-#endif
-
-#ifdef PROVIDE_SNEFRU
-#define XEROX_CKENTRY &snefru_cksumtable_entry
-#else
-#define XEROX_CKENTRY 0
-#endif
-
-#ifdef PROVIDE_DES_CBC_CKSUM
-#include "des_int.h"
-#define _DES_DONE__
-#define DES_CBC_CKENTRY &krb5_des_cbc_cksumtable_entry
-#else
-#define DES_CBC_CKENTRY 0
-#endif
-
-#ifdef PROVIDE_DES_CBC_CRC
-#ifndef _DES_DONE__
-#include "des_int.h"
-#define _DES_DONE__
-#endif
-#define DES_CBC_CRC_CSENTRY &krb5_des_crc_cst_entry
-#else
-#define DES_CBC_CRC_CSENTRY 0
-#endif
-
-#ifdef PROVIDE_DES_CBC_MD5
-#ifndef _DES_DONE__
-#include "des_int.h"
-#define _DES_DONE__
-#endif
-#define DES_CBC_MD5_CSENTRY &krb5_des_md5_cst_entry
-#else
-#define DES_CBC_MD5_CSENTRY 0
-#endif
-
-#ifdef PROVIDE_DES_CBC_RAW
-#ifndef _DES_DONE__
-#include "des_int.h"
-#define _DES_DONE__
-#endif
-#define DES_CBC_RAW_CSENTRY &krb5_raw_des_cst_entry
-#else
-#define DES_CBC_RAW_CSENTRY 0
-#endif
-
-#ifdef PROVIDE_DES3_CBC_SHA
-#ifndef _DES_DONE__
-#include "des_int.h"
-#define _DES_DONE__
-#endif
-/* Don't try to enable triple DES unless you know what you are doing; */
-/* the current implementation of triple DES is NOT the final and */
-/* correct implementation.!!! */
-/* #define DES3_CBC_SHA_CSENTRY &krb5_des3_sha_cst_entry */
-#define DES3_CBC_SHA_CSENTRY 0
-#else
-#define DES3_CBC_SHA_CSENTRY 0
-#endif
-
-#ifdef PROVIDE_DES3_CBC_RAW
-#ifndef _DES_DONE__
-#include "des_int.h"
-#define _DES_DONE__
-#endif
-/* #define DES3_CBC_RAW_CSENTRY &krb5_des3_raw_cst_entry */
-#define DES3_CBC_RAW_CSENTRY 0
-#else
-#define DES3_CBC_RAW_CSENTRY 0
-#endif
-
-
-/* WARNING:
- make sure the order of entries in these tables matches the #defines in
- "krb5/encryption.h"
- */
-
-krb5_cs_table_entry * NEAR krb5_enctype_array[] = {
- 0, /* ENCTYPE_NULL */
- DES_CBC_CRC_CSENTRY, /* ENCTYPE_DES_CBC_CRC */
- 0, /* ENCTYPE_DES_CBC_MD4 */
- DES_CBC_MD5_CSENTRY, /* ENCTYPE_DES_CBC_MD5 */
- DES_CBC_RAW_CSENTRY, /* ENCTYPE_DES_CBC_RAW */
- DES3_CBC_SHA_CSENTRY, /* ENCTYPE_DES3_CBC_SHA */
- DES3_CBC_RAW_CSENTRY /* ENCTYPE_DES3_CBC_RAW */
-};
-
-krb5_enctype krb5_max_enctype = sizeof(krb5_enctype_array)/sizeof(krb5_enctype_array[0]) - 1;
-
-krb5_checksum_entry * NEAR krb5_cksumarray[] = {
- 0,
- CRC32_CKENTRY, /* 1 - CKSUMTYPE_CRC32 */
- MD4_CKENTRY, /* 2 - CKSUMTYPE_RSA_MD4 */
- MD4_DES_CKENTRY, /* 3 - CKSUMTYPE_RSA_MD4_DES */
- DES_CBC_CKENTRY, /* 4 - CKSUMTYPE_DESCBC */
- 0, /* 5 - des-mac-k */
- 0, /* 6 - rsa-md4-des-k */
- MD5_CKENTRY, /* 7 - CKSUMTYPE_RSA_MD5 */
- MD5_DES_CKENTRY, /* 8 - CKSUMTYPE_RSA_MD5_DES */
- SHA_CKENTRY, /* 9 - CKSUMTYPE_NIST_SHA */
- HMAC_SHA_CKENTRY /* 10 - CKSUMTYPE_NIST_SHA_DES3 */
-};
-
-krb5_cksumtype krb5_max_cksum = sizeof(krb5_cksumarray)/sizeof(krb5_cksumarray[0]);
-
-#undef _DES_DONE__
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_c_decrypt(context, key, usage, ivec, input, output)
+ krb5_context context;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *ivec;
+ krb5_const krb5_enc_data *input;
+ krb5_data *output;
+{
+ int i;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == key->enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ if ((input->enctype != ENCTYPE_UNKNOWN) &&
+ (krb5_enctypes_list[i].etype != input->enctype))
+ return(KRB5_BAD_ENCTYPE);
+
+ return((*(krb5_enctypes_list[i].decrypt))
+ (krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
+ key, usage, ivec, &input->ciphertext, output));
+}
+++ /dev/null
-/*
- * Copyright 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- */
-
-#include "k5-int.h"
-
-/*
- * This routine takes a key and a krb5_enc_data structure as input, and
- * outputs the decrypted data in a krb5_data structure. Note that
- * the krb5_data structure is not allocated.
- */
-krb5_error_code
-krb5_decrypt_data(context, key, ivec, enc_data, data)
- krb5_context context;
- krb5_keyblock * key;
- krb5_pointer ivec;
- krb5_enc_data * enc_data;
- krb5_data * data;
-{
- krb5_error_code retval;
- krb5_encrypt_block eblock;
-
- krb5_use_enctype(context, &eblock, key->enctype);
- data->length = enc_data->ciphertext.length;
- if (!(data->data = malloc(data->length)))
- return ENOMEM;
-
- if ((retval = krb5_process_key(context, &eblock, key)) != 0)
- goto cleanup;
-
- if ((retval = krb5_decrypt(context,
- (krb5_pointer) enc_data->ciphertext.data,
- (krb5_pointer) data->data,
- enc_data->ciphertext.length, &eblock, ivec))) {
- krb5_finish_key(context, &eblock);
- goto cleanup;
- }
- (void) krb5_finish_key(context, &eblock);
-
- return 0;
-
-cleanup:
- if (data->data) {
- free(data->data);
- data->data = 0;
- }
- return retval;
-}
+++ /dev/null
-ignore fp.c
-ignore ip.c
-ignore key_perm.h
-ignore odd.h
-ignore p.c
-ignore p_table.h
-ignore s_table.h
-ignore doc
+Sun Jul 19 12:00:00 1998 Marc Horowitz <marc@mit.edu>
+
+ * *.c: replace the crypto layer.
+
Wed Feb 18 16:06:23 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in: Remove trailing slash from thisconfigdir. Fix up
+++ /dev/null
-File Function Where?
-
-weak_key.c mit_des_is_weak_key crypto
-string2key.c mit_des_string_to_key ?
-random_key.c mit_des_random_key ?
-process_ky.c mit_des_process_key ?
-new_rn_key.c mit_des_new_random_key ?
- mit_des_init_random_number_generator ?
- mit_des_set_random_generator_seed ?
- mit_des_set_sequence_number ?
- mit_des_generate_random_block ?
-krb_glue.c mit_des_encrypt_func ?
- mit_des_decrypt_func ?
-key_sched.c mit_des_key_sched crypto
-key_parity.c mit_des_fixup_key_parity crypto
- mit_des_check_key_parity crypto
-init_rkey.c mit_des_init_random_key crypto
-finish_key.c mit_des_finish_key crypto
-fin_rndkey.c mit_des_finish_random_key crypto
-enc_dec.c mit_des_cbc_encrypt crypto
-des.c mit_des_ecb_encrypt crypto
-cs_entry.c (var) mit_des_cryptosystem_entry krb5
- (var) krb5_des_cst_entry krb5
- (var) mit_des_cbc_cksumtable_entry krb5
-cksum.c mit_des_cbc_cksum crypto
-cbc_cksum.c mit_des_cbc_checksum crypto
RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
STLIBOBJS=\
- afsstring2key.o \
- cbc_cksum.o \
- finish_key.o \
- fin_rndkey.o \
- init_rkey.o \
- process_ky.o \
- random_key.o \
- string2key.o \
- key_sched.o \
- weak_key.o \
+ afsstring2key.o \
+ d3_cbc.o \
+ d3_kysched.o \
f_cbc.o \
- f_cksum.o \
- f_sched.o \
- f_ecb.o \
+ f_cksum.o \
f_parity.o \
+ f_sched.o \
f_tables.o \
- d3_cbc.o \
- d3_ecb.o \
- d3_kysched.o \
- d3_procky.o \
- d3_str2ky.o \
- u_nfold.o \
- u_rn_key.o
-
-OBJS= afsstring2key.$(OBJEXT) \
- cbc_cksum.$(OBJEXT) \
- finish_key.$(OBJEXT) \
- fin_rndkey.$(OBJEXT) \
- init_rkey.$(OBJEXT) \
- process_ky.$(OBJEXT) \
- random_key.$(OBJEXT) \
- string2key.$(OBJEXT) \
- key_sched.$(OBJEXT) \
- weak_key.$(OBJEXT) \
+ key_sched.o \
+ string2key.o \
+ weak_key.o
+
+OBJS= afsstring2key.$(OBJEXT) \
+ d3_cbc.$(OBJEXT) \
+ d3_kysched.$(OBJEXT) \
f_cbc.$(OBJEXT) \
- f_cksum.$(OBJEXT) \
- f_sched.$(OBJEXT) \
- f_ecb.$(OBJEXT) \
+ f_cksum.$(OBJEXT) \
f_parity.$(OBJEXT) \
+ f_sched.$(OBJEXT) \
f_tables.$(OBJEXT) \
- d3_cbc.$(OBJEXT) \
- d3_ecb.$(OBJEXT) \
- d3_kysched.$(OBJEXT) \
- d3_procky.$(OBJEXT) \
- d3_str2ky.$(OBJEXT) \
- u_nfold.$(OBJEXT) \
- u_rn_key.$(OBJEXT)
-
-SRCS= $(srcdir)/afsstring2key.c \
- $(srcdir)/cbc_cksum.c \
- $(srcdir)/finish_key.c \
- $(srcdir)/fin_rndkey.c \
- $(srcdir)/init_rkey.c \
- $(srcdir)/process_ky.c \
- $(srcdir)/random_key.c \
- $(srcdir)/string2key.c \
+ key_sched.$(OBJEXT) \
+ string2key.$(OBJEXT) \
+ weak_key.$(OBJEXT)
+
+SRCS= $(srcdir)/afsstring2key.c \
+ $(srcdir)/d3_cbc.c \
+ $(srcdir)/d3_kysched.c \
+ $(srcdir)/f_cbc.c \
+ $(srcdir)/f_cksum.c \
+ $(srcdir)/f_parity.c \
+ $(srcdir)/f_sched.c \
+ $(srcdir)/f_tables.c \
$(srcdir)/key_sched.c \
$(srcdir)/weak_key.c \
- $(srcdir)/f_cbc.c \
- $(srcdir)/f_cksum.c \
- $(srcdir)/f_sched.c \
- $(srcdir)/f_ecb.c \
- $(srcdir)/f_parity.c \
- $(srcdir)/f_tables.c \
- $(srcdir)/d3_cbc.c \
- $(srcdir)/d3_ecb.c \
- $(srcdir)/d3_kysched.c \
- $(srcdir)/d3_procky.c \
- $(srcdir)/d3_str2ky.c \
- $(srcdir)/u_nfold.c \
- $(srcdir)/u_rn_key.c
+ $(srcdir)/string2key.c
##DOS##LIBOBJS = $(OBJS)
depend:: $(SRCS)
-# FIXME, this is left from the previous DES implementation.
-clean::
- $(RM) fp.c ip.c key_perm.h odd.h p.c p_table.h s_table.h
-
-verify$(EXEEXT): t_verify.$(OBJEXT) $(KRB5_BASE_DEPLIBS)
- $(CC_LINK) -o $@ t_verify.$(OBJEXT) process_ky.o key_sched.o \
- ../cryptoconf.o ../des_crc.o $(KRB5_BASE_LIBS)
+TOBJS = key_sched.$(OBJEXT) f_sched.$(OBJEXT) f_cbc.$(OBJEXT) \
+ f_tables.$(OBJEXT) f_cksum.$(OBJEXT)
-destest$(EXEEXT): destest.$(OBJEXT) $(KRB5_BASE_DEPLIBS)
- $(CC_LINK) -o $@ destest.$(OBJEXT) process_ky.o key_sched.o \
- ../cryptoconf.o ../des_crc.o $(KRB5_BASE_LIBS)
+verify$(EXEEXT): t_verify.$(OBJEXT) $(TOBJS) f_parity.$(OBJEXT) \
+ $(COM_ERR_DEPLIB)
+ $(CC_LINK) -o $@ t_verify.$(OBJEXT) $(TOBJS) f_parity.$(OBJEXT) \
+ -lcom_err
-t_random$(EXEEXT): t_random.$(OBJEXT) $(KRB5_BASE_DEPLIBS)
- $(CC_LINK) -o $@ t_random.$(OBJEXT) $(KRB5_BASE_LIBS)
+destest$(EXEEXT): destest.$(OBJEXT) $(TOBJS)
+ $(CC_LINK) -o $@ destest.$(OBJEXT) $(TOBJS)
-check-unix:: destest verify
+check-unix:: verify destest
$(RUN_SETUP) ./verify -z
$(RUN_SETUP) ./verify -m
$(RUN_SETUP) ./verify
clean::
$(RM) destest$(EXEEXT) verify$(EXEEXT) destest.$(OBJEXT) \
- t_verify.$(OBJEXT) t_random.$(OBJEXT) t_random$(EXEEXT)
+ t_verify.$(OBJEXT)
clean-unix:: clean-libobjs
* constructed by Mark Eichin, Cygnus Support, 1995.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "des_int.h"
#include <ctype.h>
static char *afs_crypt PROTOTYPE((char*,char*));
krb5_error_code
-mit_afs_string_to_key (eblock, keyblock, data, salt)
- const krb5_encrypt_block FAR * eblock;
+mit_afs_string_to_key (keyblock, data, salt)
krb5_keyblock FAR * keyblock;
const krb5_data FAR * data;
const krb5_data FAR * salt;
register krb5_octet *key = keyblock->contents;
if (data->length <= 8) {
- char password[9]; /* trailing null for crypt() */
+ char password[9]; /* trailing nul for crypt() */
strncpy(password, realm, 8);
for (i=0; i<8; i++)
if (isupper(password[i]))
for (i=0; i<8; i++)
if (password[i] == '\0')
password[i] = 'X';
+ password[8] = '\0';
strncpy(key, (char *) afs_crypt(password, "#~") + 2, 8);
for (i=0; i<8; i++)
key[i] <<= 1;
+++ /dev/null
-/*
- * lib/crypto/des/cbc_cksum.c
- *
- * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
- * of Technology.
- * All Rights Reserved.
- *
- * Under U.S. law, this software may not be exported outside the US
- * without license from the U.S. Commerce department.
- *
- * These routines form the library interface to the DES facilities.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- *
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-/*
- produces cbc cheksum of sequence "in" of the length "in_length"
- with the help of key "key" of size "key_size" (which should be 8);
- fills out krb5_checksum structure.
-
- caller is responsible for allocating & freeing "contents" element in
- krb5_checksum structure.
-
- returns: errors
-*/
-
-static krb5_error_code mit_des_cbc_checksum
- PROTOTYPE((krb5_const krb5_pointer,
- krb5_const size_t,
- krb5_const krb5_pointer,
- krb5_const size_t,
- krb5_checksum FAR * ));
-
-static krb5_error_code mit_des_cbc_verf_cksum
- PROTOTYPE ((krb5_const krb5_checksum FAR *,
- krb5_const krb5_pointer,
- krb5_const size_t,
- krb5_const krb5_pointer,
- krb5_const size_t ));
-
-static krb5_error_code
-mit_des_cbc_checksum(in, in_length, key, key_size, cksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer key;
- krb5_const size_t key_size;
- krb5_checksum FAR * cksum;
-{
- struct mit_des_ks_struct *schedule; /* pointer to key schedules */
-
- if (cksum->length < sizeof(mit_des_cblock))
- return KRB5_BAD_MSIZE;
- if (key_size != sizeof(mit_des_cblock))
- return KRB5_BAD_KEYSIZE;
-
- if (!(schedule = (struct mit_des_ks_struct *) malloc(sizeof(mit_des_key_schedule))))
- return ENOMEM;
-
-#define cleanup() { memset((char *)schedule, 0, sizeof(mit_des_key_schedule));\
- free( (char *) schedule); }
-
- switch (mit_des_key_sched ((krb5_octet *)key, schedule)) {
- case -1:
- cleanup();
- return KRB5DES_BAD_KEYPAR;
-
- case -2:
- cleanup();
- return KRB5DES_WEAK_KEY;
-
- default:
- ;
- }
-
- cksum->checksum_type = CKSUMTYPE_DESCBC;
- cksum->length = sizeof(mit_des_cblock);
- mit_des_cbc_cksum(in, cksum->contents, in_length, schedule, key);
-
- cleanup();
-
- return 0;
-}
-
-static krb5_error_code
-mit_des_cbc_verf_cksum(cksum, in, in_length, key, key_size)
- krb5_const krb5_checksum FAR * cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer key;
- krb5_const size_t key_size;
-{
- struct mit_des_ks_struct *schedule; /* pointer to key schedules */
- mit_des_cblock contents;
- krb5_error_code retval;
-
- if (key_size != sizeof(mit_des_cblock))
- return KRB5_BAD_KEYSIZE;
-
- if (!(schedule = (struct mit_des_ks_struct *) malloc(sizeof(mit_des_key_schedule))))
- return ENOMEM;
-
-#define cleanup() { memset((char *)schedule, 0, sizeof(mit_des_key_schedule));\
- free( (char *) schedule); }
-
- switch (mit_des_key_sched ((krb5_octet *)key, schedule)) {
- case -1:
- cleanup();
- return KRB5DES_BAD_KEYPAR;
-
- case -2:
- cleanup();
- return KRB5DES_WEAK_KEY;
-
- default:
- ;
- }
-
- mit_des_cbc_cksum(in, contents, in_length, schedule, key);
-
- retval = 0;
- if (cksum->checksum_type == CKSUMTYPE_DESCBC) {
- if (cksum->length == sizeof(mit_des_cblock)) {
- if (memcmp((char *) cksum->contents,
- (char *) contents,
- sizeof(mit_des_cblock)))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
- cleanup();
-
- return retval;
-}
-
-krb5_checksum_entry krb5_des_cbc_cksumtable_entry = {
- 0,
- mit_des_cbc_checksum,
- mit_des_cbc_verf_cksum,
- sizeof(mit_des_cblock),
- 1, /* is collision proof */
- 1, /* is keyed */
-};
+++ /dev/null
-/*
- * Copyright 1995 by Richard P. Basch. All Rights Reserved.
- * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
-#include "des_int.h"
-#include "f_tables.h"
-
-/*
- * Triple-DES ECB encryption mode.
- */
-
-int
-mit_des3_ecb_encrypt(in, out, sched1, sched2, sched3, encrypt)
- const mit_des_cblock FAR *in;
- mit_des_cblock FAR *out;
- mit_des_key_schedule sched1, sched2, sched3;
- int encrypt;
-{
- if (encrypt) {
- mit_des_ecb_encrypt(in, out, sched1, encrypt);
- mit_des_ecb_encrypt(out, out, sched2, !encrypt);
- mit_des_ecb_encrypt(out, out, sched3, encrypt);
- } else {
- mit_des_ecb_encrypt(in, out, sched3, encrypt);
- mit_des_ecb_encrypt(out, out, sched2, !encrypt);
- mit_des_ecb_encrypt(out, out, sched1, encrypt);
- }
- return 0;
-}
+++ /dev/null
-/*
- * Copyright 1995 by Richard P. Basch. All Rights Reserved.
- * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-krb5_error_code
-mit_des3_process_key (eblock, keyblock)
- krb5_encrypt_block * eblock;
- const krb5_keyblock * keyblock;
-{
- struct mit_des_ks_struct *schedule; /* pointer to key schedules */
-
- if ((keyblock->enctype != ENCTYPE_DES3_CBC_SHA) &&
- (keyblock->enctype != ENCTYPE_DES3_CBC_RAW))
- return KRB5_PROG_ETYPE_NOSUPP;
-
- if (keyblock->length != sizeof (mit_des3_cblock))
- return KRB5_BAD_KEYSIZE;
-
- if ( !(schedule = (struct mit_des_ks_struct *) malloc(3*sizeof(mit_des_key_schedule))) )
- return ENOMEM;
-#define cleanup() { free( (char *) schedule); }
-
- switch (mit_des3_key_sched (*(mit_des3_cblock *)keyblock->contents,
- *(mit_des3_key_schedule *)schedule)) {
- case -1:
- cleanup();
- return KRB5DES_BAD_KEYPAR;
-
- case -2:
- cleanup();
- return KRB5DES_WEAK_KEY;
- }
-
- eblock->key = (krb5_keyblock *) keyblock;
- eblock->priv = (krb5_pointer) schedule;
- eblock->priv_size = (krb5_int32) 3*sizeof(mit_des_key_schedule);
-
- return 0;
-}
+++ /dev/null
-/*
- * Copyright 1995 by Richard P. Basch. All Rights Reserved.
- * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-/*
- * Triple-DES string-to-key algorithm
- *
- * 168-fold the input string (appended with any salt), and treat the resulting
- * 168 bits as three DES keys sans parity. Process each set of 56 bits into
- * a usable DES key with odd parity, and twice encrypt the set of three usable
- * DES keys using Triple-DES CBC mode. The result is then treated as three
- * DES keys, and should be corrected for parity. Any DES key that is weak or
- * semi-weak is to be corrected by eXclusive-ORing with 00000000000000F0.
- */
-
-static mit_des_cblock zero_ivec = { 0, 0, 0, 0, 0, 0, 0, 0 };
-
-krb5_error_code
-mit_des3_string_to_key (eblock, keyblock, data, salt)
-const krb5_encrypt_block FAR * eblock;
-krb5_keyblock FAR * keyblock;
-const krb5_data FAR * data;
-const krb5_data FAR * salt;
-{
- char *copystr;
- mit_des_cblock *key;
- unsigned int j;
-
- int length;
- mit_des3_key_schedule ks;
- krb5_enctype enctype = eblock->crypto_entry->proto_enctype;
-
- if ((enctype == ENCTYPE_DES3_CBC_SHA) ||
- (enctype == ENCTYPE_DES3_CBC_RAW))
- keyblock->length = sizeof(mit_des3_cblock);
- else
- return (KRB5_PROG_ETYPE_NOSUPP);
-
- if ( !(keyblock->contents = (krb5_octet *)malloc(keyblock->length)) )
- return(ENOMEM);
-
- keyblock->magic = KV5M_KEYBLOCK;
- keyblock->enctype = enctype;
- key = (mit_des_cblock *)keyblock->contents;
-
- if (salt)
- length = data->length + salt->length;
- else
- length = data->length;
-
- if (length < keyblock->length)
- length = keyblock->length;
-
- copystr = malloc((size_t) length);
- if (!copystr) {
- free(keyblock->contents);
- keyblock->contents = 0;
- return ENOMEM;
- }
-
- memset(copystr, 0, length);
- memcpy(copystr, (char *) data->data, data->length);
- if (salt)
- memcpy(copystr + data->length, (char *)salt->data, salt->length);
-
- /* n-fold into des3 key sans parity */
- if (mit_des_n_fold(copystr, length, keyblock->contents,
- keyblock->length * 7 / 8))
- return EINVAL;
-
- /* Add space for parity (low bit) */
- for (j = keyblock->length; j--; ) {
- register int k;
-
- k = (8-(j%8)) & 7;
- keyblock->contents[j] =
- ((keyblock->contents[j*7/8] << k) & 0xfe) +
- ((k>1) ? keyblock->contents[j*7/8 +1] >> (8-k) : 0);
- }
-
- /* fix key parity */
- for (j = 0; j < keyblock->length/sizeof(mit_des_cblock); j++) {
- mit_des_fixup_key_parity(key[j]);
- if (mit_des_is_weak_key(key[j]))
- ((krb5_octet *)(key[j]))[7] ^= 0xf0;
- }
-
- /* Now, CBC encrypt with itself */
- (void) mit_des3_key_sched(*((mit_des3_cblock *)key), ks);
- (void) mit_des3_cbc_encrypt(key, key, keyblock->length,
- ((mit_des_key_schedule *)ks)[0],
- ((mit_des_key_schedule *)ks)[1],
- ((mit_des_key_schedule *)ks)[2],
- zero_ivec, TRUE);
- (void) mit_des3_cbc_encrypt(key, key, keyblock->length,
- ((mit_des_key_schedule *)ks)[0],
- ((mit_des_key_schedule *)ks)[1],
- ((mit_des_key_schedule *)ks)[2],
- key[2], TRUE);
-
- /* erase key_sked */
- memset((char *)ks, 0, sizeof(ks));
-
- /* clean & free the input string */
- memset(copystr, 0, (size_t) length);
- krb5_xfree(copystr);
-
- /* now fix up key parity again */
- for (j = 0; j < keyblock->length/sizeof(mit_des_cblock); j++) {
- mit_des_fixup_key_parity(key[j]);
- if (mit_des_is_weak_key(key[j]))
- ((krb5_octet *)(key[j]))[7] ^= 0xf0;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * include/des.h
- *
- * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
- *
- * For copying and distribution information, please see the file
- * <mit-copyright.h>.
- *
- * Include file for the Data Encryption Standard library.
- */
-
-/* only do the whole thing once */
-#ifndef DES_DEFS
-#define DES_DEFS
-
-#include "k5-int.h"
-
-#ifndef DES_INT32
-#ifdef SIZEOF_INT
-#if SIZEOF_INT >= 4
-#define DES_INT32 int
-#else
-#define DES_INT32 long
-#endif
-#else /* !defined(SIZEOF_INT) */
-#include <limits.h>
-#if (UINT_MAX >= 0xffffffff)
-#define DES_INT32 int
-#else
-#define DES_INT32 long
-#endif
-#endif /* !defined(SIZEOF_INT) */
-#endif /* !defined(DES_INT32) */
-
-#ifndef DES_UINT32
-#define DES_UINT32 unsigned DES_INT32
-#endif
-
-#ifndef NCOMPAT
-#define C_Block des_cblock
-#define Key_schedule des_key_schedule
-#define ENCRYPT DES_ENCRYPT
-#define DECRYPT DES_DECRYPT
-#define KEY_SZ DES_KEY_SZ
-#define string_to_key des_string_to_key
-#define read_pw_string des_read_pw_string
-#define random_key des_random_key
-#define pcbc_encrypt des_pcbc_encrypt
-#define key_sched des_key_sched
-#define cbc_encrypt des_cbc_encrypt
-#define cbc_cksum des_cbc_cksum
-#define C_Block_print des_cblock_print
-#define quad_cksum des_quad_cksum
-typedef struct des_ks_struct bit_64;
-#endif
-
-#define des_cblock_print(x) des_cblock_print_file(x, stdout)
-
-#endif /* DES_DEFS */
* Private include file for the Data Encryption Standard library.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
/* only do the whole thing once */
#ifndef DES_INTERNAL_DEFS
#define DES_INTERNAL_DEFS
/* afsstring2key.c */
extern krb5_error_code mit_afs_string_to_key
- PROTOTYPE((const krb5_encrypt_block FAR *eblock,
- krb5_keyblock FAR *keyblock,
+ PROTOTYPE((krb5_keyblock FAR *keyblock,
const krb5_data FAR *data,
const krb5_data FAR *salt));
*/
-#include "k5-int.h"
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "des_int.h"
#include "com_err.h"
-extern int errno;
-extern mit_des_ecb_encrypt();
-
#include <stdio.h>
-
void convert PROTOTYPE((char *, unsigned char []));
void des_cblock_print_file PROTOTYPE((mit_des_cblock, FILE *));
+char zeroblock[8] = {0,0,0,0,0,0,0,0};
+
void
main(argc, argv)
int argc;
{
char block1[17], block2[17], block3[17];
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock;
- krb5_context context;
mit_des_cblock key, input, output, output2;
- krb5_error_code retval;
+ mit_des_key_schedule sched;
int num = 0;
+ int retval;
int error = 0;
- /* This is a crock and we know it... We win because
- none of these tests rely on a valid context pointer */
- context = 0;
-
- /* do some initialisation */
- initialize_krb5_error_table();
-
- krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_CRC);
- keyblock.magic = KV5M_KEYBLOCK;
- keyblock.enctype = ENCTYPE_DES_CBC_CRC;
- keyblock.length = sizeof (mit_des_cblock);
- keyblock.contents = (krb5_octet *)key;
while (scanf("%16s %16s %16s", block1, block2, block3) == 3) {
convert(block1, key);
convert(block2, input);
convert(block3, output);
- if (retval = krb5_process_key(context, &eblock,&keyblock)) {
- com_err("des test", retval, "can't process key");
- exit(-1);
+ if (retval = mit_des_key_sched(key, sched)) {
+ fprintf(stderr, "des test: can't process key");
+ exit(1);
}
- mit_des_ecb_encrypt(&input, &output2,
- (struct mit_des_ks_struct *)eblock.priv,1);
+ mit_des_cbc_encrypt(&input, &output2, 8, sched, zeroblock, 1);
if (memcmp((char *)output2, (char *)output, 8)) {
fprintf(stderr,
/*
* Now try decrypting....
*/
- mit_des_ecb_encrypt(&output, &output2,
- (struct mit_des_ks_struct *)eblock.priv,0);
+ mit_des_cbc_encrypt(&output, &output2, 8, sched, zeroblock, 0);
if (memcmp((char *)output2, (char *)input, 8)) {
fprintf(stderr,
error++;
}
- if (retval = krb5_finish_key(context, &eblock)) {
- com_err("des verify", retval, "can't finish key");
- exit(-1);
- }
num++;
}
* Fake out the DES library, for the purposes of testing.
*/
-#include "des.h"
#include "des_int.h"
int
+++ /dev/null
-/*
- * Copyright (c) 1990 Dennis Ferguson. All rights reserved.
- *
- * Commercial use is permitted only if products which are derived from
- * or include this software are made available for purchase and/or use
- * in Canada. Otherwise, redistribution and use in source and binary
- * forms are permitted.
- */
-
-Sorry about the poor quality of installation instructions. Included
-here are replacements for the DES portions of Eric Young's kerberos
-DES library replacement. To use this you will need his distribution.
-Untar the latter and:
-
-(1) Copy all .c and .h files into the distribution directory. This will
- overwrite some files and add others.
-
-(2) Apply the patch included here to set_key.c in the distribution directory.
-
-(3) Edit the Imakefile (or the Makefile) to include the following files
- on the SRCS= line:
-
- des_tables.c ecb_buffer.c make_sched.c
-
- Add the following files to the OBJS= line:
-
- des_tables.o ecb_buffer.o make_sched.o
-
- Add the following file to the CODE= line:
-
- des_tables.h
-
-Recompile and you're done.
-
-The salient differences between this DES and Eric Young's are as follows:
-
-(1) There are no dependencies on byte ordering, the ability to do
- unaligned loads and stores, or any other machine dependencies
- that I know of. There are no #ifdef's. The code could probably
- be made faster by adding such things, but not enough to be worth
- it.
-
-(2) Combined S and P tables are used for the inner loop of the cipher
- routine and the E expansion is computed on the fly, like Eric
- Young's code, but the computation is reordered from the standard
- to save instructions.
-
-(3) The initial and final permutations are table driven, and take
- about the same amount of work as a single round of the inner
- loop (i.e. only about 12% of the work done for an ecb encryption
- is spent in the IP and FP code).
-
-(4) Since NTP (for which this DES was originally implemented) uses
- lots of keys to encrypt small things, the key permutation code
- has been well worked over and is quite speedy (the amount of
- work required to permute a key is on the order of that required
- to do a single ECB encryption, more or less).
-
-(5) Since the code required to do an ECB encryption using the tables
- is actually fairly compact, even with lots of inlining, it was
- implemented as a macro and is expanded in situ where needed.
-
-On the one machine I ran a comparison on this code ran 80% faster than
-Eric's, compiled into a slightly smaller space, and did pass destest.
-I suspect this stuff is also faster, and not a lot larger, than the
-library MIT doesn't export with kerberos. You mileage may vary.
-
-The silly copyright was a (probably ineffective) afterthought. If it
-really inconveniences you give me a call.
+++ /dev/null
-/*
- * Copyright (c) 1990 Dennis Ferguson. All rights reserved.
- *
- * Commercial use is permitted only if products which are derived from
- * or include this software are made available for purchase and/or use
- * in Canada. Otherwise, redistribution and use in source and binary
- * forms are permitted.
- */
-
-/*
- * des_ecb_encrypt.c - do an encryption in ECB mode
- */
-#include "des_int.h"
-#include "f_tables.h"
-
-/*
- * des_ecb_encrypt - {en,de}crypt a block in ECB mode
- */
-int
-mit_des_ecb_encrypt(in, out, schedule, encrypt)
- const mit_des_cblock *in;
- mit_des_cblock *out;
- mit_des_key_schedule schedule;
- int encrypt;
-{
- register unsigned DES_INT32 left, right;
- register unsigned DES_INT32 temp;
- register int i;
-
- {
- /*
- * Need a temporary for copying the data in
- */
- register unsigned char *datap;
-
- /*
- * Copy the input block into the registers
- */
- datap = (unsigned char *)in;
- GET_HALF_BLOCK(left, datap);
- GET_HALF_BLOCK(right, datap);
- }
-
- /*
- * Do the initial permutation.
- */
- DES_INITIAL_PERM(left, right, temp);
-
- /*
- * Now the rounds. Use different code depending on whether it
- * is an encryption or a decryption (gross, should keep both
- * sets of keys in the key schedule instead).
- */
- if (encrypt) {
- register unsigned DES_INT32 *kp;
-
- kp = (unsigned DES_INT32 *)schedule;
- for (i = 0; i < 8; i++) {
- DES_SP_ENCRYPT_ROUND(left, right, temp, kp);
- DES_SP_ENCRYPT_ROUND(right, left, temp, kp);
- }
- } else {
- register unsigned DES_INT32 *kp;
-
- /*
- * Point kp past end of schedule
- */
- kp = ((unsigned DES_INT32 *)schedule) + (2 * 16);;
- for (i = 0; i < 8; i++) {
- DES_SP_DECRYPT_ROUND(left, right, temp, kp);
- DES_SP_DECRYPT_ROUND(right, left, temp, kp);
- }
- }
-
- /*
- * Do the final permutation
- */
- DES_FINAL_PERM(left, right, temp);
-
- /*
- * Finally, copy the result out a byte at a time
- */
- {
- register unsigned char *datap;
-
- datap = (unsigned char *)out;
- PUT_HALF_BLOCK(left, datap);
- PUT_HALF_BLOCK(right, datap);
- }
-
- /*
- * return nothing
- */
- return (0);
-}
+++ /dev/null
-/*
- * Copyright (c) 1990 Dennis Ferguson. All rights reserved.
- *
- * Commercial use is permitted only if products which are derived from
- * or include this software are made available for purchase and/or use
- * in Canada. Otherwise, redistribution and use in source and binary
- * forms are permitted.
- */
-
-/*
- * des_pcbc_encrypt.c - encrypt a string of characters in error propagation mode
- */
-#include "des_int.h"
-#include "f_tables.h"
-
-/*
- * des_pcbc_encrypt - {en,de}crypt a stream in PCBC mode
- */
-int
-mit_des_pcbc_encrypt(in, out, length, schedule, ivec, encrypt)
- mit_des_cblock *in;
- mit_des_cblock *out;
- long length;
- mit_des_key_schedule schedule;
- mit_des_cblock ivec;
- int encrypt;
-{
- register unsigned DES_INT32 left, right;
- register unsigned DES_INT32 temp;
- register unsigned DES_INT32 *kp;
- register unsigned char *ip, *op;
-
- /*
- * Copy the key pointer, just once
- */
- kp = (unsigned DES_INT32 *)schedule;
-
- /*
- * Deal with encryption and decryption separately.
- */
- if (encrypt) {
- register unsigned DES_INT32 plainl;
- register unsigned DES_INT32 plainr;
-
- /*
- * Initialize left and right with the contents of the initial
- * vector.
- */
- ip = (unsigned char *)ivec;
- GET_HALF_BLOCK(left, ip);
- GET_HALF_BLOCK(right, ip);
-
- /*
- * Suitably initialized, now work the length down 8 bytes
- * at a time.
- */
- ip = (unsigned char *)in;
- op = (unsigned char *)out;
- while (length > 0) {
- /*
- * Get block of input. If the length is
- * greater than 8 this is straight
- * forward. Otherwise we have to fart around.
- */
- if (length > 8) {
- GET_HALF_BLOCK(plainl, ip);
- GET_HALF_BLOCK(plainr, ip);
- left ^= plainl;
- right ^= plainr;
- length -= 8;
- } else {
- /*
- * Oh, shoot. We need to pad the
- * end with zeroes. Work backwards
- * to do this. We know this is the
- * last block, though, so we don't have
- * to save the plain text.
- */
- ip += (int) length;
- switch(length) {
- case 8:
- right ^= *(--ip) & FF_UINT32;
- case 7:
- right ^= (*(--ip) & FF_UINT32) << 8;
- case 6:
- right ^= (*(--ip) & FF_UINT32) << 16;
- case 5:
- right ^= (*(--ip) & FF_UINT32) << 24;
- case 4:
- left ^= *(--ip) & FF_UINT32;
- case 3:
- left ^= (*(--ip) & FF_UINT32) << 8;
- case 2:
- left ^= (*(--ip) & FF_UINT32) << 16;
- case 1:
- left ^= (*(--ip) & FF_UINT32) << 24;
- break;
- }
- length = 0;
- }
-
- /*
- * Encrypt what we have
- */
- DES_DO_ENCRYPT(left, right, temp, kp);
-
- /*
- * Copy the results out
- */
- PUT_HALF_BLOCK(left, op);
- PUT_HALF_BLOCK(right, op);
-
- /*
- * Xor with the old plain text
- */
- left ^= plainl;
- right ^= plainr;
- }
- } else {
- /*
- * Decrypting is harder than encrypting because of
- * the necessity of remembering a lot more things.
- * Should think about this a little more...
- */
- unsigned DES_INT32 ocipherl, ocipherr;
- unsigned DES_INT32 cipherl, cipherr;
-
- if (length <= 0)
- return 0;
-
- /*
- * Prime the old cipher with ivec.
- */
- ip = (unsigned char *)ivec;
- GET_HALF_BLOCK(ocipherl, ip);
- GET_HALF_BLOCK(ocipherr, ip);
-
- /*
- * Now do this in earnest until we run out of length.
- */
- ip = (unsigned char *)in;
- op = (unsigned char *)out;
- for (;;) { /* check done inside loop */
- /*
- * Read a block from the input into left and
- * right. Save this cipher block for later.
- */
- GET_HALF_BLOCK(left, ip);
- GET_HALF_BLOCK(right, ip);
- cipherl = left;
- cipherr = right;
-
- /*
- * Decrypt this.
- */
- DES_DO_DECRYPT(left, right, temp, kp);
-
- /*
- * Xor with the old cipher to get plain
- * text. Output 8 or less bytes of this.
- */
- left ^= ocipherl;
- right ^= ocipherr;
- if (length > 8) {
- length -= 8;
- PUT_HALF_BLOCK(left, op);
- PUT_HALF_BLOCK(right, op);
- /*
- * Save current cipher block here
- */
- ocipherl = cipherl ^ left;
- ocipherr = cipherr ^ right;
- } else {
- /*
- * Trouble here. Start at end of output,
- * work backwards.
- */
- op += (int) length;
- switch(length) {
- case 8:
- *(--op) = (unsigned char) (right & 0xff);
- case 7:
- *(--op) = (unsigned char) ((right >> 8) & 0xff);
- case 6:
- *(--op) = (unsigned char) ((right >> 16) & 0xff);
- case 5:
- *(--op) = (unsigned char) ((right >> 24) & 0xff);
- case 4:
- *(--op) = (unsigned char) (left & 0xff);
- case 3:
- *(--op) = (unsigned char) ((left >> 8) & 0xff);
- case 2:
- *(--op) = (unsigned char) ((left >> 16) & 0xff);
- case 1:
- *(--op) = (unsigned char) ((left >> 24) & 0xff);
- break;
- }
- break; /* we're done */
- }
- }
- }
-
- /*
- * Done, return nothing.
- */
- return 0;
-}
+++ /dev/null
-/*
- * lib/crypto/des/fin_rndkey.c
- *
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
- * Copyright 1996 by Lehman Brothers, Inc.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. or Lehman Brothers not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. M.I.T. and Lehman Brothers
- * make no representations about the suitability of this software for
- * any purpose. It is provided "as is" without express or implied
- * warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-/*
- free any resources held by "seed" and assigned by init_random_key()
- */
-
-krb5_error_code mit_des_finish_random_key (eblock, p_state)
- const krb5_encrypt_block * eblock;
- krb5_pointer * p_state;
-{
- mit_des_random_state * state = *p_state;
-
- if (! state) return 0;
-
- if (state->sequence.data) {
- memset((char *)state->sequence.data, 0, state->sequence.length);
- krb5_xfree(state->sequence.data);
- }
-
- mit_des_finish_key(&state->eblock);
-
- krb5_xfree(state);
- *p_state = 0;
- return 0;
-}
+++ /dev/null
-/*
- * lib/crypto/des/finish_key.c
- *
- * Copyright 1990 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- *
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-/*
- does any necessary clean-up on the eblock (such as releasing
- resources held by eblock->priv).
-
- returns: errors
- */
-
-krb5_error_code
-mit_des_finish_key (eblock)
- krb5_encrypt_block FAR * eblock;
-{
- if (eblock->priv) {
- memset((char *)eblock->priv, 0, (size_t) eblock->priv_size);
- free(eblock->priv);
- }
- eblock->priv = 0;
- eblock->priv_size = 0;
- /* free/clear other stuff here? */
- return 0;
-}
+++ /dev/null
-/*
- * lib/crypto/des/init_rkey.c
- *
- * Copyright 1990 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-/*
- initialize the random key generator using the encryption key,
- "seedblock", and allocating private sequence information, filling
- in "seed" with the address of such information.
- "seed" is later passed to the random_key() function to provide
- sequence information.
- */
-
-#ifndef min
-#define min(a,b) (((a) > (b)) ? (b) : (a))
-#endif
-
-krb5_error_code
-mit_des_init_random_key (eblock, seedblock, state)
- const krb5_encrypt_block * eblock;
- const krb5_keyblock * seedblock;
- krb5_pointer * state;
-{
- mit_des_random_state * p_state = 0;
- krb5_keyblock *new_key;
- krb5_enctype enctype = eblock->crypto_entry->proto_enctype;
- krb5_error_code kret = 0;
- krb5_address **addrs = 0;
- krb5_data seed;
- krb5_int32 now;
- krb5_int32 unow;
- unsigned char *cp;
-
- switch (enctype)
- {
- case ENCTYPE_DES_CBC_CRC:
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- enctype = ENCTYPE_DES_CBC_RAW;
- break;
-
- case ENCTYPE_DES3_CBC_SHA:
- case ENCTYPE_DES3_CBC_RAW:
- enctype = ENCTYPE_DES3_CBC_RAW;
- break;
-
- default:
- return KRB5_BAD_ENCTYPE;
- }
-
- p_state = (mit_des_random_state *) malloc(sizeof(mit_des_random_state));
- *state = (krb5_pointer) p_state;
-
- if (! p_state) {
- kret = ENOMEM;
- goto cleanup;
- }
-
- memset(p_state, 0, sizeof(*p_state));
- p_state->eblock.crypto_entry = krb5_enctype_array[enctype]->system;
- p_state->sequence.length = p_state->eblock.crypto_entry->keysize;
- p_state->sequence.data = (krb5_pointer) malloc(p_state->sequence.length);
-
- if (! p_state->sequence.data) {
- kret = ENOMEM;
- goto cleanup;
- }
-
- /*
- * Generate a temporary value that is based on the
- * input seed and the hostid (sequence number)
- * such that it gives no useful information about the input.
- *
- * Then use the temporary value as the new seed and the current
- * time as a sequence number to give us a stream that was not
- * previously used.
- *
- * This result will be the seed for the random number stream
- * (the sequence number will start at zero).
- */
-
- /* seed = input */
- seed.data = seedblock->contents;
- seed.length = seedblock->length;
- kret = mit_des_set_random_generator_seed(&seed, p_state);
- if (kret) goto cleanup;
-
- /* sequence = hostid */
- if (!krb5_crypto_os_localaddr(&addrs) && addrs && *addrs) {
- memcpy((char *)p_state->sequence.data, (char *)addrs[0]->contents,
- min(p_state->sequence.length, addrs[0]->length));
- /* XXX may not do all of the sequence number. */
- }
- if (addrs) {
- /* can't use krb5_free_addresses due to circular dependencies in
- libraries */
- register krb5_address **addr2;
- for (addr2 = addrs; *addr2; addr2++) {
- krb5_xfree((*addr2)->contents);
- krb5_xfree(*addr2);
- }
- krb5_xfree(addrs);
- }
-
- /* tmp.seed = random(input,hostid) */
- kret = mit_des_random_key(NULL, p_state, &new_key);
- if (kret) goto cleanup;
- seed.data = new_key->contents;
- seed.length = new_key->length;
- kret = mit_des_set_random_generator_seed(&seed, p_state);
- (void) memset(new_key->contents, 0, new_key->length);
- krb5_xfree(new_key->contents);
- krb5_xfree(new_key);
- if (kret) goto cleanup;
-
- /* sequence = time */
- (void) krb5_crypto_us_timeofday(&now, &unow);
- cp = p_state->sequence.data;
- *cp++ = (now >> 24) & 0xff;
- *cp++ = (now >> 16) & 0xff;
- *cp++ = (now >> 8) & 0xff;
- *cp++ = now & 0xff;
- *cp++ = (unow >> 24) & 0xff;
- *cp++ = (unow >> 16) & 0xff;
- *cp++ = (unow >> 8) & 0xff;
- *cp++ = unow &0xff;
-
- /* seed = random(tmp.seed, time) */
- kret = mit_des_random_key(NULL, p_state, &new_key);
- if (kret) goto cleanup;
- seed.data = new_key->contents;
- seed.length = new_key->length;
- kret = mit_des_set_random_generator_seed(&seed, p_state);
- (void) memset(new_key->contents, 0, new_key->length);
- krb5_xfree(new_key->contents);
- krb5_xfree(new_key);
- if (kret) goto cleanup;
-
- return 0;
-
-cleanup:
- if (kret)
- mit_des_finish_random_key(eblock, state);
- return kret;
-}
+++ /dev/null
-/*
- * lib/crypto/des/process_ky.c
- *
- * Copyright 1990 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-/*
- does any necessary key preprocessing (such as computing key
- schedules for DES).
- eblock->crypto_entry must be set by the caller; the other elements
- of eblock are to be assigned by this function.
- [in particular, eblock->key must be set by this function if the key
- is needed in raw form by the encryption routine]
-
- The caller may not move or reallocate "keyblock" before calling
- finish_key on "eblock"
-
- returns: errors
- */
-
-krb5_error_code
-mit_des_process_key (eblock, keyblock)
- krb5_encrypt_block * eblock;
- const krb5_keyblock * keyblock;
-{
- struct mit_des_ks_struct *schedule; /* pointer to key schedules */
-
- if (keyblock->length != sizeof (mit_des_cblock))
- return KRB5_BAD_KEYSIZE;
-
- if ( !(schedule = (struct mit_des_ks_struct *) malloc(sizeof(mit_des_key_schedule))) )
- return ENOMEM;
-#define cleanup() { free( (char *) schedule); }
-
- switch (mit_des_key_sched (keyblock->contents, schedule)) {
- case -1:
- cleanup();
- return KRB5DES_BAD_KEYPAR;
-
- case -2:
- cleanup();
- return KRB5DES_WEAK_KEY;
-
- default:
- eblock->key = (krb5_keyblock *) keyblock;
- eblock->priv = (krb5_pointer) schedule;
- eblock->priv_size = (krb5_int32) sizeof(mit_des_key_schedule);
- return 0;
- }
-}
+++ /dev/null
-/*
- * lib/crypto/des/random_key.c
- *
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
- * Copyright 1996 by Lehman Brothers, Inc.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. or Lehman Brothers not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. M.I.T. and Lehman Brothers
- * make no representations about the suitability of this software for
- * any purpose. It is provided "as is" without express or implied
- * warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-static void mit_des_generate_random_key
- PROTOTYPE((mit_des_random_state * state, krb5_keyblock * randkey));
-
-
-/*
- generate a random encryption key, allocating storage for it and
- filling in the keyblock address in *keyblock
- */
-
-krb5_error_code
-mit_des_random_key (eblock, state, keyblock)
- const krb5_encrypt_block * eblock;
- krb5_pointer state;
- krb5_keyblock ** keyblock;
-{
- krb5_keyblock *randkey;
- int keysize = ((mit_des_random_state *)state)->eblock.crypto_entry->keysize;
-
- if (eblock == NULL)
- /* We are being called from the random number initialization routine */
- eblock = &((mit_des_random_state *)state)->eblock;
-
- if (!(randkey = (krb5_keyblock *)malloc(sizeof(*randkey))))
- return ENOMEM;
- if (!(randkey->contents = (krb5_octet *)malloc(keysize))) {
- krb5_xfree(randkey);
- return ENOMEM;
- }
- randkey->magic = KV5M_KEYBLOCK;
- randkey->length = keysize;
- randkey->enctype = eblock->crypto_entry->proto_enctype;
-
- do {
- mit_des_generate_random_key(state, randkey);
- mit_des_fixup_keyblock_parity(randkey);
- } while (mit_des_is_weak_keyblock(randkey));
-
- *keyblock = randkey;
- return 0;
-}
-
-static mit_des_cblock zero_ivec = { 0, 0, 0, 0, 0, 0, 0, 0 };
-
-static void
-mit_des_generate_random_key(state, randkey)
- mit_des_random_state * state;
- krb5_keyblock * randkey;
-{
- krb5_encrypt_block *eblock = &state->eblock;
- int i;
-
- (* state->eblock.crypto_entry->encrypt_func)
- (state->sequence.data /*in*/, randkey->contents /*out*/,
- state->sequence.length, eblock, zero_ivec);
- if (state->sequence.length > sizeof(mit_des_cblock))
- (* state->eblock.crypto_entry->encrypt_func)
- (randkey->contents /*in*/, randkey->contents /*out*/,
- randkey->length, eblock,
- randkey->contents + randkey->length - sizeof(mit_des_cblock));
-
- /* Increment the sequence number, with wraparound (LSB) */
- for (i = 0; i < state->sequence.length; i++) {
- state->sequence.data[i] = (state->sequence.data[i] + 1) & 0xff;
- if (state->sequence.data[i])
- break;
- }
-}
* or implied warranty.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "des_int.h"
*/
krb5_error_code
-mit_des_string_to_key (eblock, keyblock, data, salt)
-const krb5_encrypt_block FAR * eblock;
+mit_des_string_to_key_int (keyblock, data, salt)
krb5_keyblock FAR * keyblock;
const krb5_data FAR * data;
const krb5_data FAR * salt;
register char *p_char;
char k_char[64];
mit_des_key_schedule key_sked;
- krb5_enctype enctype = eblock->crypto_entry->proto_enctype;
#ifndef min
#define min(A, B) ((A) < (B) ? (A): (B))
#endif
- if ((enctype != ENCTYPE_DES_CBC_CRC) && (enctype != ENCTYPE_DES_CBC_MD4) &&
- (enctype != ENCTYPE_DES_CBC_MD5) && (enctype != ENCTYPE_DES_CBC_RAW))
- return (KRB5_PROG_ETYPE_NOSUPP);
-
- if ( !(keyblock->contents = (krb5_octet *)malloc(sizeof(mit_des_cblock))) )
- return(ENOMEM);
-
keyblock->magic = KV5M_KEYBLOCK;
keyblock->length = sizeof(mit_des_cblock);
- keyblock->enctype = eblock->crypto_entry->proto_enctype;
key = keyblock->contents;
if (salt) {
if (salt->length == -1) {
/* cheat and do AFS string2key instead */
- return mit_afs_string_to_key (eblock, keyblock, data, salt);
+ return mit_afs_string_to_key (keyblock, data, salt);
} else
length = data->length + salt->length;
}
+++ /dev/null
-/*
- * lib/crypto/des/t_random.c
- *
- * Copyright 1996 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- *
- * Test a DES implementation against known inputs & outputs
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-#include <stdio.h>
-#include "com_err.h"
-
-extern krb5_cryptosystem_entry mit_des_cryptosystem_entry;
-
-char *progname;
-int nflag = 2;
-int vflag;
-int mflag;
-int zflag;
-int pid;
-int mit_des_debug;
-
-krb5_data kdata;
-
-unsigned char key2[8] = { 0x08,0x19,0x2a,0x3b,0x4c,0x5d,0x6e,0x7f };
-unsigned char zerokey[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
-
-void print_key(key)
- krb5_keyblock *key;
-{
- int i;
-
- printf("key type: %d, length = %d, contents =", key->enctype,
- key->length);
- for (i=0; i < key->length; i++) {
- printf(" %02x", key->contents[i]);
- }
- printf("\n");
-}
-
-/*
- * Can also add :
- * plaintext = 0, key = 0, cipher = 0x8ca64de9c1b123a7 (or is it a 1?)
- */
-
-void
-main(argc,argv)
- int argc;
- char *argv[];
-{
- /* Local Declarations */
- krb5_context context;
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock, *randkey;
- void *random_seed = 0;
-
-#ifdef WINDOWS
- /* Set screen window buffer to infinite size -- MS default is tiny. */
- _wsetscreenbuf (fileno (stdout), _WINBUFINF);
-#endif
-
- /* do some initialisation */
- krb5_init_context(&context);
-
- krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_CRC);
- keyblock.enctype = ENCTYPE_DES_CBC_CRC;
- keyblock.length = sizeof(mit_des_cblock);
-
- keyblock.contents = key2;
-
- printf("init_random: ");
- print_key(&keyblock);
- krb5_init_random_key(context, &eblock, &keyblock, &random_seed);
- krb5_random_key(context, &eblock, random_seed, &randkey);
- print_key(randkey);
- krb5_free_keyblock(context, randkey);
- krb5_random_key(context, &eblock, random_seed, &randkey);
- print_key(randkey);
- krb5_free_keyblock(context, randkey);
- krb5_finish_random_key(context, &eblock, &random_seed);
-
- keyblock.contents = zerokey;
-
- printf("\n\ninit_random: ");
- print_key(&keyblock);
-
- krb5_init_random_key(context, &eblock, &keyblock, &random_seed);
- krb5_random_key(context, &eblock, random_seed, &randkey);
- print_key(randkey);
- krb5_free_keyblock(context, randkey);
- krb5_random_key(context, &eblock, random_seed, &randkey);
- print_key(randkey);
- krb5_free_keyblock(context, randkey);
- krb5_finish_random_key(context, &eblock, &random_seed);
-
- krb5_free_context(context);
-}
-
* -1 ==> error
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "des_int.h"
#include <stdio.h>
#include "com_err.h"
-extern krb5_cryptosystem_entry mit_des_cryptosystem_entry;
-
char *progname;
int nflag = 2;
int vflag;
int pid;
int mit_des_debug;
-krb5_encrypt_block eblock;
-krb5_keyblock keyblock;
-krb5_data kdata;
-
unsigned char cipher_text[64];
unsigned char clear_text[64] = "Now is the time for all " ;
unsigned char clear_text2[64] = "7654321 Now is the time for ";
unsigned char msb_text[8] = {0x0,0,0,0, 0,0,0,0x40}; /* to ANSI MSB */
unsigned char *input;
-unsigned char *nfold_in[] = {
- "basch",
- "eichin",
- "sommerfeld",
- "MASSACHVSETTS INSTITVTE OF TECHNOLOGY" };
-
-unsigned char nfold_192[4][24] = {
- { 0x1a, 0xab, 0x6b, 0x42, 0x96, 0x4b, 0x98, 0xb2, 0x1f, 0x8c, 0xde, 0x2d,
- 0x24, 0x48, 0xba, 0x34, 0x55, 0xd7, 0x86, 0x2c, 0x97, 0x31, 0x64, 0x3f },
- { 0x65, 0x69, 0x63, 0x68, 0x69, 0x6e, 0x4b, 0x73, 0x2b, 0x4b, 0x1b, 0x43,
- 0xda, 0x1a, 0x5b, 0x99, 0x5a, 0x58, 0xd2, 0xc6, 0xd0, 0xd2, 0xdc, 0xca },
- { 0x2f, 0x7a, 0x98, 0x55, 0x7c, 0x6e, 0xe4, 0xab, 0xad, 0xf4, 0xe7, 0x11,
- 0x92, 0xdd, 0x44, 0x2b, 0xd4, 0xff, 0x53, 0x25, 0xa5, 0xde, 0xf7, 0x5c },
- { 0xdb, 0x3b, 0x0d, 0x8f, 0x0b, 0x06, 0x1e, 0x60, 0x32, 0x82, 0xb3, 0x08,
- 0xa5, 0x08, 0x41, 0x22, 0x9a, 0xd7, 0x98, 0xfa, 0xb9, 0x54, 0x0c, 0x1b }
-};
-
/* 0x0123456789abcdef */
unsigned char default_key[8] = {
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef
unsigned char *ivec;
unsigned char zero_key[8] = {1,1,1,1,1,1,1,1}; /* just parity bits */
int i,j;
-krb5_error_code retval;
unsigned char cipher1[8] = {
0x25,0xdd,0xac,0x3e,0x96,0x17,0x64,0x67
* plaintext = 0, key = 0, cipher = 0x8ca64de9c1b123a7 (or is it a 1?)
*/
-void
+mit_des_key_schedule sched;
+
+int
main(argc,argv)
int argc;
char *argv[];
{
/* Local Declarations */
- krb5_context context;
- int in_length;
+ int in_length, retval;
void do_encrypt();
void do_decrypt();
}
/* do some initialisation */
- initialize_krb5_error_table();
- krb5_init_context(&context);
-
- krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_CRC);
- keyblock.enctype = ENCTYPE_DES_CBC_CRC;
- keyblock.length = sizeof(mit_des_cblock);
/* use known input and key */
/* ECB zero text zero key */
if (zflag) {
input = zero_text;
- keyblock.contents = (krb5_octet *)zero_key;
- if (retval = krb5_process_key(context, &eblock,&keyblock)) {
- com_err("des verify", retval, "can't process zero key");
- exit(-1);
- }
+ mit_des_key_sched(zero_key, sched);
printf("plaintext = key = 0, cipher = 0x8ca64de9c1b123a7\n");
do_encrypt(input,cipher_text);
printf("\tcipher = (low to high bytes)\n\t\t");
printf("%02x ",cipher_text[j]);
printf("\n");
do_decrypt(output,cipher_text);
- if (retval = krb5_finish_key(context, &eblock)) {
- com_err("des verify", retval, "can't finish zero key");
- exit(-1);
- }
if ( memcmp((char *)cipher_text, (char *)zresult, 8) ) {
printf("verify: error in zero key test\n");
exit(-1);
}
- krb5_free_context(context);
exit(0);
}
if (mflag) {
input = msb_text;
- keyblock.contents = (krb5_octet *)key3;
- if (retval = krb5_process_key(context, &eblock,&keyblock)) {
- com_err("des verify", retval, "can't process key3");
- exit(-1);
- }
+ mit_des_key_sched(key3, sched);
printf("plaintext = 0x00 00 00 00 00 00 00 40, ");
printf("key = 0x80 01 01 01 01 01 01 01\n");
printf(" cipher = 0xa380e02a6be54696\n");
}
printf("\n");
do_decrypt(output,cipher_text);
- if (retval = krb5_finish_key(context, &eblock)) {
- com_err("des verify", retval, "can't finish key3");
- exit(-1);
- }
if ( memcmp((char *)cipher_text, (char *)mresult, 8) ) {
printf("verify: error in msb test\n");
exit(-1);
}
- krb5_free_context(context);
exit(0);
}
/* ECB mode Davies and Price */
{
input = zero_text;
- keyblock.contents = (krb5_octet *)key2;
- if (retval = krb5_process_key(context, &eblock,&keyblock)) {
- com_err("des verify", retval, "can't process key2");
- exit(-1);
- }
+ mit_des_key_sched(key2, sched);
printf("Examples per FIPS publication 81, keys ivs and cipher\n");
printf("in hex. These are the correct answers, see below for\n");
printf("the actual answers.\n\n");
printf("%02x ",cipher_text[j]);
printf("\n\n");
do_decrypt(output,cipher_text);
- if (retval = krb5_finish_key(context, &eblock)) {
- com_err("des verify", retval, "can't finish key2");
- exit(-1);
- }
if ( memcmp((char *)cipher_text, (char *)cipher1, 8) ) {
printf("verify: error in ECB encryption\n");
exit(-1);
/* ECB mode */
{
- keyblock.contents = (krb5_octet *)default_key;
- if (retval = krb5_process_key(context, &eblock,&keyblock)) {
- com_err("des verify", retval, "can't process key2");
- exit(-1);
- }
+ mit_des_key_sched(default_key, sched);
input = clear_text;
ivec = default_ivec;
printf("EXAMPLE ECB\tkey = 0123456789abcdef\n");
if (retval = mit_des_cbc_encrypt((mit_des_cblock *) input,
(mit_des_cblock *) cipher_text,
(size_t) in_length,
- (struct mit_des_ks_struct *)eblock.priv,
+ sched,
ivec,
MIT_DES_ENCRYPT)) {
com_err("des verify", retval, "can't encrypt");
exit(-1);
}
printf("\tciphertext = (low to high bytes)\n");
- for (i = 0; i <= 7; i++) {
+ for (i = 0; i <= 2; i++) {
printf("\t\t");
for (j = 0; j <= 7; j++) {
printf("%02x ",cipher_text[i*8+j]);
if (retval = mit_des_cbc_encrypt((mit_des_cblock *) cipher_text,
(mit_des_cblock *) clear_text,
(size_t) in_length,
- eblock.priv,
+ sched,
ivec,
MIT_DES_DECRYPT)) {
com_err("des verify", retval, "can't decrypt");
printf("or some part thereof\n");
input = clear_text2;
mit_des_cbc_cksum(input,cipher_text,(long) strlen((char *)input),
- eblock.priv,ivec);
+ sched,ivec);
printf("ACTUAL CBC checksum\n");
printf("\t\tencrypted cksum = (low to high bytes)\n\t\t");
for (j = 0; j<=7; j++)
printf("%02x ",cipher_text[j]);
printf("\n\n");
- if (retval = krb5_finish_key(context, &eblock)) {
- com_err("des verify", retval, "can't finish key2");
- exit(-1);
- }
if ( memcmp((char *)cipher_text, (char *)checksum, 8) ) {
printf("verify: error in CBC cheksum\n");
exit(-1);
else
printf("verify: CBC checksum is correct\n\n");
- printf("N-fold\n");
- for (i=0; i<sizeof(nfold_in)/sizeof(char *); i++) {
- kdata.data = nfold_in[i];
- kdata.length = strlen(kdata.data);
- printf("\tInput:\t\"%.*s\"\n", kdata.length, kdata.data);
- printf("\t192-Fold:\t");
- mit_des_n_fold(kdata.data, kdata.length, cipher_text, 24);
- for (j=0; j<24; j++)
- printf("%s%02x", (j&3) ? "" : " ", cipher_text[j]);
- printf("\n");
- if (memcmp(cipher_text, nfold_192[i], 24)) {
- printf("verify: error in n-fold\n");
- exit(-1);
- };
- }
- printf("verify: N-fold is correct\n\n");
-
- krb5_free_context(context);
-
exit(0);
}
char *out;
{
for (i =1; i<=nflag; i++) {
- mit_des_ecb_encrypt((mit_des_cblock *)in,
+ mit_des_cbc_encrypt((mit_des_cblock *)in,
(mit_des_cblock *)out,
- (struct mit_des_ks_struct *)eblock.priv,
+ 8,
+ sched,
+ zero_text,
MIT_DES_ENCRYPT);
if (mit_des_debug) {
printf("\nclear %s\n",in);
/* try to invert it */
{
for (i =1; i<=nflag; i++) {
- mit_des_ecb_encrypt((mit_des_cblock *)out,
+ mit_des_cbc_encrypt((mit_des_cblock *)out,
(mit_des_cblock *)in,
- (struct mit_des_ks_struct *)eblock.priv,
+ 8,
+ sched,
+ zero_text,
MIT_DES_DECRYPT);
if (mit_des_debug) {
printf("clear %s\n",in);
* Fake out the DES library, for the purposes of testing.
*/
-#include "des.h"
-
int
mit_des_is_weak_key(key)
mit_des_cblock key;
+++ /dev/null
-/*
- * Copyright 1995 by Richard P. Basch. All Rights Reserved.
- * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- *
- * N-folding algorithm
- * Described in "A Better Key Schedule for DES-like Ciphers"
- * by Uri Blumenthal and Steven M. Bellovin
- * based on the work done by Lars Knudsen.
- *
- * To n-fold a number X, replicate the input value X to a length that is
- * the least common multiple of n and the length of X. Before each
- * repetition, the input value is rotated to the right by 13 bit positions.
- * The successive n-bit chunks are added together using 1's complement
- * addition (addition with end-around carry) to yield a n-bit result.
- *
- * The algorithm here assumes that the input and output are padded to
- * octet boundaries (8-bit multiple).
- */
-
-#include "k5-int.h"
-
-#define ROTATE_VALUE 13
-
-krb5_error_code
-mit_des_n_fold(inbuf, inlen, outbuf, outlen)
- krb5_octet *inbuf;
- size_t inlen;
- krb5_octet *outbuf;
- size_t outlen;
-{
- register int bytes;
- register krb5_octet *tempbuf;
-
- if (inbuf == (krb5_octet *)NULL)
- return EINVAL;
- if (outbuf == (krb5_octet *)NULL)
- return EINVAL;
-
- tempbuf = (krb5_octet *)malloc(inlen);
- if (tempbuf == (krb5_octet *)NULL)
- return ENOMEM;
-
- memset(outbuf, 0, outlen);
- bytes = 0;
-
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
- do {
- unsigned int j, k;
-
- /* Rotate input */
- k = ((bytes/inlen) * ROTATE_VALUE) % (inlen*8);
- for (j = (k+7)/8; j < inlen + (k+7)/8; j++)
- tempbuf[j % inlen] =
- ((inbuf[((8*j-k)/8)%inlen] << ((8-(k&7))&7)) +
- ((k&7) ? (inbuf[((8*j-k)/8 +1)%inlen] >> (k&7)) : 0))
- & 0xff;
-
- for (k=0, j=inlen; j--; ) {
- k += outbuf[(bytes+j) % outlen] + tempbuf[j];
- outbuf[(bytes+j) % outlen] = k & 0xff;
- k >>= 8;
- }
- j = bytes % outlen;
- while (k) {
- if (j == 0)
- j = outlen;
- j--;
- k += outbuf[j];
- outbuf[j] = k & 0xff;
- k >>= 8;
- }
- bytes += inlen;
- } while (bytes % outlen);
-
- free(tempbuf);
-
- return 0;
-}
+++ /dev/null
-/*
- * Copyright 1996 by Richard P. Basch. All Rights Reserved.
- * Copyright 1996 by Lehman Brothers, Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- *
- * Based on the version written by Mark Lillibridge, MIT Project Athena.
- *
- * Under U.S. law, this software may not be exported outside the US
- * without license from the U.S. Commerce department.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-int
-mit_des_is_weak_keyblock(keyblock)
- krb5_keyblock * keyblock;
-{
- int i;
-
- for (i = 0; i < keyblock->length/sizeof(mit_des_cblock); i++)
- if (mit_des_is_weak_key(*((mit_des_cblock *)keyblock->contents + i)))
- return 1;
- return 0;
-}
-
-void
-mit_des_fixup_keyblock_parity(keyblock)
- krb5_keyblock * keyblock;
-{
- int i;
-
- for (i = 0; i < keyblock->length/sizeof(mit_des_cblock); i++)
- mit_des_fixup_key_parity(*((mit_des_cblock *)keyblock->contents + i));
-}
-
-/*
- * mit_des_set_random_generator_seed: this routine is used to select a random
- * number stream. The stream that results is
- * totally determined by the passed in key.
- * (I.e., calling this routine again with the
- * same key allows repeating a sequence of
- * random numbers)
- */
-krb5_error_code
-mit_des_set_random_generator_seed(seed, p_state)
- const krb5_data * seed;
- krb5_pointer p_state;
-{
- krb5_error_code kret;
- register int i;
- mit_des_cblock *new_key;
- mit_des_random_state *state = p_state;
-
- if (state->eblock.key) {
- if (state->eblock.key->contents) {
- memset(state->eblock.key->contents, 0, state->eblock.key->length);
- krb5_xfree(state->eblock.key->contents);
- }
- }
-
- state->eblock.key = (krb5_keyblock *)malloc(sizeof(krb5_keyblock));
- if (! state->eblock.key)
- return ENOMEM;
-
- state->eblock.key->enctype = state->eblock.crypto_entry->proto_enctype;
- state->eblock.key->length = state->eblock.crypto_entry->keysize;
- state->eblock.key->contents = (krb5_octet *)malloc(state->eblock.key->length);
- if (! state->eblock.key->contents) {
- krb5_xfree(state->eblock.key);
- state->eblock.key = 0;
- return ENOMEM;
- }
-
- kret = mit_des_n_fold(seed->data, seed->length,
- state->eblock.key->contents, state->eblock.key->length);
- if (kret) return kret;
-
- mit_des_fixup_keyblock_parity(state->eblock.key);
-
- for (i = 0; i < state->eblock.key->length/sizeof(mit_des_cblock); i++) {
- new_key = (mit_des_cblock *)state->eblock.key->contents + i;
- if (mit_des_is_weak_key(*new_key)) {
- (*new_key)[0] ^= 0xF0;
- mit_des_fixup_key_parity(*new_key);
- }
- }
-
- /* destroy any old key schedule */
- mit_des_finish_key(&state->eblock);
-
- /* compute the key schedule */
- (* state->eblock.crypto_entry->process_key)
- (&state->eblock, state->eblock.key);
-
- /* now we can destroy the key... */
- memset(state->eblock.key->contents, 0, state->eblock.key->length);
- krb5_xfree(state->eblock.key->contents);
- krb5_xfree(state->eblock.key);
- state->eblock.key = (krb5_keyblock *) 0;
-
- /* "seek" to the start of the stream: */
- memset(state->sequence.data, 0, state->sequence.length);
-
- return 0;
-}
-
-krb5_error_code
-mit_des_set_random_sequence_number(sequence, p_state)
- const krb5_data *sequence;
- krb5_pointer p_state;
-{
- mit_des_random_state *state = p_state;
- int length = state->eblock.crypto_entry->keysize;
-
- if (length > sequence->length)
- length = sequence->length;
-
- memcpy(state->sequence.data, sequence->data, length);
-
- return 0;
-}
+++ /dev/null
-/*
- * lib/crypto/des3_raw.c
- *
- * Copyright 1996 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-krb5_error_code mit_des3_raw_encrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-krb5_error_code mit_des3_raw_decrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-static krb5_cryptosystem_entry mit_des3_raw_cryptosystem_entry = {
- 0,
- mit_des3_raw_encrypt_func,
- mit_des3_raw_decrypt_func,
- mit_des3_process_key,
- mit_des_finish_key,
- mit_des3_string_to_key,
- mit_des_init_random_key,
- mit_des_finish_random_key,
- mit_des_random_key,
- sizeof(mit_des_cblock),
- 0,
- sizeof(mit_des3_cblock),
- ENCTYPE_DES3_CBC_RAW
- };
-
-krb5_cs_table_entry krb5_des3_raw_cst_entry = {
- 0,
- &mit_des3_raw_cryptosystem_entry,
- 0
- };
-
-krb5_error_code
-mit_des3_raw_decrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- return (mit_des3_cbc_encrypt((const mit_des_cblock *) in,
- out,
- size,
- (struct mit_des_ks_struct *)key->priv,
- ((struct mit_des_ks_struct *)key->priv) + 1,
- ((struct mit_des_ks_struct *)key->priv) + 2,
- ivec ? ivec : (krb5_pointer)key->key->contents,
- MIT_DES_DECRYPT));
-}
-
-krb5_error_code
-mit_des3_raw_encrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- int sumsize;
-
- /* round up to des block size */
-
- sumsize = krb5_roundup(size, sizeof(mit_des_cblock));
-
- /* assemble crypto input into the output area, then encrypt in place. */
-
- memset((char *)out, 0, sumsize);
- memcpy((char *)out, (char *)in, size);
-
- /* We depend here on the ability of this DES implementation to
- encrypt plaintext to ciphertext in-place. */
- return (mit_des3_cbc_encrypt(out,
- out,
- sumsize,
- (struct mit_des_ks_struct *)key->priv,
- ((struct mit_des_ks_struct *)key->priv) + 1,
- ((struct mit_des_ks_struct *)key->priv) + 2,
- ivec ? ivec : (krb5_pointer)key->key->contents,
- MIT_DES_ENCRYPT));
-}
+++ /dev/null
-/*
- * lib/crypto/des3-sha.c
- *
- * Copyright 1996 by Lehman Brothers, Inc.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Lehman Brothers or M.I.T. not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. Lehman Brothers and
- * M.I.T. make no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "shs.h"
-#include "des_int.h"
-
-
-#define DES3_SHA_CONFOUNDER_SIZE sizeof(mit_des_cblock)
-
-static krb5_error_code
-mit_des3_sha_encrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-static krb5_error_code
-mit_des3_sha_decrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-static mit_des_cblock zero_ivec = { 0 };
-
-static krb5_cryptosystem_entry mit_des3_sha_cryptosystem_entry = {
- 0,
- mit_des3_sha_encrypt_func,
- mit_des3_sha_decrypt_func,
- mit_des3_process_key,
- mit_des_finish_key,
- mit_des3_string_to_key,
- mit_des_init_random_key,
- mit_des_finish_random_key,
- mit_des_random_key,
- sizeof(mit_des_cblock),
- NIST_SHA_CKSUM_LENGTH + DES3_SHA_CONFOUNDER_SIZE,
- sizeof(mit_des3_cblock),
- ENCTYPE_DES3_CBC_SHA
- };
-
-krb5_cs_table_entry krb5_des3_sha_cst_entry = {
- 0,
- &mit_des3_sha_cryptosystem_entry,
- 0
- };
-
-
-static krb5_error_code
-mit_des3_sha_encrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- krb5_checksum cksum;
- krb5_octet contents[NIST_SHA_CKSUM_LENGTH];
- int sumsize;
- krb5_error_code retval;
-
- /* caller passes data size, and saves room for the padding. */
- /* format of ciphertext, per RFC is:
- +-----------+----------+-------------+-----+
- |confounder | check | msg-seq | pad |
- +-----------+----------+-------------+-----+
-
- our confounder is 8 bytes
- our checksum is NIST_SHA_CKSUM_LENGTH
- */
- sumsize = krb5_roundup(size + mit_des3_sha_cryptosystem_entry.pad_minimum,
- mit_des3_sha_cryptosystem_entry.block_length);
-
- /* assemble crypto input into the output area, then encrypt in place. */
-
- memset((char *)out, 0, sumsize);
-
- /* put in the confounder */
- if ((retval = krb5_random_confounder(DES3_SHA_CONFOUNDER_SIZE, out)))
- return retval;
-
- memcpy((char *)out + mit_des3_sha_cryptosystem_entry.pad_minimum,
- (char *)in, size);
-
- cksum.length = sizeof(contents);
- cksum.contents = contents;
-
- /* This is equivalent to krb5_calculate_checksum(CKSUMTYPE_SHA,...)
- but avoids use of the cryptosystem config table which can not be
- referenced here if this object is to be included in a shared library. */
- retval = nist_sha_cksumtable_entry.sum_func((krb5_pointer) out, sumsize,
- 0, 0, &cksum);
- if (retval)
- return retval;
-
- memcpy((char *)out + DES3_SHA_CONFOUNDER_SIZE,
- (char *)contents, NIST_SHA_CKSUM_LENGTH);
-
- /* We depend here on the ability of this DES-3 implementation to
- encrypt plaintext to ciphertext in-place. */
- retval = mit_des3_cbc_encrypt(out,
- out,
- sumsize,
- (struct mit_des_ks_struct *) key->priv,
- ((struct mit_des_ks_struct *) key->priv) + 1,
- ((struct mit_des_ks_struct *) key->priv) + 2,
- ivec ? ivec : (krb5_pointer)zero_ivec,
- MIT_DES_ENCRYPT);
- return retval;
-}
-
-static krb5_error_code
-mit_des3_sha_decrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- krb5_checksum cksum;
- krb5_octet contents_prd[NIST_SHA_CKSUM_LENGTH];
- krb5_octet contents_get[NIST_SHA_CKSUM_LENGTH];
- char *p;
- krb5_error_code retval;
-
- if ( size < krb5_roundup(mit_des3_sha_cryptosystem_entry.pad_minimum,
- mit_des3_sha_cryptosystem_entry.block_length))
- return KRB5_BAD_MSIZE;
-
- retval = mit_des3_cbc_encrypt((const mit_des_cblock *) in,
- out,
- size,
- (struct mit_des_ks_struct *) key->priv,
- ((struct mit_des_ks_struct *) key->priv) + 1,
- ((struct mit_des_ks_struct *) key->priv) + 2,
- ivec ? ivec : (krb5_pointer)zero_ivec,
- MIT_DES_DECRYPT);
- if (retval)
- return retval;
-
- cksum.length = sizeof(contents_prd);
- cksum.contents = contents_prd;
- p = (char *)out + DES3_SHA_CONFOUNDER_SIZE;
- memcpy((char *)contents_get, p, NIST_SHA_CKSUM_LENGTH);
- memset(p, 0, NIST_SHA_CKSUM_LENGTH);
-
- retval = nist_sha_cksumtable_entry.sum_func(out, size, 0, 0, &cksum);
- if (retval)
- return retval;
-
- if (memcmp((char *)contents_get,
- (char *)contents_prd,
- NIST_SHA_CKSUM_LENGTH))
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
-
- memmove((char *)out, (char *)out +
- mit_des3_sha_cryptosystem_entry.pad_minimum,
- size - mit_des3_sha_cryptosystem_entry.pad_minimum);
- return 0;
-}
+++ /dev/null
-/*
- * lib/crypto/des-crc.32
- *
- * Copyright 1994 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "crc-32.h"
-#include "des_int.h"
-
-krb5_error_code mit_des_crc_encrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-krb5_error_code mit_des_crc_decrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-
-static krb5_cryptosystem_entry mit_des_crc_cryptosystem_entry = {
- 0,
- mit_des_crc_encrypt_func,
- mit_des_crc_decrypt_func,
- mit_des_process_key,
- mit_des_finish_key,
- mit_des_string_to_key,
- mit_des_init_random_key,
- mit_des_finish_random_key,
- mit_des_random_key,
- sizeof(mit_des_cblock),
- CRC32_CKSUM_LENGTH+sizeof(mit_des_cblock),
- sizeof(mit_des_cblock),
- ENCTYPE_DES_CBC_CRC
- };
-
-krb5_cs_table_entry krb5_des_crc_cst_entry = {
- 0,
- &mit_des_crc_cryptosystem_entry,
- 0
- };
-
-
-krb5_error_code
-mit_des_crc_encrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- krb5_checksum cksum;
- krb5_octet contents[CRC32_CKSUM_LENGTH];
- int sumsize;
- krb5_error_code retval;
-
-/* if ( size < sizeof(mit_des_cblock) )
- return KRB5_BAD_MSIZE; */
-
- /* caller passes data size, and saves room for the padding. */
- /* format of ciphertext, per RFC is:
- +-----------+----------+-------------+-----+
- |confounder | check | msg-seq | pad |
- +-----------+----------+-------------+-----+
-
- our confounder is 8 bytes (one cblock);
- our checksum is CRC32_CKSUM_LENGTH
- */
- sumsize = krb5_roundup(size+CRC32_CKSUM_LENGTH+sizeof(mit_des_cblock),
- sizeof(mit_des_cblock));
-
- /* assemble crypto input into the output area, then encrypt in place. */
-
- memset((char *)out, 0, sumsize);
-
- /* put in the confounder */
- if ((retval = krb5_random_confounder(sizeof(mit_des_cblock), out)))
- return retval;
-
- memcpy((char *)out+sizeof(mit_des_cblock)+CRC32_CKSUM_LENGTH, (char *)in,
- size);
-
- cksum.length = sizeof(contents);
- cksum.contents = contents;
-
- /* This is equivalent to krb5_calculate_checksum(CKSUMTYPE_CRC32,...)
- but avoids use of the cryptosystem config table which can not be
- referenced here if this object is to be included in a shared library. */
- if ((retval = crc32_cksumtable_entry.sum_func((krb5_pointer) out,
- sumsize,
- (krb5_pointer)key->key->contents,
- sizeof(mit_des_cblock),
- &cksum)))
- return retval;
-
- memcpy((char *)out+sizeof(mit_des_cblock), (char *)contents,
- CRC32_CKSUM_LENGTH);
-
- /* We depend here on the ability of this DES implementation to
- encrypt plaintext to ciphertext in-place. */
- return (mit_des_cbc_encrypt(out,
- out,
- sumsize,
- (struct mit_des_ks_struct *) key->priv,
- ivec ? ivec : (krb5_pointer)key->key->contents,
- MIT_DES_ENCRYPT));
-
-}
-
-krb5_error_code
-mit_des_crc_decrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- krb5_checksum cksum;
- krb5_octet contents_prd[CRC32_CKSUM_LENGTH];
- krb5_octet contents_get[CRC32_CKSUM_LENGTH];
- char *p;
- krb5_error_code retval;
-
- if ( size < 2*sizeof(mit_des_cblock) )
- return KRB5_BAD_MSIZE;
-
- retval = mit_des_cbc_encrypt((const mit_des_cblock FAR *) in,
- out,
- size,
- (struct mit_des_ks_struct *) key->priv,
- ivec ? ivec : (krb5_pointer)key->key->contents,
- MIT_DES_DECRYPT);
- if (retval)
- return retval;
-
- cksum.length = sizeof(contents_prd);
- cksum.contents = contents_prd;
- p = (char *)out + sizeof(mit_des_cblock);
- memcpy((char *)contents_get, p, CRC32_CKSUM_LENGTH);
- memset(p, 0, CRC32_CKSUM_LENGTH);
-
- if ((retval = crc32_cksumtable_entry.sum_func(out, size,
- (krb5_pointer)key->key->contents,
- sizeof(mit_des_cblock),
- &cksum)))
- return retval;
-
- if (memcmp((char *)contents_get, (char *)contents_prd, CRC32_CKSUM_LENGTH) )
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
- memmove((char *)out, (char *)out +
- sizeof(mit_des_cblock) + CRC32_CKSUM_LENGTH,
- size - sizeof(mit_des_cblock) - CRC32_CKSUM_LENGTH);
- return 0;
-}
+++ /dev/null
-/*
- * lib/crypto/des-md5.32
- *
- * Copyright 1994 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "rsa-md5.h"
-#include "des_int.h"
-
-krb5_error_code mit_des_md5_encrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-krb5_error_code mit_des_md5_decrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-static mit_des_cblock zero_ivec = { 0 };
-
-static krb5_cryptosystem_entry mit_des_md5_cryptosystem_entry = {
- 0,
- mit_des_md5_encrypt_func,
- mit_des_md5_decrypt_func,
- mit_des_process_key,
- mit_des_finish_key,
- mit_des_string_to_key,
- mit_des_init_random_key,
- mit_des_finish_random_key,
- mit_des_random_key,
- sizeof(mit_des_cblock),
- RSA_MD5_CKSUM_LENGTH+sizeof(mit_des_cblock),
- sizeof(mit_des_cblock),
- ENCTYPE_DES_CBC_MD5
- };
-
-krb5_cs_table_entry krb5_des_md5_cst_entry = {
- 0,
- &mit_des_md5_cryptosystem_entry,
- 0
- };
-
-
-krb5_error_code
-mit_des_md5_encrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- krb5_checksum cksum;
- krb5_octet contents[RSA_MD5_CKSUM_LENGTH];
- int sumsize;
- krb5_error_code retval;
-
-/* if ( size < sizeof(mit_des_cblock) )
- return KRB5_BAD_MSIZE; */
-
- /* caller passes data size, and saves room for the padding. */
- /* format of ciphertext, per RFC is:
- +-----------+----------+-------------+-----+
- |confounder | check | msg-seq | pad |
- +-----------+----------+-------------+-----+
-
- our confounder is 8 bytes (one cblock);
- our checksum is RSA_MD5_CKSUM_LENGTH
- */
- sumsize = krb5_roundup(size+RSA_MD5_CKSUM_LENGTH+sizeof(mit_des_cblock),
- sizeof(mit_des_cblock));
-
- /* assemble crypto input into the output area, then encrypt in place. */
-
- memset((char *)out, 0, sumsize);
-
- /* put in the confounder */
- if ((retval = krb5_random_confounder(sizeof(mit_des_cblock), out)))
- return retval;
-
- memcpy((char *)out+sizeof(mit_des_cblock)+RSA_MD5_CKSUM_LENGTH, (char *)in,
- size);
-
- cksum.length = sizeof(contents);
- cksum.contents = contents;
-
- /* This is equivalent to krb5_calculate_checksum(CKSUMTYPE_MD5,...)
- but avoids use of the cryptosystem config table which can not be
- referenced here if this object is to be included in a shared library. */
- if ((retval = rsa_md5_cksumtable_entry.sum_func((krb5_pointer) out,
- sumsize,
- (krb5_pointer)key->key->contents,
- sizeof(mit_des_cblock),
- &cksum)))
- return retval;
-
- memcpy((char *)out+sizeof(mit_des_cblock), (char *)contents,
- RSA_MD5_CKSUM_LENGTH);
-
- /* We depend here on the ability of this DES implementation to
- encrypt plaintext to ciphertext in-place. */
- return (mit_des_cbc_encrypt(out,
- out,
- sumsize,
- (struct mit_des_ks_struct *) key->priv,
- ivec ? ivec : (krb5_pointer)zero_ivec,
- MIT_DES_ENCRYPT));
-
-}
-
-krb5_error_code
-mit_des_md5_decrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- krb5_checksum cksum;
- krb5_octet contents_prd[RSA_MD5_CKSUM_LENGTH];
- krb5_octet contents_get[RSA_MD5_CKSUM_LENGTH];
- char *p;
- krb5_error_code retval;
-
- if ( size < 2*sizeof(mit_des_cblock) )
- return KRB5_BAD_MSIZE;
-
- retval = mit_des_cbc_encrypt((const mit_des_cblock *) in,
- out,
- size,
- (struct mit_des_ks_struct *) key->priv,
- ivec ? ivec : (krb5_pointer)zero_ivec,
- MIT_DES_DECRYPT);
- if (retval)
- return retval;
-
- cksum.length = sizeof(contents_prd);
- cksum.contents = contents_prd;
- p = (char *)out + sizeof(mit_des_cblock);
- memcpy((char *)contents_get, p, RSA_MD5_CKSUM_LENGTH);
- memset(p, 0, RSA_MD5_CKSUM_LENGTH);
-
- if ((retval = rsa_md5_cksumtable_entry.sum_func(out, size,
- (krb5_pointer)key->key->contents,
- sizeof(mit_des_cblock),
- &cksum)))
- return retval;
-
- if (memcmp((char *)contents_get, (char *)contents_prd, RSA_MD5_CKSUM_LENGTH) )
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
- memmove((char *)out, (char *)out +
- sizeof(mit_des_cblock) + RSA_MD5_CKSUM_LENGTH,
- size - sizeof(mit_des_cblock) - RSA_MD5_CKSUM_LENGTH);
- return 0;
-}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_c_encrypt(context, key, usage, ivec, input, output)
+ krb5_context context;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *ivec;
+ krb5_const krb5_data *input;
+ krb5_enc_data *output;
+{
+ int i;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == key->enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ output->magic = KV5M_ENC_DATA;
+ output->kvno = 0;
+ output->enctype = key->enctype;
+
+ return((*(krb5_enctypes_list[i].encrypt))
+ (krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
+ key, usage, ivec, input, &output->ciphertext));
+}
+++ /dev/null
-/*
- * Copyright 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- */
-
-#include "k5-int.h"
-
-/*
- * This routine takes a key and a krb5_data structure as input, and
- * outputs the encrypted data in a krb5_enc_data structure. Note that
- * the krb5_enc_data structure is not allocated, and the kvno field is
- * not filled in.
- */
-krb5_error_code
-krb5_encrypt_data(context, key, ivec, data, enc_data)
- krb5_context context;
- krb5_keyblock * key;
- krb5_pointer ivec;
- krb5_data * data;
- krb5_enc_data * enc_data;
-{
- krb5_error_code retval;
- krb5_encrypt_block eblock;
-
- krb5_use_enctype(context, &eblock, key->enctype);
-
- enc_data->magic = KV5M_ENC_DATA;
- enc_data->kvno = 0;
- enc_data->enctype = key->enctype;
- enc_data->ciphertext.length = krb5_encrypt_size(data->length,
- eblock.crypto_entry);
- enc_data->ciphertext.data = malloc(enc_data->ciphertext.length);
- if (enc_data->ciphertext.data == 0)
- return ENOMEM;
-
- if ((retval = krb5_process_key(context, &eblock, key)) != 0)
- goto cleanup;
-
- if ((retval = krb5_encrypt(context, (krb5_pointer) data->data,
- (krb5_pointer) enc_data->ciphertext.data,
- data->length, &eblock, ivec))) {
- krb5_finish_key(context, &eblock);
- goto cleanup;
- }
- (void) krb5_finish_key(context, &eblock);
-
- return 0;
-
-cleanup:
- free(enc_data->ciphertext.data);
- return retval;
-}
-
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_c_encrypt_length(context, enctype, inputlen, length)
+ krb5_context context;
+ krb5_enctype enctype;
+ size_t inputlen;
+ size_t *length;
+{
+ int i;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ (*(krb5_enctypes_list[i].encrypt_len))
+ (krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
+ inputlen, length);
+
+ return(0);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code
+krb5_c_enctype_compare(context, e1, e2, similar)
+ krb5_context context;
+ krb5_enctype e1;
+ krb5_enctype e2;
+ krb5_boolean *similar;
+{
+ int i, j;
+
+ for (i=0; i<krb5_enctypes_length; i++)
+ if (krb5_enctypes_list[i].etype == e1)
+ break;
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ for (j=0; j<krb5_enctypes_length; j++)
+ if (krb5_enctypes_list[j].etype == e2)
+ break;
+
+ if (j == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ *similar =
+ ((krb5_enctypes_list[i].enc == krb5_enctypes_list[j].enc) &&
+ (krb5_enctypes_list[i].str2key == krb5_enctypes_list[j].str2key));
+
+ return(0);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_enctype_to_string(enctype, buffer, buflen)
+ krb5_enctype enctype;
+ char FAR * buffer;
+ size_t buflen;
+{
+ int i;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == enctype) {
+ if ((strlen(krb5_enctypes_list[i].out_string)+1) > buflen)
+ return(ENOMEM);
+
+ strcpy(buffer, krb5_enctypes_list[i].out_string);
+ return(0);
+ }
+ }
+
+ return(EINVAL);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "enc_provider.h"
+#include "hash_provider.h"
+#include "etypes.h"
+#include "old.h"
+#include "raw.h"
+#include "dk.h"
+
+/* these will be linear searched. if they ever get big, a binary
+ search or hash table would be better, which means these would need
+ to be sorted. An array would be more efficient, but that assumes
+ that the keytypes are all near each other. I'd rather not make
+ that assumption. */
+
+struct krb5_keytypes krb5_enctypes_list[] = {
+ { ENCTYPE_DES_CBC_CRC,
+ "des-cbc-crc", "DES cbc mode with CRC-32",
+ &krb5_enc_des, &krb5_hash_crc32,
+ krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
+ krb5_des_string_to_key },
+ { ENCTYPE_DES_CBC_MD4,
+ "des-cbc-md4", "DES cbc mode with RSA-MD4",
+ &krb5_enc_des, &krb5_hash_md4,
+ krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
+ krb5_des_string_to_key },
+ { ENCTYPE_DES_CBC_MD5,
+ "des-cbc-md5", "DES cbc mode with RSA-MD5",
+ &krb5_enc_des, &krb5_hash_md5,
+ krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
+ krb5_des_string_to_key },
+
+ { ENCTYPE_DES_CBC_RAW,
+ "des-cbc-raw", "DES cbc mode raw",
+ &krb5_enc_des, NULL,
+ krb5_raw_encrypt_length, krb5_raw_encrypt, krb5_raw_decrypt,
+ krb5_des_string_to_key },
+ { ENCTYPE_DES3_CBC_RAW,
+ "des3-cbc-raw", "Triple DES cbc mode raw",
+ &krb5_enc_des3, NULL,
+ krb5_raw_encrypt_length, krb5_raw_encrypt, krb5_raw_decrypt,
+ krb5_dk_string_to_key },
+
+ { ENCTYPE_DES3_HMAC_SHA1,
+ "des3-hmac-sha1", "Triple DES with HMAC/sha1",
+ &krb5_enc_des3, &krb5_hash_sha1,
+ krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+ krb5_dk_string_to_key },
+ { ENCTYPE_DES_HMAC_SHA1,
+ "des-hmac-sha1", "DES with HMAC/sha1",
+ &krb5_enc_des, &krb5_hash_sha1,
+ krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+ krb5_dk_string_to_key },
+};
+
+int krb5_enctypes_length =
+sizeof(krb5_enctypes_list)/sizeof(struct krb5_keytypes);
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern struct krb5_keytypes krb5_enctypes_list[];
+extern int krb5_enctypes_length;
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+/*
+ * the HMAC transform looks like:
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ *
+ * where H is a cryptographic hash
+ * K is an n byte key
+ * ipad is the byte 0x36 repeated blocksize times
+ * opad is the byte 0x5c repeated blocksize times
+ * and text is the data being protected
+ */
+
+krb5_error_code
+krb5_hmac(hash, key, icount, input, output)
+ krb5_const struct krb5_hash_provider *hash;
+ krb5_const krb5_keyblock *key;
+ unsigned int icount;
+ krb5_const krb5_data *input;
+ krb5_data *output;
+{
+ size_t hashsize, blocksize;
+ unsigned char *xorkey, *ihash;
+ int i;
+ krb5_data *hashin, hashout;
+ krb5_error_code ret;
+
+ (*(hash->hash_size))(&hashsize);
+ (*(hash->block_size))(&blocksize);
+
+ if (key->length > blocksize)
+ return(KRB5_CRYPTO_INTERNAL);
+ if (output->length < hashsize)
+ return(KRB5_BAD_MSIZE);
+ /* if this isn't > 0, then there won't be enough space in this
+ array to compute the outer hash */
+ if (icount == 0)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ /* allocate space for the xor key, hash input vector, and inner hash */
+
+ if ((xorkey = (unsigned char *) malloc(blocksize)) == NULL)
+ return(ENOMEM);
+ if ((ihash = (unsigned char *) malloc(hashsize)) == NULL) {
+ free(xorkey);
+ return(ENOMEM);
+ }
+ if ((hashin = (krb5_data *)malloc(sizeof(krb5_data)*(icount+1))) == NULL) {
+ free(ihash);
+ free(xorkey);
+ return(ENOMEM);
+ }
+
+ /* create the inner padded key */
+
+ memset(xorkey, 0x36, blocksize);
+
+ for (i=0; i<key->length; i++)
+ xorkey[i] ^= key->contents[i];
+
+ /* compute the inner hash */
+
+ for (i=0; i<icount; i++) {
+ hashin[0].length = blocksize;
+ hashin[0].data = xorkey;
+ hashin[i+1] = input[i];
+ }
+
+ hashout.length = hashsize;
+ hashout.data = ihash;
+
+ if (ret = ((*(hash->hash))(icount+1, hashin, &hashout)))
+ goto cleanup;
+
+ /* create the outer padded key */
+
+ memset(xorkey, 0x5c, blocksize);
+
+ for (i=0; i<key->length; i++)
+ xorkey[i] ^= key->contents[i];
+
+ /* compute the outer hash */
+
+ hashin[0].length = blocksize;
+ hashin[0].data = xorkey;
+ hashin[1] = hashout;
+
+ output->length = hashsize;
+
+ if (ret = ((*(hash->hash))(2, hashin, output)))
+ memset(output->data, 0, output->length);
+
+ /* ret is set correctly by the prior call */
+
+cleanup:
+ memset(xorkey, 0, blocksize);
+ memset(ihash, 0, hashsize);
+
+ free(hashin);
+ free(ihash);
+ free(xorkey);
+
+ return(ret);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "cksumtypes.h"
+
+static int etype_match(e1, e2)
+ krb5_enctype e1, e2;
+{
+ int i1, i2;
+
+ for (i1=0; i1<krb5_enctypes_length; i1++)
+ if (krb5_enctypes_list[i1].etype == e1)
+ break;
+
+ for (i2=0; i2<krb5_enctypes_length; i2++)
+ if (krb5_enctypes_list[i2].etype == e2)
+ break;
+
+ return((i1 < krb5_enctypes_length) &&
+ (i2 < krb5_enctypes_length) &&
+ (krb5_enctypes_list[i1].enc == krb5_enctypes_list[i2].enc));
+}
+
+krb5_error_code
+krb5_c_keyed_checksum_types(context, enctype, count, cksumtypes)
+ krb5_context context;
+ krb5_enctype enctype;
+ unsigned int *count;
+ krb5_cksumtype **cksumtypes;
+{
+ unsigned int i, c;
+
+ c = 0;
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if ((krb5_cksumtypes_list[i].keyhash &&
+ etype_match(krb5_cksumtypes_list[i].keyed_etype, enctype)) ||
+ (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE)) {
+ c++;
+ }
+ }
+
+ *count = c;
+
+ if ((*cksumtypes = (krb5_cksumtype *) malloc(c*sizeof(krb5_cksumtype)))
+ == NULL)
+ return(ENOMEM);
+
+ c = 0;
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if ((krb5_cksumtypes_list[i].keyhash &&
+ etype_match(krb5_cksumtypes_list[i].keyed_etype, enctype)) ||
+ (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE)) {
+ (*cksumtypes)[c] = krb5_cksumtypes_list[i].ctype;
+ c++;
+ }
+ }
+
+ return(0);
+}
+
+void
+krb5_free_cksumtypes(context, val)
+ krb5_context context;
+ krb5_cksumtype FAR * val;
+{
+ if (val)
+ krb5_xfree(val);
+ return;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_boolean is_keyed_cksum(ctype)
+ krb5_cksumtype ctype;
+{
+ int i;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == ctype) {
+ if (krb5_cksumtypes_list[i].keyhash ||
+ (krb5_cksumtypes_list[i].flags &
+ KRB5_CKSUMFLAG_DERIVE))
+ return(1);
+ else
+ return(0);
+ }
+ }
+
+ /* ick, but it's better than coredumping, which is what the
+ old code would have done */
+ return(-1);
+}
+++ /dev/null
-/*
- * lib/krb5/krb/crypto_glue.c
- *
- * Copyright 1996 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * Exported routines:
- * krb5_use_enctype()
- * krb5_checksum_size()
- * krb5_encrypt_size()
- * krb5_calculate_checksum()
- * krb5_verify_checksum()
- * krb5_encrypt()
- * krb5_decrypt()
- * krb5_process_key()
- * krb5_finish_key()
- * krb5_string_to_key()
- * krb5_init_random_key()
- * krb5_finish_random_key()
- * krb5_random_key()
- * krb5_eblock_enctype()
- *
- * Internal library routines:
- * is_coll_proof_cksum()
- * is_keyed_cksum()
- * valid_cksumtype()
- * valid_enctype()
- */
-
-#include "k5-int.h"
-
-
-KRB5_DLLIMP size_t KRB5_CALLCONV
-krb5_encrypt_size(length, crypto)
- krb5_const size_t length;
- krb5_const krb5_cryptosystem_entry FAR * crypto;
-{
- return krb5_roundup(length + crypto->pad_minimum, crypto->block_length);
-}
-
-krb5_boolean KRB5_CALLCONV
-valid_enctype(ktype)
- krb5_const krb5_enctype ktype;
-{
- return ((ktype<=krb5_max_enctype) && (ktype>0) && krb5_enctype_array[ktype]);
-}
-
-krb5_boolean KRB5_CALLCONV
-valid_cksumtype(cktype)
- krb5_const krb5_cksumtype cktype;
-{
- return ((cktype<=krb5_max_cksum) && (cktype>0) && krb5_cksumarray[cktype]);
-}
-
-krb5_boolean KRB5_CALLCONV
-is_coll_proof_cksum(cktype)
- krb5_const krb5_cksumtype cktype;
-{
- return(krb5_cksumarray[cktype]->is_collision_proof);
-}
-
-krb5_boolean KRB5_CALLCONV
-is_keyed_cksum(cktype)
- krb5_const krb5_cksumtype cktype;
-{
- return (krb5_cksumarray[cktype]->uses_key);
-}
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_use_enctype(context, eblock, enctype)
- krb5_context context;
- krb5_encrypt_block FAR * eblock;
- krb5_const krb5_enctype enctype;
-{
- eblock->crypto_entry = krb5_enctype_array[(enctype)]->system;
- return 0;
-}
-
-KRB5_DLLIMP size_t KRB5_CALLCONV
-krb5_checksum_size(context, cktype)
- krb5_context context;
- krb5_const krb5_cksumtype cktype;
-{
- return krb5_cksumarray[cktype]->checksum_length;
-}
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_calculate_checksum(context, cktype, in, in_length, seed, seed_length, outcksum)
- krb5_context context;
- krb5_const krb5_cksumtype cktype;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- return krb5_x(((*krb5_cksumarray[cktype]->sum_func)),
- (in, in_length, seed, seed_length, outcksum));
-}
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_verify_checksum(context, cktype, cksum, in, in_length, seed, seed_length)
- krb5_context context;
- krb5_const krb5_cksumtype cktype;
- krb5_const krb5_checksum FAR *cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
-{
- return krb5_x((*krb5_cksumarray[cktype]->sum_verf_func),
- (cksum, in, in_length, seed, seed_length));
-}
-
-KRB5_DLLIMP krb5_enctype KRB5_CALLCONV
-krb5_eblock_enctype(context, eblock)
- krb5_context context;
- krb5_const krb5_encrypt_block FAR * eblock;
-{
- return eblock->crypto_entry->proto_enctype;
-}
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_encrypt(context, inptr, outptr, size, eblock, ivec)
- krb5_context context;
- krb5_const krb5_pointer inptr;
- krb5_pointer outptr;
- krb5_const size_t size;
- krb5_encrypt_block FAR * eblock;
- krb5_pointer ivec;
-{
- return krb5_x(eblock->crypto_entry->encrypt_func,
- (inptr, outptr, size, eblock, ivec));
-}
-
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_decrypt(context, inptr, outptr, size, eblock, ivec)
- krb5_context context;
- krb5_const krb5_pointer inptr;
- krb5_pointer outptr;
- krb5_const size_t size;
- krb5_encrypt_block FAR * eblock;
- krb5_pointer ivec;
-{
- return krb5_x(eblock->crypto_entry->decrypt_func,
- (inptr, outptr, size, eblock, ivec));
-}
-
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_process_key(context, eblock, key)
- krb5_context context;
- krb5_encrypt_block FAR * eblock;
- krb5_const krb5_keyblock FAR * key;
-{
- return krb5_x(eblock->crypto_entry->process_key,
- (eblock, key));
-}
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_finish_key(context, eblock)
- krb5_context context;
- krb5_encrypt_block FAR * eblock;
-{
- return krb5_x(eblock->crypto_entry->finish_key,(eblock));
-}
-
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_string_to_key(context, eblock, keyblock, data, princ)
- krb5_context context;
- krb5_const krb5_encrypt_block FAR * eblock;
- krb5_keyblock FAR * keyblock;
- krb5_const krb5_data FAR * data;
- krb5_const krb5_data FAR * princ;
-{
- return krb5_x(eblock->crypto_entry->string_to_key,
- (eblock, keyblock, data, princ));
-}
-
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_init_random_key(context, eblock, keyblock, ptr)
- krb5_context context;
- krb5_const krb5_encrypt_block FAR * eblock;
- krb5_const krb5_keyblock FAR * keyblock;
- krb5_pointer FAR * ptr;
-{
- return krb5_x(eblock->crypto_entry->init_random_key,
- (eblock, keyblock, ptr));
-}
-
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_finish_random_key(context, eblock, ptr)
- krb5_context context;
- krb5_const krb5_encrypt_block FAR * eblock;
- krb5_pointer FAR * ptr;
-{
- return krb5_x(eblock->crypto_entry->finish_random_key,
- (eblock, ptr));
-}
-
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_random_key(context, eblock, ptr, keyblock)
- krb5_context context;
- krb5_const krb5_encrypt_block FAR * eblock;
- krb5_pointer ptr;
- krb5_keyblock FAR * FAR * keyblock;
-{
- return krb5_x(eblock->crypto_entry->random_key,
- (eblock, ptr, keyblock));
-}
-
-
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+#include "etypes.h"
+
+krb5_error_code
+krb5_c_make_checksum(context, cksumtype, key, usage, input, cksum)
+ krb5_context context;
+ krb5_cksumtype cksumtype;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *input;
+ krb5_checksum *cksum;
+{
+ int i, e1, e2;
+ krb5_data data;
+ krb5_error_code ret;
+ size_t cksumlen;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == cksumtype)
+ break;
+ }
+
+ if (i == krb5_cksumtypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ if (krb5_cksumtypes_list[i].keyhash)
+ (*(krb5_cksumtypes_list[i].keyhash->hash_size))(&cksumlen);
+ else
+ (*(krb5_cksumtypes_list[i].hash->hash_size))(&cksumlen);
+
+ cksum->length = cksumlen;
+
+ if ((cksum->contents = (krb5_octet *) malloc(cksum->length)) == NULL)
+ return(ENOMEM);
+
+ data.length = cksum->length;
+ data.data = cksum->contents;
+
+ if (krb5_cksumtypes_list[i].keyhash) {
+ /* check if key is compatible */
+
+ if (krb5_cksumtypes_list[i].keyed_etype) {
+ for (e1=0; e1<krb5_enctypes_length; e1++)
+ if (krb5_enctypes_list[e1].etype ==
+ krb5_cksumtypes_list[i].keyed_etype)
+ break;
+
+ for (e2=0; e2<krb5_enctypes_length; e2++)
+ if (krb5_enctypes_list[e2].etype == key->enctype)
+ break;
+
+ if ((e1 == krb5_enctypes_length) ||
+ (e2 == krb5_enctypes_length) ||
+ (krb5_enctypes_list[e1].enc != krb5_enctypes_list[e2].enc)) {
+ ret = KRB5_BAD_ENCTYPE;
+ goto cleanup;
+ }
+ }
+
+ ret = (*(krb5_cksumtypes_list[i].keyhash->hash))(key, 0, input, &data);
+ } else if (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE) {
+ /* any key is ok */
+
+ ret = krb5_dk_make_checksum(krb5_cksumtypes_list[i].hash,
+ key, usage, input, &data);
+ } else {
+ /* no key is used */
+
+ ret = (*(krb5_cksumtypes_list[i].hash->hash))(1, input, &data);
+ }
+
+ if (!ret) {
+ cksum->magic = KV5M_CHECKSUM;
+ cksum->checksum_type = cksumtype;
+ }
+
+cleanup:
+ if (ret) {
+ memset(cksum->contents, 0, cksum->length);
+ free(cksum->contents);
+ }
+
+ return(ret);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_c_make_random_key(context, enctype, random_key)
+ krb5_context context;
+ krb5_enctype enctype;
+ krb5_keyblock *random_key;
+{
+ int i;
+ krb5_error_code ret;
+ struct krb5_enc_provider *enc;
+ size_t keybytes, keylength;
+ krb5_data random;
+ unsigned char *bytes;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ enc = krb5_enctypes_list[i].enc;
+
+ (*(enc->keysize))(&keybytes, &keylength);
+
+ if ((bytes = (unsigned char *) malloc(keybytes)) == NULL)
+ return(ENOMEM);
+ if ((random_key->contents = (krb5_octet *) malloc(keylength)) == NULL) {
+ free(bytes);
+ return(ENOMEM);
+ }
+
+ random.data = bytes;
+ random.length = keybytes;
+
+ if (ret = krb5_c_random_make_octets(context, &random))
+ goto cleanup;
+
+ random_key->magic = KV5M_KEYBLOCK;
+ random_key->enctype = enctype;
+ random_key->length = keylength;
+
+ ret = ((*(enc->make_key))(&random, random_key));
+
+cleanup:
+ memset(bytes, 0, keybytes);
+ free(bytes);
+
+ if (ret) {
+ memset(random_key->contents, 0, keylength);
+ free(random_key->contents);
+ }
+
+ return(ret);
+}
+++ /dev/null
-ignore RFC1186.TXT
-ignore RFC1186B.TXT
+Sun Jul 19 12:00:00 1998 Marc Horowitz <marc@mit.edu>
+
+ * *.c: replace the crypto layer.
+
Tue Mar 3 08:39:47 1998 Ezra Peisach <epeisach@kangaroo.mit.edu>
* Makefile.in (t_cksum): Do not depend on libkrb5.a, use
thisconfigdir=./..
BUILDTOP=$(REL)$(U)$(S)$(U)$(S)$(U)
-# -I$(srcdir) is needed to pull in $(srcdir)/rsa-md4.h for ./t_mddriver.c.
-CFLAGS = $(CCOPTS) $(DEFS) -I$(srcdir)/../des -I"$(srcdir)"
+CFLAGS = $(CCOPTS) $(DEFS)
##DOS##BUILDTOP = ..\..\..
##DOS##PREFIXDIR=md4
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
-RUN_SETUP=@KRB5_RUN_ENV@
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
-STLIBOBJS=md4.o md4glue.o md4crypto.o
-OBJS= md4.$(OBJEXT) md4glue.$(OBJEXT) md4crypto.$(OBJEXT)
-SRCS= $(srcdir)/md4.c $(srcdir)/md4glue.c $(srcdir)/md4crypto.c
+STLIBOBJS= md4.o
+
+OBJS= md4.$(OBJEXT)
+
+SRCS= $(srcdir)/md4.c
##DOS##LIBOBJS = $(OBJS)
all-unix:: all-libobjs
+includes:: depend
+
+depend:: $(SRCS)
+
t_mddriver.c: $(srcdir)/../md5/t_mddriver.c
$(CP) $(srcdir)/../md5/t_mddriver.c t_mddriver.c
$(CC) -DMD=4 $(CFLAGS2) -o t_mddriver t_mddriver.c md4.c
$(RM) md4.obj
-t_cksum.c: $(srcdir)/../md5/t_cksum.c
- $(CP) $(srcdir)/../md5/t_cksum.c t_cksum.c
-
-t_cksum.o: t_cksum.c
- $(CC) -DMD=4 $(CFLAGS) -c t_cksum.c
-
-t_cksum: t_cksum.o $(KRB5_BASE_DEPLIBS)
- $(CC_LINK) -o t_cksum t_cksum.o $(KRB5_BASE_LIBS)
-
-check-unix:: t_mddriver t_cksum
+check-unix:: t_mddriver
$(RUN_SETUP) $(C)t_mddriver -x
- $(RUN_SETUP) $(C)t_cksum "this is a test"
check-windows:: t_mddriver$(EXEEXT)
$(C)t_mddriver$(EXEEXT) -x
clean::
$(RM) t_mddriver$(EXEEXT) t_mddriver.$(OBJEXT) t_mddriver.c
- $(RM) t_cksum$(EXEEXT) t_cksum.$(OBJEXT) t_cksum.c
clean-unix:: clean-libobjs
+++ /dev/null
-/*
- * lib/crypto/md4/md4crypto.c
- *
- * Copyright 1991 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- *
- * Kerberos glue for MD4 sample implementation.
- */
-
-#include "k5-int.h"
-#include "rsa-md4.h"
-#include "des_int.h" /* we cheat a bit and call it directly... */
-
-/*
- * In Kerberos V5 Beta 5 and previous releases the RSA-MD4-DES implementation
- * did not follow RFC1510. The folowing definitions control the compatibility
- * with these releases.
- *
- * If MD4_K5BETA_COMPAT is defined, then compatability mode is enabled. That
- * means that both checksum functions are compiled and available for use and
- * the additional interface md4_crypto_compat_ctl() is defined.
- *
- * If MD4_K5BETA_COMPAT_DEF is defined and compatability mode is enabled, then
- * the compatible behaviour becomes the default.
- *
- */
-#define MD4_K5BETA_COMPAT
-#define MD4_K5BETA_COMPAT_DEF
-
-
-/* Windows needs to these prototypes for the assignment below */
-
-#ifdef MD4_K5BETA_COMPAT
-krb5_error_code
-krb5_md4_crypto_compat_sum_func PROTOTYPE((
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum *outcksum));
-#endif
-
-krb5_error_code
-krb5_md4_crypto_sum_func PROTOTYPE((
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum *outcksum));
-
-krb5_error_code
-krb5_md4_crypto_verify_func PROTOTYPE((
- krb5_const krb5_checksum FAR *cksum,
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length));
-
-static mit_des_cblock zero_ivec = { 0 };
-
-static void
-krb5_md4_calculate_cksum(md4ctx, confound, confound_length, in, in_length)
- krb5_MD4_CTX *md4ctx;
- krb5_pointer confound;
- size_t confound_length;
- krb5_pointer in;
- size_t in_length;
-{
- krb5_MD4Init(md4ctx);
- if (confound && confound_length)
- krb5_MD4Update(md4ctx, confound, confound_length);
- krb5_MD4Update(md4ctx, in, in_length);
- krb5_MD4Final(md4ctx);
-}
-
-#ifdef MD4_K5BETA_COMPAT
-/*
- * Generate the RSA-MD4-DES checksum in a manner which is compatible with
- * K5 Beta implementations. Sigh...
- */
-krb5_error_code
-krb5_md4_crypto_compat_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_octet outtmp[OLD_RSA_MD4_DES_CKSUM_LENGTH];
- krb5_octet *input = (krb5_octet *)in;
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock;
- krb5_error_code retval;
- krb5_MD4_CTX working;
-
- if (outcksum->length < OLD_RSA_MD4_DES_CKSUM_LENGTH)
- return KRB5_BAD_MSIZE;
-
- krb5_MD4Init(&working);
- krb5_MD4Update(&working, input, in_length);
- krb5_MD4Final(&working);
-
- outcksum->checksum_type = CKSUMTYPE_RSA_MD4_DES;
- outcksum->length = OLD_RSA_MD4_DES_CKSUM_LENGTH;
-
- memcpy((char *)outtmp, (char *)&working.digest[0], 16);
-
- memset((char *)&working, 0, sizeof(working));
-
- keyblock.length = seed_length;
- keyblock.contents = (krb5_octet *)seed;
- keyblock.enctype = ENCTYPE_DES_CBC_MD4;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now encrypt it */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)&outtmp[0],
- (mit_des_cblock *)outcksum->contents,
- OLD_RSA_MD4_DES_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)eblock.priv,
- keyblock.contents,
- MIT_DES_ENCRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- return mit_des_finish_key(&eblock);
-}
-#endif /* MD4_K5BETA_COMPAT */
-
-/*
- * Generate the RSA-MD4-DES checksum correctly.
- */
-krb5_error_code
-krb5_md4_crypto_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_octet outtmp[NEW_RSA_MD4_DES_CKSUM_LENGTH];
- mit_des_cblock tmpkey;
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock;
- krb5_error_code retval;
- size_t i;
-
- krb5_MD4_CTX working;
-
- /* Generate the confounder in place */
- if ((retval = krb5_random_confounder(RSA_MD4_DES_CONFOUND_LENGTH, outtmp)))
- return(retval);
-
- /* Calculate the checksum */
- krb5_md4_calculate_cksum(&working,
- (krb5_pointer) outtmp,
- (size_t) RSA_MD4_DES_CONFOUND_LENGTH,
- in,
- in_length);
-
- outcksum->checksum_type = CKSUMTYPE_RSA_MD4_DES;
- outcksum->length = NEW_RSA_MD4_DES_CKSUM_LENGTH;
-
- /* Now blast in the digest */
- memcpy((char *) &outtmp[RSA_MD4_DES_CONFOUND_LENGTH],
- (char *) &working.digest[0],
- RSA_MD4_CKSUM_LENGTH);
-
- /* Clean up droppings */
- memset((char *)&working, 0, sizeof(working));
-
- /* Set up the temporary copy of the key (see RFC 1510 section 6.4.3) */
- memset((char *) tmpkey, 0, sizeof(mit_des_cblock));
- for (i=0; (i<seed_length) && (i<sizeof(mit_des_cblock)); i++)
- tmpkey[i] = (((krb5_octet *) seed)[i]) ^ 0xf0;
-
- keyblock.length = sizeof(mit_des_cblock);
- keyblock.contents = (krb5_octet *) tmpkey;
- keyblock.enctype = ENCTYPE_DES_CBC_MD4;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now encrypt it */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)&outtmp[0],
- (mit_des_cblock *)outcksum->contents,
- NEW_RSA_MD4_DES_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)eblock.priv,
- zero_ivec,
- MIT_DES_ENCRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- return mit_des_finish_key(&eblock);
-}
-
-krb5_error_code
-krb5_md4_crypto_verify_func(cksum, in, in_length, seed, seed_length)
- krb5_const krb5_checksum FAR *cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
-{
- krb5_octet outtmp[NEW_RSA_MD4_DES_CKSUM_LENGTH];
- mit_des_cblock tmpkey;
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock;
- krb5_error_code retval;
- size_t i;
-
- krb5_MD4_CTX working;
-
- retval = 0;
- if (cksum->checksum_type == CKSUMTYPE_RSA_MD4_DES) {
-#ifdef MD4_K5BETA_COMPAT
- /*
- * We have a backwards compatibility problem here. Kerberos
- * version 5 Beta 5 and previous releases did not correctly
- * generate RSA-MD4-DES checksums. The way that we can
- * differentiate is by the length of the provided checksum.
- * If it's only OLD_RSA_MD4_DES_CKSUM_LENGTH, then it's the
- * old style, otherwise it's the correct implementation.
- */
- if (cksum->length == OLD_RSA_MD4_DES_CKSUM_LENGTH) {
- /*
- * If we're verifying the Old Style (tm) checksum, then we can just
- * recalculate the checksum and encrypt it and see if it's the
- * same.
- */
-
- /* Recalculate the checksum with no confounder */
- krb5_md4_calculate_cksum(&working,
- (krb5_pointer) NULL,
- (size_t) 0,
- in,
- in_length);
-
- /* Use the key "as-is" */
- keyblock.length = seed_length;
- keyblock.contents = (krb5_octet *) seed;
- keyblock.enctype = ENCTYPE_DES_CBC_MD4;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now encrypt the checksum */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)&working.digest[0],
- (mit_des_cblock *)&outtmp[0],
- RSA_MD4_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)
- eblock.priv,
- keyblock.contents,
- MIT_DES_ENCRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- if ((retval = mit_des_finish_key(&eblock)))
- return(retval);
-
- /* Compare the encrypted checksums */
- if (memcmp((char *) &outtmp[0],
- (char *) cksum->contents,
- OLD_RSA_MD4_DES_CKSUM_LENGTH))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
-#endif /* MD4_K5BETA_COMPAT */
- if (cksum->length == (NEW_RSA_MD4_DES_CKSUM_LENGTH)) {
- /*
- * If we're verifying the correct implementation, then we have
- * to do a little more work because we must decrypt the checksum
- * because it contains the confounder in it. So, figure out
- * what our key variant is and then do it!
- */
-
- /* Set up the variant of the key (see RFC 1510 section 6.4.3) */
- memset((char *) tmpkey, 0, sizeof(mit_des_cblock));
- for (i=0; (i<seed_length) && (i<sizeof(mit_des_cblock)); i++)
- tmpkey[i] = (((krb5_octet *) seed)[i]) ^ 0xf0;
-
- keyblock.length = sizeof(mit_des_cblock);
- keyblock.contents = (krb5_octet *) tmpkey;
- keyblock.enctype = ENCTYPE_DES_CBC_MD4;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now decrypt it */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)cksum->contents,
- (mit_des_cblock *)&outtmp[0],
- NEW_RSA_MD4_DES_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)
- eblock.priv,
- zero_ivec,
- MIT_DES_DECRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- if ((retval = mit_des_finish_key(&eblock)))
- return(retval);
-
- /* Now that we have the decrypted checksum, try to regenerate it */
- krb5_md4_calculate_cksum(&working,
- (krb5_pointer) outtmp,
- (size_t) RSA_MD4_DES_CONFOUND_LENGTH,
- in,
- in_length);
-
- /* Compare the checksums */
- if (memcmp((char *) &outtmp[RSA_MD4_DES_CONFOUND_LENGTH],
- (char *) &working.digest[0],
- RSA_MD4_CKSUM_LENGTH))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
-
- /* Clean up droppings */
- memset((char *)&working, 0, sizeof(working));
- return(retval);
-}
-
-krb5_checksum_entry rsa_md4_des_cksumtable_entry =
-#if defined(MD4_K5BETA_COMPAT) && defined(MD4_K5BETA_COMPAT_DEF)
-{
- 0,
- krb5_md4_crypto_compat_sum_func,
- krb5_md4_crypto_verify_func,
- OLD_RSA_MD4_DES_CKSUM_LENGTH,
- 1, /* is collision proof */
- 1, /* uses key */
-};
-#else /* MD4_K5BETA_COMPAT && MD4_K5BETA_COMPAT_DEF */
-{
- 0,
- krb5_md4_crypto_sum_func,
- krb5_md4_crypto_verify_func,
- NEW_RSA_MD4_DES_CKSUM_LENGTH,
- 1, /* is collision proof */
- 1, /* uses key */
-};
-#endif /* MD4_K5BETA_COMPAT && MD4_K5BETA_COMPAT_DEF */
-
-#ifdef MD4_K5BETA_COMPAT
-/*
- * Turn on/off compatible checksum generation.
- */
-void
-krb5_md4_crypto_compat_ctl(scompat)
- krb5_boolean scompat;
-{
- if (scompat) {
- rsa_md4_des_cksumtable_entry.sum_func = krb5_md4_crypto_compat_sum_func;
- rsa_md4_des_cksumtable_entry.checksum_length =
- OLD_RSA_MD4_DES_CKSUM_LENGTH;
- }
- else {
- rsa_md4_des_cksumtable_entry.sum_func = krb5_md4_crypto_sum_func;
- rsa_md4_des_cksumtable_entry.checksum_length =
- NEW_RSA_MD4_DES_CKSUM_LENGTH;
- }
-}
-#endif /* MD4_K5BETA_COMPAT */
+++ /dev/null
-/*
- * lib/crypto/md4/md4driver.c
- */
-
-/*
- **********************************************************************
- ** md4driver.c -- sample routines to test **
- ** RSA Data Security, Inc. MD4 message digest algorithm. **
- ** Created: 2/16/90 RLR **
- ** Updated: 1/91 SRD **
- **********************************************************************
- */
-
-/*
- **********************************************************************
- ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
- ** **
- ** RSA Data Security, Inc. makes no representations concerning **
- ** either the merchantability of this software or the suitability **
- ** of this software for any particular purpose. It is provided "as **
- ** is" without express or implied warranty of any kind. **
- ** **
- ** These notices must be retained in any copies of any part of this **
- ** documentation and/or software. **
- **********************************************************************
- */
-
-#include "k5-int.h"
-#include "rsa-md4.h"
-
-/* Prints message digest buffer in mdContext as 32 hexadecimal digits.
- Order is from low-order byte to high-order byte of digest.
- Each byte is printed with high-order hexadecimal digit first.
- */
-static void MDPrint (mdContext)
-krb5_MD4_CTX *mdContext;
-{
- int i;
-
- for (i = 0; i < 16; i++)
- printf ("%02x", mdContext->digest[i]);
-}
-
-/* size of test block */
-#define TEST_BLOCK_SIZE 1000
-
-/* number of blocks to process */
-#define TEST_BLOCKS 2000
-
-/* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */
-static long TEST_BYTES = (long)TEST_BLOCK_SIZE * (long)TEST_BLOCKS;
-
-/* A time trial routine, to measure the speed of MD4.
- Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE
- characters.
- */
-static void MDTimeTrial ()
-{
- krb5_MD4_CTX mdContext;
- time_t endTime, startTime;
- unsigned char data[TEST_BLOCK_SIZE];
- unsigned int i;
-
- /* initialize test data */
- for (i = 0; i < TEST_BLOCK_SIZE; i++)
- data[i] = (unsigned char)(i & 0xFF);
-
- /* start timer */
- printf ("MD4 time trial. Processing %ld characters...\n", TEST_BYTES);
- time (&startTime);
-
- /* digest data in TEST_BLOCK_SIZE byte blocks */
- krb5_MD4Init (&mdContext);
- for (i = TEST_BLOCKS; i > 0; i--)
- krb5_MD4Update (&mdContext, data, TEST_BLOCK_SIZE);
- krb5_MD4Final (&mdContext);
- /* stop timer, get time difference */
- time (&endTime);
- MDPrint (&mdContext);
- printf (" is digest of test input.\n");
- printf
- ("Seconds to process test input: %ld\n", (long)(endTime-startTime));
- printf
- ("Characters processed per second: %ld\n",
- TEST_BYTES/(endTime-startTime));
-}
-
-/* Computes the message digest for string inString.
- Prints out message digest, a space, the string (in quotes) and a
- carriage return.
- */
-static void MDString (inString)
-char *inString;
-{
- krb5_MD4_CTX mdContext;
- unsigned int len = strlen (inString);
-
- krb5_MD4Init (&mdContext);
- krb5_MD4Update (&mdContext, inString, len);
- krb5_MD4Final (&mdContext);
- MDPrint (&mdContext);
- printf (" \"%s\"\n\n", inString);
-}
-
-/* Computes the message digest for a specified file.
- Prints out message digest, a space, the file name, and a carriage
- return.
- */
-static void MDFile (filename)
-char *filename;
-{
-#ifdef __STDC__
- FILE *inFile = fopen (filename, "rb");
-#else
- FILE *inFile = fopen (filename, "r");
-#endif
- krb5_MD4_CTX mdContext;
- int bytes;
- unsigned char data[1024];
-
- if (inFile == NULL) {
- printf ("%s can't be opened.\n", filename);
- return;
- }
-
- krb5_MD4Init (&mdContext);
- while ((bytes = fread (data, 1, 1024, inFile)) != 0)
- krb5_MD4Update (&mdContext, data, bytes);
- krb5_MD4Final (&mdContext);
- MDPrint (&mdContext);
- printf (" %s\n", filename);
- fclose (inFile);
-}
-
-
-/* Writes the message digest of the data from stdin onto stdout,
- followed by a carriage return.
- */
-static void MDFilter ()
-{
- krb5_MD4_CTX mdContext;
- int bytes;
- unsigned char data[16];
-
- krb5_MD4Init (&mdContext);
- while ((bytes = fread (data, 1, 16, stdin)) != 0)
- krb5_MD4Update (&mdContext, data, bytes);
- krb5_MD4Final (&mdContext);
- MDPrint (&mdContext);
- printf ("\n");
-}
-
-/* Runs a standard suite of test data.
- */
-static void MDTestSuite ()
-{
- printf ("MD4 test suite results:\n\n");
- MDString ("");
- MDString ("a");
- MDString ("abc");
- MDString ("message digest");
- MDString ("abcdefghijklmnopqrstuvwxyz");
- MDString
- ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
- MDString
- ("1234567890123456789012345678901234567890\
-1234567890123456789012345678901234567890");
- /* Contents of file foo are "abc" */
- MDFile ("foo");
-}
-
-void main (argc, argv)
-int argc;
-char *argv[];
-{
- int i;
-
- /* For each command line argument in turn:
- ** filename -- prints message digest and name of file
- ** -sstring -- prints message digest and contents of string
- ** -t -- prints time trial statistics for 1M characters
- ** -x -- execute a standard suite of test data
- ** (no args) -- writes messages digest of stdin onto stdout
- */
- if (argc == 1)
- MDFilter ();
- else
- for (i = 1; i < argc; i++)
- if (argv[i][0] == '-' && argv[i][1] == 's')
- MDString (argv[i] + 2);
- else if (strcmp (argv[i], "-t") == 0)
- MDTimeTrial ();
- else if (strcmp (argv[i], "-x") == 0)
- MDTestSuite ();
- else MDFile (argv[i]);
-}
-
-/*
- **********************************************************************
- ** End of md4driver.c **
- ******************************* (cut) ********************************
- */
+++ /dev/null
-/*
- * lib/crypto/md4/md4glue.c
- *
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * Kerberos glue for MD4 sample implementation.
- */
-
-#include "k5-int.h"
-#include "rsa-md4.h"
-
-/* Windows needs to these prototypes for the assignment below */
-
-krb5_error_code
-krb5_md4_sum_func PROTOTYPE((
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum FAR *outcksum));
-
-krb5_error_code
-krb5_md4_verify_func PROTOTYPE((
- krb5_const krb5_checksum FAR *cksum,
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length));
-
-krb5_error_code
-krb5_md4_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_octet *input = (krb5_octet *)in;
- krb5_MD4_CTX working;
-
- if (outcksum->length < RSA_MD4_CKSUM_LENGTH)
- return KRB5_BAD_MSIZE;
-
- krb5_MD4Init(&working);
- krb5_MD4Update(&working, input, in_length);
- krb5_MD4Final(&working);
-
- outcksum->checksum_type = CKSUMTYPE_RSA_MD4;
- outcksum->length = RSA_MD4_CKSUM_LENGTH;
-
- memcpy((char *)outcksum->contents, (char *)&working.digest[0],
- RSA_MD4_CKSUM_LENGTH);
-
- memset((char *)&working, 0, sizeof(working));
- return 0;
-}
-
-krb5_error_code
-krb5_md4_verify_func(cksum, in, in_length, seed, seed_length)
- krb5_const krb5_checksum FAR *cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
-{
- krb5_octet *input = (krb5_octet *)in;
- krb5_MD4_CTX working;
- krb5_error_code retval;
-
- retval = 0;
- if (cksum->checksum_type == CKSUMTYPE_RSA_MD4) {
- if (cksum->length == RSA_MD4_CKSUM_LENGTH) {
- krb5_MD4Init(&working);
- krb5_MD4Update(&working, input, in_length);
- krb5_MD4Final(&working);
-
- if (memcmp((char *) cksum->contents,
- (char *) &working.digest[0],
- RSA_MD4_CKSUM_LENGTH))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- memset((char *)&working, 0, sizeof(working));
- }
- else
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
- return retval;
-}
-
-krb5_checksum_entry rsa_md4_cksumtable_entry = {
- 0,
- krb5_md4_sum_func,
- krb5_md4_verify_func,
- RSA_MD4_CKSUM_LENGTH,
- 1, /* is collision proof */
- 0, /* doesn't use key */
-};
+Sun Jul 19 12:00:00 1998 Marc Horowitz <marc@mit.edu>
+
+ * *.c: replace the crypto layer.
+
Tue Mar 3 08:42:10 1998 Ezra Peisach <epeisach@kangaroo.mit.edu>
* Makefile.in (t_cksum): Do not depend on libkrb5.a, use
thisconfigdir=./..
BUILDTOP=$(REL)$(U)$(S)$(U)$(S)$(U)
-CFLAGS = $(CCOPTS) $(DEFS) -I$(srcdir)/../des
+CFLAGS = $(CCOPTS) $(DEFS)
##DOS##BUILDTOP = ..\..\..
##DOS##PREFIXDIR=md5
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
-RUN_SETUP = @KRB5_RUN_ENV@
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
-STLIBOBJS=md5.o md5glue.o md5crypto.o
+STLIBOBJS= md5.o
-OBJS= md5.$(OBJEXT) md5glue.$(OBJEXT) md5crypto.$(OBJEXT)
-SRCS= $(srcdir)/md5.c $(srcdir)/md5glue.c $(srcdir)/md5crypto.c
+OBJS= md5.$(OBJEXT)
+
+SRCS= $(srcdir)/md5.c
##DOS##LIBOBJS = $(OBJS)
all-unix:: all-libobjs
+includes:: depend
+
+depend:: $(SRCS)
+
t_mddriver: t_mddriver.o md5.o
$(CC) $(CFLAGS) $(LDFLAGS) -o t_mddriver t_mddriver.o md5.o
t_mddriver.exe:
$(CC) $(CFLAGS2) -o t_mddriver.exe t_mddriver.c md5.c
-t_cksum: t_cksum.o $(KRB5_BASE_DEPLIBS)
- $(CC_LINK) -o t_cksum t_cksum.o $(KRB5_BASE_LIBS)
-
-check-unix:: t_mddriver t_cksum
+check-unix:: t_mddriver
$(RUN_SETUP) $(C)t_mddriver -x
- $(RUN_SETUP) $(C)t_cksum "this is a test"
check-windows:: t_mddriver$(EXEEXT)
$(C)t_mddriver$(EXEEXT) -x
clean::
$(RM) t_mddriver$(EXEEXT) t_mddriver.$(OBJEXT)
- $(RM) t_cksum$(EXEEXT) t_cksum.$(OBJEXT)
clean-unix:: clean-libobjs
+++ /dev/null
-#include "k5-int.h"
-#include "rsa-md5.h"
-#include "des_int.h" /* we cheat a bit and call it directly... */
-
-/*
- * In Kerberos V5 Beta 5 and previous releases the RSA-MD5-DES implementation
- * did not follow RFC1510. The folowing definitions control the compatibility
- * with these releases.
- *
- * If MD5_K5BETA_COMPAT is defined, then compatability mode is enabled. That
- * means that both checksum functions are compiled and available for use and
- * the additional interface krb5_md5_crypto_compat_ctl() is defined.
- *
- * If MD5_K5BETA_COMPAT_DEF is defined and compatability mode is enabled, then
- * the compatible behaviour becomes the default.
- *
- */
-#define MD5_K5BETA_COMPAT
-#define MD5_K5BETA_COMPAT_DEF
-
-
-/* Windows needs to these prototypes for the assignment below */
-
-#ifdef MD5_K5BETA_COMPAT
-krb5_error_code
-krb5_md5_crypto_compat_sum_func PROTOTYPE((
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum FAR *outcksum));
-#endif
-
-krb5_error_code
-krb5_md5_crypto_sum_func PROTOTYPE((
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum FAR *outcksum));
-
-krb5_error_code
-krb5_md5_crypto_verify_func PROTOTYPE((
- krb5_const krb5_checksum FAR *cksum,
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length));
-
-static mit_des_cblock zero_ivec = { 0 };
-
-static void
-krb5_md5_calculate_cksum(md5ctx, confound, confound_length, in, in_length)
- krb5_MD5_CTX *md5ctx;
- krb5_pointer in;
- size_t in_length;
- krb5_pointer confound;
- size_t confound_length;
-{
- krb5_MD5Init(md5ctx);
- if (confound && confound_length)
- krb5_MD5Update(md5ctx, confound, confound_length);
- krb5_MD5Update(md5ctx, in, in_length);
- krb5_MD5Final(md5ctx);
-}
-
-#ifdef MD5_K5BETA_COMPAT
-krb5_error_code
-krb5_md5_crypto_compat_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_octet outtmp[OLD_RSA_MD5_DES_CKSUM_LENGTH];
- krb5_octet *input = (krb5_octet *)in;
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock;
- krb5_error_code retval;
-
- krb5_MD5_CTX working;
-
- krb5_MD5Init(&working);
- krb5_MD5Update(&working, input, in_length);
- krb5_MD5Final(&working);
-
- outcksum->checksum_type = CKSUMTYPE_RSA_MD5_DES;
- outcksum->length = OLD_RSA_MD5_DES_CKSUM_LENGTH;
-
- memcpy((char *)outtmp, (char *)&working.digest[0], 16);
-
- memset((char *)&working, 0, sizeof(working));
-
- keyblock.length = seed_length;
- keyblock.contents = (krb5_octet *)seed;
- keyblock.enctype = ENCTYPE_DES_CBC_MD5;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now encrypt it */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)&outtmp[0],
- (mit_des_cblock *)outcksum->contents,
- OLD_RSA_MD5_DES_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)eblock.priv,
- keyblock.contents,
- MIT_DES_ENCRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- return mit_des_finish_key(&eblock);
-}
-#endif /* MD5_K5BETA_COMPAT */
-
-krb5_error_code
-krb5_md5_crypto_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_octet outtmp[NEW_RSA_MD5_DES_CKSUM_LENGTH];
- mit_des_cblock tmpkey;
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock;
- krb5_error_code retval;
- size_t i;
- krb5_MD5_CTX working;
-
- if (outcksum->length < NEW_RSA_MD5_DES_CKSUM_LENGTH)
- return KRB5_BAD_MSIZE;
-
- /* Generate the confounder in place */
- if ((retval = krb5_random_confounder(RSA_MD5_DES_CONFOUND_LENGTH, outtmp)))
- return(retval);
-
- /* Calculate the checksum */
- krb5_md5_calculate_cksum(&working,
- (krb5_pointer) outtmp,
- (size_t) RSA_MD5_DES_CONFOUND_LENGTH,
- in,
- in_length);
-
- outcksum->checksum_type = CKSUMTYPE_RSA_MD5_DES;
- outcksum->length = NEW_RSA_MD5_DES_CKSUM_LENGTH;
-
- /* Now blast in the digest */
- memcpy((char *)&outtmp[RSA_MD5_DES_CONFOUND_LENGTH],
- (char *)&working.digest[0],
- RSA_MD5_CKSUM_LENGTH);
-
- /* Clean up the droppings */
- memset((char *)&working, 0, sizeof(working));
-
- /* Set up the temporary copy of the key (see RFC 1510 section 6.4.5) */
- memset((char *) tmpkey, 0, sizeof(mit_des_cblock));
- for (i=0; (i<seed_length) && (i<sizeof(mit_des_cblock)); i++)
- tmpkey[i] = (((krb5_octet *) seed)[i]) ^ 0xf0;
-
- keyblock.length = sizeof(mit_des_cblock);
- keyblock.contents = (krb5_octet *) tmpkey;
- keyblock.enctype = ENCTYPE_DES_CBC_MD5;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now encrypt it */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)&outtmp[0],
- (mit_des_cblock *)outcksum->contents,
- NEW_RSA_MD5_DES_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)eblock.priv,
- zero_ivec,
- MIT_DES_ENCRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- return mit_des_finish_key(&eblock);
-}
-
-krb5_error_code
-krb5_md5_crypto_verify_func(cksum, in, in_length, seed, seed_length)
- krb5_const krb5_checksum FAR *cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
-{
- krb5_octet outtmp[NEW_RSA_MD5_DES_CKSUM_LENGTH];
- mit_des_cblock tmpkey;
- krb5_encrypt_block eblock;
- krb5_keyblock keyblock;
- krb5_error_code retval;
- size_t i;
-
- krb5_MD5_CTX working;
-
- retval = 0;
- if (cksum->checksum_type == CKSUMTYPE_RSA_MD5_DES) {
-#ifdef MD5_K5BETA_COMPAT
- /*
- * We have a backwards compatibility problem here. Kerberos
- * version 5 Beta 5 and previous releases did not correctly
- * generate RSA-MD5-DES checksums. The way that we can
- * differentiate is by the length of the provided checksum.
- * If it's only OLD_RSA_MD5_DES_CKSUM_LENGTH, then it's the
- * old style, otherwise it's the correct implementation.
- */
- if (cksum->length == OLD_RSA_MD5_DES_CKSUM_LENGTH) {
- /*
- * If we're verifying the Old Style (tm) checksum, then we can just
- * recalculate the checksum and encrypt it and see if it's the
- * same.
- */
-
- /* Recalculate the checksum with no confounder */
- krb5_md5_calculate_cksum(&working,
- (krb5_pointer) NULL,
- (size_t) 0,
- in,
- in_length);
-
- /* Use the key "as-is" */
- keyblock.length = seed_length;
- keyblock.contents = (krb5_octet *) seed;
- keyblock.enctype = ENCTYPE_DES_CBC_MD5;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now encrypt the checksum */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)&working.digest[0],
- (mit_des_cblock *)&outtmp[0],
- OLD_RSA_MD5_DES_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)
- eblock.priv,
- keyblock.contents,
- MIT_DES_ENCRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- if ((retval = mit_des_finish_key(&eblock)))
- return(retval);
-
- /* Compare the encrypted checksums */
- if (memcmp((char *) &outtmp[0],
- (char *) cksum->contents,
- OLD_RSA_MD5_DES_CKSUM_LENGTH))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
-#endif /* MD5_K5BETA_COMPAT */
- if (cksum->length == (NEW_RSA_MD5_DES_CKSUM_LENGTH)) {
- /*
- * If we're verifying the correct implementation, then we have
- * to do a little more work because we must decrypt the checksum
- * because it contains the confounder in it. So, figure out
- * what our key variant is and then do it!
- */
-
- /* Set up the variant of the key (see RFC 1510 section 6.4.5) */
- memset((char *) tmpkey, 0, sizeof(mit_des_cblock));
- for (i=0; (i<seed_length) && (i<sizeof(mit_des_cblock)); i++)
- tmpkey[i] = (((krb5_octet *) seed)[i]) ^ 0xf0;
-
- keyblock.length = sizeof(mit_des_cblock);
- keyblock.contents = (krb5_octet *) tmpkey;
- keyblock.enctype = ENCTYPE_DES_CBC_MD5;
-
- if ((retval = mit_des_process_key(&eblock, &keyblock)))
- return retval;
- /* now decrypt it */
- retval = mit_des_cbc_encrypt((mit_des_cblock *)cksum->contents,
- (mit_des_cblock *)&outtmp[0],
- NEW_RSA_MD5_DES_CKSUM_LENGTH,
- (struct mit_des_ks_struct *)
- eblock.priv,
- zero_ivec,
- MIT_DES_DECRYPT);
- if (retval) {
- (void) mit_des_finish_key(&eblock);
- return retval;
- }
- if ((retval = mit_des_finish_key(&eblock)))
- return(retval);
-
- /* Now that we have the decrypted checksum, try to regenerate it */
- krb5_md5_calculate_cksum(&working,
- (krb5_pointer) outtmp,
- (size_t) RSA_MD5_DES_CONFOUND_LENGTH,
- in,
- in_length);
-
- /* Compare the checksums */
- if (memcmp((char *) &outtmp[RSA_MD5_DES_CONFOUND_LENGTH],
- (char *) &working.digest[0],
- RSA_MD5_CKSUM_LENGTH))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
-
- /* Clean up droppings */
- memset((char *)&working, 0, sizeof(working));
- return(retval);
-}
-
-krb5_checksum_entry rsa_md5_des_cksumtable_entry =
-#if defined(MD5_K5BETA_COMPAT) && defined(MD5_K5BETA_COMPAT_DEF)
-{
- 0,
- krb5_md5_crypto_compat_sum_func,
- krb5_md5_crypto_verify_func,
- OLD_RSA_MD5_DES_CKSUM_LENGTH,
- 1, /* is collision proof */
- 1, /* uses key */
-};
-#else /* MD5_K5BETA_COMPAT && MD5_K5BETA_COMPAT_DEF */
-{
- 0,
- krb5_md5_crypto_sum_func,
- krb5_md5_crypto_verify_func,
- NEW_RSA_MD5_DES_CKSUM_LENGTH,
- 1, /* is collision proof */
- 1, /* uses key */
-};
-#endif /* MD5_K5BETA_COMPAT && MD5_K5BETA_COMPAT_DEF */
-
-#ifdef MD5_K5BETA_COMPAT
-/*
- * Turn on/off compatible checksum generation.
- */
-void
-krb5_md5_crypto_compat_ctl(scompat)
- krb5_boolean scompat;
-{
- if (scompat) {
- rsa_md5_des_cksumtable_entry.sum_func = krb5_md5_crypto_compat_sum_func;
- rsa_md5_des_cksumtable_entry.checksum_length =
- OLD_RSA_MD5_DES_CKSUM_LENGTH;
- }
- else {
- rsa_md5_des_cksumtable_entry.sum_func = krb5_md5_crypto_sum_func;
- rsa_md5_des_cksumtable_entry.checksum_length =
- NEW_RSA_MD5_DES_CKSUM_LENGTH;
- }
-}
-#endif /* MD5_K5BETA_COMPAT */
-
+++ /dev/null
-#include "k5-int.h"
-#include "rsa-md5.h"
-
-/* Windows needs to these prototypes for the assignment below */
-
-krb5_error_code
-krb5_md5_sum_func PROTOTYPE((
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum FAR *outcksum));
-
-krb5_error_code
-krb5_md5_verify_func PROTOTYPE((
- krb5_const krb5_checksum FAR *cksum,
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length));
-
-krb5_error_code
-krb5_md5_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_octet *input = (krb5_octet *)in;
- krb5_MD5_CTX working;
-
- if (outcksum->length < RSA_MD5_CKSUM_LENGTH)
- return KRB5_BAD_MSIZE;
-
- krb5_MD5Init(&working);
- krb5_MD5Update(&working, input, in_length);
- krb5_MD5Final(&working);
-
- outcksum->checksum_type = CKSUMTYPE_RSA_MD5;
- outcksum->length = RSA_MD5_CKSUM_LENGTH;
-
- memcpy((char *)outcksum->contents, (char *)&working.digest[0], 16);
-
- memset((char *)&working, 0, sizeof(working));
- return 0;
-}
-
-krb5_error_code
-krb5_md5_verify_func(cksum, in, in_length, seed, seed_length)
- krb5_const krb5_checksum FAR *cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
-{
- krb5_octet *input = (krb5_octet *)in;
- krb5_MD5_CTX working;
- krb5_error_code retval;
-
- retval = 0;
- if (cksum->checksum_type == CKSUMTYPE_RSA_MD5) {
- if (cksum->length == RSA_MD5_CKSUM_LENGTH) {
- krb5_MD5Init(&working);
- krb5_MD5Update(&working, input, in_length);
- krb5_MD5Final(&working);
-
- if (memcmp((char *) cksum->contents,
- (char *) &working.digest[0],
- RSA_MD5_CKSUM_LENGTH))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- memset((char *)&working, 0, sizeof(working));
- }
- else
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- }
- else
- retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
- return retval;
-}
-
-krb5_checksum_entry rsa_md5_cksumtable_entry = {
- 0,
- krb5_md5_sum_func,
- krb5_md5_verify_func,
- RSA_MD5_CKSUM_LENGTH,
- 1, /* is collision proof */
- 0, /* doesn't use key */
-};
+++ /dev/null
-/*
- * lib/crypto/md5/t_cksum.c
- *
- * Copyright 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- */
-
-/*
- * t_cksum.c - Test checksum and checksum compatability for rsa-md[4,5]-des
- */
-
-#ifndef MD
-#define MD 5
-#endif /* MD */
-
-#include "k5-int.h"
-#if MD == 4
-#include "rsa-md4.h"
-#endif /* MD == 4 */
-#if MD == 5
-#include "rsa-md5.h"
-#endif /* MD == 5 */
-#include "des_int.h"
-
-#define MD5_K5BETA_COMPAT
-#define MD4_K5BETA_COMPAT
-
-#if MD == 4
-#define CONFOUNDER_LENGTH RSA_MD4_DES_CONFOUND_LENGTH
-#define NEW_CHECKSUM_LENGTH NEW_RSA_MD4_DES_CKSUM_LENGTH
-#define OLD_CHECKSUM_LENGTH OLD_RSA_MD4_DES_CKSUM_LENGTH
-#define CHECKSUM_TYPE CKSUMTYPE_RSA_MD4_DES
-#ifdef MD4_K5BETA_COMPAT
-#define K5BETA_COMPAT 1
-#else /* MD4_K5BETA_COMPAT */
-#undef K5BETA_COMPAT
-#endif /* MD4_K5BETA_COMPAT */
-#define CKSUM_FUNCTION krb5_md4_crypto_sum_func
-#define COMPAT_FUNCTION krb5_md4_crypto_compat_sum_func
-#define VERIFY_FUNCTION krb5_md4_crypto_verify_func
-#endif /* MD == 4 */
-
-#if MD == 5
-#define CONFOUNDER_LENGTH RSA_MD5_DES_CONFOUND_LENGTH
-#define NEW_CHECKSUM_LENGTH NEW_RSA_MD5_DES_CKSUM_LENGTH
-#define OLD_CHECKSUM_LENGTH OLD_RSA_MD5_DES_CKSUM_LENGTH
-#define CHECKSUM_TYPE CKSUMTYPE_RSA_MD5_DES
-#ifdef MD5_K5BETA_COMPAT
-#define K5BETA_COMPAT 1
-#else /* MD5_K5BETA_COMPAT */
-#undef K5BETA_COMPAT
-#endif /* MD5_K5BETA_COMPAT */
-#define CKSUM_FUNCTION krb5_md5_crypto_sum_func
-#define COMPAT_FUNCTION krb5_md5_crypto_compat_sum_func
-#define VERIFY_FUNCTION krb5_md5_crypto_verify_func
-#endif /* MD == 5 */
-
-static void
-print_checksum(text, number, message, checksum)
- char *text;
- int number;
- char *message;
- krb5_checksum *checksum;
-{
- int i;
-
- printf("%s MD%d checksum(\"%s\") = ", text, number, message);
- for (i=0; i<checksum->length; i++)
- printf("%02x", checksum->contents[i]);
- printf("\n");
-}
-
-/*
- * Test the checksum verification of Old Style (tm) and correct RSA-MD[4,5]-DES
- * checksums.
- */
-int
-main(argc, argv)
- int argc;
- char **argv;
-{
- int msgindex;
- krb5_context kcontext;
- krb5_encrypt_block encblock;
- krb5_keyblock keyblock;
- krb5_error_code kret;
- krb5_checksum oldstyle_checksum;
- krb5_checksum newstyle_checksum;
- krb5_data pwdata;
- char *pwd;
-
- pwd = "test password";
- pwdata.length = strlen(pwd);
- pwdata.data = pwd;
- krb5_use_enctype(kcontext, &encblock, DEFAULT_KDC_ENCTYPE);
- if ((kret = mit_des_string_to_key(&encblock, &keyblock, &pwdata, NULL))) {
- printf("mit_des_string_to_key choked with %d\n", kret);
- return(kret);
- }
- if ((kret = mit_des_process_key(&encblock, &keyblock))) {
- printf("mit_des_process_key choked with %d\n", kret);
- return(kret);
- }
-
- oldstyle_checksum.length = OLD_CHECKSUM_LENGTH;
- if (!(oldstyle_checksum.contents = (krb5_octet *) malloc(OLD_CHECKSUM_LENGTH))) {
- printf("cannot get memory for old style checksum\n");
- return(ENOMEM);
- }
- newstyle_checksum.length = NEW_CHECKSUM_LENGTH;
- if (!(newstyle_checksum.contents = (krb5_octet *)
- malloc(NEW_CHECKSUM_LENGTH))) {
- printf("cannot get memory for new style checksum\n");
- return(ENOMEM);
- }
- for (msgindex = 1; msgindex < argc; msgindex++) {
- if ((kret = CKSUM_FUNCTION(argv[msgindex],
- strlen(argv[msgindex]),
- (krb5_pointer) keyblock.contents,
- keyblock.length,
- &newstyle_checksum))) {
- printf("krb5_calculate_checksum choked with %d\n", kret);
- break;
- }
- print_checksum("correct", MD, argv[msgindex], &newstyle_checksum);
-#ifdef K5BETA_COMPAT
- if ((kret = COMPAT_FUNCTION(argv[msgindex],
- strlen(argv[msgindex]),
- (krb5_pointer) keyblock.contents,
- keyblock.length,
- &oldstyle_checksum))) {
- printf("old style calculate_checksum choked with %d\n", kret);
- break;
- }
- print_checksum("old", MD, argv[msgindex], &oldstyle_checksum);
-#endif /* K5BETA_COMPAT */
- if ((kret = VERIFY_FUNCTION(&newstyle_checksum,
- argv[msgindex],
- strlen(argv[msgindex]),
- (krb5_pointer) keyblock.contents,
- keyblock.length))) {
- printf("verify on new checksum choked with %d\n", kret);
- break;
- }
- printf("Verify succeeded for \"%s\"\n", argv[msgindex]);
-#ifdef K5BETA_COMPAT
- if ((kret = VERIFY_FUNCTION(&oldstyle_checksum,
- argv[msgindex],
- strlen(argv[msgindex]),
- (krb5_pointer) keyblock.contents,
- keyblock.length))) {
- printf("verify on old checksum choked with %d\n", kret);
- break;
- }
- printf("Compatible checksum verify succeeded for \"%s\"\n",
- argv[msgindex]);
-#endif /* K5BETA_COMPAT */
- newstyle_checksum.contents[0]++;
- if (!(kret = VERIFY_FUNCTION(&newstyle_checksum,
- argv[msgindex],
- strlen(argv[msgindex]),
- (krb5_pointer) keyblock.contents,
- keyblock.length))) {
- printf("verify on new checksum should have choked\n");
- break;
- }
- printf("Verify of bad checksum OK for \"%s\"\n", argv[msgindex]);
-#ifdef K5BETA_COMPAT
- oldstyle_checksum.contents[0]++;
- if (!(kret = VERIFY_FUNCTION(&oldstyle_checksum,
- argv[msgindex],
- strlen(argv[msgindex]),
- (krb5_pointer) keyblock.contents,
- keyblock.length))) {
- printf("verify on old checksum should have choked\n");
- break;
- }
- printf("Compatible checksum verify of altered checksum OK for \"%s\"\n",
- argv[msgindex]);
-#endif /* K5BETA_COMPAT */
- kret = 0;
- }
- if (!kret)
- printf("%d tests passed successfully for MD%d checksum\n", argc-1, MD);
- return(kret);
-}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include <memory.h>
+
+/*
+n-fold(k-bits):
+ l = lcm(n,k)
+ r = l/k
+ s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
+ compute the 1's complement sum:
+ n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
+*/
+
+/* representation: msb first, assume n and k are multiples of 8, and
+ that k>=16. this is the case of all the cryptosystems which are
+ likely to be used. this function can be replaced if that
+ assumption ever fails. */
+
+/* input length is in bits */
+
+void
+krb5_nfold(inbits, in, outbits, out)
+ int inbits;
+ krb5_const unsigned char *in;
+ int outbits;
+ unsigned char *out;
+{
+ int a,b,c,gcd,lcm;
+ int reps;
+ int byte, i, msbit;
+
+ /* the code below is more readable if I make these bytes
+ instead of bits */
+
+ inbits >>= 3;
+ outbits >>= 3;
+
+ /* first compute lcm(n,k) */
+
+ a = outbits;
+ b = inbits;
+
+ while(b != 0) {
+ c = b;
+ b = a%b;
+ a = c;
+ }
+
+ lcm = outbits*inbits/a;
+
+ /* now do the real work */
+
+ memset(out, 0, outbits);
+ byte = 0;
+
+ /* this will end up cycling through k lcm(k,n)/k times, which
+ is correct */
+ for (i=lcm-1; i>=0; i--) {
+ /* compute the msbit in k which gets added into this byte */
+ msbit = (/* first, start with the msbit in the first, unrotated
+ byte */
+ ((inbits<<3)-1)
+ /* then, for each byte, shift to the right for each
+ repetition */
+ +(((inbits<<3)+13)*(i/inbits))
+ /* last, pick out the correct byte within that
+ shifted repetition */
+ +((inbits-(i%inbits))<<3)
+ )%(inbits<<3);
+
+ /* pull out the byte value itself */
+ byte += (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
+ (in[((inbits)-(msbit>>3))%inbits]))
+ >>((msbit&7)+1))&0xff;
+
+ /* do the addition */
+ byte += out[i%outbits];
+ out[i%outbits] = byte&0xff;
+
+#if 0
+ printf("msbit[%d] = %d\tbyte = %02x\tsum = %03x\n", i, msbit,
+ (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
+ (in[((inbits)-(msbit>>3))%inbits]))
+ >>((msbit&7)+1))&0xff, byte);
+#endif
+
+ /* keep around the carry bit, if any */
+ byte >>= 8;
+
+#if 0
+ printf("carry=%d\n", byte);
+#endif
+ }
+
+ /* if there's a carry bit left over, add it back in */
+ if (byte) {
+ for (i=outbits-1; i>=0; i--) {
+ /* do the addition */
+ byte += out[i];
+ out[i] = byte&0xff;
+
+ /* keep around the carry bit, if any */
+ byte >>= 8;
+ }
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code krb5_encrypt(context, inptr, outptr, size, eblock, ivec)
+ krb5_context context;
+ krb5_const krb5_pointer inptr;
+ krb5_pointer outptr;
+ krb5_const size_t size;
+ krb5_encrypt_block FAR * eblock;
+ krb5_pointer ivec;
+{
+ krb5_data inputd, ivecd;
+ krb5_enc_data outputd;
+ size_t blocksize, outlen;
+ krb5_error_code ret;
+
+ if (ivec) {
+ if (ret = krb5_c_block_size(context, eblock->key->enctype, &blocksize))
+ return(ret);
+
+ ivecd.length = blocksize;
+ ivecd.data = ivec;
+ }
+
+ /* size is the length of the input cleartext data */
+ inputd.length = size;
+ inputd.data = inptr;
+
+ /* The size of the output buffer isn't part of the old api. Not too
+ safe. So, we assume here that it's big enough. */
+ if (ret = krb5_c_encrypt_length(context, eblock->key->enctype, size,
+ &outlen))
+ return(ret);
+
+ outputd.ciphertext.length = outlen;
+ outputd.ciphertext.data = outptr;
+
+ return(krb5_c_encrypt(context, eblock->key, 0, ivec?&ivecd:0,
+ &inputd, &outputd));
+}
+
+krb5_error_code krb5_decrypt(context, inptr, outptr, size, eblock, ivec)
+ krb5_context context;
+ krb5_const krb5_pointer inptr;
+ krb5_pointer outptr;
+ krb5_const size_t size;
+ krb5_encrypt_block FAR * eblock;
+ krb5_pointer ivec;
+{
+ krb5_enc_data inputd;
+ krb5_data outputd, ivecd;
+ size_t blocksize;
+ krb5_error_code ret;
+
+ if (ivec) {
+ if (ret = krb5_c_block_size(context, eblock->key->enctype, &blocksize))
+ return(ret);
+
+ ivecd.length = blocksize;
+ ivecd.data = ivec;
+ }
+
+ /* size is the length of the input ciphertext data */
+ inputd.enctype = eblock->key->enctype;
+ inputd.ciphertext.length = size;
+ inputd.ciphertext.data = inptr;
+
+ /* we don't really know how big this is, but the code tends to assume
+ that the output buffer size should be the same as the input
+ buffer size */
+ outputd.length = size;
+ outputd.data = outptr;
+
+ return(krb5_c_decrypt(context, eblock->key, 0, ivec?&ivecd:0,
+ &inputd, &outputd));
+}
+
+krb5_error_code krb5_process_key(context, eblock, key)
+ krb5_context context;
+ krb5_encrypt_block FAR * eblock;
+ krb5_const krb5_keyblock FAR * key;
+{
+ eblock->key = (krb5_keyblock *) key;
+
+ return(0);
+}
+
+krb5_error_code krb5_finish_key(context, eblock)
+ krb5_context context;
+ krb5_encrypt_block FAR * eblock;
+{
+ return(0);
+}
+
+krb5_error_code krb5_string_to_key(context, eblock, keyblock, data, salt)
+ krb5_context context;
+ krb5_const krb5_encrypt_block FAR * eblock;
+ krb5_keyblock FAR * keyblock;
+ krb5_const krb5_data FAR * data;
+ krb5_const krb5_data FAR * salt;
+{
+ return(krb5_c_string_to_key(context, eblock->crypto_entry, data, salt,
+ keyblock));
+}
+
+krb5_error_code krb5_init_random_key(context, eblock, keyblock, ptr)
+ krb5_context context;
+ krb5_const krb5_encrypt_block FAR * eblock;
+ krb5_const krb5_keyblock FAR * keyblock;
+ krb5_pointer FAR * ptr;
+{
+ krb5_data data;
+
+ data.length = keyblock->length;
+ data.data = keyblock->contents;
+
+ return(krb5_c_random_seed(context, &data));
+}
+
+krb5_error_code krb5_finish_random_key(context, eblock, ptr)
+ krb5_context context;
+ krb5_const krb5_encrypt_block FAR * eblock;
+ krb5_pointer FAR * ptr;
+{
+ return(0);
+}
+
+krb5_error_code krb5_random_key(context, eblock, ptr, keyblock)
+ krb5_context context;
+ krb5_const krb5_encrypt_block FAR * eblock;
+ krb5_pointer ptr;
+ krb5_keyblock FAR * FAR * keyblock;
+{
+ krb5_keyblock *key;
+ krb5_error_code ret;
+
+ if ((key = (krb5_keyblock *) malloc(sizeof(krb5_keyblock))) == NULL)
+ return(ENOMEM);
+
+ if (ret = krb5_c_make_random_key(context, eblock->crypto_entry, key))
+ free(key);
+
+ *keyblock = key;
+
+ return(ret);
+}
+
+krb5_enctype krb5_eblock_enctype(context, eblock)
+ krb5_context context;
+ krb5_const krb5_encrypt_block FAR * eblock;
+{
+ return(eblock->crypto_entry);
+}
+
+krb5_error_code krb5_use_enctype(context, eblock, enctype)
+ krb5_context context;
+ krb5_encrypt_block FAR * eblock;
+ krb5_const krb5_enctype enctype;
+{
+ eblock->crypto_entry = enctype;
+
+ return(0);
+}
+
+size_t krb5_encrypt_size(length, crypto)
+ size_t length;
+ krb5_enctype crypto;
+{
+ size_t ret;
+
+ if (krb5_c_encrypt_length(/* XXX */ 0, crypto, length, &ret))
+ return(-1); /* XXX */
+
+ return(ret);
+}
+
+size_t krb5_checksum_size(context, ctype)
+ krb5_context context;
+ krb5_cksumtype ctype;
+{
+ size_t ret;
+
+ if (krb5_c_checksum_length(context, ctype, &ret))
+ return(-1); /* XXX */
+
+ return(ret);
+}
+
+krb5_error_code krb5_calculate_checksum(context, ctype, in, in_length,
+ seed, seed_length, outcksum)
+ krb5_context context;
+ krb5_const krb5_cksumtype ctype;
+ krb5_const krb5_pointer in;
+ krb5_const size_t in_length;
+ krb5_const krb5_pointer seed;
+ krb5_const size_t seed_length;
+ krb5_checksum FAR * outcksum;
+{
+ krb5_data input;
+ krb5_keyblock key;
+ krb5_error_code ret;
+ krb5_checksum cksum;
+
+ input.data = in;
+ input.length = in_length;
+
+ key.length = seed_length;
+ key.contents = seed;
+
+ if (ret = krb5_c_make_checksum(context, ctype, &key, 0, &input, &cksum))
+ return(ret);
+
+ if (outcksum->length < cksum.length) {
+ memset(cksum.contents, 0, cksum.length);
+ free(cksum.contents);
+ return(KRB5_BAD_MSIZE);
+ }
+
+ outcksum->magic = cksum.magic;
+ outcksum->checksum_type = cksum.checksum_type;
+ memcpy(outcksum->contents, cksum.contents, cksum.length);
+ outcksum->length = cksum.length;
+
+ free(cksum.contents);
+
+ return(0);
+}
+
+krb5_error_code krb5_verify_checksum(context, ctype, cksum, in, in_length,
+ seed, seed_length)
+ krb5_context context;
+ krb5_cksumtype ctype;
+ krb5_const krb5_checksum FAR * cksum;
+ krb5_const krb5_pointer in;
+ krb5_const size_t in_length;
+ krb5_const krb5_pointer seed;
+ krb5_const size_t seed_length;
+{
+ krb5_data input;
+ krb5_keyblock key;
+ krb5_error_code ret;
+ krb5_boolean valid;
+
+ input.data = in;
+ input.length = in_length;
+
+ key.length = seed_length;
+ key.contents = seed;
+
+ if (ret = krb5_c_verify_checksum(context, &key, 0, &input, cksum,
+ &valid))
+ return(ret);
+
+ if (!valid)
+ return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
+
+ return(0);
+}
+
+krb5_error_code krb5_random_confounder(size, ptr)
+ size_t size;
+ krb5_pointer ptr;
+{
+ krb5_data random;
+
+ random.length = size;
+ random.data = ptr;
+
+ return(krb5_c_random_make_octets(/* XXX */ 0, &random));
+}
+
+krb5_error_code krb5_encrypt_data(context, key, ivec, data, enc_data)
+ krb5_context context;
+ krb5_keyblock *key;
+ krb5_pointer ivec;
+ krb5_data *data;
+ krb5_enc_data *enc_data;
+{
+ krb5_error_code ret;
+ size_t enclen, blocksize;
+ krb5_data ivecd;
+
+ if (ret = krb5_c_encrypt_length(context, key->enctype, data->length,
+ &enclen))
+ return(ret);
+
+ if (ivec) {
+ if (ret = krb5_c_block_size(context, key->enctype, &blocksize))
+ return(ret);
+
+ ivecd.length = blocksize;
+ ivecd.data = ivec;
+ }
+
+ enc_data->magic = KV5M_ENC_DATA;
+ enc_data->kvno = 0;
+ enc_data->enctype = key->enctype;
+ enc_data->ciphertext.length = enclen;
+ if ((enc_data->ciphertext.data = malloc(enclen)) == NULL)
+ return(ENOMEM);
+
+ if (ret = krb5_c_encrypt(context, key, 0, ivec?&ivecd:0, data, enc_data))
+ free(enc_data->ciphertext.data);
+
+ return(ret);
+}
+
+krb5_error_code krb5_decrypt_data(context, key, ivec, enc_data, data)
+ krb5_context context;
+ krb5_keyblock *key;
+ krb5_pointer ivec;
+ krb5_enc_data *enc_data;
+ krb5_data *data;
+{
+ krb5_error_code ret;
+ krb5_data ivecd;
+ size_t blocksize;
+
+ if (ivec) {
+ if (ret = krb5_c_block_size(context, key->enctype, &blocksize))
+ return(ret);
+
+ ivecd.length = blocksize;
+ ivecd.data = ivec;
+ }
+
+ data->length = enc_data->ciphertext.length;
+ if ((data->data = (krb5_octet *) malloc(data->length)) == NULL)
+ return(ENOMEM);
+
+ if (ret = krb5_c_decrypt(context, key, 0, ivec?&ivecd:0, enc_data, data))
+ free(data->data);
+
+ return(0);
+}
+++ /dev/null
-# Sanitize.in for Kerberos V5
-
-# Each directory to survive it's way into a release will need a file
-# like this one called "./.Sanitize". All keyword lines must exist,
-# and must exist in the order specified by this file. Each directory
-# in the tree will be processed, top down, in the following order.
-
-# Hash started lines like this one are comments and will be deleted
-# before anything else is done. Blank lines will also be squashed
-# out.
-
-# The lines between the "Do-first:" line and the "Things-to-keep:"
-# line are executed as a /bin/sh shell script before anything else is
-# done in this
-
-Do-first:
-
-# All files listed between the "Things-to-keep:" line and the
-# "Files-to-sed:" line will be kept. All other files will be removed.
-# Directories listed in this section will have their own Sanitize
-# called. Directories not listed will be removed in their entirety
-# with rm -rf.
-
-Things-to-keep:
-
-.cvsignore
-ChangeLog
-Makefile.in
-configure
-configure.in
-c_localaddr.c
-c_ustime.c
-rnd_confoun.c
-
-Things-to-lose:
-
-Do-last:
-
-# End of file.
+++ /dev/null
-Wed Feb 18 16:08:30 1998 Tom Yu <tlyu@mit.edu>
-
- * Makefile.in: Remove trailing slash from thisconfigdir. Fix up
- BUILDTOP for new conventions.
-
-Fri Feb 13 15:20:54 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * Makefile.in (thisconfigdir), configure.in: Point the
- configuration directory at our parent, and remove our
- local configure.in
-
-Mon Feb 2 17:02:29 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
-
-Fri Nov 28 21:23:42 1997 Tom Yu <tlyu@mit.edu>
-
- * configure.in: Add AC_PROG_LN_S to deal with symlinking in
- memmove.c. This is a kludge, as we really should have a more sane
- way to deal with missing posix functions.
-
-Thu Sep 25 21:53:11 1997 Tom Yu <tlyu@mit.edu>
-
- * c_localaddr.c: Replace KRB5_USE_INET with something more sane.
-
-Tue Aug 12 09:09:14 1997 Ezra Peisach <epeisach@mit.edu>
-
- * Makefile.in (SRCS): Add $(srcdir) as needed.
-
-Fri Jul 4 00:13:02 1997 Theodore Y. Ts'o <tytso@mit.edu>
-
- * c_localaddr.c (local_addr_fallback_kludge): Added Winsock
- kludge for finding your local IP address. May not work
- for all stacks, so we use it as a fallback.
-
-Sat Feb 22 18:54:53 1997 Richard Basch <basch@lehman.com>
-
- * Makefile.in: Use some of the new library list build rules in
- win-post.in
-
-Mon Feb 17 17:24:41 1997 Richard Basch <basch@lehman.com>
-
- * c_ustime.c: Fixed microsecond adjustment code (win32)
-
-Thu Nov 21 00:58:04 EST 1996 Richard Basch <basch@lehman.com>
-
- * Makefile.in: Win32 build
-
- * c_ustime.c: The Win32 time calculation is different from DOS'
- so the DOS version shouldn't be trying to use the same
- part of the ifdef.
-
- * rnd_confoun.c: Fix function declaration (win32)
-
-Sun Dec 29 21:54:42 1996 Tom Yu <tlyu@mit.edu>
-
- * Makefile.in:
- * configure.in: Update to use new library building procedure.
-
-Wed Jun 12 00:12:52 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * c_ustime.c: Fix WIN32 to be _WIN32
-
- * c_localaddr.c: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
-
-
-Sat Feb 24 00:34:15 1996 Theodore Y. Ts'o <tytso@dcl>
-
- * c_ustime.c (krb5_crypto_us_timeofday): Add Windows 95/NT time
- function. (Does this time function work under Windows?
- We'll find out....)
-
-Thu Feb 15 10:57:27 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
-
- * c_localaddr.c: Set magic number in krb5_address.
-
-Fri Oct 6 22:00:48 1995 Theodore Y. Ts'o <tytso@dcl>
-
- * Makefile.in: Remove ##DOS!include of config/windows.in.
- config/windows.in is now included by wconfig.
-
-Mon Sep 25 16:49:15 1995 Theodore Y. Ts'o <tytso@dcl>
-
- * Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
- Makefile.
-
-Fri Sep 22 12:00:00 1995 James Mattly <mattly@fusion.com>
-
- * c_localaddr.c: change close on a socket to closesocket, sockets on
- macintosh arn't files
-
-Wed Sep 13 10:33:53 1995 Keith Vetter (keithv@fusion.com)
-
- * Makefile.in: PC builds all C files because of function name changes.
- * c_localtime.c, c_ustime.c: removed INTERFACE keyword.
-
-Wed Sep 13 17:32:36 1995 Theodore Y. Ts'o <tytso@dcl>
-
- * c_localaddr.c (krb5_crypto_os_localaddr): Clear the buffer
- before calling the SIOCGIFCONF ioctl. This makes purify
- happy.
-
-Thu Sep 7 12:00:00 1995 James Mattly <mattly@fusion.com>
-
- * Renamed ustime.c to c_ustime.c
- * Renamed localaddr.c to c_localaddr.c because Mac can't have
- two files with the same name.
- * Makefile.in, .Sanitize updated for the above change.
-
-Thu Aug 24 18:40:48 1995 Theodore Y. Ts'o <tytso@dcl>
-
- * .Sanitize: Update file list
-
-Sat Jul 29 03:17:21 1995 Tom Yu <tlyu@lothlorien.MIT.EDU>
-
- * localaddr.c (krb5_crypto_os_localaddr): Don't bash the return
- from SIOCGIFCONF with the output of a SIOCGIFFLAGS. Duh.
-
-Wed Jul 19 17:17:54 1995 Tom Yu <tlyu@lothlorien.MIT.EDU>
-
- * localaddr.c: also add definition of max if it's not there.
-
- * localaddr.c: fix definition of ifreq_size so it actually works
-
-Mon Jul 17 16:04:00 1995 Sam Hartman <hartmans@tertius.mit.edu>
-
- * localaddr.c (krb5_crypto_os_localaddr): Deal with variable sized
- ifreq structures if sockaddr contains sa_len field.
-
- * configure.in: Check to see if struct sockaddr has sa_len.
-
-Thu Jul 6 17:13:11 1995 Tom Yu <tlyu@lothlorien.MIT.EDU>
-
- * localaddr.c: migrated from lib/krb5/os
-
- * ustime.c: migrated from lib/krb5/os; removed context variable
- from arglist.
-
- * Makefile.in: don't copy or remove localaddr.c and ustime.c;
- they're local now.
-
-Fri Jun 9 19:18:41 1995 <tytso@rsx-11.mit.edu>
-
- * configure.in: Remove standardized set of autoconf macros, which
- are now handled by CONFIG_RULES.
-
-Thu May 25 22:16:35 1995 Theodore Y. Ts'o (tytso@dcl)
-
- * configure.in, Makefile.in: Add support for shared libraries.
-
-Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
-
- * *.[ch]: removed unneeded INTERFACE from non-api functions.
-
-Sat Mar 25 15:38:23 1995 Mark Eichin <eichin@cygnus.com>
-
- * Makefile.in (memmove.c): memmove.c is in krb5/posix, not krb5/os.
-
-Wed Mar 22 11:44:07 1995 <tytso@rsx-11.mit.edu>
-
- * Makefile.in: Use $(SRCTOP) instead of $(srcdir), since Mac's
- don't like dealing with $(U)$(U).
-
-Fri Mar 17 16:21:46 1995 Theodore Y. Ts'o (tytso@dcl)
-
- * Makefile.in: Fix rules for localdr.c, ustime.c, and memmove.c so
- that they reference $(srcdir) where appropriate.
-
-Thu Mar 16 21:24:43 1995 John Gilmore (gnu at toad.com)
-
- * Makefile.in (LDFLAGS): Eliminate, comes in from pre.in.
- (all-mac): Add.
- (localaddr.c, ustime.c, memmove.c): Fix paths to work on Mac.
-
-Tue Mar 14 17:23:02 1995 Keith Vetter (keithv@fusion.com)
-
- * Makefile.in: no longer need to bring in ustime and localaddr for
- windows since everything's going into one DLL in the end.
-
-Thu Mar 2 17:56:48 1995 Keith Vetter (keithv@fusion.com)
-
- * Makefile.in: changed LIBNAME for the PC, and brought in ustime
- and localaddr from the krb/os directory.
- * rnd_conf.c: added cast to the seed assignment.
-
-Mon Feb 20 16:25:36 1995 Keith Vetter (keithv@fusion.com)
-
- * Makfile.in: made to work for the PC
- * rnd_confoun.c: added windows INTERFACE keyword
-
-Wed Jan 25 20:24:35 1995 John Gilmore (gnu at toad.com)
-
- * rnd_confoun.c: Replace <.../...> includes with "..."s.
-
-Mon Oct 24 14:58:14 1994 (tytso@rsx-11)
-
- * configure.in:
- * rnd_confoun.c (krb5_random_confounder): Use the srand48/lrand48
- functions if available.
-
-Fri Oct 14 00:21:05 1994 Theodore Y. Ts'o (tytso@dcl)
-
- * Makefile.in: Remove symlinked files on make clean.
-
+++ /dev/null
-thisconfigdir=./..
-BUILDTOP=$(REL)$(U)$(S)$(U)$(S)$(U)
-CFLAGS = $(CCOPTS) $(DEFS)
-
-##DOS##BUILDTOP = ..\..\..
-##DOS##PREFIXDIR=os
-##DOS##OBJFILE=..\os.lst
-##WIN16##LIBNAME=..\crypto.lib
-
-STLIBOBJS = rnd_confoun.o c_localaddr.o c_ustime.o @LIBOBJS@
-
-COBJS= rnd_confoun.$(OBJEXT) c_localaddr.$(OBJEXT) c_ustime.$(OBJEXT)
-OBJS= $(COBJS) $(LIBOBJS)
-
-SRCS= $(srcdir)/rnd_confoun.c $(srcdir)/c_localaddr.c $(srcdir)/c_ustime.c
-
-##DOS##LIBOBJS = $(COBJS)
-
-all-unix:: all-libobjs
-
-memmove.c: $(SRCTOP)$(S)lib$(S)krb5$(S)posix$(S)memmove.c
- -$(LN) $(SRCTOP)$(S)lib$(S)krb5$(S)posix$(S)memmove.c $@
-
-memmove.o: memmove.c
-
-clean-unix:: clean-libobjs
-clean::
- $(RM) memmove.c
+++ /dev/null
-/*
- * lib/crypto/os/c_localaddr.c
- *
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- *
- * Return the protocol addresses supported by this host.
- *
- * XNS support is untested, but "Should just work".
- */
-
-
-#define NEED_SOCKETS
-#include "k5-int.h"
-
-#if !defined(HAVE_MACSOCK_H) && !defined(_MSDOS) && !defined(_WIN32)
-
-/* needed for solaris, harmless elsewhere... */
-#define BSD_COMP
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <errno.h>
-
-/*
- * The SIOCGIF* ioctls require a socket.
- * It doesn't matter *what* kind of socket they use, but it has to be
- * a socket.
- *
- * Of course, you can't just ask the kernel for a socket of arbitrary
- * type; you have to ask for one with a valid type.
- *
- */
-#ifdef HAVE_NETINET_IN_H
-
-#include <netinet/in.h>
-
-#ifndef USE_AF
-#define USE_AF AF_INET
-#define USE_TYPE SOCK_DGRAM
-#define USE_PROTO 0
-#endif
-
-#endif
-
-#ifdef KRB5_USE_NS
-
-#include <netns/ns.h>
-
-#ifndef USE_AF
-#define USE_AF AF_NS
-#define USE_TYPE SOCK_DGRAM
-#define USE_PROTO 0 /* guess */
-#endif
-
-#endif
-/*
- * Add more address families here.
- */
-
-/*
- * BSD 4.4 defines the size of an ifreq to be
- * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
- * However, under earlier systems, sa_len isn't present, so the size is
- * just sizeof(struct ifreq)
- */
-#ifdef HAVE_SA_LEN
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-#define ifreq_size(i) max(sizeof(struct ifreq),\
- sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
-#else
-#define ifreq_size(i) sizeof(struct ifreq)
-#endif /* HAVE_SA_LEN*/
-
-
-
-extern int errno;
-
-/*
- * Return all the protocol addresses of this host.
- *
- * We could kludge up something to return all addresses, assuming that
- * they're valid kerberos protocol addresses, but we wouldn't know the
- * real size of the sockaddr or know which part of it was actually the
- * host part.
- *
- * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
- */
-
-krb5_error_code
-krb5_crypto_os_localaddr(addr)
- krb5_address ***addr;
-{
- struct ifreq *ifr, ifreq;
- struct ifconf ifc;
- int s, code, n, i;
- char buf[1024];
- krb5_address *addr_temp [ 1024/sizeof(struct ifreq) ];
- int n_found;
- int mem_err = 0;
-
- memset(buf, 0, sizeof(buf));
- ifc.ifc_len = sizeof(buf);
- ifc.ifc_buf = buf;
-
- s = socket (USE_AF, USE_TYPE, USE_PROTO);
- if (s < 0)
- return errno;
-
- code = ioctl (s, SIOCGIFCONF, (char *)&ifc);
- if (code < 0) {
- int retval = errno;
- closesocket (s);
- return retval;
- }
- n = ifc.ifc_len;
-
-n_found = 0;
- for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
- krb5_address *address;
- ifr = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
-
- strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
- if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0)
- continue;
-
-#ifdef IFF_LOOPBACK
- if (ifreq.ifr_flags & IFF_LOOPBACK)
- continue;
-#endif
-
- if (!(ifreq.ifr_flags & IFF_UP))
- /* interface is down; skip */
- continue;
-
- /* ifr->ifr_addr has what we want! */
- switch (ifr->ifr_addr.sa_family) {
-#ifdef HAVE_NETINET_IN_H
- case AF_INET:
- {
- struct sockaddr_in *in =
- (struct sockaddr_in *)&ifr->ifr_addr;
-
- address = (krb5_address *)
- malloc (sizeof(krb5_address));
- if (address) {
- address->magic = KV5M_ADDRESS;
- address->addrtype = ADDRTYPE_INET;
- address->length = sizeof(struct in_addr);
- address->contents = (unsigned char *)malloc(address->length);
- if (!address->contents) {
- krb5_xfree(address);
- address = 0;
- mem_err++;
- } else {
- memcpy ((char *)address->contents,
- (char *)&in->sin_addr,
- address->length);
- break;
- }
- } else mem_err++;
- }
-#endif
-#ifdef KRB5_USE_NS
- case AF_XNS:
- {
- struct sockaddr_ns *ns =
- (struct sockaddr_ns *)&ifr->ifr_addr;
- address = (krb5_address *)
- malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
- if (address) {
- address->magic = KV5M_ADDRESS;
- address->addrtype = ADDRTYPE_XNS;
-
- /* XXX should we perhaps use ns_host instead? */
-
- address->length = sizeof(struct ns_addr);
- address->contents = (unsigned char *)malloc(address->length);
- if (!address->contents) {
- krb5_xfree(address);
- address = 0;
- mem_err++;
- } else {
- memcpy ((char *)address->contents,
- (char *)&ns->sns_addr,
- address->length);
- break;
- }
- } else mem_err++;
- break;
- }
-#endif
- /*
- * Add more address families here..
- */
- default:
- continue;
- }
- if (address)
- addr_temp[n_found++] = address;
- address = 0;
- }
- closesocket(s);
-
- *addr = (krb5_address **)malloc (sizeof (krb5_address *) * (n_found+1));
- if (*addr == 0)
- mem_err++;
-
- if (mem_err) {
- for (i=0; i<n_found; i++) {
- krb5_xfree(addr_temp[i]);
- addr_temp[i] = 0;
- }
- return ENOMEM;
- }
-
- for (i=0; i<n_found; i++) {
- (*addr)[i] = addr_temp[i];
- }
- (*addr)[n_found] = 0;
- return 0;
-}
-
-#else /* Windows/Mac version */
-
-/*
- * Hold on to your lunch! Backup kludge method of obtaining your
- * local IP address, courtesy of Windows Socket Network Programming,
- * by Robert Quinn
- */
-#if defined(_MSDOS) || defined(_WIN32)
-static struct hostent *local_addr_fallback_kludge()
-{
- static struct hostent host;
- static SOCKADDR_IN addr;
- static char * ip_ptrs[2];
- SOCKET sock;
- int size = sizeof(SOCKADDR);
- int err;
-
- sock = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock == INVALID_SOCKET)
- return NULL;
-
- /* connect to arbitrary port and address (NOT loopback) */
- addr.sin_family = AF_INET;
- addr.sin_port = htons(IPPORT_ECHO);
- addr.sin_addr.s_addr = inet_addr("204.137.220.51");
-
- err = connect(sock, (LPSOCKADDR) &addr, sizeof(SOCKADDR));
- if (err == SOCKET_ERROR)
- return NULL;
-
- err = getsockname(sock, (LPSOCKADDR) &addr, (int FAR *) size);
- if (err == SOCKET_ERROR)
- return NULL;
-
- closesocket(sock);
-
- host.h_name = 0;
- host.h_aliases = 0;
- host.h_addrtype = AF_INET;
- host.h_length = 4;
- host.h_addr_list = ip_ptrs;
- ip_ptrs[0] = (char *) &addr.sin_addr.s_addr;
- ip_ptrs[1] = NULL;
-
- return &host;
-}
-#endif
-
-/* No ioctls in winsock so we just assume there is only one networking
- * card per machine, so gethostent is good enough.
- */
-krb5_error_code
-krb5_crypto_os_localaddr (krb5_address ***addr) {
- char host[64]; /* Name of local machine */
- struct hostent *hostrec;
- int err;
-
- *addr = calloc (2, sizeof (krb5_address *));
- if (*addr == NULL)
- return ENOMEM;
-
-#ifdef HAVE_MACSOCK_H
- hostrec = getmyipaddr();
-#else /* HAVE_MACSOCK_H */
- err = 0;
-
- if (gethostname (host, sizeof(host))) {
- err = WSAGetLastError();
- }
-
- if (!err) {
- hostrec = gethostbyname (host);
- if (hostrec == NULL) {
- err = WSAGetLastError();
- }
- }
-
- if (err) {
- hostrec = local_addr_fallback_kludge();
- if (!hostrec)
- return err;
- }
-#endif /* HAVE_MACSOCK_H */
-
- (*addr)[0] = calloc (1, sizeof(krb5_address));
- if ((*addr)[0] == NULL) {
- free (*addr);
- return ENOMEM;
- }
- (*addr)[0]->magic = KV5M_ADDRESS;
- (*addr)[0]->addrtype = hostrec->h_addrtype;
- (*addr)[0]->length = hostrec->h_length;
- (*addr)[0]->contents = (unsigned char *)malloc((*addr)[0]->length);
- if (!(*addr)[0]->contents) {
- free((*addr)[0]);
- free(*addr);
- return ENOMEM;
- } else {
- memcpy ((*addr)[0]->contents,
- hostrec->h_addr,
- (*addr)[0]->length);
- }
- /* FIXME, deal with the case where gethostent returns multiple addrs */
-
- return(0);
-}
-#endif
+++ /dev/null
-/*
- * lib/crypto/os/rnd_confoun.c
- *
- * Copyright 1990 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- *
- * krb5_random_confounder()
- */
-
-#include "k5-int.h"
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#ifdef TIME_WITH_SYS_TIME
-#include <time.h>
-#endif
-#else
-#include <time.h>
-#endif
-
-#ifdef HAVE_SRAND48
-#define SRAND srand48
-#define RAND lrand48
-#define RAND_TYPE long
-#endif
-
-#if !defined(RAND_TYPE) && defined(HAVE_SRAND)
-#define SRAND srand
-#define RAND rand
-#define RAND_TYPE int
-#endif
-
-#if !defined(RAND_TYPE) && defined(HAVE_SRANDOM)
-#define SRAND srandom
-#define RAND random
-#define RAND_TYPE long
-#endif
-
-#if !defined(RAND_TYPE)
-You need a random number generator!
-#endif
-
-/*
- * Generate a random confounder
- */
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_random_confounder(size, fillin)
-size_t size;
-krb5_pointer fillin;
-{
- static int seeded = 0;
- register krb5_octet *real_fill;
- RAND_TYPE rval;
-
- if (!seeded) {
- /* time() defined in 4.12.2.4, but returns a time_t, which is an
- "arithmetic type" (4.12.1) */
- rval = (RAND_TYPE) time(0);
- SRAND(rval);
-#ifdef HAVE_GETPID
- rval = RAND();
- rval ^= getpid();
- SRAND(rval);
-#endif
- seeded = 1;
- }
-
- real_fill = (krb5_octet *)fillin;
- while (size > 0) {
- rval = RAND();
- *real_fill = rval & 0xff;
- real_fill++;
- size--;
- if (size) {
- *real_fill = (rval >> 8) & 0xff;
- real_fill++;
- size--;
- }
- }
- return 0;
-}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "enc_provider.h"
+
+/* This random number generator is a feedback generator based on a
+ block cipher. It uses DES by default, since it guaranteed to be
+ present in the system, but can be changed. As new seed data comes
+ in, the old state is folded with the new seed into new state. Each
+ time random bytes are requested, the seed is used as a key and
+ cblock, and the encryption is used as the output. The output is
+ fed back as new seed data, as described above. */
+
+/* this can be replaced with another encryption provider, since
+ everything below uses it abstractly */
+
+struct krb5_enc_provider *enc = &krb5_enc_des;
+
+/* XXX state. Should it be in krb5_context? */
+
+static int inited = 0;
+static size_t blocksize, keybytes, keylength;
+static int random_count;
+/* keybytes | state-block | encblock | key | new-keybytes | new-state-block */
+static unsigned char *random_state;
+#define STATE (random_state)
+#define STATEKEY (STATE)
+#define STATEBLOCK (STATEKEY+keybytes)
+#define STATESIZE (keybytes+blocksize)
+#define OUTPUT (STATE)
+#define OUTPUTSIZE (STATESIZE+blocksize)
+#define RANDBLOCK (STATEBLOCK+blocksize)
+#define KEYCONTENTS (RANDBLOCK+blocksize)
+#define NEWSTATE (KEYCONTENTS+keylength)
+#define ALLSTATESIZE (keybytes+blocksize*2+keylength+keybytes+blocksize)
+
+krb5_error_code
+krb5_c_random_seed(krb5_context context, krb5_data *data)
+{
+ unsigned char *fold_input;
+
+ if (inited == 0) {
+ /* this does a bunch of malloc'ing up front, so that
+ generating random keys doesn't have to malloc, so it can't
+ fail. seeding still malloc's, but that's less common. */
+
+ enc->block_size(&blocksize);
+ enc->keysize(&keybytes, &keylength);
+ if ((random_state = (unsigned char *) malloc(ALLSTATESIZE)) == NULL)
+ return(ENOMEM);
+ random_count = 0;
+ inited = 1;
+
+ krb5_nfold(data->length*8, data->data, STATESIZE*8, STATE);
+
+ return(0);
+ }
+
+ if ((fold_input =
+ (unsigned char *) malloc(data->length+STATESIZE)) == NULL)
+ return(ENOMEM);
+
+ memcpy(fold_input, data->data, data->length);
+ memcpy(fold_input+data->length, STATE, STATESIZE);
+
+ krb5_nfold((data->length+STATESIZE)*8, fold_input,
+ STATESIZE*8, STATE);
+ free(fold_input);
+ return(0);
+}
+
+krb5_error_code
+krb5_c_random_make_octets(krb5_context context, krb5_data *data)
+{
+ krb5_error_code ret;
+ krb5_data data1, data2;
+ krb5_keyblock key;
+ int bytes;
+
+ if (inited == 0) {
+ /* i need some entropy. I'd use the current time and pid, but
+ that could cause portability problems. */
+ abort();
+ }
+
+ bytes = 0;
+
+ while (bytes < data->length) {
+ if (random_count == 0) {
+ /* set up random krb5_data, and key to be filled in */
+ data1.length = keybytes;
+ data1.data = STATEKEY;
+ key.length = keylength;
+ key.contents = KEYCONTENTS;
+
+ /* fill it in */
+ if (ret = ((*(enc->make_key))(&data1, &key)))
+ return(ret);
+
+ /* encrypt the block */
+ data1.length = blocksize;
+ data1.data = STATEBLOCK;
+ data2.length = blocksize;
+ data2.data = RANDBLOCK;
+ if (ret = ((*(enc->encrypt))(&key, NULL, &data1, &data2)))
+ return(ret);
+
+ /* fold the new output back into the state */
+
+ krb5_nfold(OUTPUTSIZE*8, OUTPUT, STATESIZE*8, NEWSTATE);
+ memcpy(STATE, NEWSTATE, STATESIZE);
+
+ random_count = blocksize;
+ }
+
+ if ((data->length - bytes) <= random_count) {
+ memcpy(data->data + bytes, RANDBLOCK+(blocksize-random_count),
+ data->length - bytes);
+ random_count -= (data->length - bytes);
+ break;
+ }
+
+ memcpy(data->data + bytes, RANDBLOCK+(blocksize - random_count),
+ random_count);
+
+ bytes += random_count;
+ random_count = 0;
+ }
+
+ return(0);
+}
+++ /dev/null
-/*
- * lib/crypto/raw-des.c
- *
- * Copyright 1994, 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-
-krb5_error_code mit_raw_des_encrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-krb5_error_code mit_raw_des_decrypt_func
- PROTOTYPE(( krb5_const_pointer, krb5_pointer, const size_t,
- krb5_encrypt_block *, krb5_pointer ));
-
-static krb5_cryptosystem_entry mit_raw_des_cryptosystem_entry = {
- 0,
- mit_raw_des_encrypt_func,
- mit_raw_des_decrypt_func,
- mit_des_process_key,
- mit_des_finish_key,
- mit_des_string_to_key,
- mit_des_init_random_key,
- mit_des_finish_random_key,
- mit_des_random_key,
- sizeof(mit_des_cblock),
- 0,
- sizeof(mit_des_cblock),
- ENCTYPE_DES_CBC_RAW
- };
-
-krb5_cs_table_entry krb5_raw_des_cst_entry = {
- 0,
- &mit_raw_des_cryptosystem_entry,
- 0
- };
-
-krb5_error_code
-mit_raw_des_decrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- return (mit_des_cbc_encrypt ((const mit_des_cblock *) in,
- out,
- size,
- (struct mit_des_ks_struct *)key->priv,
- ivec ? ivec : (krb5_pointer)key->key->contents,
- MIT_DES_DECRYPT));
-}
-
-krb5_error_code
-mit_raw_des_encrypt_func(in, out, size, key, ivec)
- krb5_const_pointer in;
- krb5_pointer out;
- const size_t size;
- krb5_encrypt_block * key;
- krb5_pointer ivec;
-{
- int sumsize;
-
- /* round up to des block size */
-
- sumsize = krb5_roundup(size, sizeof(mit_des_cblock));
-
- /* assemble crypto input into the output area, then encrypt in place. */
-
- memset((char *)out, 0, sumsize);
- memcpy((char *)out, (char *)in, size);
-
- /* We depend here on the ability of this DES implementation to
- encrypt plaintext to ciphertext in-place. */
- return (mit_des_cbc_encrypt (out,
- out,
- sumsize,
- (struct mit_des_ks_struct *)key->priv,
- ivec ? ivec : (krb5_pointer)key->key->contents,
- MIT_DES_ENCRYPT));
-}
+++ /dev/null
-# Sanitize.in for Kerberos V5
-
-# Each directory to survive it's way into a release will need a file
-# like this one called "./.Sanitize". All keyword lines must exist,
-# and must exist in the order specified by this file. Each directory
-# in the tree will be processed, top down, in the following order.
-
-# Hash started lines like this one are comments and will be deleted
-# before anything else is done. Blank lines will also be squashed
-# out.
-
-# The lines between the "Do-first:" line and the "Things-to-keep:"
-# line are executed as a /bin/sh shell script before anything else is
-# done in this
-
-Do-first:
-
-# All files listed between the "Things-to-keep:" line and the
-# "Files-to-sed:" line will be kept. All other files will be removed.
-# Directories listed in this section will have their own Sanitize
-# called. Directories not listed will be removed in their entirety
-# with rm -rf.
-
-Things-to-keep:
-
-.cvsignore
-ChangeLog
-Makefile.in
-configure
-configure.in
-sha_crypto.c
-sha_glue.c
-shs.c
-shs.h
-hmac_sha.c
-t_shs.c
-
-Things-to-lose:
-
-Do-last:
-
-# End of file.
+++ /dev/null
-Wed Feb 18 16:09:05 1998 Tom Yu <tlyu@mit.edu>
-
- * Makefile.in: Remove trailing slash from thisconfigdir. Fix up
- BUILDTOP for new conventions.
-
-Fri Feb 13 15:20:54 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * Makefile.in (thisconfigdir), configure.in: Point the
- configuration directory at our parent, and remove our
- local configure.in
-
-Mon Feb 2 17:02:29 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
-
-Tue Oct 28 16:37:18 1997 Tom Yu <tlyu@voltage-multiplier.mit.edu>
-
- * shs.c, sha_glue.c, hmac_sha.c: Fix to deal with LONG wider than
- 32 bits.
-
- * t_shs.c: Print out the actual and expected values on error.
-
-Sat Feb 22 18:52:09 1997 Richard Basch <basch@lehman.com>
-
- * Makefile.in: Use some of the new library list build rules in
- win-post.in
-
-Thu Jan 30 21:31:39 1997 Richard Basch <basch@lehman.com>
-
- * sha_crypto.c sha_glue.c:
- Declare the functions to take const args where possible
- Remove extra includes
-
- * sha_crypto.c: Function prototypes did not match function names.
-
-Thu Nov 21 00:58:04 EST 1996 Richard Basch <basch@lehman.com>
-
- * Makefile.in: Win32 build fixed
-
-Sun Dec 29 21:56:35 1996 Tom Yu <tlyu@mit.edu>
-
- * Makefile.in:
- * configure.in: Update to use new library build procedure.
-
-Wed Aug 28 17:40:53 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * shs.c: Only include sys/types.h if present.
-
- * configure.in: Check for sys/types.h
-
-Thu Jun 13 10:54:27 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
-
- * hmac_sha.c: Include string.h for memcpy prototype
-
-Sat Jun 8 07:44:35 1996 Ezra Peisach (epeisach@mit.edu)
-
- * shs.c (longReverse): Test for big vs little endian failed for
- little endian machines.
-
-Thu Jun 6 15:43:26 1996 Theodore Y. Ts'o <tytso@mit.edu>
-
- * shs.c (longReverse): Don't use htonl(); it doesn't exist under
- Windows. Instead do the test by casting a pointer to an
- integer to a char *.
-
-Mon May 20 17:15:32 1996 Theodore Y. Ts'o <tytso@mit.edu>
-
- * t_shs.c (main): Don't do timing tests; it takes too long!
-
-Tue May 14 17:09:36 1996 Richard Basch <basch@lehman.com>
-
- * .Sanitize: reflect current files
- * Makefile.in: added hmac-sha
- * hmac_sha.c: implement HMAC-SHA
- * sha_crypto.c: use hmac-sha
- * sha_glue.c: sanity check the passed in checksum length
- * shs.h: replaced sha-des3 with hmac-sha
-
-Fri May 10 11:19:53 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
-
- * shs.c (longReverse): Remove extraneous \.
- (expand): Start #define in first column.
-
-Fri May 10 01:19:18 1996 Richard Basch <basch@lehman.com>
-
- * Makefile.in configure.in t_shs.c sha_glue.c sha_crypto.c shs.c shs.h:
- Initial check-in of the functions to support the NIST FIPS 180
- SHA algorithm. Provide interfaces for cksum-sha, cksum-sha-des3.
- (enctype-des3-sha is also being defined)
+++ /dev/null
-thisconfigdir=./..
-BUILDTOP=$(REL)$(U)$(S)$(U)$(S)$(U)
-CFLAGS = $(CCOPTS) $(DEFS) -I$(srcdir)/../des
-
-##DOS##BUILDTOP = ..\..\..
-##DOS##PREFIXDIR=sha
-##DOS##OBJFILE=..\sha.lst
-##WIN16##LIBNAME=..\crypto.lib
-
-STLIBOBJS=shs.o hmac_sha.o sha_crypto.o sha_glue.o
-
-OBJS= shs.$(OBJEXT) \
- hmac_sha.$(OBJEXT) \
- sha_crypto.$(OBJEXT) \
- sha_glue.$(OBJEXT)
-
-SRCS= $(srcdir)/shs.c \
- $(srcdir)/hmac_sha.c \
- $(srcdir)/sha_crypto.c \
- $(srcdir)/sha_glue.c
-
-
-##DOS##LIBOBJS = $(OBJS)
-
-
-all-unix:: all-libobjs
-
-t_shs: t_shs.o shs.o
- $(CC) $(CFLAGS) $(LDFLAGS) -o t_shs t_shs.o shs.o
-
-t_shs.exe:
- $(CC) $(CFLAGS2) -o t_shs.exe t_shs.c shs.c
-
-check-unix:: t_shs
- $(C)t_shs -x
-
-check-windows:: t_shs$(EXEEXT)
- $(C)t_shs$(EXEEXT) -x
-
-clean::
- $(RM) t_shs$(EXEEXT) t_shs.$(OBJEXT)
-
-clean-unix:: clean-libobjs
+++ /dev/null
-#include <string.h>
-#include "shs.h"
-
-#define PAD_SZ 64
-
-
-krb5_error_code
-hmac_sha(text, text_len, key, key_len, digest)
- krb5_octet * text; /* pointer to data stream */
- int text_len; /* length of data stream */
- krb5_octet * key; /* pointer to authentication key */
- int key_len; /* length of authentication key */
- krb5_octet * digest; /* caller digest to be filled in */
-{
- SHS_INFO context;
- krb5_octet k_ipad[PAD_SZ]; /* inner padding - key XORd with ipad */
- krb5_octet k_opad[PAD_SZ]; /* outer padding - key XORd with opad */
- int i;
- krb5_octet *cp;
- LONG *lp;
-
- /* sanity check parameters */
- if (!text || !key || !digest)
- /* most heinous, probably should log something */
- return EINVAL;
-
- /* if key is longer than 64 bytes reset it to key=SHA(key) */
- if (key_len > sizeof(k_ipad)) {
- shsInit(&context);
- shsUpdate(&context, key, key_len);
- shsFinal(&context);
-
- cp = digest;
- lp = context.digest;
- while (cp < digest + SHS_DIGESTSIZE) {
- *cp++ = (*lp >> 24) & 0xff;
- *cp++ = (*lp >> 16) & 0xff;
- *cp++ = (*lp >> 8) & 0xff;
- *cp++ = *lp++ & 0xff;
- }
- key = digest;
- key_len = SHS_DIGESTSIZE;
- }
-
- /*
- * the HMAC_SHA transform looks like:
- *
- * SHA(K XOR opad, SHA(K XOR ipad, text))
- *
- * where K is an n byte key
- * ipad is the byte 0x36 repeated 64 times
- * opad is the byte 0x5c repeated 64 times
- * and text is the data being protected
- */
-
- /* start out by storing key in pads */
- memset(k_ipad, 0x36, sizeof(k_ipad));
- memset(k_opad, 0x5c, sizeof(k_opad));
-
- /* XOR key with ipad and opad values */
- for (i = 0; i < key_len; i++) {
- k_ipad[i] ^= key[i];
- k_opad[i] ^= key[i];
- }
-
- /*
- * perform inner SHA
- */
- shsInit(&context);
- shsUpdate(&context, k_ipad, sizeof(k_ipad));
- shsUpdate(&context, text, text_len);
- shsFinal(&context);
-
- cp = digest;
- lp = context.digest;
- while (cp < digest + SHS_DIGESTSIZE) {
- *cp++ = (*lp >> 24) & 0xff;
- *cp++ = (*lp >> 16) & 0xff;
- *cp++ = (*lp >> 8) & 0xff;
- *cp++ = *lp++ & 0xff;
- }
-
- /*
- * perform outer SHA
- */
- shsInit(&context);
- shsUpdate(&context, k_opad, sizeof(k_opad));
- shsUpdate(&context, digest, SHS_DIGESTSIZE);
- shsFinal(&context);
-
- cp = digest;
- lp = context.digest;
- while (cp < digest + SHS_DIGESTSIZE) {
- *cp++ = (*lp >> 24) & 0xff;
- *cp++ = (*lp >> 16) & 0xff;
- *cp++ = (*lp >> 8) & 0xff;
- *cp++ = *lp++ & 0xff;
- }
-
- return 0;
-}
+++ /dev/null
-#include "shs.h"
-
-/* Windows needs to these prototypes for the assignment below */
-
-static krb5_error_code
-krb5_sha_crypto_sum_func
- PROTOTYPE((krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum FAR *outcksum));
-
-static krb5_error_code
-krb5_sha_crypto_verify_func
- PROTOTYPE((krb5_const krb5_checksum FAR *cksum,
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length));
-
-static krb5_error_code
-krb5_sha_crypto_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_error_code retval;
-
- if (outcksum->length < HMAC_SHA_CKSUM_LENGTH)
- return KRB5_BAD_MSIZE;
-
- outcksum->checksum_type = CKSUMTYPE_HMAC_SHA;
- outcksum->length = HMAC_SHA_CKSUM_LENGTH;
-
- retval = hmac_sha(in, in_length, seed, seed_length, outcksum->contents);
- return retval;
-}
-
-static krb5_error_code
-krb5_sha_crypto_verify_func(cksum, in, in_length, seed, seed_length)
- krb5_const krb5_checksum FAR *cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
-{
- krb5_octet digest[HMAC_SHA_CKSUM_LENGTH];
- krb5_error_code retval;
-
- if (cksum->checksum_type != CKSUMTYPE_HMAC_SHA)
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
- if (cksum->length != HMAC_SHA_CKSUM_LENGTH)
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
-
- retval = hmac_sha(in, in_length, seed, seed_length, digest);
- if (retval) goto cleanup;
-
- if (memcmp((char *)digest, (char *)cksum->contents, cksum->length))
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
-
-cleanup:
- memset((char *)digest, 0, sizeof(digest));
- return retval;
-}
-
-krb5_checksum_entry hmac_sha_cksumtable_entry =
-{
- 0,
- krb5_sha_crypto_sum_func,
- krb5_sha_crypto_verify_func,
- HMAC_SHA_CKSUM_LENGTH,
- 1, /* is collision proof */
- 1, /* uses key */
-};
+++ /dev/null
-#include "shs.h"
-
-krb5_error_code
-krb5_sha_sum_func
- PROTOTYPE((krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length,
- krb5_checksum FAR *outcksum));
-
-krb5_error_code
-krb5_sha_verify_func
- PROTOTYPE((krb5_const krb5_checksum FAR *cksum,
- krb5_const krb5_pointer in,
- krb5_const size_t in_length,
- krb5_const krb5_pointer seed,
- krb5_const size_t seed_length));
-
-krb5_error_code
-krb5_sha_sum_func(in, in_length, seed, seed_length, outcksum)
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
- krb5_checksum FAR *outcksum;
-{
- krb5_octet *input = (krb5_octet *)in;
- krb5_octet *cp;
- LONG *lp;
- SHS_INFO working;
-
- if (outcksum->length < SHS_DIGESTSIZE)
- return KRB5_BAD_MSIZE;
-
- shsInit(&working);
- shsUpdate(&working, input, in_length);
- shsFinal(&working);
-
- outcksum->checksum_type = CKSUMTYPE_NIST_SHA;
- outcksum->length = SHS_DIGESTSIZE;
-
- cp = outcksum->contents;
- lp = working.digest;
- while (lp < working.digest + 16) {
- *cp++ = (*lp >> 24) & 0xff;
- *cp++ = (*lp >> 16) & 0xff;
- *cp++ = (*lp >> 8) & 0xff;
- *cp++ = (*lp++) & 0xff;
- }
- memset((char *)&working, 0, sizeof(working));
- return 0;
-}
-
-krb5_error_code
-krb5_sha_verify_func(cksum, in, in_length, seed, seed_length)
- krb5_const krb5_checksum FAR *cksum;
- krb5_const krb5_pointer in;
- krb5_const size_t in_length;
- krb5_const krb5_pointer seed;
- krb5_const size_t seed_length;
-{
- krb5_octet *input = (krb5_octet *)in;
- SHS_INFO working;
- krb5_error_code retval;
- int i;
- krb5_octet *cp;
-
- if (cksum->checksum_type != CKSUMTYPE_NIST_SHA)
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
- if (cksum->length != SHS_DIGESTSIZE)
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
-
- shsInit(&working);
- shsUpdate(&working, input, in_length);
- shsFinal(&working);
-
- retval = 0;
- for (i = 0, cp = cksum->contents; i < 5; i++, cp += 4) {
- if (working.digest[i] !=
- (LONG) cp[0] << 24 | (LONG) cp[1] << 16 |
- (LONG) cp[2] << 8 | (LONG) cp[3]) {
- retval = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- break;
- }
- }
- memset((char *) &working, 0, sizeof(working));
- return retval;
-}
-
-krb5_checksum_entry nist_sha_cksumtable_entry = {
- 0,
- krb5_sha_sum_func,
- krb5_sha_verify_func,
- SHS_DIGESTSIZE,
- 1, /* is collision proof */
- 0, /* doesn't use key */
-};
+++ /dev/null
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#include <string.h>
-#include "shs.h"
-
-/* The SHS f()-functions. The f1 and f3 functions can be optimized to
- save one boolean operation each - thanks to Rich Schroeppel,
- rcs@cs.arizona.edu for discovering this */
-
-#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */
-#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
-#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */
-#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
-
-/* The SHS Mysterious Constants */
-
-#define K1 0x5A827999L /* Rounds 0-19 */
-#define K2 0x6ED9EBA1L /* Rounds 20-39 */
-#define K3 0x8F1BBCDCL /* Rounds 40-59 */
-#define K4 0xCA62C1D6L /* Rounds 60-79 */
-
-/* SHS initial values */
-
-#define h0init 0x67452301L
-#define h1init 0xEFCDAB89L
-#define h2init 0x98BADCFEL
-#define h3init 0x10325476L
-#define h4init 0xC3D2E1F0L
-
-/* Note that it may be necessary to add parentheses to these macros if they
- are to be called with expressions as arguments */
-
-/* 32-bit rotate left - kludged with shifts */
-
-#define ROTL(n,X) (((X) << (n)) & 0xffffffff | ((X) >> (32 - n)))
-
-/* The initial expanding function. The hash function is defined over an
- 80-word expanded input array W, where the first 16 are copies of the input
- data, and the remaining 64 are defined by
-
- W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]
-
- This implementation generates these values on the fly in a circular
- buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
- optimization.
-
- The updated SHS changes the expanding function by adding a rotate of 1
- bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
- for this information */
-
-#ifdef NEW_SHS
-#define expand(W,i) ( W[ i & 15 ] = ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
- W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] )))
-#else
-#define expand(W,i) ( W[ i & 15 ] ^= W[ (i - 14) & 15 ] ^ \
- W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] )
-#endif /* NEW_SHS */
-
-/* The prototype SHS sub-round. The fundamental sub-round is:
-
- a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
- b' = a;
- c' = ROTL( 30, b );
- d' = c;
- e' = d;
-
- but this is implemented by unrolling the loop 5 times and renaming the
- variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
- This code is then replicated 20 times for each of the 4 functions, using
- the next 20 values from the W[] array each time */
-
-#define subRound(a, b, c, d, e, f, k, data) \
- ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, \
- e &= 0xffffffff, b = ROTL( 30, b ) )
-
-/* Initialize the SHS values */
-
-void shsInit(shsInfo)
- SHS_INFO *shsInfo;
-{
- /* Set the h-vars to their initial values */
- shsInfo->digest[ 0 ] = h0init;
- shsInfo->digest[ 1 ] = h1init;
- shsInfo->digest[ 2 ] = h2init;
- shsInfo->digest[ 3 ] = h3init;
- shsInfo->digest[ 4 ] = h4init;
-
- /* Initialise bit count */
- shsInfo->countLo = shsInfo->countHi = 0;
-}
-
-/* Perform the SHS transformation. Note that this code, like MD5, seems to
- break some optimizing compilers due to the complexity of the expressions
- and the size of the basic block. It may be necessary to split it into
- sections, e.g. based on the four subrounds
-
- Note that this corrupts the shsInfo->data area */
-
-static void SHSTransform KRB5_PROTOTYPE((LONG *digest, LONG *data));
-
-static
-void SHSTransform(digest, data)
- LONG *digest;
- LONG *data;
-{
- LONG A, B, C, D, E; /* Local vars */
- LONG eData[ 16 ]; /* Expanded data */
-
- /* Set up first buffer and local data buffer */
- A = digest[ 0 ];
- B = digest[ 1 ];
- C = digest[ 2 ];
- D = digest[ 3 ];
- E = digest[ 4 ];
- memcpy(eData, data, sizeof (eData));
-
- /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
- subRound( A, B, C, D, E, f1, K1, eData[ 0 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 1 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 2 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 3 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 4 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 5 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 6 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 7 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 8 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 9 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 10 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 11 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 12 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 13 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 14 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 15 ] );
- subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) );
- subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) );
- subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) );
- subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) );
-
- subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) );
-
- subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) );
-
- subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) );
-
- /* Build message digest */
- digest[ 0 ] += A;
- digest[ 0 ] &= 0xffffffff;
- digest[ 1 ] += B;
- digest[ 1 ] &= 0xffffffff;
- digest[ 2 ] += C;
- digest[ 2 ] &= 0xffffffff;
- digest[ 3 ] += D;
- digest[ 3 ] &= 0xffffffff;
- digest[ 4 ] += E;
- digest[ 4 ] &= 0xffffffff;
-}
-
-/* When run on a little-endian CPU we need to perform byte reversal on an
- array of longwords. It is possible to make the code endianness-
- independant by fiddling around with data at the byte level, but this
- makes for very slow code, so we rely on the user to sort out endianness
- at compile time */
-
-void longReverse( LONG *buffer, int byteCount )
-{
- LONG value;
- static int init = 0;
- char *cp;
-
- switch (init) {
- case 0:
- init=1;
- cp = (char *) &init;
- if (*cp == 1) {
- init=2;
- break;
- }
- init=1;
- /* fall through - MSB */
- case 1:
- return;
- }
-
- byteCount /= sizeof( LONG );
- while( byteCount-- ) {
- value = *buffer;
- value = ( ( value & 0xFF00FF00L ) >> 8 ) |
- ( ( value & 0x00FF00FFL ) << 8 );
- *buffer++ = ( value << 16 ) | ( value >> 16 );
- }
-}
-
-/* Update SHS for a block of data */
-
-void shsUpdate(shsInfo, buffer, count)
- SHS_INFO *shsInfo;
- BYTE *buffer;
- int count;
-{
- LONG tmp;
- int dataCount, canfill;
- LONG *lp;
-
- /* Update bitcount */
- tmp = shsInfo->countLo;
- shsInfo->countLo = tmp + (((LONG) count) << 3 );
- if ((shsInfo->countLo &= 0xffffffff) < tmp)
- shsInfo->countHi++; /* Carry from low to high */
- shsInfo->countHi += count >> 29;
-
- /* Get count of bytes already in data */
- dataCount = (int) (tmp >> 3) & 0x3F;
-
- /* Handle any leading odd-sized chunks */
- if (dataCount) {
- lp = shsInfo->data + dataCount / 4;
- canfill = (count >= dataCount);
- dataCount = SHS_DATASIZE - dataCount;
-
- if (dataCount % 4) {
- /* Fill out a full 32 bit word first if needed -- this
- is not very efficient (computed shift amount),
- but it shouldn't happen often. */
- while (dataCount % 4 && count > 0) {
- *lp |= (LONG) *buffer++ << ((3 - dataCount++ % 4) * 8);
- count--;
- }
- lp++;
- }
- while (lp < shsInfo->data + 16) {
- *lp = (LONG) *buffer++ << 24;
- *lp |= (LONG) *buffer++ << 16;
- *lp |= (LONG) *buffer++ << 8;
- *lp++ |= (LONG) *buffer++;
- if ((count -= 4) < 4 && lp < shsInfo->data + 16) {
- *lp = 0;
- switch (count % 4) {
- case 3:
- *lp |= (LONG) buffer[2] << 8;
- case 2:
- *lp |= (LONG) buffer[1] << 16;
- case 1:
- *lp |= (LONG) buffer[0] << 24;
- }
- break;
- count = 0;
- }
- }
- if (canfill) {
- SHSTransform(shsInfo->digest, shsInfo->data);
- }
- }
-
- /* Process data in SHS_DATASIZE chunks */
- while (count >= SHS_DATASIZE) {
- lp = shsInfo->data;
- while (lp < shsInfo->data + 16) {
- *lp = ((LONG) *buffer++) << 24;
- *lp |= ((LONG) *buffer++) << 16;
- *lp |= ((LONG) *buffer++) << 8;
- *lp++ |= (LONG) *buffer++;
- }
- SHSTransform(shsInfo->digest, shsInfo->data);
- count -= SHS_DATASIZE;
- }
-
- if (count > 0) {
- lp = shsInfo->data;
- while (count > 4) {
- *lp = ((LONG) *buffer++) << 24;
- *lp |= ((LONG) *buffer++) << 16;
- *lp |= ((LONG) *buffer++) << 8;
- *lp++ |= (LONG) *buffer++;
- count -= 4;
- }
- *lp = 0;
- switch (count % 4) {
- case 0:
- *lp |= ((LONG) buffer[3]);
- case 3:
- *lp |= ((LONG) buffer[2]) << 8;
- case 2:
- *lp |= ((LONG) buffer[1]) << 16;
- case 1:
- *lp |= ((LONG) buffer[0]) << 24;
- }
- }
-}
-
-/* Final wrapup - pad to SHS_DATASIZE-byte boundary with the bit pattern
- 1 0* (64-bit count of bits processed, MSB-first) */
-
-void shsFinal(shsInfo)
- SHS_INFO *shsInfo;
-{
- int count;
- LONG *lp;
- BYTE *dataPtr;
-
- /* Compute number of bytes mod 64 */
- count = (int) shsInfo->countLo;
- count = (count >> 3) & 0x3F;
-
- /* Set the first char of padding to 0x80. This is safe since there is
- always at least one byte free */
- lp = shsInfo->data + count / 4;
- switch (count % 4) {
- case 3:
- *lp++ |= (LONG) 0x80;
- break;
- case 2:
- *lp++ |= (LONG) 0x80 << 8;
- break;
- case 1:
- *lp++ |= (LONG) 0x80 << 16;
- break;
- case 0:
- *lp++ = (LONG) 0x80 << 24;
- }
-
- if (lp > shsInfo->data + 14) {
- /* Pad out to 64 bytes if not enough room for length words */
- *lp = 0;
- SHSTransform(shsInfo->digest, shsInfo->data);
- lp = shsInfo->data;
- }
- /* Pad out to 56 bytes */
- while (lp < shsInfo->data + 14)
- *lp++ = 0;
- /* Append length in bits and transform */
- *lp++ = shsInfo->countHi;
- *lp++ = shsInfo->countLo;
- SHSTransform(shsInfo->digest, shsInfo->data);
-}
+++ /dev/null
-#ifndef _SHS_DEFINED
-
-#include <k5-int.h>
-
-#define _SHS_DEFINED
-
-/* Some useful types */
-
-typedef krb5_octet BYTE;
-
-/* Old DOS/Windows compilers are case-insensitive */
-#if !defined(_MSDOS) && !defined(_WIN32)
-typedef krb5_ui_4 LONG;
-#endif
-
-
-/* Define the following to use the updated SHS implementation */
-#define NEW_SHS /**/
-
-/* The SHS block size and message digest sizes, in bytes */
-
-#define SHS_DATASIZE 64
-#define SHS_DIGESTSIZE 20
-
-/* The structure for storing SHS info */
-
-typedef struct {
- LONG digest[ 5 ]; /* Message digest */
- LONG countLo, countHi; /* 64-bit bit count */
- LONG data[ 16 ]; /* SHS data buffer */
- } SHS_INFO;
-
-/* Message digest functions (shs.c) */
-void shsInit
- KRB5_PROTOTYPE((SHS_INFO *shsInfo));
-void shsUpdate
- KRB5_PROTOTYPE((SHS_INFO *shsInfo, BYTE *buffer, int count));
-void shsFinal
- KRB5_PROTOTYPE((SHS_INFO *shsInfo));
-
-
-/* Keyed Message digest functions (hmac_sha.c) */
-krb5_error_code hmac_sha
- KRB5_PROTOTYPE((krb5_octet *text,
- int text_len,
- krb5_octet *key,
- int key_len,
- krb5_octet *digest));
-
-
-#define NIST_SHA_CKSUM_LENGTH SHS_DIGESTSIZE
-#define HMAC_SHA_CKSUM_LENGTH SHS_DIGESTSIZE
-
-
-extern krb5_checksum_entry
- nist_sha_cksumtable_entry,
- hmac_sha_cksumtable_entry;
-
-#endif /* _SHS_DEFINED */
+++ /dev/null
-/****************************************************************************
-* *
-* SHS Test Code *
-* *
-****************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include "shs.h"
-
-/* Test the SHS implementation */
-
-#ifdef NEW_SHS
-
-static LONG shsTestResults[][ 5 ] = {
- { 0xA9993E36L, 0x4706816AL, 0xBA3E2571L, 0x7850C26CL, 0x9CD0D89DL, },
- { 0x84983E44L, 0x1C3BD26EL, 0xBAAE4AA1L, 0xF95129E5L, 0xE54670F1L, },
- { 0x34AA973CL, 0xD4C4DAA4L, 0xF61EEB2BL, 0xDBAD2731L, 0x6534016FL, }
- };
-
-#else
-
-static LONG shsTestResults[][ 5 ] = {
- { 0x0164B8A9L, 0x14CD2A5EL, 0x74C4F7FFL, 0x082C4D97L, 0xF1EDF880L },
- { 0xD2516EE1L, 0xACFA5BAFL, 0x33DFC1C4L, 0x71E43844L, 0x9EF134C8L },
- { 0x3232AFFAL, 0x48628A26L, 0x653B5AAAL, 0x44541FD9L, 0x0D690603L }
- };
-#endif /* NEW_SHS */
-
-static int compareSHSresults(shsInfo, shsTestLevel)
-SHS_INFO *shsInfo;
-int shsTestLevel;
-{
- int i, fail = 0;
-
- /* Compare the returned digest and required values */
- for( i = 0; i < 5; i++ )
- if( shsInfo->digest[ i ] != shsTestResults[ shsTestLevel ][ i ] )
- fail = 1;
- if (fail) {
- printf("\nExpected: ");
- for (i = 0; i < 5; i++) {
- printf("%8.8lx ", shsTestResults[shsTestLevel][i]);
- }
- printf("\nGot: ");
- for (i = 0; i < 5; i++) {
- printf("%8.8lx ", shsInfo->digest[i]);
- }
- printf("\n");
- return( -1 );
- }
- return( 0 );
-}
-
-main()
-{
- SHS_INFO shsInfo;
- unsigned int i;
- time_t secondCount;
- BYTE data[ 200 ];
-
- /* Make sure we've got the endianness set right. If the machine is
- big-endian (up to 64 bits) the following value will be signed,
- otherwise it will be unsigned. Unfortunately we can't test for odd
- things like middle-endianness without knowing the size of the data
- types */
-
- /* Test SHS against values given in SHS standards document */
- printf( "Running SHS test 1 ... " );
- shsInit( &shsInfo );
- shsUpdate( &shsInfo, ( BYTE * ) "abc", 3 );
- shsFinal( &shsInfo );
- if( compareSHSresults( &shsInfo, 0 ) == -1 )
- {
- putchar( '\n' );
- puts( "SHS test 1 failed" );
- exit( -1 );
- }
-#ifdef NEW_SHS
- puts( "passed, result= A9993E364706816ABA3E25717850C26C9CD0D89D" );
-#else
- puts( "passed, result= 0164B8A914CD2A5E74C4F7FF082C4D97F1EDF880" );
-#endif /* NEW_SHS */
-
- printf( "Running SHS test 2 ... " );
- shsInit( &shsInfo );
- shsUpdate( &shsInfo, ( BYTE * ) "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56 );
- shsFinal( &shsInfo );
- if( compareSHSresults( &shsInfo, 1 ) == -1 )
- {
- putchar( '\n' );
- puts( "SHS test 2 failed" );
- exit( -1 );
- }
-#ifdef NEW_SHS
- puts( "passed, result= 84983E441C3BD26EBAAE4AA1F95129E5E54670F1" );
-#else
- puts( "passed, result= D2516EE1ACFA5BAF33DFC1C471E438449EF134C8" );
-#endif /* NEW_SHS */
-
- printf( "Running SHS test 3 ... " );
- shsInit( &shsInfo );
- for( i = 0; i < 15625; i++ )
- shsUpdate( &shsInfo, ( BYTE * ) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 64 );
- shsFinal( &shsInfo );
- if( compareSHSresults( &shsInfo, 2 ) == -1 )
- {
- putchar( '\n' );
- puts( "SHS test 3 failed" );
- exit( -1 );
- }
-#ifdef NEW_SHS
- puts( "passed, result= 34AA973CD4C4DAA4F61EEB2BDBAD27316534016F" );
-#else
- puts( "passed, result= 3232AFFA48628A26653B5AAA44541FD90D690603" );
-#endif /* NEW_SHS */
-
-#if 0
- printf( "\nTesting speed for 100MB data... " );
- shsInit( &shsInfo );
- secondCount = time( NULL );
- for( i = 0; i < 500000U; i++ )
- shsUpdate( &shsInfo, data, 200 );
- secondCount = time( NULL ) - secondCount;
- printf( "done. Time = %ld seconds, %ld kbytes/second.\n", \
- secondCount, 100500L / secondCount );
-#endif
-
- puts( "\nAll SHS tests passed" );
- exit( 0 );
-}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_string_to_cksumtype(string, cksumtypep)
+ char FAR * string;
+ krb5_cksumtype FAR * cksumtypep;
+{
+ int i;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (strcasecmp(krb5_cksumtypes_list[i].in_string, string) == 0) {
+ *cksumtypep = krb5_cksumtypes_list[i].ctype;
+ return(0);
+ }
+ }
+
+ return(EINVAL);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_string_to_enctype(string, enctypep)
+ char FAR * string;
+ krb5_enctype FAR * enctypep;
+{
+ int i;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (strcasecmp(krb5_enctypes_list[i].in_string, string) == 0) {
+ *enctypep = krb5_enctypes_list[i].etype;
+ return(0);
+ }
+ }
+
+ return(EINVAL);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_c_string_to_key(context, enctype, string, salt, key)
+ krb5_context context;
+ krb5_enctype enctype;
+ krb5_const krb5_data *string;
+ krb5_const krb5_data *salt;
+ krb5_keyblock *key;
+{
+ int i;
+ krb5_error_code ret;
+ struct krb5_enc_provider *enc;
+ size_t keybytes, keylength;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ enc = krb5_enctypes_list[i].enc;
+
+ (*(enc->keysize))(&keybytes, &keylength);
+
+ if ((key->contents = (krb5_octet *) malloc(keylength)) == NULL)
+ return(ENOMEM);
+
+ key->magic = KV5M_KEYBLOCK;
+ key->enctype = enctype;
+ key->length = keylength;
+
+ if (ret = ((*(krb5_enctypes_list[i].str2key))(enc, string, salt, key))) {
+ memset(key->contents, 0, keylength);
+ free(key->contents);
+ }
+
+ return(ret);
+}
--- /dev/null
+/*
+ * lib/crypto/t_nfold.c
+ *
+ * Copyright 1988, 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Program to test the correctness of nfold implementation.
+ *
+ * exit returns 0 ==> success
+ * -1 ==> error
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "k5-int.h"
+
+unsigned char *nfold_in[] = {
+ "basch",
+ "eichin",
+ "sommerfeld",
+ "MASSACHVSETTS INSTITVTE OF TECHNOLOGY" };
+
+unsigned char nfold_192[4][24] = {
+ { 0x1a, 0xab, 0x6b, 0x42, 0x96, 0x4b, 0x98, 0xb2, 0x1f, 0x8c, 0xde, 0x2d,
+ 0x24, 0x48, 0xba, 0x34, 0x55, 0xd7, 0x86, 0x2c, 0x97, 0x31, 0x64, 0x3f },
+ { 0x65, 0x69, 0x63, 0x68, 0x69, 0x6e, 0x4b, 0x73, 0x2b, 0x4b, 0x1b, 0x43,
+ 0xda, 0x1a, 0x5b, 0x99, 0x5a, 0x58, 0xd2, 0xc6, 0xd0, 0xd2, 0xdc, 0xca },
+ { 0x2f, 0x7a, 0x98, 0x55, 0x7c, 0x6e, 0xe4, 0xab, 0xad, 0xf4, 0xe7, 0x11,
+ 0x92, 0xdd, 0x44, 0x2b, 0xd4, 0xff, 0x53, 0x25, 0xa5, 0xde, 0xf7, 0x5c },
+ { 0xdb, 0x3b, 0x0d, 0x8f, 0x0b, 0x06, 0x1e, 0x60, 0x32, 0x82, 0xb3, 0x08,
+ 0xa5, 0x08, 0x41, 0x22, 0x9a, 0xd7, 0x98, 0xfa, 0xb9, 0x54, 0x0c, 0x1b }
+};
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ unsigned char cipher_text[64];
+ int i, j;
+
+ printf("N-fold\n");
+ for (i=0; i<sizeof(nfold_in)/sizeof(char *); i++) {
+ printf("\tInput:\t\"%.*s\"\n", strlen(nfold_in[i]), nfold_in[i]);
+ printf("\t192-Fold:\t");
+ krb5_nfold(strlen(nfold_in[i])*8, nfold_in[i], 24*8, cipher_text);
+ for (j=0; j<24; j++)
+ printf("%s%02x", (j&3) ? "" : " ", cipher_text[j]);
+ printf("\n");
+ if (memcmp(cipher_text, nfold_192[i], 24)) {
+ printf("verify: error in n-fold\n");
+ exit(-1);
+ };
+ }
+ printf("verify: N-fold is correct\n\n");
+
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_boolean valid_cksumtype(ctype)
+ krb5_cksumtype ctype;
+{
+ int i;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == ctype)
+ return(1);
+ }
+
+ return(0);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_boolean valid_enctype(etype)
+ krb5_enctype etype;
+{
+ int i;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == etype)
+ return(1);
+ }
+
+ return(0);
+}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_error_code
+krb5_c_verify_checksum(context, key, usage, data, cksum, valid)
+ krb5_context context;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *data;
+ krb5_const krb5_checksum *cksum;
+ krb5_boolean *valid;
+{
+ int i;
+ size_t hashsize;
+ krb5_error_code ret;
+ krb5_data indata;
+ krb5_checksum computed;
+
+ for (i=0; i<krb5_cksumtypes_length; i++) {
+ if (krb5_cksumtypes_list[i].ctype == cksum->checksum_type)
+ break;
+ }
+
+ if (i == krb5_cksumtypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ /* if there's actually a verify function, call it */
+
+ indata.length = cksum->length;
+ indata.data = cksum->contents;
+
+ if (krb5_cksumtypes_list[i].keyhash &&
+ krb5_cksumtypes_list[i].keyhash->verify)
+ return((*(krb5_cksumtypes_list[i].keyhash->verify))(key, 0, data,
+ &indata, valid));
+
+ /* otherwise, make the checksum again, and compare */
+
+ if (ret = krb5_c_checksum_length(context, cksum->checksum_type, &hashsize))
+ return(ret);
+
+ if (cksum->length != hashsize)
+ return(KRB5_BAD_MSIZE);
+
+ computed.length = hashsize;
+
+ if (ret = krb5_c_make_checksum(context, cksum->checksum_type, key, usage,
+ data, &computed)) {
+ free(computed.contents);
+ return(ret);
+ }
+
+ *valid = (memcmp(computed.contents, cksum->contents, hashsize) == 0);
+
+ free(computed.contents);
+
+ return(0);
+}
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * random_key.c, new_rnd_key.c: make the v4 compat random key code
+ use the krb5 crypto interface, instead of the des implementation
+ internals.
+
Wed Apr 15 18:03:43 1998 Tom Yu <tlyu@mit.edu>
- * Makefile.in (SHLIB_EXPDEPS):
+ * Makefile.in (SHLIB_EXPDEPS):
(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
Tue Mar 3 08:59:03 1998 Ezra Peisach <epeisach@kangaroo.mit.edu>
RUN_SETUP=@KRB5_RUN_ENV@
LIB=des425
-LIBMAJOR=2
+LIBMAJOR=3
LIBMINOR=0
RELDIR=des425
# Depends on libk5crypto and libkrb5
STOBJLISTS=OBJS.ST
STLIBOBJS=cksum.o \
- des.o \
enc_dec.o \
key_parity.o \
key_sched.o \
OBJS= cksum.$(OBJEXT) \
- des.$(OBJEXT) \
enc_dec.$(OBJEXT) \
key_parity.$(OBJEXT) \
key_sched.$(OBJEXT) \
k4_glue.$(OBJEXT)
SRCS= $(srcdir)/cksum.c \
- $(srcdir)/des.c \
$(srcdir)/enc_dec.c \
$(srcdir)/key_parity.c \
$(srcdir)/key_sched.c \
*
*/
-
-#include "des.h"
-
-krb5_pointer des425_random_state = 0;
-
/*
- * des_new_random_key: create a random des key
- *
- * Requires: des_set_random_number_generater_seed must be at called least
- * once before this routine is called.
- *
- * Notes: the returned key has correct parity and is guarenteed not
- * to be a weak des key. Des_generate_random_block is used to
- * provide the random bits.
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-KRB5_DLLIMP int KRB5_CALLCONV
-des_new_random_key(key)
- mit_des_cblock key;
-{
- krb5_keyblock * keyblock;
- krb5_error_code kret;
- kret = mit_des_random_key(NULL, des425_random_state, &keyblock);
- if (kret) return kret;
-
- memcpy(key, keyblock->contents, sizeof(mit_des_cblock));
- krb5_free_keyblock(NULL, keyblock);
- return 0;
-}
+
+#include "des.h"
/*
* des_init_random_number_generator:
des_init_random_number_generator(key)
mit_des_cblock key;
{
- krb5_keyblock keyblock;
- krb5_encrypt_block eblock;
-
- krb5_use_enctype(NULL, &eblock, ENCTYPE_DES_CBC_CRC);
+ krb5_data seed;
- keyblock.enctype = ENCTYPE_DES_CBC_CRC;
- keyblock.length = sizeof(mit_des_cblock);
- keyblock.contents = (krb5_octet *)key;
+ seed.length = sizeof(key);
+ seed.data = key;
- if (des425_random_state)
- mit_des_finish_random_key(&eblock, &des425_random_state);
- mit_des_init_random_key(&eblock, &keyblock, &des425_random_state);
+ if (krb5_c_random_seed(/* XXX */ 0, &seed))
+ /* XXX */ abort();
}
/*
- * This module implements a random number generator faculty such that the next
- * number in any random number stream is very hard to predict without knowing
- * the seed for that stream even given the preceeding random numbers.
- */
-
-/*
- * des_set_random_generator_seed: this routine is used to select a random
- * number stream. The stream that results is
- * totally determined by the passed in key.
- * (I.e., calling this routine again with the
- * same key allows repeating a sequence of
- * random numbers)
+ * des_new_random_key: create a random des key
+ *
+ * Requires: des_set_random_number_generater_seed must be at called least
+ * once before this routine is called.
*
- * Requires: key is a valid des key. I.e., has correct parity and is not a
- * weak des key.
+ * Notes: the returned key has correct parity and is guarenteed not
+ * to be a weak des key. Des_generate_random_block is used to
+ * provide the random bits.
*/
-KRB5_DLLIMP void KRB5_CALLCONV
-des_set_random_generator_seed(key)
+KRB5_DLLIMP int KRB5_CALLCONV
+des_new_random_key(key)
mit_des_cblock key;
{
- krb5_data seed;
+ krb5_keyblock keyblock;
+ krb5_error_code kret;
- seed.length = sizeof(mit_des_cblock);
- seed.data = (krb5_pointer) key;
+ kret = krb5_c_make_random_key(/* XXX */ 0, ENCTYPE_DES_CBC_CRC, &keyblock);
+ if (kret) return kret;
+
+ memcpy(key, keyblock.contents, sizeof(mit_des_cblock));
+ krb5_free_keyblock_contents(/* XXX */ 0, &keyblock);
- if (!des425_random_state)
- des_init_random_number_generator(key);
- mit_des_set_random_generator_seed(&seed, des425_random_state);
+ return 0;
}
-
-/*
- * des_set_sequence_number: this routine is used to set the sequence number
- * of the current random number stream. This routine
- * may be used to "seek" within the current random
- * number stream.
- *
- * Note that des_set_random_generator_seed resets the sequence number to 0.
- */
-void
-des_set_sequence_number(new_sequence_number)
- mit_des_cblock new_sequence_number;
-{
- krb5_data sequence;
-
- sequence.length = sizeof(new_sequence_number);
- sequence.data = (char FAR *)new_sequence_number;
- mit_des_set_random_sequence_number(&sequence, des425_random_state);
-}
*
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
#include "des.h"
-extern krb5_pointer des425_random_state;
-
/* random_key */
int
des_random_key(key)
mit_des_cblock *key;
{
- krb5_encrypt_block eblock;
krb5_keyblock keyblock;
- krb5_keyblock *new_key;
krb5_error_code kret;
- mit_des_cblock nullkey;
-
- krb5_use_enctype(NULL, &eblock, ENCTYPE_DES_CBC_CRC);
-
- memset(nullkey, 0, sizeof(mit_des_cblock));
- mit_des_fixup_key_parity(*key);
-
- keyblock.enctype = ENCTYPE_DES_CBC_CRC;
- keyblock.length = sizeof(mit_des_cblock);
- keyblock.contents = (krb5_octet *)nullkey;
- if (! des425_random_state)
- mit_des_init_random_key(&eblock, &keyblock, &des425_random_state);
+ if (kret = krb5_c_make_random_key(/* XXX */ 0, ENCTYPE_DES_CBC_CRC,
+ &keyblock))
+ return(kret);
- kret = mit_des_random_key(NULL, des425_random_state, &new_key);
- if (kret) return kret;
+ memcpy(key, keyblock.contents, sizeof(mit_des_cblock));
- memcpy(key, new_key->contents, sizeof(mit_des_cblock));
- krb5_free_keyblock(NULL, new_key);
return(0);
}
MAC_SUBDIRS = generic krb5
LIB=gssapi_krb5
-LIBMAJOR=1
+LIBMAJOR=2
LIBMINOR=1
STOBJLISTS=generic/OBJS.ST krb5/OBJS.ST
SHLIB_EXPDEPS=\
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * gssapi.hin: define GSS_S_DUPLICATE_ELEMENT, GSS_S_NAME_NOT_MN,
+ and GSS_S_GAP_TOKEN as per gss v2 c bindings
+
1998-06-08 Theodore Ts'o <tytso@rsts-11.mit.edu>
* oid_ops.c (generic_gss_release_oid): Recognize our own "self"
#define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET)
-/*
- * XXX new functions. Check to get official error number assigments?
- */
#define GSS_S_DUPLICATE_ELEMENT \
(((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN \
+ (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET)
/*
* Supplementary info bits:
#define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
#define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
#define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
-/*
- * XXX not in the cbindings yet. remove this comment when it is
- */
#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
error_code G_WRONG_MECH, "Mechanism is incorrect"
error_code G_BAD_TOK_HEADER, "Token header is malformed or corrupt"
error_code G_BAD_DIRECTION, "Packet was replayed in wrong direction"
+error_code G_TOK_TRUNC, "Token is missing data"
+error_code G_REFLECT, "Token was reflected"
+error_code G_WRONG_TOKID, "Received token ID does not match expected token ID"
end
if ((toksize-=2) < 0)
return(G_BAD_TOK_HEADER);
+ if (ret)
+ return(ret);
+
if ((*buf++ != ((tok_type>>8)&0xff)) ||
- (*buf++ != (tok_type&0xff)))
- return(G_BAD_TOK_HEADER);
+ (*buf++ != (tok_type&0xff)))
+ return(G_WRONG_TOKID);
if (!ret) {
*buf_in = buf;
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.in, accept_sec_context.c, acquire_cred.c, canon_name.c,
+ delete_sec_context.c, disp_status.c, gssapiP_krb5.h,
+ gssapi_err_krb5.et, gssapi_krb5.c, gssapi_krb5.h,
+ init_sec_context.c, inq_cred.c, inq_names.c, k5seal.c, k5unseal.c,
+ rel_oid.c, ser_sctx.c, util_cksum.c, util_crypt.c, util_seed.c,
+ util_seqnum.c, wrap_size_limit.c: convert to new crypto api.
+ Implement new krb5 v2 gssapi mechanism.
+
+ * add_cred.c, util_ctxsetup.c: New files needed to implement the
+ krb5 v2 mech.
+
+Mon Sep 21 00:32:28 1998 Tom Yu <tlyu@mit.edu>
+
+ * accept_sec_context.c (krb5_gss_accept_sec_context): Free authdat
+ even on success to avoid a memory leak.
+
+ * util_cksum.c (kg_checksum_channel_bindings): Fix memory leak by
+ not allocating cksum->contents unless we have to return a
+ zero-filled one.
+
+ * k5unseal.c (kg_unseal_v1): Fix memorly leak by not allocating
+ md5cksum.contents.
+
+ * k5seal.c (make_seal_token_v1): Fix memory leak by not allocating
+ md5cksum.contents.
+
+ * accept_sec_context.c (krb5_gss_accept_sec_context): Only free
+ ap_req.data if it was allocated by kg2_parse_token(), otherwise we
+ lose very badly trying to free the middle of a potentially
+ malloc()'ed block, possibly coredumping.
+
+Thu Sep 3 19:35:44 1998 Tom Yu <tlyu@mit.edu>
+
+ * accept_sec_context.c (krb5_gss_accept_sec_context): Fix typo;
+ bash the enctype in ctx->subkey->enctype rather than just
+ "enctype", which nothing checks.
+
Fri Jul 24 21:13:53 1998 Tom Yu <tlyu@mit.edu>
* wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix to round down
SRCS = \
$(srcdir)/accept_sec_context.c \
$(srcdir)/acquire_cred.c \
+ $(srcdir)/add_cred.c \
$(srcdir)/canon_name.c \
$(srcdir)/compare_name.c \
$(srcdir)/context_time.c \
$(srcdir)/unseal.c \
$(srcdir)/util_cksum.c \
$(srcdir)/util_crypt.c \
+ $(srcdir)/util_ctxsetup.c \
$(srcdir)/util_seed.c \
$(srcdir)/util_seqnum.c \
$(srcdir)/val_cred.c \
OBJS = \
accept_sec_context.$(OBJEXT) \
acquire_cred.$(OBJEXT) \
+ add_cred.$(OBJEXT) \
canon_name.$(OBJEXT) \
compare_name.$(OBJEXT) \
context_time.$(OBJEXT) \
unseal.$(OBJEXT) \
util_cksum.$(OBJEXT) \
util_crypt.$(OBJEXT) \
+ util_ctxsetup.$(OBJEXT) \
util_seed.$(OBJEXT) \
util_seqnum.$(OBJEXT) \
val_cred.$(OBJEXT) \
STLIBOBJS = \
accept_sec_context.o \
acquire_cred.o \
+ add_cred.o \
canon_name.o \
compare_name.o \
context_time.o \
unseal.o \
util_cksum.o \
util_crypt.o \
+ util_ctxsetup.o \
util_seed.o \
util_seqnum.o \
val_cred.o \
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "gssapiP_krb5.h"
#include <memory.h>
/* Decode, decrypt and store the forwarded creds in the local ccache. */
static krb5_error_code
-rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
+rd_and_store_for_creds(context, inbuf, out_cred)
krb5_context context;
- krb5_auth_context auth_context;
krb5_data *inbuf;
krb5_gss_cred_id_t *out_cred;
{
krb5_ccache ccache;
krb5_gss_cred_id_t cred = NULL;
extern krb5_cc_ops krb5_mcc_ops;
+ krb5_auth_context auth_context = NULL;
- if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)))
+ if ((retval = krb5_auth_con_init(context, &auth_context)))
return(retval);
+ krb5_auth_con_setflags(context, auth_context, 0);
+
+ if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)))
+ goto cleanup;
+
/* Lots of kludging going on here... Some day the ccache interface
will be rewritten though */
/* generate a delegated credential handle */
if (out_cred) {
- /* allocate memory for a cred_t... */
- if (!(cred =
- (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
- retval = ENOMEM; /* out of memory? */
- goto cleanup;
- }
+ /* allocate memory for a cred_t... */
+ if (!(cred =
+ (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
+ retval = ENOMEM; /* out of memory? */
+ goto cleanup;
+ }
- /* zero it out... */
- memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
+ /* zero it out... */
+ memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
- /* copy the client principle into it... */
- if ((retval =
- krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
- retval = ENOMEM; /* out of memory? */
- xfree(cred); /* clean up memory on failure */
- cred = NULL;
- goto cleanup;
- }
-
- cred->usage = GSS_C_INITIATE; /* we can't accept with this */
- /* cred->princ already set */
- cred->actual_mechs = gss_mech_set_krb5_both; /* both mechs work */
- cred->prerfc_mech = cred->rfc_mech = 1; /* Ibid. */
- cred->keytab = NULL; /* no keytab associated with this... */
- cred->ccache = ccache; /* but there is a credential cache */
- cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
+ /* copy the client principle into it... */
+ if ((retval =
+ krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
+ retval = ENOMEM; /* out of memory? */
+ xfree(cred); /* clean up memory on failure */
+ cred = NULL;
+ goto cleanup;
+ }
+
+ cred->usage = GSS_C_INITIATE; /* we can't accept with this */
+ /* cred->princ already set */
+ cred->prerfc_mech = 1; /* this cred will work with all three mechs */
+ cred->rfc_mech = 1;
+ cred->rfcv2_mech = 1;
+ cred->keytab = NULL; /* no keytab associated with this... */
+ cred->ccache = ccache; /* but there is a credential cache */
+ cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
}
/* If there were errors, there might have been a memory leak
- if (!cred)
- if ((retval = krb5_cc_close(context, ccache)))
- goto cleanup;
- */
+ if (!cred)
+ if ((retval = krb5_cc_close(context, ccache)))
+ goto cleanup;
+ */
cleanup:
krb5_free_tgt_creds(context, creds);
if (!cred && ccache)
- (void)krb5_cc_close(context, ccache);
+ (void)krb5_cc_close(context, ccache);
if (out_cred)
- *out_cred = cred; /* return credential */
+ *out_cred = cred; /* return credential */
+
+ if (auth_context)
+ krb5_auth_con_free(context, auth_context);
return retval;
}
unsigned char *ptr, *ptr2;
char *sptr;
long tmp;
+ size_t md5len;
int bigend;
krb5_gss_cred_id_t cred = 0;
- krb5_data ap_req;
+ krb5_data ap_rep, ap_req, mic;
int i;
krb5_error_code code;
krb5_address addr, *paddr;
krb5_authenticator *authdat = 0;
- krb5_checksum md5;
+ krb5_checksum reqcksum;
krb5_principal name = NULL;
- int gss_flags = 0;
+ krb5_ui_4 gss_flags = 0;
int decode_req_message = 0;
krb5_gss_ctx_id_rec *ctx = 0;
krb5_enctype enctype;
krb5_auth_context auth_context = NULL;
krb5_ticket * ticket = NULL;
int option_id;
- krb5_data option;
- krb5_auth_context auth_context_cred = NULL;
+ krb5_data option, cksumdata;
const gss_OID_desc *mech_used = NULL;
OM_uint32 major_status = GSS_S_FAILURE;
krb5_error krb_error_data;
krb5_data scratch;
gss_cred_id_t cred_handle = NULL;
krb5_gss_cred_id_t deleg_cred = NULL;
+ int token_length;
+ int gsskrb5_vers;
+ int nctypes;
+ krb5_cksumtype *ctypes;
+ struct kg2_option fwcred;
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
output_token->length = 0;
output_token->value = NULL;
token.value = 0;
- md5.contents = 0;
+ reqcksum.contents = 0;
+ mic.data = 0;
+ ap_req.data = 0;
+ ap_rep.data = 0;
+ cksumdata.data = 0;
if (mech_type)
*mech_type = GSS_C_NULL_OID;
/* handle default cred handle */
if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
- major_status = krb5_gss_acquire_cred(&code, GSS_C_NO_NAME,
- GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
- GSS_C_ACCEPT, &cred_handle,
- NULL, NULL);
- if (major_status != GSS_S_COMPLETE)
- goto fail;
- } else
- cred_handle = verifier_cred_handle;
+ major_status = krb5_gss_acquire_cred(&code, GSS_C_NO_NAME,
+ GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+ GSS_C_ACCEPT, &cred_handle,
+ NULL, NULL);
+ if (major_status != GSS_S_COMPLETE)
+ goto fail;
+ } else {
+ cred_handle = verifier_cred_handle;
+ }
- major_status = krb5_gss_validate_cred(minor_status, verifier_cred_handle);
+ major_status = krb5_gss_validate_cred(&code, verifier_cred_handle);
if (GSS_ERROR(major_status))
- goto fail;
+ goto fail;
cred = (krb5_gss_cred_id_t) cred_handle;
if ((cred->usage != GSS_C_ACCEPT) &&
(cred->usage != GSS_C_BOTH)) {
- code = 0;
- major_status = GSS_S_NO_CRED;
- goto fail;
+ code = 0;
+ major_status = GSS_S_NO_CRED;
+ goto fail;
}
/* verify the token's integrity, and leave the token in ap_req.
ptr = (unsigned char *) input_token->value;
- if ((err = g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length),
- &ptr, KG_TOK_CTX_AP_REQ,
- input_token->length))) {
- /*
- * Previous versions of this library used the old mech_id
- * and some broken behavior (wrong IV on checksum
- * encryption). We support the old mech_id for
- * compatibility, and use it to decide when to use the
- * old behavior.
- */
- if (err != G_WRONG_MECH ||
- (code = g_verify_token_header((gss_OID) gss_mech_krb5_old,
- &(ap_req.length),
- &ptr, KG_TOK_CTX_AP_REQ,
- input_token->length))) {
- major_status = GSS_S_DEFECTIVE_TOKEN;
- goto fail;
- } else {
-#if 0 /* Don't restrict mechanisms when accepting contexts */
- if (! cred->prerfc_mech) {
- code = G_WRONG_MECH;
- major_status = GSS_S_DEFECTIVE_TOKEN;
- goto fail;
- }
-#endif
- mech_used = gss_mech_krb5_old;
- }
+ if (!(code = g_verify_token_header((gss_OID) gss_mech_krb5,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length))) {
+ if (! cred->rfc_mech) {
+ code = G_WRONG_MECH;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+ mech_used = gss_mech_krb5;
+ gsskrb5_vers = 1000;
+ } else if ((code == G_WRONG_MECH) &&
+ !(code = g_verify_token_header((gss_OID) gss_mech_krb5_old,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length))) {
+ /*
+ * Previous versions of this library used the old mech_id
+ * and some broken behavior (wrong IV on checksum
+ * encryption). We support the old mech_id for
+ * compatibility, and use it to decide when to use the
+ * old behavior.
+ */
+ if (! cred->prerfc_mech) {
+ code = G_WRONG_MECH;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+ mech_used = gss_mech_krb5_old;
+ gsskrb5_vers = 1000;
+ } else if ((code == G_WRONG_MECH) &&
+ !(code = g_verify_token_header((gss_OID) gss_mech_krb5_v2,
+ &token_length,
+ &ptr, KG2_TOK_INITIAL,
+ input_token->length))) {
+ if (! cred->rfcv2_mech) {
+ code = G_WRONG_MECH;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+ mech_used = gss_mech_krb5_v2;
+ gsskrb5_vers = 2000;
} else {
-#if 0 /* Don't restrict mechanisms when accepting contexts */
- if (! cred->rfc_mech) {
- code = G_WRONG_MECH;
- major_status = GSS_S_DEFECTIVE_TOKEN;
- goto fail;
- }
-#endif
- mech_used = gss_mech_krb5;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
}
- sptr = (char *) ptr;
- TREAD_STR(sptr, ap_req.data, ap_req.length);
- decode_req_message = 1;
+ if (gsskrb5_vers == 2000) {
+ /* gss krb5 v2 */
+
+ fwcred.option_id = KRB5_GSS_FOR_CREDS_OPTION;
+ fwcred.data = NULL;
+
+ if (GSS_ERROR(major_status =
+ kg2_parse_token(&code, ptr, token_length,
+ &gss_flags, &nctypes, &ctypes,
+ delegated_cred_handle?1:0,
+ &fwcred, &ap_req, NULL))) {
+ goto fail;
+ }
+
+ gss_flags = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3];
+
+ gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag;
+ if there's a delegation, we'll
+ set it below */
+ } else {
+ /* gss krb5 v1 */
+
+ sptr = (char *) ptr;
+ TREAD_STR(sptr, ap_req.data, ap_req.length);
+ decode_req_message = 1;
+ }
/* construct the sender_addr */
if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
(input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
- /* XXX is this right? */
- addr.addrtype = ADDRTYPE_INET;
- addr.length = input_chan_bindings->initiator_address.length;
- addr.contents = input_chan_bindings->initiator_address.value;
+ /* XXX is this right? */
+ addr.addrtype = ADDRTYPE_INET;
+ addr.length = input_chan_bindings->initiator_address.length;
+ addr.contents = input_chan_bindings->initiator_address.value;
- paddr = &addr;
+ paddr = &addr;
} else {
- paddr = NULL;
+ paddr = NULL;
}
/* decode the AP_REQ message */
/* decode the message */
if ((code = krb5_auth_con_init(context, &auth_context))) {
- *minor_status = code;
- return(GSS_S_FAILURE);
+ major_status = GSS_S_FAILURE;
+ goto fail;
}
if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
- *minor_status = code;
- return(GSS_S_FAILURE);
+ major_status = GSS_S_FAILURE;
+ goto fail;
}
+ if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
if ((code = krb5_rd_req(context, &auth_context, &ap_req, cred->princ,
cred->keytab, NULL, &ticket))) {
major_status = GSS_S_FAILURE;
if ((authdat->authenticator->subkey == NULL) ||
(authdat->ticket->enc_part2 == NULL)) {
code = KG_NO_SUBKEY;
+ major_status = GSS_S_FAILURE;
goto fail;
}
#endif
- /* verify that the checksum is correct */
+ if (gsskrb5_vers == 2000) {
+ bigend = 1;
+ } else {
+ /* gss krb5 v1 */
- /*
- The checksum may be either exactly 24 bytes, in which case
- no options are specified, or greater than 24 bytes, in which case
- one or more options are specified. Currently, the only valid
- option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
- */
-
- if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
- (authdat->checksum->length < 24)) {
- code = 0;
- major_status = GSS_S_BAD_BINDINGS;
+ /* stash this now, for later. */
+ if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5,
+ &md5len)) {
+ major_status = GSS_S_FAILURE;
goto fail;
- }
+ }
- /*
- "Be liberal in what you accept, and
- conservative in what you send"
- -- rfc1123
+ /* verify that the checksum is correct */
- This code will let this acceptor interoperate with an initiator
- using little-endian or big-endian integer encoding.
- */
+ /*
+ The checksum may be either exactly 24 bytes, in which case
+ no options are specified, or greater than 24 bytes, in which case
+ one or more options are specified. Currently, the only valid
+ option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
+ */
+
+ if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
+ (authdat->checksum->length < 24)) {
+ code = 0;
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
- ptr = (unsigned char *) authdat->checksum->contents;
- bigend = 0;
+ /*
+ "Be liberal in what you accept, and
+ conservative in what you send"
+ -- rfc1123
- TREAD_INT(ptr, tmp, bigend);
+ This code will let this acceptor interoperate with an initiator
+ using little-endian or big-endian integer encoding.
+ */
- if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) {
ptr = (unsigned char *) authdat->checksum->contents;
- bigend = 1;
+ bigend = 0;
TREAD_INT(ptr, tmp, bigend);
- if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) {
- major_status = GSS_S_FAILURE;
- code = KG_BAD_LENGTH;
- goto fail;
+ if (tmp != md5len) {
+ ptr = (unsigned char *) authdat->checksum->contents;
+ bigend = 1;
+
+ TREAD_INT(ptr, tmp, bigend);
+
+ if (tmp != md5len) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
}
- }
- /* at this point, bigend is set according to the initiator's byte order */
+ /* at this point, bigend is set according to the initiator's
+ byte order */
- if ((code = kg_checksum_channel_bindings(context, input_chan_bindings, &md5,
- bigend))) {
- major_status = GSS_S_BAD_BINDINGS;
- goto fail;
- }
+ if ((code = kg_checksum_channel_bindings(context, input_chan_bindings,
+ &reqcksum, bigend))) {
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
- TREAD_STR(ptr, ptr2, md5.length);
- if (memcmp(ptr2, md5.contents, md5.length) != 0) {
+ TREAD_STR(ptr, ptr2, reqcksum.length);
+ if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
code = 0;
major_status = GSS_S_BAD_BINDINGS;
goto fail;
- }
-
- xfree(md5.contents);
- md5.contents = 0;
-
- TREAD_INT(ptr, gss_flags, bigend);
- gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; if there's
- a delegation, we'll set it below */
- decode_req_message = 0;
-
- /* if the checksum length > 24, there are options to process */
+ }
- if(authdat->checksum->length > 24) {
+ xfree(reqcksum.contents);
+ reqcksum.contents = 0;
- i = authdat->checksum->length - 24;
+ TREAD_INT(ptr, gss_flags, bigend);
+ gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; if
+ there's a delegation, we'll set
+ it below */
+ decode_req_message = 0;
- while(i>0) {
+ /* if the checksum length > 24, there are options to process */
- TREAD_INT16(ptr, option_id, bigend);
+ if(authdat->checksum->length > 24) {
- switch(option_id) {
+ i = authdat->checksum->length - 24;
- case KRB5_GSS_FOR_CREDS_OPTION:
+ while(i>0) {
- TREAD_INT16(ptr, option.length, bigend);
+ TREAD_INT16(ptr, option_id, bigend);
- /* have to use ptr2, since option.data is wrong type and
- macro uses ptr as both lvalue and rvalue */
+ switch(option_id) {
- TREAD_STR(ptr, ptr2, bigend);
- option.data = (char FAR *) ptr2;
+ case KRB5_GSS_FOR_CREDS_OPTION:
- /* get a temporary auth_context structure for the
- call to rd_and_store_for_creds() and clear its flags */
+ TREAD_INT16(ptr, option.length, bigend);
- if ((code = krb5_auth_con_init(context,
- &auth_context_cred))) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
+ /* have to use ptr2, since option.data is wrong type and
+ macro uses ptr as both lvalue and rvalue */
- krb5_auth_con_setflags(context, auth_context_cred, 0);
+ TREAD_STR(ptr, ptr2, bigend);
+ option.data = (char FAR *) ptr2;
- /* store the delegated credential */
+ /* store the delegated credential */
- rd_and_store_for_creds(context, auth_context_cred,
- &option,
- (delegated_cred_handle) ?
- &deleg_cred : NULL);
+ if (code = rd_and_store_for_creds(context, &option,
+ (delegated_cred_handle) ?
+ &deleg_cred : NULL)) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
- i -= option.length + 4;
+ i -= option.length + 4;
- krb5_auth_con_free(context, auth_context_cred);
+ gss_flags |= GSS_C_DELEG_FLAG; /* got a delegation */
- gss_flags |= GSS_C_DELEG_FLAG; /* got a delegation */
+ break;
- break;
+ /* default: */
+ /* unknown options aren't an error */
- /* default: */
- /* unknown options aren't an error */
+ } /* switch */
+ } /* while */
+ } /* if */
+ }
- } /* switch */
- } /* while */
- } /* if */
-
/* create the ctx struct and start filling it in */
if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
== NULL) {
- major_status = GSS_S_FAILURE;
code = ENOMEM;
+ major_status = GSS_S_FAILURE;
goto fail;
}
ctx->gss_flags = KG_IMPLFLAGS(gss_flags);
ctx->seed_init = 0;
ctx->big_endian = bigend;
-
- major_status = GSS_S_FAILURE;
+ ctx->gsskrb5_version = gsskrb5_vers;
/* Intern the ctx pointer so that delete_sec_context works */
if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
- code = G_VALIDATE_FAILED;
- xfree(ctx);
- ctx = 0;
- goto fail;
+ xfree(ctx);
+ ctx = 0;
+
+ code = G_VALIDATE_FAILED;
+ major_status = GSS_S_FAILURE;
+ goto fail;
}
-
- if ((code = krb5_copy_principal(context, cred->princ, &ctx->here)))
- goto fail;
- if ((code = krb5_copy_principal(context, authdat->client, &ctx->there)))
- goto fail;
+ if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
- /* done with authdat */
- krb5_free_authenticator(context, authdat);
- authdat = 0;
+ if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
if ((code = krb5_auth_con_getremotesubkey(context, auth_context,
- &ctx->subkey)))
- goto fail;
+ &ctx->subkey))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
/* use the session key if the subkey isn't present */
if (ctx->subkey == NULL) {
if ((code = krb5_auth_con_getkey(context, auth_context,
- &ctx->subkey)))
- goto fail;
+ &ctx->subkey))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
}
if (ctx->subkey == NULL) {
/* this isn't a very good error, but it's not clear to me this
can actually happen */
+ major_status = GSS_S_FAILURE;
code = KRB5KDC_ERR_NULL_KEY;
goto fail;
}
- switch(ctx->subkey->enctype) {
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_CRC:
- enctype = ENCTYPE_DES_CBC_RAW;
- ctx->signalg = 0;
- ctx->cksum_size = 8;
- ctx->sealalg = 0;
- break;
+ if (gsskrb5_vers == 2000) {
+ int cblen;
+ krb5_boolean valid;
+
+ /* intersect the token ctypes with the local ctypes */
+
+ if (code = krb5_c_keyed_checksum_types(context, ctx->subkey->enctype,
+ &ctx->nctypes, &ctx->ctypes))
+ goto fail;
+
+ if (nctypes == 0) {
+ code = KRB5_CRYPTO_INTERNAL;
+ goto fail;
+ }
+
+ kg2_intersect_ctypes(&ctx->nctypes, ctx->ctypes, nctypes, ctypes);
+
+ if (nctypes == 0) {
+ code = KG_NO_CTYPES;
+ goto fail;
+ }
+
+ /* process the delegated cred, if any */
+
+ if (fwcred.data) {
+ krb5_data option;
+
+ option.length = fwcred.length;
+ option.data = fwcred.data;
+
+ if (code = rd_and_store_for_creds(context, &option, &deleg_cred)) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ gss_flags |= GSS_C_DELEG_FLAG; /* got a delegation */
+ }
+
+ /* construct the checksum buffer */
+
+ cblen = 4*5;
+ if (input_chan_bindings)
+ cblen += (input_chan_bindings->initiator_address.length+
+ input_chan_bindings->acceptor_address.length+
+ input_chan_bindings->application_data.length);
+
+ cksumdata.length = cblen + ((char *)(ap_req.data-2) - (char *)(ptr-2));
+
+ if ((cksumdata.data = (char *) malloc(cksumdata.length)) == NULL) {
+ code = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ ptr2 = cksumdata.data;
+
+ if (input_chan_bindings) {
+ TWRITE_INT(ptr2, input_chan_bindings->initiator_addrtype, 1);
+ TWRITE_BUF(ptr2, input_chan_bindings->initiator_address, 1);
+ TWRITE_INT(ptr2, input_chan_bindings->acceptor_addrtype, 1);
+ TWRITE_BUF(ptr2, input_chan_bindings->acceptor_address, 1);
+ TWRITE_BUF(ptr2, input_chan_bindings->application_data, 1);
+ } else {
+ memset(ptr2, 0, cblen);
+ ptr2 += cblen;
+ }
+
+ memcpy(ptr2, ptr-2, ((char *)(ap_req.data-2) - (char *)(ptr-2)));
+
+ if (code = krb5_c_verify_checksum(context, ctx->subkey,
+ KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
+ &cksumdata, authdat->checksum,
+ &valid)) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ free(cksumdata.data);
+ cksumdata.data = 0;
+
+ if (!valid) {
+ code = 0;
+ major_status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+ } else {
+ /* gss krb5 v1 */
+
+ switch(ctx->subkey->enctype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_CRC:
+ ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->signalg = 0;
+ ctx->cksum_size = 8;
+ ctx->sealalg = 0;
+ break;
#if 0
- case ENCTYPE_DES3_CBC_MD5:
- enctype = ENCTYPE_DES3_CBC_RAW;
- ctx->signalg = 3;
- ctx->cksum_size = 16;
- ctx->sealalg = 1;
- break;
+ case ENCTYPE_DES3_CBC_MD5:
+ enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->signalg = 3;
+ ctx->cksum_size = 16;
+ ctx->sealalg = 1;
+ break;
#endif
- default:
- code = KRB5_BAD_ENCTYPE;
- goto fail;
- }
-
- /* fill in the encryption descriptors */
+ default:
+ code = KRB5_BAD_ENCTYPE;
+ goto fail;
+ }
- krb5_use_enctype(context, &ctx->enc.eblock, enctype);
- ctx->enc.processed = 0;
+ /* fill in the encryption descriptors */
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key)))
+ if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
+ major_status = GSS_S_FAILURE;
goto fail;
+ }
- for (i=0; i<ctx->enc.key->length; i++)
- /*SUPPRESS 113*/
- ctx->enc.key->contents[i] ^= 0xf0;
+ for (i=0; i<ctx->enc->length; i++)
+ /*SUPPRESS 113*/
+ ctx->enc->contents[i] ^= 0xf0;
- krb5_use_enctype(context, &ctx->seq.eblock, enctype);
- ctx->seq.processed = 0;
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key)))
+ if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
+ major_status = GSS_S_FAILURE;
goto fail;
+ }
+ }
ctx->endtime = ticket->enc_part2->times.endtime;
ctx->krb_flags = ticket->enc_part2->flags;
krb5_auth_con_getremoteseqnumber(context, auth_context, &ctx->seq_recv);
- if ((code = krb5_timeofday(context, &now)))
- goto fail;
+ if ((code = krb5_timeofday(context, &now))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
if (ctx->endtime < now) {
- code = 0;
- major_status = GSS_S_CREDENTIALS_EXPIRED;
- goto fail;
+ code = 0;
+ major_status = GSS_S_CREDENTIALS_EXPIRED;
+ goto fail;
}
g_order_init(&(ctx->seqstate), ctx->seq_recv,
/* generate an AP_REP if necessary */
if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
- krb5_data ap_rep;
- unsigned char * ptr;
- if ((code = krb5_mk_rep(context, auth_context, &ap_rep)))
- goto fail;
-
- krb5_auth_con_getlocalseqnumber(context, auth_context, &ctx->seq_send);
- token.length = g_token_size((gss_OID) mech_used, ap_rep.length);
-
- if ((token.value = (unsigned char *) xmalloc(token.length)) == NULL) {
- code = ENOMEM;
- goto fail;
- }
- ptr = token.value;
- g_make_token_header((gss_OID) mech_used, ap_rep.length,
- &ptr, KG_TOK_CTX_AP_REP);
-
- TWRITE_STR(ptr, ap_rep.data, ap_rep.length);
- xfree(ap_rep.data);
+ unsigned char * ptr;
+ if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ krb5_auth_con_getlocalseqnumber(context, auth_context,
+ &ctx->seq_send);
+
+ /* the reply token hasn't been sent yet, but that's ok. */
+ ctx->established = 1;
+
+ if (ctx->gsskrb5_version == 2000) {
+ krb5_ui_4 tok_flags;
+
+ tok_flags =
+ (ctx->gss_flags & GSS_C_DELEG_FLAG)?KG2_RESP_FLAG_DELEG_OK:0;
+
+ cksumdata.length = 8 + 4*ctx->nctypes + 4;
+
+ if ((cksumdata.data = (char *) malloc(cksumdata.length)) == NULL) {
+ code = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* construct the token fields */
+
+ ptr = cksumdata.data;
+
+ ptr[0] = (KG2_TOK_RESPONSE >> 8) & 0xff;
+ ptr[1] = KG2_TOK_RESPONSE & 0xff;
+
+ ptr[2] = (tok_flags >> 24) & 0xff;
+ ptr[3] = (tok_flags >> 16) & 0xff;
+ ptr[4] = (tok_flags >> 8) & 0xff;
+ ptr[5] = tok_flags & 0xff;
+
+ ptr[6] = (ctx->nctypes >> 8) & 0xff;
+ ptr[7] = ctx->nctypes & 0xff;
+
+ ptr += 8;
+
+ for (i=0; i<ctx->nctypes; i++) {
+ ptr[i] = (ctx->ctypes[i] >> 24) & 0xff;
+ ptr[i+1] = (ctx->ctypes[i] >> 16) & 0xff;
+ ptr[i+2] = (ctx->ctypes[i] >> 8) & 0xff;
+ ptr[i+3] = ctx->ctypes[i] & 0xff;
+
+ ptr += 4;
+ }
+
+ memset(ptr, 0, 4);
+
+ /* make the MIC token */
+
+ {
+ gss_buffer_desc text, token;
+
+ text.length = cksumdata.length;
+ text.value = cksumdata.data;
+
+ /* ctx->seq_send must be set before this call */
+
+ if (GSS_ERROR(major_status =
+ krb5_gss_get_mic(&code, ctx,
+ GSS_C_QOP_DEFAULT,
+ &text, &token)))
+ goto fail;
+
+ mic.length = token.length;
+ mic.data = token.value;
+ }
+
+ token.length = g_token_size((gss_OID) mech_used,
+ (cksumdata.length-2)+4+ap_rep.length+
+ mic.length);
+
+ if ((token.value = (unsigned char *) xmalloc(token.length))
+ == NULL) {
+ code = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ ptr = token.value;
+ g_make_token_header((gss_OID) mech_used,
+ (cksumdata.length-2)+4+ap_rep.length+mic.length,
+ &ptr, KG2_TOK_RESPONSE);
+
+ memcpy(ptr, cksumdata.data+2, cksumdata.length-2);
+ ptr += cksumdata.length-2;
+
+ ptr[0] = (ap_rep.length >> 8) & 0xff;
+ ptr[1] = ap_rep.length & 0xff;
+ memcpy(ptr+2, ap_rep.data, ap_rep.length);
+
+ ptr += (2+ap_rep.length);
+
+ ptr[0] = (mic.length >> 8) & 0xff;
+ ptr[1] = mic.length & 0xff;
+ memcpy(ptr+2, mic.data, mic.length);
+
+ ptr += (2+mic.length);
+
+ free(cksumdata.data);
+ cksumdata.data = 0;
+
+ /* gss krb5 v2 */
+ } else {
+ /* gss krb5 v1 */
+
+ token.length = g_token_size((gss_OID) mech_used, ap_rep.length);
+
+ if ((token.value = (unsigned char *) xmalloc(token.length))
+ == NULL) {
+ major_status = GSS_S_FAILURE;
+ code = ENOMEM;
+ goto fail;
+ }
+ ptr = token.value;
+ g_make_token_header((gss_OID) mech_used, ap_rep.length,
+ &ptr, KG_TOK_CTX_AP_REP);
+
+ TWRITE_STR(ptr, ap_rep.data, ap_rep.length);
+ xfree(ap_rep.data);
+
+ ctx->established = 1;
+
+ }
} else {
- token.length = 0;
- token.value = NULL;
- ctx->seq_send = ctx->seq_recv;
+ token.length = 0;
+ token.value = NULL;
+ ctx->seq_send = ctx->seq_recv;
+
+ ctx->established = 1;
}
/* set the return arguments */
if (src_name) {
- if ((code = krb5_copy_principal(context, ctx->there, &name)))
- goto fail;
- /* intern the src_name */
- if (! kg_save_name((gss_name_t) name)) {
- code = G_VALIDATE_FAILED;
- goto fail;
- }
+ if ((code = krb5_copy_principal(context, ctx->there, &name))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ /* intern the src_name */
+ if (! kg_save_name((gss_name_t) name)) {
+ code = G_VALIDATE_FAILED;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
}
if (mech_type)
if (ret_flags)
*ret_flags = ctx->gss_flags;
- ctx->established = 1;
*context_handle = ctx;
*output_token = token;
*src_name = (gss_name_t) name;
if (delegated_cred_handle && deleg_cred) {
- if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
- code = G_VALIDATE_FAILED;
- goto fail;
- }
+ if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
+ major_status = GSS_S_FAILURE;
+ code = G_VALIDATE_FAILED;
+ goto fail;
+ }
- *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
+ *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
}
/* finally! */
*minor_status = 0;
- return(GSS_S_COMPLETE);
+ major_status = GSS_S_COMPLETE;
-fail:
+ fail:
+ if (ctypes)
+ free(ctypes);
if (authdat)
- krb5_free_authenticator(context, authdat);
+ krb5_free_authenticator(context, authdat);
+ if (reqcksum.contents)
+ xfree(reqcksum.contents);
+ if (ap_rep.data)
+ xfree(ap_rep.data);
+ if (mic.data)
+ xfree(mic.data);
+ if (cksumdata.data)
+ xfree(cksumdata.data);
+
+ if (!GSS_ERROR(major_status))
+ return(major_status);
+
+ /* from here on is the real "fail" code */
+
if (ctx)
- (void) krb5_gss_delete_sec_context(minor_status,
- (gss_ctx_id_t *) &ctx, NULL);
+ (void) krb5_gss_delete_sec_context(minor_status,
+ (gss_ctx_id_t *) &ctx, NULL);
+ if (deleg_cred) { /* free memory associated with the deleg credential */
+ if (deleg_cred->ccache)
+ (void)krb5_cc_close(context, deleg_cred->ccache);
+ if (deleg_cred->princ)
+ krb5_free_principal(context, deleg_cred->princ);
+ xfree(deleg_cred);
+ }
if (token.value)
- xfree(token.value);
+ xfree(token.value);
if (name) {
- (void) kg_delete_name((gss_name_t) name);
- krb5_free_principal(context, name);
- }
- if (md5.contents)
- xfree(md5.contents);
- if (deleg_cred) { /* free memory associated with the deleg credential */
- if (deleg_cred->ccache)
- (void)krb5_cc_close(context, deleg_cred->ccache);
- if (deleg_cred->princ)
- krb5_free_principal(context, deleg_cred->princ);
- xfree(deleg_cred);
+ (void) kg_delete_name((gss_name_t) name);
+ krb5_free_principal(context, name);
}
*minor_status = code;
* decode the authenticator to read out the gss_flags field.
*/
if (decode_req_message) {
- krb5_ap_req * request;
+ krb5_ap_req * request;
- if (decode_krb5_ap_req(&ap_req, &request))
- return (major_status);
- if (request->ap_options & AP_OPTS_MUTUAL_REQUIRED)
- gss_flags |= GSS_C_MUTUAL_FLAG;
- krb5_free_ap_req(context, request);
+ if (decode_krb5_ap_req(&ap_req, &request))
+ return (major_status);
+ if (request->ap_options & AP_OPTS_MUTUAL_REQUIRED)
+ gss_flags |= GSS_C_MUTUAL_FLAG;
+ krb5_free_ap_req(context, request);
}
if (cred && (gss_flags & GSS_C_MUTUAL_FLAG)) {
- /*
- * The client is expecting a response, so we can send an
- * error token back
- */
- memset(&krb_error_data, 0, sizeof(krb_error_data));
-
- code -= ERROR_TABLE_BASE_krb5;
- if (code < 0 || code > 128)
- code = 60 /* KRB_ERR_GENERIC */;
-
- krb_error_data.error = code;
- (void) krb5_us_timeofday(context, &krb_error_data.stime,
- &krb_error_data.susec);
- krb_error_data.server = cred->princ;
+ int tmsglen, toktype;
+
+ /*
+ * The client is expecting a response, so we can send an
+ * error token back
+ */
+ memset(&krb_error_data, 0, sizeof(krb_error_data));
+
+ code -= ERROR_TABLE_BASE_krb5;
+ if (code < 0 || code > 128)
+ code = 60 /* KRB_ERR_GENERIC */;
+
+ krb_error_data.error = code;
+ (void) krb5_us_timeofday(context, &krb_error_data.stime,
+ &krb_error_data.susec);
+ krb_error_data.server = cred->princ;
- code = krb5_mk_error(context, &krb_error_data, &scratch);
- if (code)
- return (major_status);
+ code = krb5_mk_error(context, &krb_error_data, &scratch);
+ if (code)
+ return (major_status);
+
+ if (gsskrb5_vers == 2000) {
+ tmsglen = 12+scratch.length;
+ toktype = KG2_TOK_RESPONSE;
+ } else {
+ tmsglen = scratch.length;
+ toktype = KG_TOK_CTX_ERROR;
+ }
- token.length = g_token_size((gss_OID) mech_used, scratch.length);
- token.value = (unsigned char *) xmalloc(token.length);
- if (!token.value)
- return (major_status);
+ token.length = g_token_size((gss_OID) mech_used, tmsglen);
+ token.value = (unsigned char *) xmalloc(token.length);
+ if (!token.value)
+ return (major_status);
- ptr = token.value;
- g_make_token_header((gss_OID) mech_used, scratch.length,
- &ptr, KG_TOK_CTX_ERROR);
+ ptr = token.value;
+ g_make_token_header((gss_OID) mech_used, tmsglen, &ptr, toktype);
+
+ if (gsskrb5_vers == 2000) {
+ krb5_ui_4 flags;
+
+ flags = KG2_RESP_FLAG_ERROR;
+
+ ptr[0] = (flags << 24) & 0xff;
+ ptr[1] = (flags << 16) & 0xff;
+ ptr[2] = (flags << 8) & 0xff;
+ ptr[3] = flags & 0xff;
+
+ memset(ptr+4, 0, 6);
+
+ ptr[10] = (scratch.length << 8) & 0xff;
+ ptr[11] = scratch.length & 0xff;
+
+ ptr += 12;
+ }
- TWRITE_STR(ptr, scratch.data, scratch.length);
- xfree(scratch.data);
+ TWRITE_STR(ptr, scratch.data, scratch.length);
+ xfree(scratch.data);
- *output_token = token;
+ *output_token = token;
}
if (!verifier_cred_handle && cred_handle) {
krb5_gss_release_cred(&code, cred_handle);
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "gssapiP_krb5.h"
#ifdef HAVE_STRING_H
#include <string.h>
size_t i;
krb5_gss_cred_id_t cred;
gss_OID_set ret_mechs;
- const gss_OID_set_desc FAR * valid_mechs;
- int req_old, req_new;
+ int req_old, req_new, req_v2;
OM_uint32 ret;
krb5_error_code code;
contains krb5 */
if (desired_mechs == GSS_C_NULL_OID_SET) {
- valid_mechs = gss_mech_set_krb5_both;
req_old = 1;
req_new = 1;
+ req_v2 = 1;
} else {
req_old = 0;
req_new = 0;
+ req_v2 = 0;
for (i=0; i<desired_mechs->count; i++) {
if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i])))
req_old++;
if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i])))
req_new++;
+ if (g_OID_equal(gss_mech_krb5_v2, &(desired_mechs->elements[i])))
+ req_v2++;
}
- if (req_old && req_new) {
- valid_mechs = gss_mech_set_krb5_both;
- } else if (req_old) {
- valid_mechs = gss_mech_set_krb5_old;
- } else if (req_new) {
- valid_mechs = gss_mech_set_krb5;
- } else {
+ if (!req_old && !req_new && !req_v2) {
*minor_status = 0;
return(GSS_S_BAD_MECH);
}
cred->usage = cred_usage;
cred->princ = NULL;
- cred->actual_mechs = valid_mechs;
cred->prerfc_mech = req_old;
cred->rfc_mech = req_new;
+ cred->rfcv2_mech = req_v2;
cred->keytab = NULL;
cred->ccache = NULL;
/* create mechs */
if (actual_mechs) {
- if (! g_copy_OID_set(cred->actual_mechs, &ret_mechs)) {
- if (cred->ccache)
- (void)krb5_cc_close(context, cred->ccache);
- if (cred->keytab)
- (void)krb5_kt_close(context, cred->keytab);
- if (cred->princ)
- krb5_free_principal(context, cred->princ);
- xfree(cred);
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
+ if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
+ &ret_mechs)) ||
+ (cred->prerfc_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_old,
+ &ret_mechs))) ||
+ (cred->rfc_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5,
+ &ret_mechs))) ||
+ (cred->rfcv2_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_v2,
+ &ret_mechs)))) {
+ if (cred->ccache)
+ (void)krb5_cc_close(context, cred->ccache);
+ if (cred->keytab)
+ (void)krb5_kt_close(context, cred->keytab);
+ if (cred->princ)
+ krb5_free_principal(context, cred->princ);
+ xfree(cred);
+ /* *minor_status set above */
+ return(ret);
+ }
}
/* intern the credential handle */
return(GSS_S_COMPLETE);
}
-
-/* V2 interface */
-OM_uint32
-krb5_gss_add_cred(minor_status, input_cred_handle,
- desired_name, desired_mech, cred_usage,
- initiator_time_req, acceptor_time_req,
- output_cred_handle, actual_mechs,
- initiator_time_rec, acceptor_time_rec)
- OM_uint32 *minor_status;
- gss_cred_id_t input_cred_handle;
- gss_name_t desired_name;
- gss_OID desired_mech;
- gss_cred_usage_t cred_usage;
- OM_uint32 initiator_time_req;
- OM_uint32 acceptor_time_req;
- gss_cred_id_t *output_cred_handle;
- gss_OID_set *actual_mechs;
- OM_uint32 *initiator_time_rec;
- OM_uint32 *acceptor_time_rec;
-{
- /*
- * This does not apply to our single-mechanism implementation. Decide
- * if the correct error is BAD_MECH or DUPLICATE_ELEMENT.
- */
-
- /* verify that the requested mechanism is the default, or
- is krb5 */
-
- if ((desired_mech != GSS_C_NULL_OID) &&
- (g_OID_equal(desired_mech, gss_mech_krb5)))
- return(GSS_S_BAD_MECH);
-
- *minor_status = 0;
- return(GSS_S_DUPLICATE_ELEMENT);
-}
-
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * $Id$
+ */
+
+/* V2 interface */
+OM_uint32
+krb5_gss_add_cred(minor_status, input_cred_handle,
+ desired_name, desired_mech, cred_usage,
+ initiator_time_req, acceptor_time_req,
+ output_cred_handle, actual_mechs,
+ initiator_time_rec, acceptor_time_rec)
+ OM_uint32 *minor_status;
+ gss_cred_id_t input_cred_handle;
+ gss_name_t desired_name;
+ gss_OID desired_mech;
+ gss_cred_usage_t cred_usage;
+ OM_uint32 initiator_time_req;
+ OM_uint32 acceptor_time_req;
+ gss_cred_id_t *output_cred_handle;
+ gss_OID_set *actual_mechs;
+ OM_uint32 *initiator_time_rec;
+ OM_uint32 *acceptor_time_rec;
+{
+ krb5_context context;
+ OM_uint32 major_status, lifetime;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code;
+
+ /* this is pretty simple, since there's not really any difference
+ between the underlying mechanisms. The main hair is in copying
+ a mechanism if requested. */
+
+ /* check if the desired_mech is bogus */
+
+ if (!g_OID_equal(desired_mech, gss_mech_krb5_v2) &&
+ !g_OID_equal(desired_mech, gss_mech_krb5) &&
+ !g_OID_equal(desired_mech, gss_mech_krb5_old)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ /* check if the desired_mech is bogus */
+
+ if ((cred_usage != GSS_C_INITIATE) &&
+ (cred_usage != GSS_C_ACCEPT) &&
+ (cred_usage != GSS_C_BOTH)) {
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ return(GSS_S_FAILURE);
+ }
+
+ /* since the default credential includes all the mechanisms,
+ return an error for that case. */
+
+ /*SUPPRESS 29*/
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ *minor_status = 0;
+ return(GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ /* verify the credential */
+ if (GSS_ERROR(major_status =
+ krb5_gss_validate_cred(minor_status, input_cred_handle)))
+ return(major_status);
+
+ cred = (krb5_gss_cred_id_t) input_cred_handle;
+
+ /* check if the cred_usage is equal or "less" than the passed-in cred
+ if copying */
+
+ if (!((cred->usage == cred_usage) ||
+ ((cred->usage == GSS_C_BOTH) &&
+ (output_cred_handle != NULL)))) {
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ return(GSS_S_FAILURE);
+ }
+
+ /* check that desired_mech isn't already in the credential */
+
+ if ((g_OID_equal(desired_mech, gss_mech_krb5_old) && cred->prerfc_mech) ||
+ (g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech) ||
+ (g_OID_equal(desired_mech, gss_mech_krb5_v2) && cred->rfcv2_mech)) {
+ *minor_status = 0;
+ return(GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
+ /* verify the desired_name */
+
+ /*SUPPRESS 29*/
+ if ((desired_name != (gss_name_t) NULL) &&
+ (! kg_validate_name(desired_name))) {
+ *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+ return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+ }
+
+ /* make sure the desired_name is the same as the existing one */
+
+ if (desired_name &&
+ !krb5_principal_compare(context, (krb5_principal) desired_name,
+ cred->princ)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_NAME);
+ }
+
+ /* copy the cred if necessary */
+
+ if (output_cred_handle) {
+ /* make a copy */
+ krb5_gss_cred_id_t new_cred;
+ char *kttype, ktboth[1024];
+ char *cctype, *ccname, ccboth[1024];
+
+ if ((new_cred =
+ (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))
+ == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ memset(new_cred, 0, sizeof(krb5_gss_cred_id_rec));
+
+ new_cred->usage = cred_usage;
+ new_cred->prerfc_mech = cred->prerfc_mech;
+ new_cred->rfc_mech = cred->rfc_mech;
+ new_cred->rfcv2_mech = cred->rfcv2_mech;
+ new_cred->tgt_expire = cred->tgt_expire;
+
+ if (code = krb5_copy_principal(context, cred->princ,
+ &new_cred->princ)) {
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (cred->keytab) {
+ kttype = krb5_kt_get_type(context, cred->keytab);
+ if ((strlen(kttype)+2) > sizeof(ktboth)) {
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ strcpy(ktboth, kttype);
+ strcat(ktboth, ":");
+
+ if (code = krb5_kt_get_name(context, cred->keytab,
+ ktboth+strlen(ktboth),
+ sizeof(ktboth)-strlen(ktboth))) {
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (code = krb5_kt_resolve(context, ktboth, &new_cred->keytab)) {
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ new_cred->keytab = NULL;
+ }
+
+ if (cred->rcache) {
+ /* Open the replay cache for this principal. */
+ if ((code = krb5_get_server_rcache(context,
+ krb5_princ_component(context, cred->princ, 0),
+ &new_cred->rcache))) {
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ new_cred->rcache = NULL;
+ }
+
+ if (cred->ccache) {
+ cctype = krb5_cc_get_type(context, cred->ccache);
+ ccname = krb5_cc_get_name(context, cred->ccache);
+
+ if ((strlen(cctype)+strlen(ccname)+2) > sizeof(ccboth)) {
+ if (new_cred->rcache)
+ krb5_rc_close(context, new_cred->rcache);
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ strcpy(ccboth, cctype);
+ strcat(ccboth, ":");
+ strcat(ccboth, ccname);
+
+ if (code = krb5_cc_resolve(context, ccboth, &new_cred->ccache)) {
+ if (new_cred->rcache)
+ krb5_rc_close(context, new_cred->rcache);
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ new_cred->ccache = NULL;
+ }
+
+ /* intern the credential handle */
+
+ if (! kg_save_cred_id((gss_cred_id_t) new_cred)) {
+ if (new_cred->ccache)
+ krb5_cc_close(context, new_cred->ccache);
+ if (new_cred->rcache)
+ krb5_rc_close(context, new_cred->rcache);
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+ return(GSS_S_FAILURE);
+ }
+
+ /* modify new_cred */
+
+ cred = new_cred;
+ }
+
+ /* set the flag for the new mechanism */
+
+ if (g_OID_equal(desired_mech, gss_mech_krb5_old))
+ cred->prerfc_mech = 1;
+ else if (g_OID_equal(desired_mech, gss_mech_krb5))
+ cred->rfc_mech = 1;
+ else if (g_OID_equal(desired_mech, gss_mech_krb5_v2))
+ cred->rfcv2_mech = 1;
+
+ /* set the outputs */
+
+ if (GSS_ERROR(major_status = krb5_gss_inquire_cred(minor_status, cred,
+ NULL, &lifetime,
+ NULL, actual_mechs))) {
+ OM_uint32 dummy;
+
+ if (output_cred_handle)
+ (void) krb5_gss_release_cred(&dummy, (gss_cred_id_t *) &cred);
+
+ return(major_status);
+ }
+
+ if (initiator_time_rec)
+ *initiator_time_rec = lifetime;
+ if (acceptor_time_rec)
+ *acceptor_time_rec = lifetime;
+
+ if (output_cred_handle)
+ *output_cred_handle = cred;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
const gss_OID mech_type,
gss_name_t *output_name)
{
- if ((mech_type == GSS_C_NULL_OID) ||
- !g_OID_equal(mech_type, gss_mech_krb5)) {
- if (minor_status)
- *minor_status = 0;
- return(GSS_S_BAD_MECH);
- }
-
- return gss_duplicate_name(minor_status, input_name,
- output_name);
+ if (!g_OID_equal(gss_mech_krb5_v2, mech_type) &&
+ !g_OID_equal(gss_mech_krb5, mech_type) &&
+ !g_OID_equal(gss_mech_krb5_old, mech_type)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ return(gss_duplicate_name(minor_status, input_name, output_name));
}
if (ctx->seqstate)
g_order_free(&(ctx->seqstate));
- if (ctx->enc.processed)
- krb5_finish_key(context, &ctx->enc.eblock);
- if (ctx->enc.key)
- krb5_free_keyblock(context, ctx->enc.key);
+ if (ctx->enc)
+ krb5_free_keyblock(context, ctx->enc);
- if (ctx->seq.processed)
- krb5_finish_key(context, &ctx->seq.eblock);
- if (ctx->seq.key)
- krb5_free_keyblock(context, ctx->seq.key);
+ if (ctx->seq)
+ krb5_free_keyblock(context, ctx->seq);
if (ctx->here)
krb5_free_principal(context, ctx->here);
if (ctx->mech_used)
gss_release_oid(minor_status, &ctx->mech_used);
+ if (ctx->ctypes)
+ xfree(ctx->ctypes);
+
/* Zero out context */
memset(ctx, 0, sizeof(*ctx));
xfree(ctx);
return(GSS_S_FAILURE);
if ((mech_type != GSS_C_NULL_OID) &&
- (! g_OID_equal(gss_mech_krb5, mech_type))) {
- *minor_status = 0;
- return(GSS_S_BAD_MECH);
- }
+ !g_OID_equal(gss_mech_krb5_v2, mech_type) &&
+ !g_OID_equal(gss_mech_krb5, mech_type) &&
+ !g_OID_equal(gss_mech_krb5_old, mech_type)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
if (status_type == GSS_C_GSS_CODE) {
return(g_display_major_status(minor_status, status_value,
((x) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \
GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)))
+#define KG2_TOK_INITIAL 0x0101
+#define KG2_TOK_RESPONSE 0x0202
+#define KG2_TOK_MIC 0x0303
+#define KG2_TOK_WRAP_INTEG 0x0404
+#define KG2_TOK_WRAP_PRIV 0x0505
+
#define KRB5_GSS_FOR_CREDS_OPTION 1
+#define KG2_RESP_FLAG_ERROR 0x0001
+#define KG2_RESP_FLAG_DELEG_OK 0x0002
+
/** internal types **/
typedef krb5_principal krb5_gss_name_t;
/* name/type of credential */
gss_cred_usage_t usage;
krb5_principal princ; /* this is not interned as a gss_name_t */
- const gss_OID_set_desc *actual_mechs;
- int prerfc_mech; /* these are a cache of the set above */
+ int prerfc_mech;
int rfc_mech;
+ int rfcv2_mech;
/* keytab (accept) data */
krb5_keytab keytab;
+ krb5_rcache rcache;
/* ccache (init) data */
krb5_ccache ccache;
krb5_timestamp tgt_expire;
- krb5_rcache rcache;
} krb5_gss_cred_id_rec, *krb5_gss_cred_id_t;
-typedef struct _krb5_gss_enc_desc {
- int processed;
- krb5_keyblock *key;
- krb5_encrypt_block eblock;
-} krb5_gss_enc_desc;
-
typedef struct _krb5_gss_ctx_id_rec {
int initiate; /* nonzero if initiating, zero if accepting */
OM_uint32 gss_flags;
int signalg;
int cksum_size;
int sealalg;
- krb5_gss_enc_desc enc;
- krb5_gss_enc_desc seq;
+ krb5_keyblock *enc;
+ krb5_keyblock *seq;
krb5_timestamp endtime;
krb5_flags krb_flags;
- krb5_int32 seq_send;
- krb5_int32 seq_recv;
+ /* XXX these used to be signed. the old spec is inspecific, and
+ the new spec specifies unsigned. I don't believe that the change
+ affects the wire encoding. */
+ krb5_ui_4 seq_send;
+ krb5_ui_4 seq_recv;
void *seqstate;
int established;
int big_endian;
krb5_auth_context auth_context;
gss_OID_desc *mech_used;
+ int gsskrb5_version;
+ int nctypes;
+ krb5_cksumtype *ctypes;
} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
extern void *kg_vdb;
+struct kg2_option {
+ int option_id; /* set by caller */
+ int length; /* filled in by parser */
+ unsigned char *data; /* filled in by parser. points inside
+ passed-in token, so nothing needs to
+ be freed */
+};
+
/* helper macros */
#define kg_save_name(name) g_save_name(&kg_vdb,name)
int bigend));
krb5_error_code kg_make_seq_num PROTOTYPE((krb5_context context,
- krb5_gss_enc_desc *ed,
+ krb5_keyblock *key,
int direction, krb5_int32 seqnum, unsigned char *cksum,
unsigned char *buf));
krb5_error_code kg_get_seq_num PROTOTYPE((krb5_context context,
- krb5_gss_enc_desc *ed,
+ krb5_keyblock *key,
unsigned char *cksum, unsigned char *buf, int *direction,
krb5_int32 *seqnum));
krb5_keyblock *key,
unsigned char *seed));
-int kg_confounder_size PROTOTYPE((krb5_gss_enc_desc *ed));
+int kg_confounder_size PROTOTYPE((krb5_context context, krb5_keyblock *key));
-krb5_error_code kg_make_confounder PROTOTYPE((krb5_gss_enc_desc *ed,
- unsigned char *buf));
+krb5_error_code kg_make_confounder PROTOTYPE((krb5_context context,
+ krb5_keyblock *key, unsigned char *buf));
-int kg_encrypt_size PROTOTYPE((krb5_gss_enc_desc *ed, int n));
+int kg_encrypt_size PROTOTYPE((krb5_context context,
+ krb5_keyblock *key, int n));
krb5_error_code kg_encrypt PROTOTYPE((krb5_context context,
- krb5_gss_enc_desc *ed,
+ krb5_keyblock *key,
krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length));
krb5_error_code kg_decrypt PROTOTYPE((krb5_context context,
- krb5_gss_enc_desc *ed,
+ krb5_keyblock *key,
krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length));
OM_uint32 kg_seal PROTOTYPE((krb5_context context,
OM_uint32 kg_get_context PROTOTYPE((OM_uint32 *minor_status,
krb5_context *context));
+OM_uint32
+kg2_parse_token PROTOTYPE((OM_uint32 *minor_status,
+ unsigned char *ptr,
+ int length,
+ krb5_ui_4 *flags,
+ int *nctypes, /* OUT */
+ krb5_cksumtype **ctypes, /* OUT */
+ int noptions,
+ struct kg2_option *options, /* INOUT */
+ krb5_data *kmsg,
+ krb5_data *mic));
+
+void kg2_intersect_ctypes PROTOTYPE((int *nc1,
+ krb5_cksumtype *c1,
+ int nc2,
+ const krb5_cksumtype *c2));
+
/** declarations of internal name mechanism functions **/
OM_uint32 krb5_gss_acquire_cred
error_code KG_ENC_DESC, "Bad magic number for krb5_gss_enc_desc"
error_code KG_BAD_SEQ, "Sequence number in token is corrupt"
error_code KG_EMPTY_CCACHE, "Credential cache is empty"
+error_code KG_NO_CTYPES, "Acceptor and Initiator share no checksum types"
end
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
/*
* $Id$
*/
* The OID of the proposed standard krb5 mechanism is:
* iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
* krb5(2) = 1.2.840.113554.1.2.2
+ * The OID of the proposed standard krb5 v2 mechanism is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5v2(3) = 1.2.840.113554.1.2.3
*
*/
{5, "\053\005\001\005\002"},
/* this is the official, rfc-specified OID */
{9, "\052\206\110\206\367\022\001\002\002"},
+ /* these two are name type OID's */
{10, "\052\206\110\206\367\022\001\002\002\001"},
{10, "\052\206\110\206\367\022\001\002\002\002"},
+ /* this is the v2 assigned OID */
+ {9, "\052\206\110\206\367\022\001\002\003"},
+ /* this is the official, rfc-specified OID again */
+ {9, "\052\206\110\206\367\022\001\002\002"},
{ 0, 0 }
};
const gss_OID_desc * const gss_mech_krb5 = krb5_gss_oid_array+1;
const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+2;
const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+3;
+const gss_OID_desc * const gss_mech_krb5_v2 = krb5_gss_oid_array+4;
static const gss_OID_set_desc oidsets[] = {
{1, (gss_OID) krb5_gss_oid_array+0},
{1, (gss_OID) krb5_gss_oid_array+1},
{2, (gss_OID) krb5_gss_oid_array+0},
+ {1, (gss_OID) krb5_gss_oid_array+4},
+ {2, (gss_OID) krb5_gss_oid_array+4},
};
const gss_OID_set_desc * const gss_mech_set_krb5_old = oidsets+0;
const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+1;
const gss_OID_set_desc * const gss_mech_set_krb5_both = oidsets+2;
+const gss_OID_set_desc * const gss_mech_set_krb5_v2 = oidsets+3;
+const gss_OID_set_desc * const gss_mech_set_krb5_v1v2 = oidsets+4;
void *kg_vdb = NULL;
extern const gss_OID_desc * const gss_mech_krb5;
extern const gss_OID_desc * const gss_mech_krb5_old;
+extern const gss_OID_desc * const gss_mech_krb5_v2;
extern const gss_OID_set_desc * const gss_mech_set_krb5;
extern const gss_OID_set_desc * const gss_mech_set_krb5_old;
extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
+extern const gss_OID_set_desc * const gss_mech_set_krb5_v2;
+extern const gss_OID_set_desc * const gss_mech_set_krb5_v1v2;
extern const gss_OID_desc * const gss_nt_krb5_name;
extern const gss_OID_desc * const gss_nt_krb5_principal;
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "gssapiP_krb5.h"
#include <memory.h>
#include <stdlib.h>
int krb5_gss_dbg_client_expcreds = 0;
static krb5_error_code
-make_ap_req(context, auth_context, cred, server, now, endtime, chan_bindings,
- req_flags, krb_flags, mech_type, token)
+make_ap_req_v2(context, auth_context, cred, server, now, endtime,
+ chan_bindings, req_flags, krb_flags, mech_type,
+ ret_nctypes, ret_ctypes, token)
+ krb5_context context;
+ krb5_auth_context * auth_context;
+ krb5_gss_cred_id_t cred;
+ krb5_principal server;
+ krb5_timestamp now;
+ krb5_timestamp *endtime;
+ gss_channel_bindings_t chan_bindings;
+ OM_uint32 *req_flags;
+ krb5_flags *krb_flags;
+ gss_OID mech_type;
+ int *ret_nctypes;
+ krb5_cksumtype **ret_ctypes;
+ gss_buffer_t token;
+{
+ krb5_flags mk_req_flags = 0;
+ krb5_int32 con_flags;
+ krb5_error_code code;
+ krb5_creds in_creds, *out_creds = 0;
+ krb5_data credmsg, cksumdata, ap_req;
+ int i, tlen, cblen, nctypes;
+ krb5_cksumtype *ctypes;
+ unsigned char *t, *ptr;
+
+ credmsg.data = 0;
+ cksumdata.data = 0;
+ ap_req.data = 0;
+ ctypes = 0;
+
+ /* this probably isn't necessary */
+ if (*auth_context)
+ krb5_auth_con_free(context, *auth_context);
+
+ *auth_context = 0;
+
+ /* create the option data if necessary */
+
+ if (*req_flags & GSS_C_DELEG_FLAG) {
+ /* first get KRB_CRED message, so we know its length */
+
+ /* clear the time check flag that was set in krb5_auth_con_init() */
+ krb5_auth_con_getflags(context, *auth_context, &con_flags);
+ krb5_auth_con_setflags(context, *auth_context,
+ con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
+
+ code = krb5_fwd_tgt_creds(context, *auth_context, 0,
+ cred->princ, server, cred->ccache, 1,
+ &credmsg);
+
+ /* turn KRB5_AUTH_CONTEXT_DO_TIME back on */
+ krb5_auth_con_setflags(context, *auth_context, con_flags);
+
+ if (code) {
+ /* don't fail here; just don't accept/do the delegation
+ request */
+ *req_flags &= ~GSS_C_DELEG_FLAG;
+ } else {
+ if (credmsg.length > KRB5_INT16_MAX) {
+ krb5_free_data_contents(context, &credmsg);
+ return(KRB5KRB_ERR_FIELD_TOOLONG);
+ }
+ }
+ } else {
+ credmsg.length = 0;
+ }
+
+ /*
+ * Get the credential, for the session key etype
+ */
+
+ memset((char *) &in_creds, 0, sizeof(krb5_creds));
+
+ if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
+ goto cleanup;
+ if ((code = krb5_copy_principal(context, server, &in_creds.server)))
+ goto cleanup;
+ in_creds.times.endtime = *endtime;
+
+ if ((code = krb5_get_credentials(context, 0, cred->ccache,
+ &in_creds, &out_creds)))
+ goto cleanup;
+
+ /*
+ * Enforce a stricter limit (without timeskew forgiveness at the
+ * boundaries) because accept_sec_context code is also similarly
+ * non-forgiving.
+ */
+ if (!krb5_gss_dbg_client_expcreds && out_creds->times.endtime < now) {
+ code = KRB5KRB_AP_ERR_TKT_EXPIRED;
+ goto cleanup;
+ }
+
+ /* construct the list of compatible cksum types */
+
+ if (code = krb5_c_keyed_checksum_types(context,
+ out_creds->keyblock.enctype,
+ &nctypes, &ctypes))
+ goto cleanup;
+
+ if (nctypes == 0) {
+ code = KRB5_CRYPTO_INTERNAL;
+ goto cleanup;
+ }
+
+ /* construct the checksum fields */
+
+ cblen = 4*5;
+ if (chan_bindings)
+ cblen += (chan_bindings->initiator_address.length+
+ chan_bindings->acceptor_address.length+
+ chan_bindings->application_data.length);
+
+ cksumdata.length = cblen + 8 + 4*nctypes + 4;
+ if (credmsg.length)
+ cksumdata.length += 4 + credmsg.length;
+
+ if ((cksumdata.data = (char *) malloc(cksumdata.length)) == NULL)
+ goto cleanup;
+
+ /* helper macros. This code currently depends on a long being 32
+ bits, and htonl dtrt. */
+
+ ptr = cksumdata.data;
+
+ if (chan_bindings) {
+ TWRITE_INT(ptr, chan_bindings->initiator_addrtype, 1);
+ TWRITE_BUF(ptr, chan_bindings->initiator_address, 1);
+ TWRITE_INT(ptr, chan_bindings->acceptor_addrtype, 1);
+ TWRITE_BUF(ptr, chan_bindings->acceptor_address, 1);
+ TWRITE_BUF(ptr, chan_bindings->application_data, 1);
+ } else {
+ memset(ptr, 0, cblen);
+ ptr += cblen;
+ }
+
+ /* construct the token fields */
+
+ ptr[0] = (KG2_TOK_INITIAL >> 8) & 0xff;
+ ptr[1] = KG2_TOK_INITIAL & 0xff;
+
+ ptr[2] = (*req_flags >> 24) & 0xff;
+ ptr[3] = (*req_flags >> 16) & 0xff;
+ ptr[4] = (*req_flags >> 8) & 0xff;
+ ptr[5] = *req_flags & 0xff;
+
+ ptr[6] = (nctypes >> 8) & 0xff;
+ ptr[7] = nctypes & 0xff;
+
+ ptr += 8;
+
+ for (i=0; i<nctypes; i++) {
+ ptr[0] = (ctypes[i] >> 24) & 0xff;
+ ptr[1] = (ctypes[i] >> 16) & 0xff;
+ ptr[2] = (ctypes[i] >> 8) & 0xff;
+ ptr[3] = ctypes[i] & 0xff;
+
+ ptr += 4;
+ }
+
+ if (credmsg.length) {
+ ptr[0] = (KRB5_GSS_FOR_CREDS_OPTION >> 8) & 0xff;
+ ptr[1] = KRB5_GSS_FOR_CREDS_OPTION & 0xff;
+
+ ptr[2] = (credmsg.length >> 8) & 0xff;
+ ptr[3] = credmsg.length & 0xff;
+
+ ptr += 4;
+
+ memcpy(ptr, credmsg.data, credmsg.length);
+
+ ptr += credmsg.length;
+ }
+
+ memset(ptr, 0, 4);
+
+ /* call mk_req. subkey and ap_req need to be used or destroyed */
+
+ mk_req_flags = AP_OPTS_USE_SUBKEY;
+
+ if (*req_flags & GSS_C_MUTUAL_FLAG)
+ mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED;
+
+ if ((code = krb5_mk_req_extended(context, auth_context, mk_req_flags,
+ &cksumdata, out_creds, &ap_req)))
+ goto cleanup;
+
+ /* store the interesting stuff from creds and authent */
+ *endtime = out_creds->times.endtime;
+ *krb_flags = out_creds->ticket_flags;
+
+ /* build up the token */
+
+ /* allocate space for the token */
+ tlen = g_token_size((gss_OID) mech_type,
+ (cksumdata.length-(2+cblen))+2+ap_req.length);
+
+ if ((t = (unsigned char *) xmalloc(tlen)) == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ ptr = t;
+
+ g_make_token_header((gss_OID) mech_type,
+ (cksumdata.length-(2+cblen))+2+ap_req.length,
+ &ptr, KG2_TOK_INITIAL);
+
+ /* skip over the channel bindings and the token id */
+ memcpy(ptr, cksumdata.data+cblen+2, cksumdata.length-(cblen+2));
+ ptr += cksumdata.length-(cblen+2);
+ ptr[0] = (ap_req.length >> 8) & 0xff;
+ ptr[1] = ap_req.length & 0xff;
+ ptr += 2;
+ memcpy(ptr, ap_req.data, ap_req.length);
+
+ /* pass allocated data back */
+
+ *ret_nctypes = nctypes;
+ *ret_ctypes = ctypes;
+
+ token->length = tlen;
+ token->value = (void *) t;
+
+ code = 0;
+
+cleanup:
+ if (code) {
+ if (*auth_context)
+ krb5_auth_con_free(context, *auth_context);
+ if (ctypes)
+ krb5_free_cksumtypes(context, ctypes);
+ }
+
+ if (out_creds)
+ krb5_free_creds(context, out_creds);
+ krb5_free_cred_contents(context, &in_creds);
+ if (credmsg.data)
+ free(credmsg.data);
+ if (ap_req.data)
+ free(ap_req.data);
+ if (cksumdata.data)
+ free(cksumdata.data);
+
+ return(code);
+}
+
+static krb5_error_code
+make_ap_req_v1(context, auth_context, cred, server, now, endtime,
+ chan_bindings, req_flags, krb_flags, mech_type, token)
krb5_context context;
krb5_auth_context * auth_context;
krb5_gss_cred_id_t cred;
/* fill in the necessary fields in creds */
memset((char *) &in_creds, 0, sizeof(krb5_creds));
+
if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
goto cleanup;
if ((code = krb5_copy_principal(context, server, &in_creds.server)))
goto cleanup;
- in_creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
in_creds.times.endtime = *endtime;
+ in_creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
/*
- * Get the credential..., I don't know in 0 is a good value for the
+ * Get the credential..., I don't know if 0 is a good value for the
* kdcoptions
*/
if ((code = krb5_get_credentials(context, 0, cred->ccache,
return (code);
}
-#define IS_KRB_ERROR(dat)\
- ((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\
- (dat)->data[0] == 0x5e))
-
OM_uint32
krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
context_handle, target_name, mech_type,
krb5_error_code code;
krb5_gss_ctx_id_rec *ctx;
krb5_timestamp now;
- krb5_enctype enctype;
gss_buffer_desc token;
- int i;
- int err;
+ int gsskrb5_vers;
+ int i, err;
+ krb5_ui_4 resp_flags, field_length, opt_id;
+ OM_uint32 major_status, dummy;
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
err = 0;
if (mech_type == GSS_C_NULL_OID) {
- mech_type = cred->rfc_mech?gss_mech_krb5:gss_mech_krb5_old;
+ if (cred->rfcv2_mech) {
+ mech_type = gss_mech_krb5_v2;
+ gsskrb5_vers = 2000;
+ } else if (cred->rfc_mech) {
+ mech_type = gss_mech_krb5;
+ gsskrb5_vers = 1000;
+ } else if (cred->prerfc_mech) {
+ mech_type = gss_mech_krb5_old;
+ gsskrb5_vers = 1000;
+ } else {
+ err = 1;
+ }
+ } else if (g_OID_equal(mech_type, gss_mech_krb5_v2)) {
+ if (!cred->rfcv2_mech)
+ err = 1;
+ gsskrb5_vers = 2000;
} else if (g_OID_equal(mech_type, gss_mech_krb5)) {
if (!cred->rfc_mech)
err = 1;
+ gsskrb5_vers = 1000;
} else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
if (!cred->prerfc_mech)
err = 1;
- } else
+ gsskrb5_vers = 1000;
+ } else {
err = 1;
+ }
if (err) {
*minor_status = 0;
ctx->seed_init = 0;
ctx->big_endian = 0; /* all initiators do little-endian, as per spec */
ctx->seqstate = 0;
+ ctx->gsskrb5_version = gsskrb5_vers;
+ ctx->nctypes = 0;
+ ctx->ctypes = 0;
if ((code = krb5_timeofday(context, &now))) {
free(ctx);
return(GSS_S_FAILURE);
}
- if ((code = make_ap_req(context, &(ctx->auth_context), cred,
- ctx->there, now, &ctx->endtime,
- input_chan_bindings,
- &ctx->gss_flags, &ctx->krb_flags, mech_type,
- &token))) {
- krb5_free_principal(context, ctx->here);
- krb5_free_principal(context, ctx->there);
- xfree(ctx);
- *minor_status = code;
-
- if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
- (code == KG_EMPTY_CCACHE))
- return GSS_S_NO_CRED;
- if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
- return GSS_S_CREDENTIALS_EXPIRED;
- return(GSS_S_FAILURE);
- }
-
- krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &ctx->seq_send);
- krb5_auth_con_getlocalsubkey(context, ctx->auth_context, &ctx->subkey);
-
- /* fill in the encryption descriptors */
-
- switch(ctx->subkey->enctype) {
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_CRC:
- enctype = ENCTYPE_DES_CBC_RAW;
- ctx->signalg = 0;
- ctx->cksum_size = 8;
- ctx->sealalg = 0;
- break;
+ if (ctx->gsskrb5_version == 2000) {
+ /* gsskrb5 v2 */
+
+ ctx->gss_flags & ~GSS_C_DELEG_FLAG;
+
+ if ((code = make_ap_req_v2(context, &(ctx->auth_context), cred,
+ ctx->there, now, &ctx->endtime,
+ input_chan_bindings,
+ &ctx->gss_flags, &ctx->krb_flags,
+ mech_type, &ctx->nctypes, &ctx->ctypes,
+ &token))) {
+ krb5_free_principal(context, ctx->here);
+ krb5_free_principal(context, ctx->there);
+ xfree(ctx);
+ *minor_status = code;
+
+ if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
+ (code == KG_EMPTY_CCACHE))
+ return GSS_S_NO_CRED;
+ if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
+ return GSS_S_CREDENTIALS_EXPIRED;
+ return(GSS_S_FAILURE);
+ }
+
+ krb5_auth_con_getlocalseqnumber(context, ctx->auth_context,
+ &ctx->seq_send);
+ krb5_auth_con_getlocalsubkey(context, ctx->auth_context,
+ &ctx->subkey);
+ } else {
+ /* gsskrb5 v1 */
+
+ if ((code = make_ap_req_v1(context, &(ctx->auth_context), cred,
+ ctx->there, now, &ctx->endtime,
+ input_chan_bindings,
+ &ctx->gss_flags, &ctx->krb_flags,
+ mech_type,
+ &token))) {
+ krb5_free_principal(context, ctx->here);
+ krb5_free_principal(context, ctx->there);
+ xfree(ctx);
+ *minor_status = code;
+
+ if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
+ (code == KG_EMPTY_CCACHE))
+ return GSS_S_NO_CRED;
+ if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
+ return GSS_S_CREDENTIALS_EXPIRED;
+ return(GSS_S_FAILURE);
+ }
+
+ krb5_auth_con_getlocalseqnumber(context, ctx->auth_context,
+ &ctx->seq_send);
+ krb5_auth_con_getlocalsubkey(context, ctx->auth_context,
+ &ctx->subkey);
+
+ /* fill in the encryption descriptors */
+
+ switch(ctx->subkey->enctype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_CRC:
+ ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->signalg = 0;
+ ctx->cksum_size = 8;
+ ctx->sealalg = 0;
+ break;
#if 0
- case ENCTYPE_DES3_CBC_MD5:
- enctype = ENCTYPE_DES3_CBC_RAW;
- ctx->signalg = 3;
- ctx->cksum_size = 16;
- ctx->sealalg = 1;
- break;
+ case ENCTYPE_DES3_CBC_MD5:
+ enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->signalg = 3;
+ ctx->cksum_size = 16;
+ ctx->sealalg = 1;
+ break;
#endif
- default:
- return GSS_S_FAILURE;
- }
+ default:
+ return GSS_S_FAILURE;
+ }
- /* the encryption key is the session key XOR 0xf0f0f0f0f0f0f0f0 */
+ /* the encryption key is the session key XOR 0xf0f0f0f0f0f0f0f0 */
- krb5_use_enctype(context, &ctx->enc.eblock, enctype);
- ctx->enc.processed = 0;
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key)))
- return(code);
- for (i=0; i<ctx->enc.key->length; i++)
- /*SUPPRESS 113*/
- ctx->enc.key->contents[i] ^= 0xf0;
+ if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc)))
+ return(code);
+ for (i=0; i<ctx->enc->length; i++)
+ /*SUPPRESS 113*/
+ ctx->enc->contents[i] ^= 0xf0;
- krb5_use_enctype(context, &ctx->seq.eblock, enctype);
- ctx->seq.processed = 0;
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key)))
- return(code);
+ if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq)))
+ return(code);
+ }
/* at this point, the context is constructed and valid,
hence, releaseable */
} else {
unsigned char *ptr;
char *sptr;
- krb5_data ap_rep;
+ krb5_data ap_rep, mic;
krb5_ap_rep_enc_part *ap_rep_data;
krb5_error *krb_error;
if ((ctx->established) ||
(((gss_cred_id_t) cred) != claimant_cred_handle) ||
((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
- (void)krb5_gss_delete_sec_context(minor_status,
- context_handle, NULL);
- /* XXX this minor status is wrong if an arg was changed */
- *minor_status = KG_CONTEXT_ESTABLISHED;
- return(GSS_S_FAILURE);
+ code = KG_CONTEXT_ESTABLISHED;
+ goto fail;
}
if (! krb5_principal_compare(context, ctx->there,
ptr = (unsigned char *) input_token->value;
- if ((err = g_verify_token_header((gss_OID) mech_type, &(ap_rep.length),
- &ptr, KG_TOK_CTX_AP_REP,
- input_token->length))) {
+ if (ctx->gsskrb5_version == 2000) {
+ int token_length;
+ int nctypes;
+ krb5_cksumtype *ctypes;
+
+ /* gsskrb5 v2 */
+
+ if ((err = g_verify_token_header((gss_OID) mech_type,
+ &token_length,
+ &ptr, KG2_TOK_RESPONSE,
+ input_token->length))) {
+ (void)krb5_gss_delete_sec_context(minor_status,
+ context_handle, NULL);
+ *minor_status = err;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ if (GSS_ERROR(major_status =
+ kg2_parse_token(minor_status, ptr, token_length,
+ &resp_flags, &nctypes, &ctypes,
+ 0, NULL, &ap_rep, &mic))) {
+ free(ctypes);
+ (void)krb5_gss_delete_sec_context(&dummy, context_handle, NULL);
+ return(major_status);
+ }
+
+ kg2_intersect_ctypes(&ctx->nctypes, ctx->ctypes, nctypes, ctypes);
+
+ free(ctypes);
+
+ if (ctx->nctypes == 0) {
+ code = KG_NO_CTYPES;
+ goto fail;
+ }
+
+ if (resp_flags & KG2_RESP_FLAG_ERROR) {
+ if (code = krb5_rd_error(context, &ap_rep, &krb_error))
+ goto fail;
+
+ if (krb_error->error)
+ code = krb_error->error + ERROR_TABLE_BASE_krb5;
+ else
+ code = 0;
+
+ krb5_free_error(context, krb_error);
+
+ goto fail;
+ }
+
+ if (resp_flags & KG2_RESP_FLAG_DELEG_OK)
+ ctx->gss_flags |= GSS_C_DELEG_FLAG;
+
+ /* drop through to ap_rep handling */
+ } else {
+ /* gsskrb5 v1 */
+
+ if ((err = g_verify_token_header((gss_OID) mech_type,
+ &(ap_rep.length),
+ &ptr, KG_TOK_CTX_AP_REP,
+ input_token->length))) {
if (g_verify_token_header((gss_OID) mech_type, &(ap_rep.length),
&ptr, KG_TOK_CTX_ERROR,
input_token->length) == 0) {
- /* Handle a KRB_ERROR message from the server */
+ /* Handle a KRB_ERROR message from the server */
- sptr = (char *) ptr; /* PC compiler bug */
- TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+ sptr = (char *) ptr; /* PC compiler bug */
+ TREAD_STR(sptr, ap_rep.data, ap_rep.length);
- code = krb5_rd_error(context, &ap_rep, &krb_error);
- if (code)
- goto fail;
- if (krb_error->error)
- code = krb_error->error + ERROR_TABLE_BASE_krb5;
- else
- code = 0;
- krb5_free_error(context, krb_error);
+ code = krb5_rd_error(context, &ap_rep, &krb_error);
+ if (code)
goto fail;
+ if (krb_error->error)
+ code = krb_error->error + ERROR_TABLE_BASE_krb5;
+ else
+ code = 0;
+ krb5_free_error(context, krb_error);
+ goto fail;
} else {
- *minor_status = err;
- return(GSS_S_DEFECTIVE_TOKEN);
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
}
- }
+ }
- sptr = (char *) ptr; /* PC compiler bug */
- TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+ sptr = (char *) ptr; /* PC compiler bug */
+ TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+ }
/* decode the ap_rep */
- if ((code = krb5_rd_rep(context,ctx->auth_context,&ap_rep,
+ if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
&ap_rep_data))) {
- /*
- * XXX A hack for backwards compatiblity.
- * To be removed in 1999 -- proven
- */
- krb5_auth_con_setuseruserkey(context,ctx->auth_context,ctx->subkey);
- if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
- &ap_rep_data)))
- goto fail;
+ /*
+ * XXX A hack for backwards compatiblity.
+ * To be removed in 1999 -- proven
+ */
+ krb5_auth_con_setuseruserkey(context, ctx->auth_context,
+ ctx->subkey);
+ if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+ &ap_rep_data)))
+ goto fail;
}
/* store away the sequence number */
/* set established */
ctx->established = 1;
+ if (ctx->gsskrb5_version == 2000) {
+ gss_buffer_desc mic_data, mic_token;
+
+ /* start with the token id */
+ mic_data.value = ptr-2;
+ /* end before the ap-rep length */
+ mic_data.length = ((char*)(ap_rep.data-2)-(char*)(ptr-2));
+
+ mic_token.length = mic.length;
+ mic_token.value = mic.data;
+
+ if (GSS_ERROR(major_status =
+ krb5_gss_verify_mic(minor_status, *context_handle,
+ &mic_data, &mic_token, NULL))) {
+ (void)krb5_gss_delete_sec_context(&dummy, context_handle, NULL);
+ return(major_status);
+ }
+ }
+
/* set returns */
if (time_rec) {
}
if (ret_flags)
- *ret_flags = KG_IMPLFLAGS(req_flags);
+ *ret_flags = ctx->gss_flags;
if (actual_mech_type)
*actual_mech_type = mech_type;
return(GSS_S_COMPLETE);
fail:
- (void)krb5_gss_delete_sec_context(minor_status,
- (gss_ctx_id_t) ctx, NULL);
+ (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+
*minor_status = code;
return(GSS_S_FAILURE);
}
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "gssapiP_krb5.h"
OM_uint32
krb5_deltat lifetime;
krb5_principal ret_name;
gss_OID_set mechs;
+ OM_uint32 ret;
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
}
}
- if (mechanisms)
- if (! g_copy_OID_set(cred->actual_mechs, &mechs)) {
- krb5_free_principal(context, ret_name);
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
+ if (mechanisms) {
+ if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
+ &mechs)) ||
+ (cred->prerfc_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_old,
+ &mechs))) ||
+ (cred->rfc_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5,
+ &mechs))) ||
+ (cred->rfcv2_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_v2,
+ &mechs)))) {
+ krb5_free_principal(context, ret_name);
+ /* *minor_status set above */
+ return(ret);
+ }
+ }
if (name) {
if (! kg_save_name((gss_name_t) ret_name)) {
* We only know how to handle our own creds.
*/
if ((mech_type != GSS_C_NULL_OID) &&
- !g_OID_equal(gss_mech_krb5, mech_type)) {
+ !g_OID_equal(gss_mech_krb5_old, mech_type) &&
+ !g_OID_equal(gss_mech_krb5, mech_type) &&
+ !g_OID_equal(gss_mech_krb5_v2, mech_type)) {
*minor_status = 0;
return(GSS_S_NO_CRED);
}
* We only know how to handle our own mechanism.
*/
if ((mechanism != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_krb5_v2, mechanism) &&
!g_OID_equal(gss_mech_krb5, mechanism) &&
!g_OID_equal(gss_mech_krb5_old, mechanism)) {
*minor_status = 0;
- return(GSS_S_FAILURE);
+ return(GSS_S_BAD_MECH);
}
/* We're okay. Create an empty OID set */
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "gssapiP_krb5.h"
static krb5_error_code
-make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token,
- signalg, cksum_size, sealalg, encrypt, toktype,
- bigend, oid)
+make_priv_token_v2 PROTOTYPE((krb5_context context,
+ krb5_keyblock *subkey,
+ krb5_int32 *seqnum,
+ int direction,
+ gss_buffer_t text,
+ gss_buffer_t token,
+ gss_OID oid));
+
+static krb5_error_code
+make_priv_token_v2(context, subkey, seqnum, direction, text, token, oid)
krb5_context context;
- krb5_gss_enc_desc *enc_ed;
- krb5_gss_enc_desc *seq_ed;
+ krb5_keyblock *subkey;
+ krb5_int32 *seqnum;
+ int direction;
+ gss_buffer_t text;
+ gss_buffer_t token;
+ gss_OID oid;
+{
+ krb5_data plain;
+ krb5_enc_data cipher;
+ krb5_error_code code;
+ size_t enclen;
+ int tlen;
+ unsigned char *t, *ptr;
+
+ plain.data = 0;
+ cipher.ciphertext.data = 0;
+ t = 0;
+
+ plain.length = 7+text->length;
+ if ((plain.data = (void *) malloc(plain.length)) == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ plain.data[0] = (*seqnum >> 24) & 0xff;
+ plain.data[1] = (*seqnum >> 16) & 0xff;
+ plain.data[2] = (*seqnum >> 8) & 0xff;
+ plain.data[3] = *seqnum & 0xff;
+
+ plain.data[4] = direction?0:0xff;
+
+ plain.data[5] = (text->length >> 8) & 0xff;
+ plain.data[6] = text->length & 0xff;
+
+ memcpy(plain.data+7, text->value, text->length);
+
+ if (code = krb5_c_encrypt_length(context, subkey->enctype,
+ plain.length, &enclen))
+ goto cleanup;
+
+ tlen = g_token_size((gss_OID) oid, 2+enclen);
+
+ if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
+ return(ENOMEM);
+
+ ptr = t;
+
+ g_make_token_header((gss_OID) oid, 2+enclen, &ptr,
+ KG2_TOK_WRAP_PRIV);
+
+ ptr[0] = (enclen >> 8) & 0xff;
+ ptr[1] = enclen & 0xff;
+
+ cipher.ciphertext.length = enclen;
+ cipher.ciphertext.data = ptr+2;
+
+ if (code = krb5_c_encrypt(context, subkey,
+ KRB5_KEYUSAGE_GSS_TOK_WRAP_PRIV,
+ 0, &plain, &cipher))
+ goto cleanup;
+
+ /* that's it. return the token */
+
+ (*seqnum)++;
+
+ token->length = tlen;
+ token->value = (void *) t;
+
+ code = 0;
+
+cleanup:
+ if (plain.data)
+ free(plain.data);
+ if (code) {
+ if (t)
+ free(t);
+ }
+
+ return(code);
+}
+
+static krb5_error_code
+make_integ_token_v2 PROTOTYPE((krb5_context context,
+ krb5_keyblock *subkey,
+ krb5_cksumtype ctype,
+ krb5_int32 *seqnum,
+ int direction,
+ gss_buffer_t text,
+ gss_buffer_t token,
+ int toktype,
+ gss_OID oid));
+
+static krb5_error_code
+make_integ_token_v2(context, subkey, ctype, seqnum, direction, text, token,
+ toktype, oid)
+ krb5_context context;
+ krb5_keyblock *subkey;
+ krb5_cksumtype ctype;
+ krb5_int32 *seqnum;
+ int direction;
+ gss_buffer_t text;
+ gss_buffer_t token;
+ int toktype;
+ gss_OID oid;
+{
+ krb5_error_code code;
+ int tmp, tlen;
+ unsigned char *t, *ptr;
+ krb5_data plain;
+ krb5_checksum cksum;
+
+ plain.data = 0;
+ t = 0;
+ cksum.contents = 0;
+
+ /* assemble the checksum buffer and compute the checksum */
+
+ plain.length = 7+text->length;
+
+ if ((plain.data = (char *) malloc(plain.length)) == NULL)
+ goto cleanup;
+
+ plain.data[0] = (*seqnum >> 24) & 0xff;
+ plain.data[1] = (*seqnum >> 16) & 0xff;
+ plain.data[2] = (*seqnum >> 8) & 0xff;
+ plain.data[3] = *seqnum & 0xff;
+
+ plain.data[4] = direction?0:0xff;
+
+ plain.data[5] = (text->length >> 8) & 0xff;
+ plain.data[6] = text->length & 0xff;
+
+ memcpy(plain.data+7, text->value, text->length);
+
+ if (code = krb5_c_make_checksum(context, ctype, subkey,
+ (toktype == KG2_TOK_WRAP_INTEG)?
+ KRB5_KEYUSAGE_GSS_TOK_WRAP_INTEG:
+ KRB5_KEYUSAGE_GSS_TOK_MIC,
+ &plain, &cksum))
+ goto cleanup;
+
+ /* assemble the token itself */
+
+ if (toktype == KG2_TOK_WRAP_INTEG)
+ tmp = 4+(7+text->length)+2+cksum.length;
+ else
+ tmp = 4+(5)+2+cksum.length;
+
+ tlen = g_token_size((gss_OID) oid, tmp);
+
+ if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
+ return(ENOMEM);
+
+ ptr = t;
+
+ g_make_token_header((gss_OID) oid, tmp, &ptr, toktype);
+
+ ptr[0] = (ctype >> 24) & 0xff;
+ ptr[1] = (ctype >> 16) & 0xff;
+ ptr[2] = (ctype >> 8) & 0xff;
+ ptr[3] = ctype & 0xff;
+
+ ptr += 4;
+
+ if (toktype == KG2_TOK_WRAP_INTEG) {
+ memcpy(ptr, plain.data, 7+text->length);
+ ptr += 7+text->length;
+ } else {
+ memcpy(ptr, plain.data, 5);
+ ptr += 5;
+ }
+
+ ptr[0] = (cksum.length >> 8) & 0xff;
+ ptr[1] = cksum.length & 0xff;
+ ptr += 2;
+
+ memcpy(ptr, cksum.contents, cksum.length);
+
+ /* that's it. return the token */
+
+ (*seqnum)++;
+
+ token->length = tlen;
+ token->value = (void *) t;
+
+ code = 0;
+
+cleanup:
+ if (plain.data)
+ free(plain.data);
+ if (cksum.contents)
+ krb5_free_checksum_contents(context, &cksum);
+ if (code) {
+ if (t)
+ free(t);
+ }
+
+ return(code);
+}
+
+static krb5_error_code
+make_seal_token_v1 PROTOTYPE((krb5_context context,
+ krb5_keyblock *enc,
+ krb5_keyblock *seq,
+ krb5_int32 *seqnum,
+ int direction,
+ gss_buffer_t text,
+ gss_buffer_t token,
+ int signalg,
+ int cksum_size,
+ int sealalg,
+ int encrypt,
+ int toktype,
+ int bigend,
+ gss_OID oid));
+
+static krb5_error_code
+make_seal_token_v1(context, enc, seq, seqnum, direction, text, token,
+ signalg, cksum_size, sealalg, encrypt, toktype,
+ bigend, oid)
+ krb5_context context;
+ krb5_keyblock *enc;
+ krb5_keyblock *seq;
krb5_int32 *seqnum;
int direction;
gss_buffer_t text;
gss_OID oid;
{
krb5_error_code code;
+ size_t sumlen;
char *data_ptr;
+ krb5_data plaind;
krb5_checksum md5cksum;
krb5_checksum cksum;
int conflen=0, tmsglen, tlen;
if (bigend && !encrypt) {
tmsglen = text->length;
} else {
- conflen = kg_confounder_size(enc_ed);
+ conflen = kg_confounder_size(context, enc);
/* XXX knows that des block size is 8 */
tmsglen = (conflen+text->length+8)&(~7);
}
/* pad the plaintext, encrypt if needed, and stick it in the token */
- /* initialize the the cksum and allocate the contents buffer */
+ /* initialize the the cksum */
+ if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen))
+ return(code);
+
md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
- md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5);
- if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) {
- return(ENOMEM);
- }
-
+ md5cksum.length = sumlen;
if (toktype == KG_TOK_SEAL_MSG) {
unsigned char *plain;
unsigned char pad;
if (!bigend || encrypt) {
if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
- xfree(md5cksum.contents);
xfree(t);
return(ENOMEM);
}
- if ((code = kg_make_confounder(enc_ed, plain))) {
+ if ((code = kg_make_confounder(context, enc, plain))) {
xfree(plain);
- xfree(md5cksum.contents);
xfree(t);
return(code);
}
}
if (encrypt) {
- if ((code = kg_encrypt(context, enc_ed, NULL, (krb5_pointer) plain,
+ if ((code = kg_encrypt(context, enc, NULL, (krb5_pointer) plain,
(krb5_pointer) (ptr+cksum_size+14),
tmsglen))) {
if (plain)
xfree(plain);
- xfree(md5cksum.contents);
xfree(t);
return(code);
}
(char *) xmalloc(8 + (bigend ? text->length : tmsglen)))) {
if (plain)
xfree(plain);
- xfree(md5cksum.contents);
xfree(t);
return(ENOMEM);
}
(void) memcpy(data_ptr+8, text->value, text->length);
else
(void) memcpy(data_ptr+8, plain, tmsglen);
- code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr,
- 8 + (bigend ? text->length : tmsglen),
- 0, 0, &md5cksum);
+ plaind.length = 8 + (bigend ? text->length : tmsglen);
+ plaind.data = data_ptr;
+ code = krb5_c_make_checksum(context, md5cksum.checksum_type,
+ 0, 0, &plaind, &md5cksum);
xfree(data_ptr);
if (code) {
if (plain)
xfree(plain);
- xfree(md5cksum.contents);
xfree(t);
return(code);
memcpy(ptr+14+cksum_size, plain, tmsglen);
/* compute the checksum */
if (! (data_ptr = (char *) xmalloc(8 + text->length))) {
- xfree(md5cksum.contents);
xfree(t);
return(ENOMEM);
}
(void) memcpy(data_ptr, ptr-2, 8);
(void) memcpy(data_ptr+8, text->value, text->length);
- code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr,
- 8 + text->length,
- 0, 0, &md5cksum);
+ plaind.length = 8 + text->length;
+ plaind.data = data_ptr;
+ code = krb5_c_make_checksum(context, md5cksum.checksum_type, 0, 0,
+ &plaind, &md5cksum);
xfree(data_ptr);
if (code) {
- xfree(md5cksum.contents);
xfree(t);
return(code);
}
DES encryption the long way, and keep the last block
as the MAC */
+ /* XXX not converted to new api since it's inside an #if 0 */
+
/* initialize the the cksum and allocate the contents buffer */
cksum.checksum_type = CKSUMTYPE_DESCBC;
cksum.length = krb5_checksum_size(context, CKSUMTYPE_DESCBC);
if ((cksum.contents = (krb5_octet *) xmalloc(cksum.length)) == NULL)
return(ENOMEM);
+ /* XXX not converted to new api since it's inside an #if 0 */
if (code = krb5_calculate_checksum(context, cksum.checksum_type,
md5cksum.contents, 16,
- seq_ed->key->contents,
- seq_ed->key->length,
+ seq->contents,
+ seq->length,
&cksum)) {
xfree(cksum.contents);
xfree(md5cksum.contents);
xfree(cksum.contents);
#else
- if ((code = kg_encrypt(context, seq_ed,
+ if ((code = kg_encrypt(context, seq,
(g_OID_equal(oid, gss_mech_krb5_old) ?
- seq_ed->key->contents : NULL),
+ seq->contents : NULL),
md5cksum.contents, md5cksum.contents, 16))) {
xfree(md5cksum.contents);
xfree(t);
/* create the seq_num */
- if ((code = kg_make_seq_num(context, seq_ed, direction?0:0xff, *seqnum,
+ if ((code = kg_make_seq_num(context, seq, direction?0:0xff, *seqnum,
ptr+14, ptr+6))) {
xfree(t);
return(code);
return(GSS_S_FAILURE);
}
- if ((code = make_seal_token(context, &ctx->enc, &ctx->seq,
- &ctx->seq_send, ctx->initiate,
- input_message_buffer, output_message_buffer,
- ctx->signalg, ctx->cksum_size, ctx->sealalg,
- conf_req_flag, toktype, ctx->big_endian,
- ctx->mech_used))) {
+ if (ctx->gsskrb5_version == 2000) {
+ if (toktype == KG_TOK_WRAP_MSG) {
+ if (conf_req_flag)
+ toktype = KG2_TOK_WRAP_PRIV;
+ else
+ toktype = KG2_TOK_WRAP_INTEG;
+ } else {
+ toktype = KG2_TOK_MIC;
+ }
+
+ if (conf_req_flag) {
+ code = make_priv_token_v2(context, ctx->subkey, &ctx->seq_send,
+ ctx->initiate, input_message_buffer,
+ output_message_buffer, ctx->mech_used);
+ } else {
+ code = make_integ_token_v2(context, ctx->subkey, ctx->ctypes[0],
+ &ctx->seq_send, ctx->initiate,
+ input_message_buffer,
+ output_message_buffer, toktype,
+ ctx->mech_used);
+ }
+ } else {
+ code = make_seal_token_v1(context, ctx->enc, ctx->seq,
+ &ctx->seq_send, ctx->initiate,
+ input_message_buffer, output_message_buffer,
+ ctx->signalg, ctx->cksum_size, ctx->sealalg,
+ conf_req_flag, toktype, ctx->big_endian,
+ ctx->mech_used);
+ }
+
+ if (code) {
*minor_status = code;
return(GSS_S_FAILURE);
}
- if ((toktype == KG_TOK_SEAL_MSG) && conf_state)
+ if (conf_state)
*conf_state = conf_req_flag;
*minor_status = 0;
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "gssapiP_krb5.h"
#include <memory.h>
* $Id$
*/
+static OM_uint32
+kg2_verify_mic(context, minor_status, ctx, ptr, bodysize,
+ text, qop_state)
+ krb5_context context;
+ OM_uint32 *minor_status;
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
+ gss_buffer_t text;
+ gss_qop_t *qop_state;
+{
+ size_t cksumlen;
+ krb5_error_code code;
+ krb5_data plain;
+ krb5_cksumtype tctype;
+ krb5_ui_4 tseqnum;
+ int tdirection;
+ krb5_checksum cksum;
+ krb5_boolean ckvalid;
+ krb5_timestamp now;
+ OM_uint32 retval;
+
+ plain.data = 0;
+ cksum.contents = 0;
+
+ /* verify the header */
+
+ if (bodysize < 11) {
+ free(plain.data);
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ /* allocate the checksum buffer */
+
+ plain.length = 7+text->length;
+
+ if ((plain.data = (char *) malloc(plain.length)) == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ /* suck out the body parts from the token */
+
+ tctype = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) |
+ (ptr[2]<<8) | ptr[3]);
+ ptr += 4;
+
+ memcpy(plain.data, ptr, 5);
+ tseqnum = ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
+ ptr += 4;
+ tdirection = ptr[0];
+ ptr += 1;
+
+ cksum.length = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ bodysize -= 11;
+
+ if (cksum.length != bodysize) {
+ free(plain.data);
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ cksum.contents = ptr;
+ cksum.checksum_type = tctype;
+
+ /* finish assembling the checksum buffer and compute the checksum */
+
+ plain.data[5] = (text->length >> 8) & 0xff;
+ plain.data[6] = text->length & 0xff;
+
+ memcpy(plain.data+7, text->value, text->length);
+
+ if (code = krb5_c_verify_checksum(context, ctx->subkey,
+ KRB5_KEYUSAGE_GSS_TOK_MIC,
+ &plain, &cksum, &ckvalid)) {
+ free(plain.data);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (!ckvalid) {
+ free(plain.data);
+ *minor_status = 0;
+ return(GSS_S_BAD_SIG);
+ }
+
+ /* check context expiry */
+
+ if ((code = krb5_timeofday(context, &now))) {
+ free(plain.data);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (now > ctx->endtime) {
+ free(plain.data);
+ *minor_status = 0;
+ return(GSS_S_CONTEXT_EXPIRED);
+ }
+
+ /* do sequencing checks */
+
+ if ((ctx->initiate && tdirection != 0xff) ||
+ (!ctx->initiate && tdirection != 0)) {
+ free(plain.data);
+ *minor_status = G_BAD_DIRECTION;
+ return(GSS_S_BAD_SIG);
+ }
+
+ retval = g_order_check(&(ctx->seqstate), tseqnum);
+
+ free(plain.data);
+
+ if (retval) {
+ *minor_status = 0;
+ return(retval);
+ }
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+static OM_uint32
+kg2_unwrap_integ(context, minor_status, ctx, ptr, bodysize, output, qop_state)
+ krb5_context context;
+ OM_uint32 *minor_status;
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
+ gss_buffer_t output;
+ gss_qop_t *qop_state;
+{
+ krb5_error_code code;
+ OM_uint32 retval;
+ krb5_ui_4 tseqnum;
+ int tdirection;
+ int tmsglen;
+ unsigned char *tmsg;
+ krb5_data plain;
+ krb5_checksum tcksum;
+ krb5_boolean ckvalid;
+ krb5_timestamp now;
+
+ output->length = 0;
+ output->value = NULL;
+
+ /* read the body parts out of the message */
+
+ if (bodysize < 11) {
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ tcksum.checksum_type = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) |
+ (ptr[2]<<8) | ptr[3]);
+ ptr += 4;
+
+ plain.data = ptr;
+
+ tseqnum = ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
+ ptr += 4;
+ tdirection = ptr[0];
+ ptr += 1;
+
+ tmsglen = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ bodysize -= 11;
+
+ if (bodysize < tmsglen) {
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ tmsg = ptr;
+ ptr += tmsglen;
+ bodysize -= tmsglen;
+
+ plain.length = ((char*)ptr) - ((char *)plain.data);
+
+ tcksum.length = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ bodysize -= 2;
+
+ if (bodysize != tcksum.length) {
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ tcksum.contents = ptr;
+
+ /* verify the MIC */
+
+ if (code = krb5_c_verify_checksum(context, ctx->subkey,
+ KRB5_KEYUSAGE_GSS_TOK_WRAP_INTEG,
+ &plain, &tcksum, &ckvalid)) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (!ckvalid) {
+ *minor_status = 0;
+ return(GSS_S_BAD_SIG);
+ }
+
+ /* check context expiry */
+
+ if ((code = krb5_timeofday(context, &now))) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (now > ctx->endtime) {
+ *minor_status = 0;
+ return(GSS_S_CONTEXT_EXPIRED);
+ }
+
+ /* do sequencing checks */
+
+ if ((ctx->initiate && tdirection != 0xff) ||
+ (!ctx->initiate && tdirection != 0)) {
+ *minor_status = G_BAD_DIRECTION;
+ return(GSS_S_BAD_SIG);
+ }
+
+ if (retval = g_order_check(&(ctx->seqstate), tseqnum)) {
+ *minor_status = 0;
+ return(retval);
+ }
+
+ if ((output->value = (void *) malloc(tmsglen)) == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ memcpy(output->value, tmsg, tmsglen);
+ output->length = tmsglen;
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+static OM_uint32
+kg2_unwrap_priv(context, minor_status, ctx, ptr, bodysize, output, qop_state)
+ krb5_context context;
+ OM_uint32 *minor_status;
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
+ gss_buffer_t output;
+ gss_qop_t *qop_state;
+{
+ krb5_error_code code;
+ OM_uint32 retval;
+ krb5_enc_data cipher;
+ krb5_data plain;
+ krb5_ui_4 tseqnum;
+ int tdirection;
+ int tmsglen;
+ unsigned char *tmsg;
+ krb5_timestamp now;
+
+ output->length = 0;
+ output->value = NULL;
+
+ /* read the body parts out of the message */
+
+ if (bodysize < 2) {
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ cipher.ciphertext.length = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ bodysize -= 2;
+
+ if (bodysize != cipher.ciphertext.length) {
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ cipher.ciphertext.data = ptr;
+ cipher.enctype = ENCTYPE_UNKNOWN;
+
+ plain.length = cipher.ciphertext.length;
+ if ((plain.data = (char *) malloc(plain.length)) == NULL) {
+ *minor_status = 0;
+ return(GSS_S_FAILURE);
+ }
+
+ /* decrypt (and implicitly verify) the encrypted data */
+
+ if (code = krb5_c_decrypt(context, ctx->subkey,
+ KRB5_KEYUSAGE_GSS_TOK_WRAP_PRIV,
+ 0, &cipher, &plain)) {
+ free(plain.data);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ /* parse out the encrypted fields */
+
+ ptr = plain.data;
+ bodysize = plain.length;
+
+ if (bodysize < 7) {
+ free(plain.data);
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ tseqnum = ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
+ ptr += 4;
+ tdirection = ptr[0];
+ ptr += 1;
+
+ tmsglen = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ bodysize -= 7;
+
+ /* check context expiry */
+
+ if ((code = krb5_timeofday(context, &now))) {
+ free(plain.data);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (now > ctx->endtime) {
+ free(plain.data);
+ *minor_status = 0;
+ return(GSS_S_CONTEXT_EXPIRED);
+ }
+
+ /* do sequencing checks */
+
+ if ((ctx->initiate && tdirection != 0xff) ||
+ (!ctx->initiate && tdirection != 0)) {
+ free(plain.data);
+ *minor_status = G_BAD_DIRECTION;
+ return(GSS_S_BAD_SIG);
+ }
+
+ if (retval = g_order_check(&(ctx->seqstate), tseqnum)) {
+ free(plain.data);
+ *minor_status = 0;
+ return(retval);
+ }
+
+ /* now copy out the data. can't do a strict equality check here,
+ since the output could be padded. */
+
+ if (bodysize < tmsglen) {
+ free(plain.data);
+ *minor_status = G_TOK_TRUNC;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ tmsg = ptr;
+
+ if ((output->value = (void *) malloc(tmsglen)) == NULL) {
+ free(plain.data);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ memcpy(output->value, tmsg, tmsglen);
+ output->length = tmsglen;
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ free(plain.data);
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
- conf_state is only valid if SEAL.
- */
+ conf_state is only valid if SEAL. */
OM_uint32
-kg_unseal(context, minor_status, context_handle, input_token_buffer,
- message_buffer, conf_state, qop_state, toktype)
+kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
+ conf_state, qop_state, toktype)
krb5_context context;
OM_uint32 *minor_status;
- gss_ctx_id_t context_handle;
- gss_buffer_t input_token_buffer;
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
gss_buffer_t message_buffer;
int *conf_state;
int *qop_state;
int toktype;
{
- krb5_gss_ctx_id_rec *ctx;
krb5_error_code code;
- int bodysize;
int tmsglen;
int conflen = 0;
int signalg;
int sealalg;
gss_buffer_desc token;
- unsigned char *ptr;
krb5_checksum cksum;
krb5_checksum desmac;
krb5_checksum md5cksum;
+ krb5_data plaind;
char *data_ptr;
krb5_timestamp now;
unsigned char *plain;
int direction;
krb5_int32 seqnum;
OM_uint32 retval;
+ size_t sumlen;
if (toktype == KG_TOK_SEAL_MSG) {
message_buffer->length = 0;
message_buffer->value = NULL;
}
- /* validate the context handle */
- if (! kg_validate_ctx_id(context_handle)) {
- *minor_status = (OM_uint32) G_VALIDATE_FAILED;
- return(GSS_S_NO_CONTEXT);
- }
-
- ctx = (krb5_gss_ctx_id_rec *) context_handle;
-
- if (! ctx->established) {
- *minor_status = KG_CTX_INCOMPLETE;
- return(GSS_S_NO_CONTEXT);
- }
-
- /* parse the token, leave the data in message_buffer, setting conf_state */
-
- /* verify the header */
-
- ptr = (unsigned char *) input_token_buffer->value;
-
- if ((err = g_verify_token_header((gss_OID) ctx->mech_used, &bodysize,
- &ptr, toktype,
- input_token_buffer->length))) {
- *minor_status = err;
- return(GSS_S_DEFECTIVE_TOKEN);
- }
-
/* get the sign and seal algorithms */
signalg = ptr[0] + (ptr[1]<<8);
return(GSS_S_FAILURE);
}
- if ((code = kg_decrypt(context, &ctx->enc, NULL,
+ if ((code = kg_decrypt(context, ctx->enc, NULL,
ptr+14+cksum_len, plain, tmsglen))) {
xfree(plain);
*minor_status = code;
if ((sealalg == 0xffff) && ctx->big_endian) {
token.length = tmsglen;
} else {
- conflen = kg_confounder_size(&ctx->enc);
+ conflen = kg_confounder_size(context, ctx->enc);
token.length = tmsglen - conflen - plain[tmsglen-1];
}
/* compute the checksum of the message */
- /* initialize the the cksum and allocate the contents buffer */
+ /* initialize the the cksum */
+ if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen))
+ return(code);
+
md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
- md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5);
- if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) {
- if (sealalg != 0xffff)
- xfree(plain);
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
+ md5cksum.length = sumlen;
switch (signalg) {
case 0:
if (! (data_ptr = (void *)
xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
- xfree(md5cksum.contents);
if (sealalg != 0xffff)
xfree(plain);
if (toktype == KG_TOK_SEAL_MSG)
else
(void) memcpy(data_ptr+8, plain, plainlen);
- code = krb5_calculate_checksum(context, md5cksum.checksum_type,
- data_ptr, 8 +
- (ctx->big_endian ? token.length :
- plainlen), 0, 0, &md5cksum);
+ plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
+ plaind.data = data_ptr;
+ code = krb5_c_make_checksum(context, md5cksum.checksum_type, 0, 0,
+ &plaind, &md5cksum);
xfree(data_ptr);
if (code) {
- xfree(md5cksum.contents);
if (toktype == KG_TOK_SEAL_MSG)
xfree(token.value);
*minor_status = code;
return(GSS_S_FAILURE);
}
+ /* XXX not converted to new api since it's inside an #if 0 */
if (code = krb5_calculate_checksum(context, cksum.checksum_type,
md5cksum.contents, 16,
ctx->seq.key->contents,
xfree(cksum.contents);
#else
- if ((code = kg_encrypt(context, &ctx->seq,
+ if ((code = kg_encrypt(context, ctx->seq,
(g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
- ctx->seq.key->contents : NULL),
+ ctx->seq->contents : NULL),
md5cksum.contents, md5cksum.contents, 16))) {
xfree(md5cksum.contents);
if (toktype == KG_TOK_SEAL_MSG)
else
(void) memcpy(data_ptr+8+sizeof(ctx->seed),
plain, plainlen);
- code = krb5_calculate_checksum(context, md5cksum.checksum_type,
- data_ptr, 8 + sizeof(ctx->seed) +
- (ctx->big_endian ? token.length :
- plainlen), 0, 0, &md5cksum);
-
+ plaind.length = 8 + sizeof(ctx->seed) +
+ (ctx->big_endian ? token.length : plainlen);
+ plaind.data = data_ptr;
+ xfree(md5cksum.contents);
+ code = krb5_c_make_checksum(context, md5cksum.checksum_type, 0, 0,
+ &plaind, &md5cksum);
xfree(data_ptr);
if (code) {
- xfree(md5cksum.contents);
if (sealalg == 0)
xfree(plain);
if (toktype == KG_TOK_SEAL_MSG)
/* do sequencing checks */
- if ((code = kg_get_seq_num(context, &(ctx->seq), ptr+14, ptr+6, &direction,
+ if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
&seqnum))) {
if (toktype == KG_TOK_SEAL_MSG)
xfree(token.value);
*minor_status = 0;
return(retval);
}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+OM_uint32
+kg_unseal(context, minor_status, context_handle, input_token_buffer,
+ message_buffer, conf_state, qop_state, toktype)
+ krb5_context context;
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t input_token_buffer;
+ gss_buffer_t message_buffer;
+ int *conf_state;
+ int *qop_state;
+ int toktype;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
+ int err;
+ OM_uint32 retval;
+
+ /* validate the context handle */
+ if (! kg_validate_ctx_id(context_handle)) {
+ *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (! ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ /* parse the token, leave the data in message_buffer, setting conf_state */
+
+ /* verify the header */
+
+ ptr = (unsigned char *) input_token_buffer->value;
+
+ if (ctx->gsskrb5_version == 2000) {
+ if (!(err = g_verify_token_header((gss_OID) ctx->mech_used,
+ &bodysize, &ptr, KG2_TOK_MIC,
+ input_token_buffer->length))) {
+ return(kg2_verify_mic(context, minor_status, ctx, ptr, bodysize,
+ message_buffer, qop_state));
+ } else if (!(err = g_verify_token_header((gss_OID) ctx->mech_used,
+ &bodysize, &ptr,
+ KG2_TOK_WRAP_INTEG,
+ input_token_buffer->length))) {
+ if (GSS_ERROR(retval = kg2_unwrap_integ(context, minor_status,
+ ctx, ptr, bodysize,
+ message_buffer, qop_state)))
+ return(retval);
+
+ if (conf_state)
+ *conf_state = 0;
+ return(GSS_S_COMPLETE);
+ } else if (!(err = g_verify_token_header((gss_OID) ctx->mech_used,
+ &bodysize, &ptr,
+ KG2_TOK_WRAP_PRIV,
+ input_token_buffer->length))) {
+ if (GSS_ERROR(retval = kg2_unwrap_priv(context, minor_status,
+ ctx, ptr, bodysize,
+ message_buffer, qop_state)))
+ return(retval);
+
+ if (conf_state)
+ *conf_state = 1;
+ return(GSS_S_COMPLETE);
+ }
+ } else {
+ if (!(err = g_verify_token_header((gss_OID) ctx->mech_used,
+ &bodysize, &ptr, toktype,
+ input_token_buffer->length))) {
+ return(kg_unseal_v1(context, minor_status, ctx, ptr, bodysize,
+ message_buffer, conf_state, qop_state,
+ toktype));
+ }
+ }
+
+ *minor_status = err;
+ return(GSS_S_DEFECTIVE_TOKEN);
+}
* return GSS_S_CONTINUE_NEEDED for any OIDs it does not recognize.
*/
- if ((*oid != gss_mech_krb5) &&
+ if ((*oid != gss_mech_krb5_v2) &&
+ (*oid != gss_mech_krb5) &&
(*oid != gss_mech_krb5_old) &&
(*oid != gss_nt_krb5_name) &&
(*oid != gss_nt_krb5_principal)) {
* still be done. --marc
*/
-/*
- * Determine the size required for this krb5_gss_enc_desc.
- */
-static krb5_error_code
-kg_enc_desc_size(kcontext, arg, sizep)
- krb5_context kcontext;
- krb5_pointer arg;
- size_t *sizep;
-{
- krb5_error_code kret;
- krb5_gss_enc_desc *edescp;
- size_t required;
-
- /*
- * krb5_gss_cred_id_t requires:
- * krb5_int32 for KG_ENC_DESC
- * krb5_int32 for processed.
- * krb5_int32 for trailer.
- */
- kret = EINVAL;
- if ((edescp = (krb5_gss_enc_desc *) arg)) {
- required = 3*sizeof(krb5_int32);
- if (edescp->key)
- kret = krb5_size_opaque(kcontext,
- KV5M_KEYBLOCK,
- (krb5_pointer) edescp->key,
- &required);
- else
- kret = 0;
-
- /*
- * We need to use size_opaque here because we're not sure as to the
- * ancestry of this eblock, and we can't be sure that the magic number
- * is set in it, so we ASSuME that it's ok.
- */
- if (!kret)
- kret = krb5_size_opaque(kcontext,
- KV5M_ENCRYPT_BLOCK,
- (krb5_pointer) &edescp->eblock,
- &required);
-
- if (!kret)
- *sizep += required;
- }
- return(kret);
-}
-
-/*
- * Externalize this krb5_gss_enc_desc.
- */
-static krb5_error_code
-kg_enc_desc_externalize(kcontext, arg, buffer, lenremain)
- krb5_context kcontext;
- krb5_pointer arg;
- krb5_octet **buffer;
- size_t *lenremain;
-{
- krb5_error_code kret;
- krb5_gss_enc_desc *enc_desc;
- size_t required;
- krb5_octet *bp;
- size_t remain;
-
- required = 0;
- bp = *buffer;
- remain = *lenremain;
- kret = EINVAL;
- if ((enc_desc = (krb5_gss_enc_desc *) arg)) {
- kret = ENOMEM;
- if (!kg_enc_desc_size(kcontext, arg, &required) &&
- (required <= remain)) {
- /* Our identifier */
- (void) krb5_ser_pack_int32(KG_ENC_DESC, &bp, &remain);
-
- /* Now static data */
- (void) krb5_ser_pack_int32((krb5_int32) enc_desc->processed,
- &bp, &remain);
-
- /* Now pack up dynamic data */
- if (enc_desc->key)
- kret = krb5_externalize_opaque(kcontext,
- KV5M_KEYBLOCK,
- (krb5_pointer) enc_desc->key,
- &bp, &remain);
- else
- kret = 0;
-
- if (!kret)
- kret = krb5_externalize_opaque(kcontext,
- KV5M_ENCRYPT_BLOCK,
- (krb5_pointer)&enc_desc->eblock,
- &bp, &remain);
- if (!kret) {
- (void) krb5_ser_pack_int32(KG_ENC_DESC, &bp, &remain);
- *buffer = bp;
- *lenremain = remain;
- }
- }
- }
- return(kret);
-}
-
-/*
- * Internalize this krb5_gss_enc_desc.
- */
-static krb5_error_code
-kg_enc_desc_internalize(kcontext, argp, buffer, lenremain)
- krb5_context kcontext;
- krb5_pointer *argp;
- krb5_octet **buffer;
- size_t *lenremain;
-{
- krb5_error_code kret;
- krb5_gss_enc_desc *edescp;
- krb5_int32 ibuf;
- krb5_octet *bp;
- krb5_encrypt_block *eblockp;
- size_t remain;
-
- bp = *buffer;
- remain = *lenremain;
- kret = EINVAL;
- /* Read our magic number */
- if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
- ibuf = 0;
- if (ibuf == KG_ENC_DESC) {
- kret = ENOMEM;
-
- /* Get an enc_desc */
- if ((remain >= (2*sizeof(krb5_int32))) &&
- (edescp = (krb5_gss_enc_desc *)
- xmalloc(sizeof(krb5_gss_enc_desc)))) {
- memset(edescp, 0, sizeof(krb5_gss_enc_desc));
-
- /* Get the static data */
- (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
- edescp->processed = (int) ibuf;
-
- /* edescp->key */
- if ((kret = krb5_internalize_opaque(kcontext,
- KV5M_KEYBLOCK,
- (krb5_pointer *) &edescp->key,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
-
- /* edescp->eblock */
- if (!kret &&
- (kret = krb5_internalize_opaque(kcontext,
- KV5M_ENCRYPT_BLOCK,
- (krb5_pointer *) &eblockp,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
- else {
- /* Successful, copy in allocated eblock to our structure */
- memcpy(&edescp->eblock, eblockp, sizeof(edescp->eblock));
- krb5_xfree(eblockp);
- }
-
- /* trailer */
- if (!kret &&
- !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) &&
- (ibuf == KG_ENC_DESC)) {
- *buffer = bp;
- *lenremain = remain;
- *argp = (krb5_pointer) edescp;
- }
- else {
- if (!kret && (ibuf != KG_ENC_DESC))
- kret = EINVAL;
- if (edescp->eblock.key)
- krb5_free_keyblock(kcontext, edescp->eblock.key);
- if (edescp->eblock.priv && edescp->eblock.priv_size)
- krb5_xfree(edescp->eblock.priv);
- if (edescp->key)
- krb5_free_keyblock(kcontext, edescp->key);
- xfree(edescp);
- }
- }
- }
- return(kret);
-}
-
static krb5_error_code
kg_oid_externalize(kcontext, arg, buffer, lenremain)
krb5_context kcontext;
* krb5_int32 for seq_recv.
* krb5_int32 for established.
* krb5_int32 for big_endian.
+ * krb5_int32 for gsskrb5_version.
+ * krb5_int32 for nctypes.
* krb5_int32 for trailer.
*/
kret = EINVAL;
if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
- required = 14*sizeof(krb5_int32);
+ required = 16*sizeof(krb5_int32);
required += sizeof(ctx->seed);
+ required += ctx->nctypes*sizeof(krb5_int32);
kret = 0;
if (!kret && ctx->here)
(krb5_pointer) ctx->subkey,
&required);
- if (!kret)
- kret = kg_enc_desc_size(kcontext,
- (krb5_pointer) &ctx->enc,
+ if (!kret && ctx->enc)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) ctx->enc,
&required);
- if (!kret)
- kret = kg_enc_desc_size(kcontext,
- (krb5_pointer) &ctx->seq,
+ if (!kret && ctx->seq)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) ctx->seq,
&required);
if (!kret)
size_t required;
krb5_octet *bp;
size_t remain;
+ int i;
required = 0;
bp = *buffer;
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->big_endian,
&bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->gsskrb5_version,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->nctypes,
+ &bp, &remain);
/* Now dynamic data */
kret = 0;
(krb5_pointer) ctx->subkey,
&bp, &remain);
- if (!kret)
- kret = kg_enc_desc_externalize(kcontext,
- (krb5_pointer) &ctx->enc,
+ if (!kret && ctx->enc)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) ctx->enc,
&bp, &remain);
- if (!kret)
- kret = kg_enc_desc_externalize(kcontext,
- (krb5_pointer) &ctx->seq,
+ if (!kret && ctx->seq)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) ctx->seq,
&bp, &remain);
if (!kret && ctx->seqstate)
KV5M_AUTH_CONTEXT,
(krb5_pointer) ctx->auth_context,
&bp, &remain);
+
+ for (i=0; i<ctx->nctypes; i++) {
+ if (!kret) {
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->ctypes[i],
+ &bp, &remain);
+ }
+ }
if (!kret) {
(void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
- krb5_gss_enc_desc *edp;
+ int i;
bp = *buffer;
remain = *lenremain;
ctx->established = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->big_endian = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->gsskrb5_version = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->nctypes = (int) ibuf;
if ((kret = kg_oid_internalize(kcontext, &ctx->mech_used, &bp,
&remain))) {
if (kret == EINVAL)
kret = 0;
}
- if (!kret) {
- if ((kret = kg_enc_desc_internalize(kcontext,
- (krb5_pointer *) &edp,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
- else {
- memcpy(&ctx->enc, edp, sizeof(ctx->enc));
- xfree(edp);
- }
+ if (!kret &&
+ (kret = krb5_internalize_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer *) &ctx->enc,
+ &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
}
- if (!kret) {
- if ((kret = kg_enc_desc_internalize(kcontext,
- (krb5_pointer *) &edp,
- &bp, &remain))) {
- if (kret == EINVAL)
- kret = 0;
- }
- else {
- memcpy(&ctx->seq, edp, sizeof(ctx->seq));
- xfree(edp);
- }
+ if (!kret &&
+ (kret = krb5_internalize_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer *) &ctx->seq,
+ &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
}
if (!kret) {
(krb5_pointer *) &ctx->auth_context,
&bp, &remain);
+ if (!kret) {
+ if (ctx->nctypes) {
+ if ((ctx->ctypes = (krb5_cksumtype *)
+ malloc(ctx->nctypes*sizeof(krb5_cksumtype))) == NULL){
+ kret = ENOMEM;
+ }
+
+ for (i=0; i<ctx->nctypes; i++) {
+ if (!kret) {
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->ctypes[i] = (krb5_cksumtype) ibuf;
+ }
+ }
+ }
+ }
+
/* Get trailer */
if (!kret &&
!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) &&
else {
if (!kret && (ibuf != KG_CONTEXT))
kret = EINVAL;
- if (ctx->seq.eblock.key)
- krb5_free_keyblock(kcontext, ctx->seq.eblock.key);
- if (ctx->seq.eblock.priv && ctx->seq.eblock.priv_size)
- krb5_xfree(ctx->seq.eblock.priv);
- if (ctx->seq.key)
- krb5_free_keyblock(kcontext, ctx->seq.key);
- if (ctx->enc.eblock.key)
- krb5_free_keyblock(kcontext, ctx->enc.eblock.key);
- if (ctx->enc.eblock.priv && ctx->enc.eblock.priv_size)
- krb5_xfree(ctx->enc.eblock.priv);
- if (ctx->enc.key)
- krb5_free_keyblock(kcontext, ctx->enc.key);
+ if (ctx->seq)
+ krb5_free_keyblock(kcontext, ctx->seq);
+ if (ctx->enc)
+ krb5_free_keyblock(kcontext, ctx->enc);
if (ctx->subkey)
krb5_free_keyblock(kcontext, ctx->subkey);
if (ctx->there)
{
int len;
char *buf, *ptr;
+ size_t sumlen;
+ krb5_data plaind;
krb5_error_code code;
- /* initialize the the cksum and allocate the contents buffer */
+ /* initialize the the cksum */
+ if (code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen))
+ return(code);
+
cksum->checksum_type = CKSUMTYPE_RSA_MD5;
- cksum->length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5);
- if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
- return(ENOMEM);
- }
+ cksum->length = sumlen;
/* generate a buffer full of zeros if no cb specified */
if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
- memset(cksum->contents, '\0', cksum->length);
- return(0);
+ if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
+ return(ENOMEM);
+ }
+ memset(cksum->contents, '\0', cksum->length);
+ return(0);
}
/* create the buffer to checksum into */
/* checksum the data */
- if (code = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5,
- buf, len, NULL, 0, cksum)) {
- xfree(cksum->contents);
+ plaind.length = len;
+ plaind.data = buf;
+
+ if (code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
+ &plaind, cksum)) {
xfree(buf);
return(code);
}
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "gssapiP_krb5.h"
#include <memory.h>
static unsigned char zeros[8] = {0,0,0,0,0,0,0,0};
int
-kg_confounder_size(ed)
- krb5_gss_enc_desc *ed;
+kg_confounder_size(context, key)
+ krb5_context context;
+ krb5_keyblock *key;
{
- /* XXX Abstraction violation!!! */
+ krb5_error_code code;
+ size_t blocksize;
+
+ if (code = krb5_c_block_size(context, key->enctype, &blocksize))
+ return(-1); /* XXX */
- return(ed->eblock.crypto_entry->block_length);
+ return(blocksize);
}
krb5_error_code
-kg_make_confounder(ed, buf)
- krb5_gss_enc_desc *ed;
+kg_make_confounder(context, key, buf)
+ krb5_context context;
+ krb5_keyblock *key;
unsigned char *buf;
{
- /* XXX Abstraction violation!!! */
+ krb5_error_code code;
+ size_t blocksize;
+ krb5_data random;
+
+ if (code = krb5_c_block_size(context, key->enctype, &blocksize))
+ return(code);
- return(krb5_random_confounder(ed->eblock.crypto_entry->block_length, buf));
+ random.length = blocksize;
+ random.data = buf;
+
+ return(krb5_c_random_make_octets(context, &random));
}
int
-kg_encrypt_size(ed, n)
- krb5_gss_enc_desc *ed;
+kg_encrypt_size(context, key, n)
+ krb5_context context;
+ krb5_keyblock *key;
int n;
{
- return(krb5_encrypt_size(n, ed->eblock.crypto_entry));
+ krb5_error_code code;
+ size_t enclen;
+
+ if (code = krb5_c_encrypt_length(context, key->enctype, n, &enclen))
+ return(-1); /* XXX */
+
+ return(enclen);
}
krb5_error_code
-kg_encrypt(context, ed, iv, in, out, length)
+kg_encrypt(context, key, iv, in, out, length)
krb5_context context;
- krb5_gss_enc_desc *ed;
+ krb5_keyblock *key;
krb5_pointer iv;
krb5_pointer in;
krb5_pointer out;
int length;
{
krb5_error_code code;
- krb5_pointer tmp;
-
- if (! ed->processed) {
- if (code = krb5_process_key(context, &ed->eblock, ed->key))
- return(code);
- ed->processed = 1;
+ size_t blocksize;
+ krb5_data ivd, *pivd, inputd;
+ krb5_enc_data outputd;
+
+ if (iv) {
+ if (code = krb5_c_block_size(context, key->enctype, &blocksize))
+ return(code);
+
+ ivd.length = blocksize;
+ ivd.data = iv;
+ pivd = &ivd;
+ } else {
+ pivd = NULL;
}
- /* this is lame. the krb5 encryption interfaces no longer allow
- you to encrypt in place. perhaps this should be fixed, but
- dealing here is easier for now --marc */
-
- if ((tmp = (krb5_pointer) xmalloc(length)) == NULL)
- return(ENOMEM);
+ inputd.length = length;
+ inputd.data = in;
- memcpy(tmp, in, length);
+ outputd.ciphertext.length = length;
+ outputd.ciphertext.data = out;
- code = krb5_encrypt(context, tmp, out, length, &ed->eblock,
- iv?iv:(krb5_pointer)zeros);
-
- xfree(tmp);
-
- if (code)
- return(code);
-
- return(0);
+ return(krb5_c_encrypt(context, key,
+ /* XXX this routine is only used for the old
+ bare-des stuff which doesn't use the
+ key usage */ 0, pivd, &inputd, &outputd));
}
/* length is the length of the cleartext. */
krb5_error_code
-kg_decrypt(context, ed, iv, in, out, length)
+kg_decrypt(context, key, iv, in, out, length)
krb5_context context;
- krb5_gss_enc_desc *ed;
+ krb5_keyblock *key;
krb5_pointer iv;
krb5_pointer in;
krb5_pointer out;
int length;
{
krb5_error_code code;
- int elen;
- char *buf;
-
- if (! ed->processed) {
- if (code = krb5_process_key(context, &ed->eblock, ed->key))
- return(code);
- ed->processed = 1;
+ size_t blocksize, enclen;
+ krb5_data ivd, *pivd, outputd;
+ krb5_enc_data inputd;
+
+ if (iv) {
+ if (code = krb5_c_block_size(context, key->enctype, &blocksize))
+ return(code);
+
+ ivd.length = blocksize;
+ ivd.data = iv;
+ pivd = &ivd;
+ } else {
+ pivd = NULL;
}
- elen = krb5_encrypt_size(length, ed->eblock.crypto_entry);
- if ((buf = (char *) xmalloc(elen)) == NULL)
- return(ENOMEM);
-
- if (code = krb5_decrypt(context, in, buf, elen, &ed->eblock,
- iv?iv:(krb5_pointer)zeros)) {
- xfree(buf);
- return(code);
- }
+ inputd.enctype = ENCTYPE_UNKNOWN;
+ inputd.ciphertext.length = length;
+ inputd.ciphertext.data = in;
- memcpy(out, buf, length);
- xfree(buf);
+ outputd.length = length;
+ outputd.data = out;
- return(0);
+ return(krb5_c_decrypt(context, key,
+ /* XXX this routine is only used for the old
+ bare-des stuff which doesn't use the
+ key usage */ 0, pivd, &inputd, &outputd));
}
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* from the token, flags is stored directly. nctypes/ctypes is
+ allocated and returns the length and list of ctypes in the token.
+ noptions/options lists all the options which the caller cares
+ about. Those which are present in the token are filled in; the
+ order and length are not changed. If an error is returned, the
+ option list is in an indeterminate state. */
+
+OM_uint32
+kg2_parse_token(minor_status, ptr, token_length, flags, nctypes, ctypes,
+ noptions, options, kmsg, mic)
+ OM_uint32 *minor_status;
+ unsigned char *ptr;
+ int token_length;
+ krb5_ui_4 *flags;
+ int *nctypes; /* OUT */
+ krb5_cksumtype **ctypes; /* OUT */
+ int noptions;
+ struct kg2_option *options; /* INOUT */
+ krb5_data *kmsg;
+ krb5_data *mic;
+{
+ int field_length, i;
+ int opt_id;
+
+ *ctypes = 0;
+
+ /* read the flags */
+
+ if (token_length < 4)
+ goto defective;
+ *flags = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3];
+ ptr += 4;
+ token_length -= 4;
+
+ /* read out the token list */
+
+ if (token_length < 2)
+ goto defective;
+ field_length = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ token_length -= 2;
+
+ *nctypes = field_length;
+
+ if (*nctypes == 0) {
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ if ((*ctypes = (krb5_cksumtype *)
+ malloc((*nctypes) * sizeof(krb5_cksumtype))) == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ for (i=0; i<field_length; i++) {
+ if (token_length < 4)
+ goto defective;
+
+ (*ctypes)[i] = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) |
+ (ptr[2]<<8) | ptr[3]);
+ ptr += 4;
+ token_length -= 4;
+ }
+
+ do {
+ if (token_length < 4)
+ goto defective;
+ opt_id = (ptr[0]<<8) | ptr[1];
+ field_length = (ptr[2]<<8) | ptr[3];
+ ptr += 4;
+ token_length -= 4;
+
+ if (token_length < field_length)
+ goto defective;
+
+ for (i=0; i<noptions; i++) {
+ if (options[i].option_id = opt_id) {
+ options[i].length = field_length;
+ options[i].data = ptr;
+ }
+ break;
+ }
+
+ ptr += field_length;
+ token_length -= field_length;
+ } while (opt_id);
+
+ if (token_length < 2)
+ goto defective;
+ field_length = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ token_length -= 2;
+
+ if (token_length < field_length)
+ goto defective;
+
+ kmsg->length = field_length;
+ kmsg->data = ptr;
+
+ ptr += field_length;
+ token_length -= field_length;
+
+ /* if there's anything left, assume it's a mic. the mic isn't
+ necessarily present */
+
+ if (mic && token_length) {
+ if (token_length < 2)
+ goto defective;
+ field_length = (ptr[0]<<8) | ptr[1];
+ ptr += 2;
+ token_length -= 2;
+
+ if (token_length < field_length)
+ goto defective;
+
+ mic->length = field_length;
+ mic->data = ptr;
+
+ ptr += field_length;
+ token_length -= field_length;
+ } else if (mic) {
+ mic->length = 0;
+ mic->data = ptr;
+ }
+
+ if (token_length)
+ goto defective;
+
+ return(GSS_S_COMPLETE);
+
+defective:
+ if (*ctypes)
+ free(*ctypes);
+
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+}
+
+/* nc1/c1 will be modified to contain the intersection of the
+ two lists. */
+
+void
+kg2_intersect_ctypes(nc1, c1, nc2, c2)
+ int *nc1;
+ krb5_cksumtype *c1;
+ int nc2;
+ const krb5_cksumtype *c2;
+{
+ int i, j, count;
+ krb5_cksumtype tmp;
+
+ count = 0;
+
+ for (i=0; i<*nc1; i++) {
+ /* first, check to make sure that c1[i] isn't a duplicate in c1 */
+ for (j=0; j<i; j++)
+ if (c1[i] == c1[j])
+ break;
+ if (j<i)
+ continue;
+ /* check if c1[i] is in c2. If it is, keep it by swapping
+ it into c1[count] and incrementing count. If count < i, then
+ that field has already been looked at and skipped as
+ not intersecting, which is ok. */
+
+ for (j=0; j<nc2; j++)
+ if (c1[i] == c2[j])
+ break;
+ if ((j<nc2) && (count != i)) {
+ tmp = c1[count];
+ c1[count] = c1[i];
+ c1[i] = tmp;
+ }
+ count++;
+ }
+
+ *nc1 = count;
+}
+
unsigned char *seed;
{
krb5_error_code code;
- krb5_gss_enc_desc ed;
+ krb5_keyblock *tmpkey;
int i;
- if (code = krb5_copy_keyblock(context, key, &ed.key))
+ if (code = krb5_copy_keyblock(context, key, &tmpkey))
return(code);
/* reverse the key bytes, as per spec */
- for (i=0; i<ed.key->length; i++)
- ed.key->contents[i] = key->contents[key->length - 1 - i];
+ for (i=0; i<tmpkey->length; i++)
+ tmpkey->contents[i] = key->contents[key->length - 1 - i];
- krb5_use_enctype(context, &ed.eblock, ENCTYPE_DES_CBC_RAW);
- ed.processed = 0;
+ code = kg_encrypt(context, tmpkey, NULL, zeros, seed, 16);
- code = kg_encrypt(context, &ed, NULL, zeros, seed, 16);
-
- krb5_finish_key(context, &ed.eblock);
- krb5_free_keyblock(context, ed.key);
+ krb5_free_keyblock(context, tmpkey);
return(code);
}
*/
krb5_error_code
-kg_make_seq_num(context, ed, direction, seqnum, cksum, buf)
+kg_make_seq_num(context, key, direction, seqnum, cksum, buf)
krb5_context context;
- krb5_gss_enc_desc *ed;
+ krb5_keyblock *key;
int direction;
krb5_int32 seqnum;
unsigned char *cksum;
plain[6] = direction;
plain[7] = direction;
- return(kg_encrypt(context, ed, cksum, plain, buf, 8));
+ return(kg_encrypt(context, key, cksum, plain, buf, 8));
}
-krb5_error_code kg_get_seq_num(context, ed, cksum, buf, direction, seqnum)
+krb5_error_code kg_get_seq_num(context, key, cksum, buf, direction, seqnum)
krb5_context context;
- krb5_gss_enc_desc *ed;
+ krb5_keyblock *key;
unsigned char *cksum;
unsigned char *buf;
int *direction;
krb5_error_code code;
unsigned char plain[8];
- if (code = kg_decrypt(context, ed, cksum, buf, plain, 8))
+ if (code = kg_decrypt(context, key, cksum, buf, plain, 8))
return(code);
if ((plain[4] != plain[5]) ||
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "gssapiP_krb5.h"
/*
{
krb5_context context;
krb5_gss_ctx_id_rec *ctx;
- OM_uint32 cfsize;
- OM_uint32 ohlen;
+ krb5_error_code code;
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
return(GSS_S_NO_CONTEXT);
}
- /* Calculate the token size and subtract that from the output size */
- cfsize = (conf_req_flag) ? kg_confounder_size(&ctx->enc) : 0;
- ohlen = g_token_size((gss_OID) ctx->mech_used,
- (unsigned int) cfsize + ctx->cksum_size + 14);
+ if (ctx->gsskrb5_version == 2000) {
+ if (conf_req_flag) {
+ /* this is pretty gross. take the max output, and call
+ krb5_c_encrypt_length to see how much overhead is added
+ on. subtract that much, and see if it fits in the
+ requested space. If not, start subtracting 1 until it
+ does. This doesn't necessarily give us the optimal
+ packing, but I think that's ok (I could start adding 1
+ until I went over, but that seems like it's not worth
+ the effort). This is probably O(blocksize), but that's
+ never going to be large. */
+
+ OM_uint32 headerlen, plainlen;
+ size_t enclen;
+
+ headerlen = g_token_size((gss_OID) ctx->mech_used, 2);
+ plainlen = req_output_size - headerlen;
+
+ if (code = krb5_c_encrypt_length(context, ctx->enc->enctype,
+ plainlen, &enclen)) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ plainlen -= plainlen - (enclen - plainlen);
+
+ if (code = krb5_c_encrypt_length(context, ctx->enc->enctype,
+ plainlen, &enclen)) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
- if (ohlen < req_output_size)
+ while (headerlen + enclen > req_output_size) {
+ plainlen--;
+
+ if (code = krb5_c_encrypt_length(context, ctx->enc->enctype,
+ plainlen, &enclen)) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ }
+
+ /* subtract off the fixed size inside the encrypted part */
+
+ plainlen -= 7;
+
+ *max_input_size = plainlen;
+ } else {
+ size_t cksumlen;
+ OM_uint32 headerlen;
+
+ if (code = krb5_c_checksum_length(context, ctx->ctypes[0],
+ &cksumlen)) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ headerlen = g_token_size((gss_OID) ctx->mech_used, 13 + cksumlen);
+
+ *max_input_size = req_output_size - headerlen;
+ }
+ } else {
+ OM_uint32 cfsize;
+ OM_uint32 ohlen;
+
+ /* Calculate the token size and subtract that from the output size */
+ cfsize = (conf_req_flag) ? kg_confounder_size(context, ctx->enc) : 0;
+ ohlen = g_token_size((gss_OID) ctx->mech_used,
+ (unsigned int) cfsize + ctx->cksum_size + 14);
+
+ if (ohlen < req_output_size)
/*
* Cannot have trailer length that will cause us to pad over
* our length
*/
*max_input_size = (req_output_size - ohlen - 1) & (~7);
- else
+ else
*max_input_size = 0;
+ }
+
*minor_status = 0;
return(GSS_S_COMPLETE);
}
+Thu Aug 13 17:21:06 1998 Tom Yu <tlyu@mit.edu>
+
+ * alt_prof.c (krb5_read_realm_params): Fix to check
+ "supported_enctypes" if "kdc_supported_enctypes" isn't there.
+
+Wed Aug 12 20:19:08 1998 Tom Yu <tlyu@mit.edu>
+
+ * alt_prof.c (krb5_read_realm_params): Use
+ "kdc_supported_enctypes" instead of "supported_enctypes" so that
+ the KDC and the kadmind will use different enctype lists.
+
Wed Jul 8 04:48:50 1998 Geoffrey J. King <gjking@mit.edu>
* logger.c: Add the function krb5_klog_reopen() which closes
}
/* Get the value for the supported enctype/salttype matrix */
- hierarchy[2] = "supported_enctypes";
- if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+ /* XXX This is so that the kdc will search a different
+ enctype list than kadmind */
+ hierarchy[2] = "kdc_supported_enctypes";
+ kret = krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue);
+ if (kret) {
+ hierarchy[2] = "supported_enctypes";
+ kret = krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue);
+ }
+ if (!kret) {
krb5_string_to_keysalts(svalue,
", \t", /* Tuple separators */
":.-", /* Key/salt separators */
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * client_init.c (_kadm5_init_any): try the krb5 v2 mechanism
+ first, and if that fails, try the krb5 v1 mech.
+
+Sun Jul 26 18:11:56 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (LIBMAJOR): bump libmajor
+
Wed Apr 15 18:05:57 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in (SHLIB_EXPDEPS):
CFLAGS = $(CCOPTS) $(DEFS) -I$(BUILDTOP)/include/kadm5
LIB=kadm5clnt
-LIBMAJOR=2
+LIBMAJOR=3
LIBMINOR=0
STOBJLISTS=../OBJS.ST OBJS.ST
SHLIB_EXPDEPS=\
* $Header$
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header$";
#endif
&minor_stat,
gss_client_creds,
gss_target,
- GSS_C_NULL_OID,
+ gss_mech_krb5_v2,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+
+ if (!handle->clnt->cl_auth)
+ handle->clnt->cl_auth = auth_gssapi_create(handle->clnt,
+ &gssstat,
+ &minor_stat,
+ gss_client_creds,
+ gss_target,
+ gss_mech_krb5,
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
0,
NULL,
NULL,
NULL);
+
(void) gss_release_name(&minor_stat, &gss_target);
#endif /* ! INIT_TEST */
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * server_kdb.c, svr_principal.c: convert to new crypto api
+
+Sun Jul 26 18:09:55 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (LIBMAJOR): bump libmajor
+
Wed Apr 15 18:06:14 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in (SHLIB_EXPDEPS):
##DOSLIBNAME = libkadm5srv.lib
LIB=kadm5srv
-LIBMAJOR=2
+LIBMAJOR=3
LIBMINOR=0
STOBJLISTS=../OBJS.ST OBJS.ST
SHLIB_EXPDEPS=\
#include "server_internal.h"
krb5_principal master_princ;
-krb5_encrypt_block master_encblock;
krb5_keyblock master_keyblock;
krb5_db_entry master_db;
krb5_principal hist_princ;
-krb5_encrypt_block hist_encblock;
krb5_keyblock hist_key;
krb5_db_entry hist_db;
krb5_kvno hist_kvno;
master_keyblock.enctype = handle->params.enctype;
- krb5_use_enctype(handle->context, &master_encblock,
- master_keyblock.enctype);
-
if (ret = krb5_db_fetch_mkey(handle->context, master_princ,
- &master_encblock, from_keyboard,
+ master_keyblock.enctype, from_keyboard,
FALSE /* only prompt once */,
handle->params.stash_file,
NULL /* I'm not sure about this,
goto done;
if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
- &master_keyblock,
- &master_encblock))) {
+ &master_keyblock))) {
krb5_db_fini(handle->context);
return ret;
}
- /* the kdc gets the db mkvno here. The admin server never uses this
- bit of information, so there's no reason to retrieve it. */
-
- if ((ret = krb5_process_key(handle->context, &master_encblock,
- &master_keyblock))) {
- krb5_db_fini(handle->context);
- goto done;
- }
-
done:
if (r == NULL)
free(realm);
&key_data))
goto done;
- if (ret = krb5_dbekd_decrypt_key_data(handle->context, &master_encblock,
+ if (ret = krb5_dbekd_decrypt_key_data(handle->context, &master_keyblock,
key_data, &hist_key, NULL))
goto done;
- krb5_use_enctype(handle->context, &hist_encblock, hist_key.enctype);
-
- if ((ret = krb5_process_key(handle->context, &hist_encblock,
- &hist_key)) != KSUCCESS)
- goto done;
-
hist_kvno = key_data->key_data_kvno;
done:
extern krb5_principal master_princ;
extern krb5_principal hist_princ;
-extern krb5_encrypt_block master_encblock;
-extern krb5_encrypt_block hist_encblock;
extern krb5_keyblock master_keyblock;
extern krb5_keyblock hist_key;
extern krb5_db_entry master_db;
/* initialize the keys */
- if (ret = krb5_dbe_cpw(handle->context, &master_encblock,
+ if (ret = krb5_dbe_cpw(handle->context, &master_keyblock,
handle->params.keysalts,
handle->params.num_keysalts,
password,
* Arguments:
*
* context (r) the krb5 context
- * histkey_encblock (r) the encblock that hist_key_data is
+ * hist_keyblock (r) the key that hist_key_data is
* encrypted in
* n_new_key_data (r) length of new_key_data
* new_key_data (r) keys to check against
- * pw_hist_data, encrypted in histkey_encblock
+ * pw_hist_data, encrypted in hist_keyblock
* n_pw_hist_data (r) length of pw_hist_data
* pw_hist_data (r) passwords to check new_key_data against
*
* Effects:
* For each new_key in new_key_data:
- * decrypt new_key with the master_encblock
+ * decrypt new_key with the master_keyblock
* for each password in pw_hist_data:
* for each hist_key in password:
- * decrypt hist_key with histkey_encblock
+ * decrypt hist_key with hist_keyblock
* compare the new_key and hist_key
*
* Returns krb5 errors, KADM5_PASS_RESUSE if a key in
*/
static kadm5_ret_t
check_pw_reuse(krb5_context context,
- krb5_encrypt_block *histkey_encblock,
+ krb5_keyblock *hist_keyblock,
int n_new_key_data, krb5_key_data *new_key_data,
int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
{
for (x = 0; x < n_new_key_data; x++) {
if (ret = krb5_dbekd_decrypt_key_data(context,
- &master_encblock,
+ &master_keyblock,
&(new_key_data[x]),
&newkey, NULL))
return(ret);
for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
if (ret =
krb5_dbekd_decrypt_key_data(context,
- histkey_encblock,
+ hist_keyblock,
&pw_hist_data[y].key_data[z],
&histkey, NULL))
return(ret);
* Effects:
*
* hist->key_data is allocated to store n_key_data key_datas. Each
- * element of key_data is decrypted with master_encblock, re-encrypted
- * in hist_encblock, and added to hist->key_data. hist->n_key_data is
+ * element of key_data is decrypted with master_keyblock, re-encrypted
+ * in hist_key, and added to hist->key_data. hist->n_key_data is
* set to n_key_data.
*/
int create_history_entry(krb5_context context, int n_key_data,
for (i = 0; i < n_key_data; i++) {
if (ret = krb5_dbekd_decrypt_key_data(context,
- &master_encblock,
+ &master_keyblock,
&key_data[i],
&key, &salt))
return ret;
if (ret = krb5_dbekd_encrypt_key_data(context,
- &hist_encblock,
+ &hist_key,
&key, &salt,
key_data[i].key_data_kvno,
&hist->key_data[i]))
KADM5_POLICY, &pol, principal)))
goto done;
- if (ret = krb5_dbe_cpw(handle->context, &master_encblock,
+ if (ret = krb5_dbe_cpw(handle->context, &master_keyblock,
handle->params.keysalts,
handle->params.num_keysalts,
password, 0 /* increment kvno */, &kdb))
goto done;
if (ret = check_pw_reuse(handle->context,
- &hist_encblock,
+ &hist_key,
kdb.n_key_data, kdb.key_data,
1, &hist))
goto done;
}
if (ret = check_pw_reuse(handle->context,
- &hist_encblock,
+ &hist_key,
kdb.n_key_data, kdb.key_data,
adb.old_key_len, adb.old_keys))
goto done;
if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
return(ret);
- if (ret = krb5_dbe_crk(handle->context, &master_encblock,
+ if (ret = krb5_dbe_crk(handle->context, &master_keyblock,
handle->params.keysalts,
handle->params.num_keysalts,
&kdb))
}
if (ret = check_pw_reuse(handle->context,
- &hist_encblock,
+ &hist_key,
kdb.n_key_data, kdb.key_data,
adb.old_key_len, adb.old_keys))
goto done;
keysalt.data.data = NULL;
if (ret = krb5_dbekd_encrypt_key_data(handle->context,
- &master_encblock,
+ &master_keyblock,
keyblock, &keysalt,
kvno + 1,
kdb.key_data)) {
}
if (ret = check_pw_reuse(handle->context,
- &hist_encblock,
+ &hist_key,
kdb.n_key_data, kdb.key_data,
adb.old_key_len, adb.old_keys))
goto done;
krb5_int32 now;
kadm5_policy_ent_rec pol;
krb5_key_data *key_data;
- int i, kvno, ret, last_pwd, have_pol = 0;
- int deskeys;
+ int i, j, kvno, ret, last_pwd, have_pol = 0;
kadm5_server_handle_t handle = server_handle;
+ krb5_boolean similar;
CHECK_HANDLE(server_handle);
principal, hist_princ)) == TRUE))
return KADM5_PROTECT_PRINCIPAL;
- for (i = 0, deskeys = 0; i < n_keys; i++) {
- if (keyblocks[i].enctype == ENCTYPE_DES_CBC_MD4 ||
- keyblocks[i].enctype == ENCTYPE_DES_CBC_MD5 ||
- keyblocks[i].enctype == ENCTYPE_DES_CBC_RAW ||
- keyblocks[i].enctype == ENCTYPE_DES_CBC_CRC)
- deskeys++;
- if (deskeys > 1)
- return KADM5_SETKEY_DUP_ENCTYPES;
+ for (i = 0; i < n_keys; i++) {
+ for (j = i+1; j < n_keys; j++) {
+ if (ret = krb5_c_enctype_compare(handle->context,
+ keyblocks[i].enctype,
+ keyblocks[j].enctype,
+ &similar))
+ return(ret);
+ if (similar)
+ return KADM5_SETKEY_DUP_ENCTYPES;
+ }
}
if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
for (i = 0; i < n_keys; i++) {
if (ret = krb5_dbekd_encrypt_key_data(handle->context,
- &master_encblock,
+ &master_keyblock,
&keyblocks[i], NULL,
kvno + 1,
&kdb.key_data[i]))
}
if (ret = check_pw_reuse(handle->context,
- &hist_encblock,
+ &hist_key,
kdb.n_key_data, kdb.key_data,
adb.old_key_len, adb.old_keys))
goto done;
/*
* Allocate an array of n_key_data krb5_keyblocks, fill in each
* element with the results of decrypting the nth key in key_data with
- * master_encblock, and if n_keys is not NULL fill it in with the
+ * master_keyblock, and if n_keys is not NULL fill it in with the
* number of keys decrypted.
*/
static int decrypt_key_data(krb5_context context,
for (i = 0; i < n_key_data; i++) {
if (ret = krb5_dbekd_decrypt_key_data(context,
- &master_encblock,
+ &master_keyblock,
&key_data[i],
&keys[i], NULL)) {
return ret;
if (ret = krb5_dbekd_decrypt_key_data(handle->context,
- &master_encblock, key_data,
+ &master_keyblock, key_data,
keyblock, keysalt))
return ret;
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * kdb_xdr.c, kdb_cpw.c: remove the special knowledge of ENCTYPE
+ string-to-key equivalances. the crypto api has a function for
+ this now.
+
+ * decrypt_key.c, encrypt_key.c, fetch_mkey.c, kdb_cpw.c,
+ kdb_db2.c, kdb_db2.h, kdb_dbm.c, keytab.c, verify_mky.c: change or
+ remove all the places krb5_encrypt_block was used
+ (this is mostly relevant to kdb manipulations). It was usually
+ used to specify an enctype (which is now implied by the keyblock),
+ or to store or pass in a processed key (now the api just takes a
+ key directly, so these structures and functions do, too). The kdb
+ key manuipulation functions also need to be made to use the new
+ api.
+
+Fri Sep 25 19:42:10 1998 Tom Yu <tlyu@mit.edu>
+
+ * kdb_xdr.c (krb5_dbe_search_enctype): Re-order booleans so that
+ similar doesn't get checked unless (ktype >= 0) to avoid it being
+ stack garbage.
+
+Sun Aug 16 16:52:10 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (SHLIB_EXPLIBS): Include $(LIBS) so building on AIX works
+
+Sun Jul 26 18:12:22 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (LIBMAJOR): bump libmajor
+
1998-05-06 Theodore Ts'o <tytso@rsts-11.mit.edu>
* t_kdb.c (main): POSIX states that getopt returns -1
PROG_RPATH=$(KRB5_LIBDIR)
LIB=kdb5
-LIBMAJOR=2
+LIBMAJOR=3
LIBMINOR=0
RELDIR=kdb
# Depends on libk5crypto and libkrb5
SHLIB_EXPDEPS = \
$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
$(TOPLIBD)/libkrb5$(SHLIBEXT)
-SHLIB_EXPLIBS=-lkrb5 -lcom_err -lk5crypto
+SHLIB_EXPLIBS=-lkrb5 -lcom_err -lk5crypto $(LIBS)
SHLIB_DIRS=-L$(TOPLIBD)
SHLIB_RDIRS=$(KRB5_LIBDIR)
* krb5_kdb_encrypt_key(), krb5_kdb_decrypt_key functions
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
/*
*/
krb5_error_code
-krb5_dbekd_decrypt_key_data(context, eblock, key_data, keyblock, keysalt)
+krb5_dbekd_decrypt_key_data(context, mkey, key_data, dbkey, keysalt)
krb5_context context;
- krb5_encrypt_block * eblock;
+ const krb5_keyblock * mkey;
const krb5_key_data * key_data;
- krb5_keyblock * keyblock;
+ krb5_keyblock * dbkey;
krb5_keysalt * keysalt;
{
krb5_error_code retval = 0;
krb5_int16 tmplen;
krb5_octet * ptr;
+ krb5_enc_data cipher;
+ krb5_data plain;
- keyblock->magic = KV5M_KEYBLOCK;
- keyblock->enctype = key_data->key_data_type[0];
-
- /* Decrypt key_data_contents */
- if ((keyblock->contents = (krb5_octet *)malloc(krb5_encrypt_size(
- key_data->key_data_length[0] - 2, eblock->crypto_entry))) == NULL)
- return ENOMEM;
-
- keyblock->length = 0;
ptr = key_data->key_data_contents[0];
+
if (ptr) {
krb5_kdb_decode_int16(ptr, tmplen);
ptr += 2;
- keyblock->length = (int) tmplen;
- if ((retval = krb5_decrypt(context, (krb5_pointer) ptr,
- (krb5_pointer)keyblock->contents,
- key_data->key_data_length[0] - 2,
- eblock, 0))) {
- krb5_xfree(keyblock->contents);
- keyblock->contents = 0;
- keyblock->length = 0;
+
+ cipher.enctype = ENCTYPE_UNKNOWN;
+ cipher.ciphertext.length = key_data->key_data_length[0]-2;
+ cipher.ciphertext.data = ptr;
+ plain.length = key_data->key_data_length[0]-2;
+ if ((plain.data = (krb5_octet *) malloc(plain.length)) == NULL)
+ return(ENOMEM);
+
+ if ((retval = krb5_c_decrypt(context, mkey, 0 /* XXX */, 0,
+ &cipher, &plain))) {
+ krb5_xfree(plain.data);
return retval;
}
+
+ /* tmplen is the true length of the key. plain.data is the
+ plaintext data length, but it may be padded, since the
+ old-style etypes didn't store the real length. I can check
+ to make sure that there are enough bytes, but I can't do
+ any better than that. */
+
+ if (tmplen > plain.length) {
+ krb5_xfree(plain.data);
+ return(KRB5_CRYPTO_INTERNAL);
+ }
+
+ dbkey->magic = KV5M_KEYBLOCK;
+ dbkey->enctype = key_data->key_data_type[0];
+ dbkey->length = tmplen;
+ dbkey->contents = plain.data;
}
/* Decode salt data */
keysalt->type = key_data->key_data_type[1];
if ((keysalt->data.length = key_data->key_data_length[1])) {
if (!(keysalt->data.data=(char *)malloc(keysalt->data.length))){
- krb5_xfree(keyblock->contents);
- keyblock->contents = 0;
- keyblock->length = 0;
+ if (key_data->key_data_contents[0]) {
+ krb5_xfree(dbkey->contents);
+ dbkey->contents = 0;
+ dbkey->length = 0;
+ }
return ENOMEM;
}
memcpy(keysalt->data.data, key_data->key_data_contents[1],
keysalt->data.length = 0;
}
}
+
return retval;
}
* krb5_kdb_encrypt_key(), krb5_kdb_decrypt_key functions
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
/*
*/
krb5_error_code
-krb5_dbekd_encrypt_key_data(context, eblock, keyblock, keysalt, keyver,key_data)
+krb5_dbekd_encrypt_key_data(context, mkey, dbkey, keysalt, keyver, key_data)
krb5_context context;
- krb5_encrypt_block * eblock;
- const krb5_keyblock * keyblock;
+ const krb5_keyblock * mkey;
+ const krb5_keyblock * dbkey;
const krb5_keysalt * keysalt;
int keyver;
krb5_key_data * key_data;
krb5_error_code retval;
krb5_keyblock tmp;
krb5_octet * ptr;
- krb5_int16 len;
+ size_t len;
int i;
+ krb5_data plain;
+ krb5_enc_data cipher;
for (i = 0; i < key_data->key_data_ver; i++)
if (key_data->key_data_contents[i])
* The First element of the type/length/contents
* fields is the key type/length/contents
*/
- key_data->key_data_type[0] = keyblock->enctype;
- key_data->key_data_length[0] = krb5_encrypt_size(keyblock->length,
- eblock->crypto_entry) + 2;
+ if ((retval = krb5_c_encrypt_length(context, mkey->enctype, dbkey->length,
+ &len)))
+ return(retval);
- /*
- * because of checksum space requirements imposed by the encryption
- * interface, we need to copy the input key into a larger area.
- */
- tmp.contents = (krb5_octet *)malloc(key_data->key_data_length[0] - 2);
- len = tmp.length = keyblock->length;
- if (tmp.contents == NULL)
- return ENOMEM;
+ if ((ptr = (krb5_octet *) malloc(2 + len)) == NULL)
+ return(ENOMEM);
- memcpy((char *)tmp.contents, (const char *)keyblock->contents, tmp.length);
- key_data->key_data_contents[0] = ptr = (krb5_octet *)malloc(
- key_data->key_data_length[0]);
- if (key_data->key_data_contents[0] == NULL) {
- krb5_xfree(tmp.contents);
- return ENOMEM;
- }
+ key_data->key_data_type[0] = dbkey->enctype;
+ key_data->key_data_length[0] = 2 + len;
+ key_data->key_data_contents[0] = ptr;
- krb5_kdb_encode_int16(len, ptr);
+ krb5_kdb_encode_int16(dbkey->length, ptr);
ptr += 2;
- if ((retval = krb5_encrypt(context, (krb5_pointer) tmp.contents,
- (krb5_pointer)(ptr), tmp.length,
- eblock, 0))) {
+
+ plain.length = dbkey->length;
+ plain.data = dbkey->contents;
+
+ cipher.ciphertext.length = len;
+ cipher.ciphertext.data = ptr;
+
+ if ((retval = krb5_c_encrypt(context, mkey, /* XXX */ 0, 0,
+ &plain, &cipher))) {
krb5_xfree(key_data->key_data_contents[0]);
- krb5_xfree(tmp.contents);
return retval;
}
- krb5_xfree(tmp.contents);
-
/* After key comes the salt in necessary */
if (keysalt) {
if (keysalt->type > 0) {
}
}
}
+
return retval;
}
* Fetch a database master key from somewhere.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
/* these are available to other funcs, and the pointers may be reassigned */
#endif
krb5_error_code
-krb5_db_fetch_mkey(context, mname, eblock, fromkeyboard, twice, keyfile, salt, key)
+krb5_db_fetch_mkey(context, mname, etype, fromkeyboard, twice, keyfile,
+ salt, key)
krb5_context context;
krb5_principal mname;
- krb5_encrypt_block * eblock;
+ krb5_enctype etype;
krb5_boolean fromkeyboard;
krb5_boolean twice;
char *keyfile;
krb5_data pwd;
int size = sizeof(password);
-
if (fromkeyboard) {
krb5_data scratch;
if (retval)
return retval;
}
- retval = krb5_string_to_key(context, eblock, key, &pwd,
- salt ? salt : &scratch);
+ retval = krb5_c_string_to_key(context, etype, &pwd, salt?salt:&scratch,
+ key);
+
if (!salt)
krb5_xfree(scratch.data);
memset(password, 0, sizeof(password)); /* erase it */
key->contents = 0;
} else
retval = 0;
- krb5_use_enctype(context, eblock, key->enctype);
+
+ key->enctype = etype;
errout:
(void) fclose(kf);
*
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include "krb5/adm.h"
#include <stdio.h>
free(data);
}
-/*
- * Currently we can only generate random keys for preinitialized
- * krb5_encrypt_block with a seed. This is bogus but currently
- * necessary to insure that we don't generate two keys with the
- * same data.
- */
static krb5_error_code
-add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno)
+add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
krb5_context context;
- krb5_encrypt_block * master_eblock;
+ krb5_keyblock * master_key;
krb5_key_salt_tuple * ks_tuple;
int ks_tuple_count;
krb5_db_entry * db_entry;
int kvno;
{
krb5_principal krbtgt_princ;
- krb5_keyblock krbtgt_key, * key;
- krb5_pointer krbtgt_seed;
- krb5_encrypt_block krbtgt_eblock;
+ krb5_keyblock key;
krb5_db_entry krbtgt_entry;
krb5_key_data * krbtgt_kdata;
- krb5_boolean more, found;
+ krb5_boolean more;
int max_kvno, one, i, j;
krb5_error_code retval;
- memset(&krbtgt_key, 0, sizeof(krbtgt_key));
retval = krb5_build_principal_ext(context, &krbtgt_princ,
db_entry->princ->realm.length,
db_entry->princ->realm.data,
}
for (i = 0; i < ks_tuple_count; i++) {
- krb5_enctype new_enctype, old_enctype;
+ krb5_boolean similar;
- switch (new_enctype = ks_tuple[i].ks_enctype) {
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- new_enctype = ENCTYPE_DES_CBC_CRC;
- default:
- break;
- }
- found = 0;
+ similar = 0;
/*
* We could use krb5_keysalt_iterate to replace this loop, or use
* circular library dependencies.
*/
for (j = 0; j < i; j++) {
- switch (old_enctype = ks_tuple[j].ks_enctype) {
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- old_enctype = ENCTYPE_DES_CBC_CRC;
- default:
- break;
- }
- if (old_enctype == new_enctype) {
- found = 1;
+ if ((retval = krb5_c_enctype_compare(context,
+ ks_tuple[i].ks_enctype,
+ ks_tuple[j].ks_enctype,
+ &similar)))
+ return(retval);
+
+ if (similar)
break;
- }
}
- if (found)
- continue;
- if (retval = krb5_dbe_create_key_data(context, db_entry))
- goto add_key_rnd_err;
- if (retval = krb5_dbe_find_enctype(context, &krbtgt_entry,
- ks_tuple[i].ks_enctype,
- -1, 0, &krbtgt_kdata))
- goto add_key_rnd_err;
+ if (similar)
+ continue;
- /* Decrypt key */
- if (retval = krb5_dbekd_decrypt_key_data(context, master_eblock,
- krbtgt_kdata,&krbtgt_key,NULL))
+ if (retval = krb5_dbe_create_key_data(context, db_entry))
goto add_key_rnd_err;
- /* Init key */
- krbtgt_key.enctype = ks_tuple[i].ks_enctype;
- krb5_use_enctype(context, &krbtgt_eblock, ks_tuple[i].ks_enctype);
- if (retval = krb5_process_key(context, &krbtgt_eblock, &krbtgt_key)) {
- goto add_key_rnd_err;
- }
+ /* there used to be code here to extract the old key, and derive
+ a new key from it. Now that there's a unified prng, that isn't
+ necessary. */
- /* Init random generator */
- if (retval = krb5_init_random_key(context, &krbtgt_eblock,
- &krbtgt_key, &krbtgt_seed)) {
- krb5_finish_key(context, &krbtgt_eblock);
+ /* make new key */
+ if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
+ &key)))
goto add_key_rnd_err;
- }
- if (retval = krb5_random_key(context,&krbtgt_eblock,krbtgt_seed,&key)) {
- krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
- krb5_finish_key(context, &krbtgt_eblock);
- goto add_key_rnd_err;
- }
+ retval = krb5_dbekd_encrypt_key_data(context, master_key,
+ &key, NULL, kvno,
+ &db_entry->key_data[db_entry->n_key_data-1]);
- krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
- krb5_finish_key(context, &krbtgt_eblock);
+ krb5_free_keyblock_contents(context, &key);
- if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock,
- key, NULL, kvno,
- &db_entry->key_data[db_entry->n_key_data-1])) {
- krb5_free_keyblock(context, key);
+ if (retval)
goto add_key_rnd_err;
- }
-
- /* Finish random key */
- krb5_free_keyblock(context, key);
}
-add_key_rnd_err:;
+add_key_rnd_err:
krb5_db_free_principal(context, &krbtgt_entry, one);
- if (krbtgt_key.contents && krbtgt_key.length) {
- memset(krbtgt_key.contents, 0, krbtgt_key.length);
- krb5_xfree(krbtgt_key.contents);
- }
+
return(retval);
}
* As a side effect all old keys are nuked.
*/
krb5_error_code
-krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
+krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, db_entry)
krb5_context context;
- krb5_encrypt_block * master_eblock;
+ krb5_keyblock * master_key;
krb5_key_salt_tuple * ks_tuple;
int ks_tuple_count;
krb5_db_entry * db_entry;
/* increment the kvno */
kvno++;
- if (retval = add_key_rnd(context, master_eblock, ks_tuple,
+ if (retval = add_key_rnd(context, master_key, ks_tuple,
ks_tuple_count, db_entry, kvno)) {
cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
db_entry->n_key_data = key_data_count;
* As a side effect all old keys older than the max kvno are nuked.
*/
krb5_error_code
-krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
+krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
krb5_context context;
- krb5_encrypt_block * master_eblock;
+ krb5_keyblock * master_key;
krb5_key_salt_tuple * ks_tuple;
int ks_tuple_count;
krb5_db_entry * db_entry;
/* increment the kvno */
kvno++;
- if (retval = add_key_rnd(context, master_eblock, ks_tuple,
+ if (retval = add_key_rnd(context, master_key, ks_tuple,
ks_tuple_count, db_entry, kvno)) {
cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
db_entry->n_key_data = key_data_count;
* If passwd is NULL the assumes that the caller wants a random password.
*/
static krb5_error_code
-add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
+add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
db_entry, kvno)
krb5_context context;
- krb5_encrypt_block * master_eblock;
+ krb5_keyblock * master_key;
krb5_key_salt_tuple * ks_tuple;
int ks_tuple_count;
char * passwd;
int kvno;
{
krb5_error_code retval;
- krb5_encrypt_block key_eblock;
krb5_keysalt key_salt;
krb5_keyblock key;
krb5_data pwd;
retval = 0;
for (i = 0; i < ks_tuple_count; i++) {
- krb5_enctype new_enctype, old_enctype;
+ krb5_boolean similar;
+
+ similar = 0;
- switch (new_enctype = ks_tuple[i].ks_enctype) {
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- new_enctype = ENCTYPE_DES_CBC_CRC;
- default:
- break;
- }
/*
* We could use krb5_keysalt_iterate to replace this loop, or use
* krb5_keysalt_is_present for the loop below, but we want to avoid
* circular library dependencies.
*/
- for (found = j = 0; j < i; j++) {
- if (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype) {
- switch (old_enctype = ks_tuple[j].ks_enctype) {
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- old_enctype = ENCTYPE_DES_CBC_CRC;
- default:
- break;
- }
- if (old_enctype == new_enctype) {
- found = 1;
- break;
- }
- }
+ for (j = 0; j < i; j++) {
+ if ((retval = krb5_c_enctype_compare(context,
+ ks_tuple[i].ks_enctype,
+ ks_tuple[j].ks_enctype,
+ &similar)))
+ return(retval);
+
+ if (similar &&
+ (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
+ break;
}
- if (found)
+
+ if (j < i)
continue;
- krb5_use_enctype(context, &key_eblock, ks_tuple[i].ks_enctype);
+
if (retval = krb5_dbe_create_key_data(context, db_entry))
return(retval);
pwd.data = passwd;
pwd.length = strlen(passwd);
- if (retval = krb5_string_to_key(context, &key_eblock, &key, &pwd,
- &key_salt.data)) {
+
+ if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
+ &pwd, &key_salt.data, &key))) {
if (key_salt.data.data)
free(key_salt.data.data);
return(retval);
key_salt.data.length =
krb5_princ_realm(context, db_entry->princ)->length;
- if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
+ if (retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
(const krb5_keysalt *)&key_salt,
kvno, &db_entry->key_data[db_entry->n_key_data-1])) {
if (key_salt.data.data)
* As a side effect all old keys are nuked.
*/
krb5_error_code
-krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
+krb5_dbe_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
new_kvno, db_entry)
krb5_context context;
- krb5_encrypt_block * master_eblock;
+ krb5_keyblock * master_key;
krb5_key_salt_tuple * ks_tuple;
int ks_tuple_count;
char * passwd;
if (new_kvno < old_kvno+1)
new_kvno = old_kvno+1;
- if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
+ if (retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
passwd, db_entry, new_kvno)) {
cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
db_entry->n_key_data = key_data_count;
* As a side effect all old keys older than the max kvno are nuked.
*/
krb5_error_code
-krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
+krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
krb5_context context;
- krb5_encrypt_block * master_eblock;
+ krb5_keyblock * master_key;
krb5_key_salt_tuple * ks_tuple;
int ks_tuple_count;
char * passwd;
/* increment the kvno */
new_kvno = old_kvno+1;
- if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
+ if (retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
passwd, db_entry, new_kvno)) {
cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
db_entry->n_key_data = key_data_count;
*
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
* Set/Get the master key associated with the database
*/
krb5_error_code
-krb5_db2_db_set_mkey(context, eblock)
+krb5_db2_db_set_mkey(context, key)
krb5_context context;
- krb5_encrypt_block *eblock;
+ krb5_keyblock *key;
{
krb5_db2_context *db_ctx;
return(KRB5_KDB_DBNOTINITED);
db_ctx = context->db_context;
- db_ctx->db_master_key = eblock;
+ db_ctx->db_master_key = key;
return 0;
}
krb5_error_code
-krb5_db2_db_get_mkey(context, eblock)
+krb5_db2_db_get_mkey(context, key)
krb5_context context;
- krb5_encrypt_block **eblock;
+ krb5_keyblock **key;
{
krb5_db2_context *db_ctx;
return(KRB5_KDB_DBNOTINITED);
db_ctx = context->db_context;
- *eblock = db_ctx->db_master_key;
+ *key = db_ctx->db_master_key;
return 0;
}
int db_locks_held; /* Number of times locked */
int db_lock_mode; /* Last lock mode, e.g. greatest*/
krb5_boolean db_nb_locks; /* [Non]Blocking lock modes */
- krb5_encrypt_block *db_master_key; /* Master key of database */
+ krb5_keyblock *db_master_key; /* Master key of database */
} krb5_db2_context;
#define KRB5_DB2_MAX_RETRY 5
* The should really reference the db_context
*/
krb5_error_code
-krb5_dbm_db_set_mkey(context, db_context, eblock)
+krb5_dbm_db_set_mkey(context, db_context, key)
krb5_context context;
krb5_db_context * db_context;
- krb5_encrypt_block * eblock;
+ krb5_keyblock * key;
{
krb5_db_context *db_ctx;
return(KRB5_KDB_DBNOTINITED);
db_ctx = context->db_context;
- db_ctx->db_master_key = eblock;
+ db_ctx->db_master_key = key;
return 0;
}
krb5_error_code
-krb5_dbm_db_get_mkey(context, db_context, eblock)
+krb5_dbm_db_get_mkey(context, db_context, key)
krb5_context context;
krb5_db_context * db_context;
- krb5_encrypt_block **eblock;
+ krb5_keyblock **key;
{
krb5_db_context *db_ctx;
return(KRB5_KDB_DBNOTINITED);
db_ctx = context->db_context;
- *eblock = db_ctx->db_master_key;
+ *key = db_ctx->db_master_key;
return 0;
}
}
}
- /*
- * ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD4, ENCTYPE_DES_CBC_MD5,
- * ENCTYPE_DES_CBC_RAW all use the same key.
- */
- switch (ktype) {
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- ktype = ENCTYPE_DES_CBC_CRC;
- break;
- default:
- break;
- }
-
maxkvno = -1;
datap = (krb5_key_data *) NULL;
for (i = *start; i < dbentp->n_key_data; i++) {
- krb5_enctype db_ktype;
- krb5_int32 db_stype;
-
- switch (db_ktype = dbentp->key_data[i].key_data_type[0]) {
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_RAW:
- db_ktype = ENCTYPE_DES_CBC_CRC;
- default:
- break;
- }
+ krb5_boolean similar;
+ krb5_error_code ret;
+ krb5_int32 db_stype;
+
if (dbentp->key_data[i].key_data_ver > 1) {
db_stype = dbentp->key_data[i].key_data_type[1];
} else {
db_stype = KRB5_KDB_SALTTYPE_NORMAL;
}
- if (((db_ktype == (krb5_enctype) ktype) || (ktype < 0)) &&
+
+ if (ktype >= 0) {
+ if ((ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype,
+ dbentp->key_data[i].key_data_type[0],
+ &similar)))
+ return(ret);
+ }
+
+ if (((ktype < 0) || similar) &&
((db_stype == stype) || (stype < 0))) {
if (kvno >= 0) {
if (kvno == dbentp->key_data[i].key_data_kvno) {
krb5_enctype enctype;
krb5_keytab_entry * entry;
{
- krb5_encrypt_block * master_key;
+ krb5_keyblock * master_key;
krb5_error_code kerror = 0;
krb5_key_data * key_data;
krb5_db_entry db_entry;
/*
* Verify that the master key in *mkey matches the database entry
* for mprinc.
- *
- * eblock points to an encrypt_block used for the realm in question.
*/
krb5_error_code
-krb5_db_verify_master_key(context, mprinc, mkey, eblock)
+krb5_db_verify_master_key(context, mprinc, mkey)
krb5_context context;
krb5_principal mprinc;
krb5_keyblock *mkey;
- krb5_encrypt_block *eblock;
{
krb5_error_code retval;
krb5_db_entry master_entry;
return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
}
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, eblock, mkey))) {
- krb5_db_free_principal(context, &master_entry, nprinc);
- return(retval);
- }
- if ((retval = krb5_dbekd_decrypt_key_data(context, eblock,
+ if ((retval = krb5_dbekd_decrypt_key_data(context, mkey,
&master_entry.key_data[0],
&tempkey, NULL))) {
- (void) krb5_finish_key(context, eblock);
krb5_db_free_principal(context, &master_entry, nprinc);
return retval;
}
+
if (mkey->length != tempkey.length ||
- memcmp((char *)mkey->contents, (char *)tempkey.contents,mkey->length)) {
+ memcmp((char *)mkey->contents,
+ (char *)tempkey.contents,mkey->length)) {
retval = KRB5_KDB_BADMASTERKEY;
- (void) krb5_finish_key(context, eblock);
- } else
- retval = krb5_finish_key(context, eblock);
+ }
memset((char *)tempkey.contents, 0, tempkey.length);
krb5_xfree(tempkey.contents);
+Wed Aug 12 18:32:44 1998 Tom Yu <tlyu@mit.edu>
+
+ * rd_req.c (krb_set_key): Nuke the krb5_keyblock if it's set.
+ (krb_set_key_krb5): New function to set a static krb5_keyblock for
+ decryption purposes.
+ (krb_clear_key_krb5): New function to clear the static
+ krb5_keyblock if it's set.
+ (krb_rd_req): Call decomp_ticket or decomp_tkt_krb5 as appropriate
+ to the key type.
+
+ * decomp_tkt.c (decomp_tkt_krb5): New wrapper to call
+ dcmp_tkt_int.
+ (decomp_ticket): Transform into wrapper to call dcmp_tkt_int.
+ (dcmp_tkt_int): New internal function; use a krb5_keyblock to
+ decrypt the ticket if present; else just use plain old C_Block.
+
+ * cr_tkt.c (krb_create_ticket): Transform into a wrapper that
+ calls krb_cr_tkt_int.
+ (krb_cr_tkt_krb5): New wrapper to call krb_cr_tkt_int.
+ (krb_cr_tkt_int): New internal function that potentially uses a
+ krb5_keyblock to encrypt the ticket, or just a C_Block if the
+ krb5_keyblock is not set.
+
Mon Aug 10 17:51:59 1998 Matthew D Hancher <mdh@mit.edu>
* rd_svc_key.c (read_service_key): Don't call krb5_kt_close() if
* tf_util.c (tf_init): Add call to getuid() to initialize me.
+Thu Jul 30 13:13:30 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * tf_util.c (tf_init): s/,/= so getuid() actually gets called
+
+Sun Jul 26 17:51:24 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (LIBMAJOR): Bump libmajor
+
Thu Jul 9 19:35:01 1998 Matthew D Hancher <mdh@mit.edu>
* tf_util.c (tf_init): Fixed a potential race condition in the opening
##DOS##OBJFILE=krb4.lst
LIB=krb4
-LIBMAJOR=1
+LIBMAJOR=2
LIBMINOR=0
RELDIR=krb4
#include "krb.h"
#include "prot.h"
#include <string.h>
-
+#include <krb5.h>
/*
* Create ticket takes as arguments information that should be in a
* ticket, and the KTEXT object in which the ticket should be
* <=7 bytes null null pad to 8 byte multiple
*
*/
+int
+krb_create_ticket(tkt, flags, pname, pinstance, prealm, paddress,
+ session, life, time_sec, sname, sinstance, key, k5key)
+ KTEXT tkt; /* Gets filled in by the ticket */
+ unsigned char flags; /* Various Kerberos flags */
+ char *pname; /* Principal's name */
+ char *pinstance; /* Principal's instance */
+ char *prealm; /* Principal's authentication domain */
+ long paddress; /* Net address of requesting entity */
+ char *session; /* Session key inserted in ticket */
+ short life; /* Lifetime of the ticket */
+ long time_sec; /* Issue time and date */
+ char *sname; /* Service Name */
+ char *sinstance; /* Instance Name */
+ C_Block key; /* Service's secret key */
+{
+ return krb_cr_tkt_int(tkt, flags, pname, pinstance, prealm, paddress,
+ session, life, time_sec, sname, sinstance,
+ key, NULL);
+}
-int krb_create_ticket(tkt, flags, pname, pinstance, prealm, paddress,
- session, life, time_sec, sname, sinstance, key)
+int
+krb_cr_tkt_krb5(tkt, flags, pname, pinstance, prealm, paddress,
+ session, life, time_sec, sname, sinstance, k5key)
+ KTEXT tkt; /* Gets filled in by the ticket */
+ unsigned char flags; /* Various Kerberos flags */
+ char *pname; /* Principal's name */
+ char *pinstance; /* Principal's instance */
+ char *prealm; /* Principal's authentication domain */
+ long paddress; /* Net address of requesting entity */
+ char *session; /* Session key inserted in ticket */
+ short life; /* Lifetime of the ticket */
+ long time_sec; /* Issue time and date */
+ char *sname; /* Service Name */
+ char *sinstance; /* Instance Name */
+ krb5_keyblock *k5key; /* NULL if not present */
+{
+ C_Block key;
+
+ return krb_cr_tkt_int(tkt, flags, pname, pinstance, prealm, paddress,
+ session, life, time_sec, sname, sinstance,
+ key, k5key);
+}
+
+static int
+krb_cr_tkt_int(tkt, flags, pname, pinstance, prealm, paddress,
+ session, life, time_sec, sname, sinstance, key, k5key)
KTEXT tkt; /* Gets filled in by the ticket */
unsigned char flags; /* Various Kerberos flags */
char *pname; /* Principal's name */
char *sname; /* Service Name */
char *sinstance; /* Instance Name */
C_Block key; /* Service's secret key */
+ krb5_keyblock *k5key; /* NULL if not present */
{
Key_schedule key_s;
register char *data; /* running index into ticket */
}
#ifndef NOENCRYPTION
- /* Encrypt the ticket in the services key */
- key_sched(key,key_s);
- pcbc_encrypt((C_Block *)tkt->dat,(C_Block *)tkt->dat,
- (long) tkt->length,key_s,(C_Block *)key,1);
+ /* Encrypt the ticket in the services key */
+ if (k5key != NULL) {
+ /* block locals */
+ krb5_data in;
+ krb5_enc_data out;
+ krb5_error_code ret;
+ size_t enclen;
+
+ in.length = tkt->length;
+ in.data = tkt->dat;
+ /* XXX assumes context arg is ignored */
+ ret = krb5_c_encrypt_length(NULL, k5key->enctype,
+ (size_t)in.length, &enclen);
+ if (ret)
+ return KFAILURE;
+ out.ciphertext.length = enclen;
+ out.ciphertext.data = malloc(enclen);
+ if (out.ciphertext.data == NULL)
+ return KFAILURE; /* XXX maybe ENOMEM? */
+
+ /* XXX assumes context arg is ignored */
+ ret = krb5_c_encrypt(NULL, k5key, KRB5_KEYUSAGE_KDC_REP_TICKET,
+ NULL, &in, &out);
+ if (ret) {
+ free(out.ciphertext.data);
+ return KFAILURE;
+ } else {
+ tkt->length = out.ciphertext.length;
+ memcpy(tkt->dat, out.ciphertext.data, out.ciphertext.length);
+ memset(out.ciphertext.data, 0, out.ciphertext.length);
+ free(out.ciphertext.data);
+ }
+ } else {
+ key_sched(key,key_s);
+ pcbc_encrypt((C_Block *)tkt->dat,(C_Block *)tkt->dat,
+ (long) tkt->length,key_s,(C_Block *)key,1);
+ }
#endif /* !NOENCRYPTION */
return 0;
}
#include "krb.h"
#include "prot.h"
#include <string.h>
+#include <krb5.h>
#ifdef KRB_CRYPT_DEBUG
extern int krb_debug;
C_Block key; /* Service's secret key
* (to decrypt the ticket) */
Key_schedule key_s; /* The precomputed key schedule */
+{
+ return
+ dcmp_tkt_int(tkt, flags, pname, pinstance, prealm,
+ paddress, session, life, time_sec, sname, sinstance,
+ key, key_s, NULL);
+}
+
+int
+decomp_tkt_krb5(tkt, flags, pname, pinstance, prealm, paddress, session,
+ life, time_sec, sname, sinstance, k5key)
+ KTEXT tkt; /* The ticket to be decoded */
+ unsigned char *flags; /* Kerberos ticket flags */
+ char *pname; /* Authentication name */
+ char *pinstance; /* Principal's instance */
+ char *prealm; /* Principal's authentication domain */
+ unsigned KRB4_32 *paddress; /* Net address of entity
+ * requesting ticket */
+ C_Block session; /* Session key inserted in ticket */
+ int *life; /* Lifetime of the ticket */
+ unsigned KRB4_32 *time_sec; /* Issue time and date */
+ char *sname; /* Service name */
+ char *sinstance; /* Service instance */
+ krb5_keyblock *k5key; /* krb5 keyblock of service */
+{
+ C_Block key; /* placeholder; doesn't get used */
+ Key_schedule key_s; /* placeholder; doesn't get used */
+
+ return
+ dcmp_tkt_int(tkt, flags, pname, pinstance, prealm, paddress, session,
+ life, time_sec, sname, sinstance, key, key_s, k5key);
+}
+
+static int
+dcmp_tkt_int(tkt, flags, pname, pinstance, prealm, paddress, session,
+ life, time_sec, sname, sinstance, key, key_s, k5key)
+ KTEXT tkt; /* The ticket to be decoded */
+ unsigned char *flags; /* Kerberos ticket flags */
+ char *pname; /* Authentication name */
+ char *pinstance; /* Principal's instance */
+ char *prealm; /* Principal's authentication domain */
+ unsigned KRB4_32 *paddress; /* Net address of entity
+ * requesting ticket */
+ C_Block session; /* Session key inserted in ticket */
+ int *life; /* Lifetime of the ticket */
+ unsigned KRB4_32 *time_sec; /* Issue time and date */
+ char *sname; /* Service name */
+ char *sinstance; /* Service instance */
+ C_Block key; /* Service's secret key
+ * (to decrypt the ticket) */
+ Key_schedule key_s; /* The precomputed key schedule */
+ krb5_keyblock *k5key; /* krb5 keyblock of service */
{
static int tkt_swap_bytes;
unsigned char *uptr;
memset(keybuf, 0, sizeof(keybuf)); /* Clear the buffer */
}
#endif
- pcbc_encrypt((C_Block *)tkt->dat,(C_Block *)tkt->dat,
- (long) tkt->length,key_s,(C_Block *) key,0);
+ if (k5key != NULL) {
+ /* block locals */
+ krb5_enc_data in;
+ krb5_data out;
+ krb5_error_code ret;
+
+ in.enctype = k5key->enctype;
+ in.kvno = 0;
+ in.ciphertext.length = tkt->length;
+ in.ciphertext.data = tkt->dat;
+ out.length = tkt->length;
+ out.data = malloc(tkt->length);
+ if (out.data == NULL)
+ return KFAILURE; /* XXX maybe ENOMEM? */
+
+ /* XXX note the following assumes that context arg isn't used */
+ ret =
+ krb5_c_decrypt(NULL, k5key,
+ KRB5_KEYUSAGE_KDC_REP_TICKET, NULL, &in, &out);
+ if (ret) {
+ free(out.data);
+ return KFAILURE;
+ } else {
+ memcpy(tkt->dat, out.data, out.length);
+ memset(out.data, 0, out.length);
+ free(out.data);
+ }
+ } else {
+ pcbc_encrypt((C_Block *)tkt->dat,(C_Block *)tkt->dat,
+ (long) tkt->length,key_s,(C_Block *) key,0);
+ }
#endif /* ! NOENCRYPTION */
#ifdef KRB_CRYPT_DEBUG
if (krb_debug) {
static char st_rlm[REALM_SZ]; /* server's realm */
static char st_nam[ANAME_SZ]; /* service name */
static char st_inst[INST_SZ]; /* server's instance */
+static int krb5_key; /* whether krb5 key is used for decrypt */
/*
* This file contains two functions. krb_set_key() takes a DES
* krb_rd_req().
*/
+#include <krb5.h>
+static krb5_keyblock srv_k5key;
+
int
krb_set_key(key,cvt)
char *key;
int cvt;
{
+ if (krb5_key)
+ /* XXX assumes that context arg is ignored */
+ krb5_free_keyblock_contents(NULL, &srv_k5key);
+ krb5_key = 0;
#ifdef NOENCRYPTION
memset(ky, 0, sizeof(ky));
return KSUCCESS;
#endif /* NOENCRYPTION */
}
+int
+krb_set_key_krb5(ctx, key)
+ krb5_context ctx;
+ krb5_keyblock *key;
+{
+ if (krb5_key)
+ krb5_free_keyblock_contents(ctx, &srv_k5key);
+ krb5_key = 1;
+ return krb5_copy_keyblock_contents(ctx, key, &srv_k5key);
+}
+
+void
+krb_clear_key_krb5(ctx)
+ krb5_context ctx;
+{
+ if (krb5_key)
+ krb5_free_keyblock_contents(ctx, &srv_k5key);
+ krb5_key = 0;
+}
/*
* krb_rd_req() takes an AUTH_MSG_APPL_REQUEST or
/* Decrypt and take apart ticket */
#endif
- if (decomp_ticket(tkt,&ad->k_flags,ad->pname,ad->pinst,ad->prealm,
- &(ad->address),ad->session, &(ad->life),
- &(ad->time_sec),sname,iname,ky,serv_key)) {
+ if (!krb5_key) {
+ if (decomp_ticket(tkt,&ad->k_flags,ad->pname,ad->pinst,ad->prealm,
+ &(ad->address),ad->session, &(ad->life),
+ &(ad->time_sec),sname,iname,ky,serv_key)) {
#ifdef KRB_CRYPT_DEBUG
- log("Can't decode ticket");
+ log("Can't decode ticket");
#endif
- return(RD_AP_UNDEC);
+ return(RD_AP_UNDEC);
+ }
+ } else {
+ if (decomp_tkt_krb5(tkt, &ad->k_flags, ad->pname, ad->pinst,
+ ad->prealm, &ad->address, ad->session,
+ &ad->life, &ad->time_sec, sname, iname,
+ srv_k5key)) {
+ return RD_AP_UNDEC;
+ }
}
+
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug) {
log("Ticket Contents.");
int rw;
{
int wflag;
- uid_t me, getuid();
+ uid_t me= getuid();
struct stat stat_buf, stat_buffd;
#ifdef TKT_SHMEM
char shmidname[MAXPATHLEN];
+Thu Jul 30 13:12:57 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * configure.in: Test for sa_len so localaddr works on NetBSD.
+
+Sun Jul 26 17:46:47 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (LIBMAJOR): bump to 2
+
Wed Apr 15 18:07:20 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in (SHLIB_EXPDEPS):
#SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
LIB=krb5
-LIBMAJOR=1
-LIBMINOR=2
+LIBMAJOR=2
+LIBMINOR=1
STOBJLISTS= \
error_tables/OBJS.ST \
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * asn1buf.c (asn1buf_sync): interoperation testing against heimdal
+ revealed a bug. if extra fields are present in a SEQUENCE, they
+ are not ignored and skipped. This caused the decoder to get out
+ of sync.
+
Thu Jul 2 15:30:25 1998 Theodore Y. Ts'o <tytso@mit.edu>
* asn1_encode.c: Make the magic Macintosh EPOCH offset be 70 years
asn1buf * buf;
asn1buf * subbuf;
{
- buf->next = subbuf->next;
+ buf->next = subbuf->bound + 1;
}
asn1_error_code asn1buf_destroy(buf)
* Added Frank's CCache API cache implementation and made
it default on the Mac
+Thu Jul 30 13:12:30 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * ccbase.c: Enable memory ccache (merge adapted from Kerbnet)
+
1998-05-27 Theodore Ts'o <tytso@rsts-11.mit.edu>
* Makefile.in: Add ccache/memory as a directory to be recursively
+++ /dev/null
-thisconfigdir=./../..
-BUILDTOP=$(REL)$(U)$(S)$(U)$(S)$(U)$(S)$(U)
-CFLAGS = $(CCOPTS) $(DEFS)
-
-##DOS##BUILDTOP = ..\..\..\..
-##DOS##PREFIXDIR = ccache\file
-##DOS##OBJFILE = file.lst
-##WIN16##LIBNAME=..\..\krb5.lib
-
-STLIBOBJS = \
- stdcc.o \
- stdcc_util.o
-
-OBJS = stdcc.${OBJEXT} stdcc_util.${OBJEXT}
-
-SRCS = $(srcdir)/stdcc.c $(srcdir)/stdcc_util.c
-
-##DOS##LIBOBJS = $(OBJS)
-
-all-unix:: all-libobjs
-clean-unix:: clean-libobjs
+++ /dev/null
-/**********************************************************
- *
- * stdcc.c - additions to the Kerberos 5 library to support the memory credentical cache API
- *
- * Revision 1.1.1.1 - Frank Dabek July 1998
- *
- **********************************************************/
-
-#include "stdcc.h"
-#include "string.h"
-
-//declare our global object wanna-be
-//must be installed in ccdefops.c
-krb5_cc_ops krb5_cc_stdcc_ops = {
- 0,
- "API",
- krb5_stdcc_get_name,
- krb5_stdcc_resolve,
- krb5_stdcc_generate_new,
- krb5_stdcc_initialize,
- krb5_stdcc_destroy,
- krb5_stdcc_close,
- krb5_stdcc_store,
- krb5_stdcc_retrieve,
- krb5_stdcc_get_principal,
- krb5_stdcc_start_seq_get,
- krb5_stdcc_next_cred,
- krb5_stdcc_end_seq_get,
- krb5_stdcc_remove,
- krb5_stdcc_set_flags,
-};
-
-// -- generate_new --------------------------------
-// - create a new cache with a unique name, corresponds to creating a named cache
-// - iniitialize the API here if we have to.
-krb5_error_code krb5_stdcc_generate_new
- (krb5_context context, krb5_ccache *id )
-
- {
-
- krb5_ccache newCache;
- char name[kStringLiteralLen];
- cc_time_t time;
- int err;
-
- //make sure the API has been intialized
- if (gCntrlBlock == NULL) {
- err = cc_initialize(&gCntrlBlock, CC_API_VER_1, NULL, NULL);
- if (err != CC_NOERROR) return err;
- }
-
- //allocate the cache structure
- newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
- if (newCache == NULL) return KRB5_CC_NOMEM;
-
- //create a unique name
- cc_get_change_time(gCntrlBlock, &time);
- sprintf(name, "gen_new_cache%d", time);
-
- //create the new cache
- err = cc_create(gCntrlBlock, name, CC_CRED_V5,
- name, 0L, &(((stdccCacheDataPtr)(newCache->data))->NamedCache) );
- if (err != CC_NOERROR) return err;
-
- //setup some fields
- newCache->ops = &krb5_cc_stdcc_ops;
- newCache->data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData));
-
- //return a pointer to the new cache
- *id = newCache;
-
- return CC_NOERROR;
- }
-
-// -- resolve ------------------------------
-//
-// - create a new cache with the name stored in residual
-krb5_error_code krb5_stdcc_resolve
- (krb5_context context, krb5_ccache *id , const char *residual ) {
-
- krb5_ccache newCache;
- int err,pos;
- char *cName;
-
- //make sure the API has been intialized
- if (gCntrlBlock == NULL) {
- err = cc_initialize(&gCntrlBlock, CC_API_VER_1, NULL, NULL);
- if (err != CC_NOERROR) return err;
- }
-
- newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
- if (newCache == NULL) return KRB5_CC_NOMEM;
-
- newCache->ops = &krb5_cc_stdcc_ops;
- newCache->data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData));
- if (newCache->data == NULL) return KRB5_CC_NOMEM;
-
- cName = residual;
- //attempt to find a cache by the same name before creating it
- err = cc_open(gCntrlBlock, cName, CC_CRED_V5, 0L, &(((stdccCacheDataPtr)(newCache->data))->NamedCache));
- //we didn't find it.. create it.
- if (err) {
- err = cc_create(gCntrlBlock, cName, CC_CRED_V5, cName,
- 0L, &(((stdccCacheDataPtr)(newCache->data))->NamedCache) );
- if (err != CC_NOERROR) return err; //still an error, return it
- }
-
- //return new cache structure
- *id = newCache;
- return CC_NOERROR;
- }
-
- // -- initialize --------------------------------
- //-initialize the cache, check to see if one already exists for this principal
- // if not set our principal to this principal. This searching enables ticket sharing
- krb5_error_code krb5_stdcc_initialize
- (krb5_context context, krb5_ccache id, krb5_principal princ)
-
- {
-
- int err, err1, found;
- //char cName[kStringLiteralLen];
- char *cName = nil;
- ccache_p *testNC = NULL;
- ccache_it *it;
- char *p = NULL, *targetName = NULL;
-
- //test id for null
- if (id == NULL) return KRB5_CC_NOMEM;
-
- //test for initialized API
- if (gCntrlBlock == NULL)
- return CC_NO_EXIST;
-
- //create a principal name for the named cache
- err = krb5_unparse_name(context, princ, &cName);
- if (err)
- return(err);
-
- //sprintf(cName, "%s@%s", krb5_princ_name(context, princ)->data, krb5_princ_realm(context, princ)->data);
-
- //look for a cache already extant for this principal
- it = NULL;
- found = err = 0;
- while ((err != CC_END) && (!found)) {
- err = cc_seq_fetch_NCs(gCntrlBlock, &testNC, &it);
- if (err == CC_NOERROR) {
- cc_get_principal(gCntrlBlock, testNC, &p);
- if (strcmp(p, cName) == 0) {
- found = 1;
- cc_get_name(gCntrlBlock, testNC, &targetName);
- }
- cc_free_principal(gCntrlBlock, p);
- err1 = cc_close(gCntrlBlock, &testNC);
- }
- }
-
- if (!found)
- //we didn't find one with the name we were looking for, use the one we had and change the name
- cc_set_principal(gCntrlBlock, (((stdccCacheDataPtr)(id->data))->NamedCache), CC_CRED_V5, cName);
- else {
- //we found a cache for this guy, lets trash ours and use that one - let's not; sgm 10/7/98
- //cc_destroy(gCntrlBlock, &(((stdccCacheDataPtr)(id->data))->NamedCache));
- err = cc_open(gCntrlBlock, targetName, CC_CRED_V5, 0L, &(((stdccCacheDataPtr)(id->data))->NamedCache));
- if (err != CC_NOERROR) return err; //error opening
- cc_free_name(gCntrlBlock, targetName);
- }
-
- free(cName);
-
- return CC_NOERROR;
-
- }
-
-
-// -- store ----------------------------------
-// - store some credentials in our cache
- krb5_error_code krb5_stdcc_store
- (krb5_context context, krb5_ccache id , krb5_creds *creds ) {
-
- cred_union *cu = NULL;
- int err;
-
-
- //copy the fields from the almost identical structures
- dupK52cc(context, creds, &cu);
-
- //finally store the credential
- //store will copy (that is duplicate) everything
- err = cc_store(gCntrlBlock, ((stdccCacheDataPtr)(id->data))->NamedCache, *cu);
- if (err != CC_NOERROR) return err;
-
- //free the cred union
- err = cc_free_creds(gCntrlBlock, &cu);
-
- return err;
-}
-
-
-// -- start_seq_get --------------------------
-// - begin an iterator call to get all of the credentials in the cache
-krb5_error_code krb5_stdcc_start_seq_get
-(krb5_context context, krb5_ccache id , krb5_cc_cursor *cursor ) {
-
- //all we have to do is initialize the cursor
- *cursor = NULL;
- return CC_NOERROR;
-}
-
-// -- next cred ---------------------------
-// - get the next credential in the cache as part of an iterator call
-// - this maps to call to cc_seq_fetch_creds
-krb5_error_code krb5_stdcc_next_cred
- (krb5_context context,
- krb5_ccache id ,
- krb5_cc_cursor *cursor ,
- krb5_creds *creds ) {
-
- int err;
- cred_union *credU = NULL;
- cc_creds *c = NULL;
-
- err = cc_seq_fetch_creds(gCntrlBlock, ((stdccCacheDataPtr)(id->data))->NamedCache,
- &credU, (ccache_it **)cursor);
-
- if (err != CC_NOERROR)
- return err;
-
- //copy data (with translation)
- dupCCtoK5(context, credU->cred.pV5Cred, creds);
-
- //free our version of the cred
- cc_free_creds(gCntrlBlock, &credU);
-
- return CC_NOERROR;
-
-}
-
-
-// -- retreive -------------------
-// - try to find a matching credential in the cache
-krb5_error_code krb5_stdcc_retrieve
- (krb5_context context,
- krb5_ccache id,
- krb5_flags whichfields,
- krb5_creds *mcreds,
- krb5_creds *creds ) {
-
- krb5_cc_cursor curs = NULL;
- krb5_creds *fetchcreds;
-
- fetchcreds = (krb5_creds *)malloc(sizeof(krb5_creds));
- if (fetchcreds == NULL) return KRB5_CC_NOMEM;
-
- //we're going to use the iterators
- krb5_stdcc_start_seq_get(context, id, &curs);
-
- while (krb5_stdcc_next_cred(context, id, &curs, fetchcreds) == CC_NOERROR) {
- //look at each credential for a match
- //use this match routine since it takes the whichfields and the API doesn't
- if (stdccCredsMatch(context, fetchcreds, mcreds, whichfields)) {
- //we found it, copy and exit
- *creds = *fetchcreds;
- krb5_stdcc_end_seq_get(context, id, &curs);
- return CC_NOERROR;
- }
- //free copy allocated by next_cred
- krb5_free_cred_contents(context, fetchcreds);
- }
-
- //no luck, end get and exti
- krb5_stdcc_end_seq_get(context, id, &curs);
-
- return KRB5_CC_NOTFOUND;
-}
-
-// -- end seq ------------------------
-// - just free up the storage assoicated with the cursor (if we could)
- krb5_error_code krb5_stdcc_end_seq_get
- (krb5_context context, krb5_ccache id , krb5_cc_cursor *cursor ) {
-
- //the limitation of the Ccache api and the seq calls
- //causes trouble. cursor might have already been freed
- //and anyways it is in the mac's heap so we need FreePtr
- //but all i have is free
- // FreePtr(*cursor);
-
- //LEAK IT!
- *cursor = NULL;
- }
-
-// -- close ---------------------------
-// - free our pointers to the NC
-krb5_error_code
-krb5_stdcc_close(context, id, princ)
- krb5_context context;
- krb5_ccache id;
- krb5_principal princ;
-{
-
- //free it
- free((stdccCacheDataPtr)(id->data));
- //null it out
- (stdccCacheDataPtr)(id->data) = NULL;
-
- return CC_NOERROR;
-}
-
-// -- destroy -------------
-// - free our storage and the cache
-krb5_error_code
-krb5_stdcc_destroy (krb5_context context, krb5_ccache id ) {
-
- int err;
-
- //destroy the named cache
- err = cc_destroy(gCntrlBlock, &(((stdccCacheDataPtr)(id->data))->NamedCache));
- //free the pointer to the record that held the pointer to the cache
- free((stdccCacheDataPtr)(id->data));
- //null it out
- (stdccCacheDataPtr)(id->data) = NULL;
-
- return err;
-}
-
-
-// -- getname ---------------------------
-// - return the name of the named cache
-char * krb5_stdcc_get_name
- (krb5_context context, krb5_ccache id ) {
-
- char *ret = NULL;
- int err;
-
- //just a wrapper
- err = cc_get_name(gCntrlBlock, (((stdccCacheDataPtr)(id->data))->NamedCache), &ret);
-
- if (err != CC_NOERROR)
- return ret;
- else
- return NULL;
-
-}
-
-// -- get_principal ---------------------------
-// - return the principal associated with the named cache
-krb5_error_code
-krb5_stdcc_get_principal (krb5_context context, krb5_ccache id , krb5_principal *princ ) {
-
- int err;
- char *name = NULL;
-
- //another wrapper
- err = cc_get_principal(gCntrlBlock, (((stdccCacheDataPtr)(id->data))->NamedCache), &name);
-
- if (err != CC_NOERROR)
- return err;
-
- //turn it into a krb principal
- err = krb5_parse_name(context, name, princ);
-
- return err;
-}
-
-// -- set_flags ---------------------------
-// - currently a NOP since we don't store any flags in the NC
-krb5_error_code krb5_stdcc_set_flags
- (krb5_context context, krb5_ccache id , krb5_flags flags ) {
-
- return CC_NOERROR;
-}
-
-// - remove ---------------------------
-// - remove the specified credentials from the NC
-krb5_error_code krb5_stdcc_remove
- (krb5_context context, krb5_ccache id , krb5_flags flags, krb5_creds *creds ) {
-
- cred_union *cu = NULL;
- int err;
-
- //convert to a cred union
- dupK52cc(context, creds, &cu);
-
- //remove it
- err = cc_remove_cred(gCntrlBlock, (((stdccCacheDataPtr)(id->data))->NamedCache), *cu);
- if (err != CC_NOERROR) return err;
-
- //free the temp cred union
- err = cc_free_creds(gCntrlBlock, &cu);
- if (err != CC_NOERROR) return err;
-
- return CC_NOERROR;
- }
-
\ No newline at end of file
+++ /dev/null
-//#include "k5-int.h"
-#include "krb5.h"
-
-#if defined(macintosh)
-#include "CCache.h"
-#endif
-
-#if defined(_MSDOS) || defined(_WIN32)
-#include "cacheapi.h"
-#endif
-
-#define kStringLiteralLen 255
-
-//globals to be exported
-extern krb5_cc_ops krb5_cc_stdcc_ops;
-
-//structure to stash in the cache's data field
-//only holds another pointer to the actual cache right now
-typedef struct _stdccCacheData {
- ccache_p *NamedCache;
-} stdccCacheData, *stdccCacheDataPtr;
-
-
-//function protoypes complete with bogus windowsesque macros..
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_close
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_destroy
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_end_seq_get
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id , krb5_cc_cursor *cursor ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_generate_new
- KRB5_PROTOTYPE((krb5_context, krb5_ccache *id ));
-
-KRB5_DLLIMP char * krb5_stdcc_get_name
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_get_principal
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id , krb5_principal *princ ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_initialize
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id , krb5_principal princ ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_next_cred
- KRB5_PROTOTYPE((krb5_context,
- krb5_ccache id ,
- krb5_cc_cursor *cursor ,
- krb5_creds *creds ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_resolve
- KRB5_PROTOTYPE((krb5_context, krb5_ccache *id , const char *residual ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_retrieve
- KRB5_PROTOTYPE((krb5_context,
- krb5_ccache id ,
- krb5_flags whichfields ,
- krb5_creds *mcreds ,
- krb5_creds *creds ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_start_seq_get
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id , krb5_cc_cursor *cursor ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_store
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id , krb5_creds *creds ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_set_flags
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id , krb5_flags flags ));
-
-KRB5_DLLIMP krb5_error_code krb5_stdcc_remove
- KRB5_PROTOTYPE((krb5_context, krb5_ccache id , krb5_flags flags, krb5_creds *creds));
+++ /dev/null
-// stdcc_util.c
-// utility functions used in implementing the ccache api for krb5
-// not publicly exported
-// Frank Dabek, July 1998
-
-#include <stdlib.h>
-#include <string.h>
-#include "stdcc_util.h"
-#include "krb5.h"
-#include "kv5m_err.h"
-
-#define fieldSize 255
-
-/* on the Mac, we need the calls which allocate memory for the Credentials Cache to use
- Ptr's in the system help, so that they stay global and so that bad things don't happen
- when we call DisposePtr() on them. However, on other systems, malloc is probably the
- right thing to use.
- So for any place where we allocate memory for the Credentials Cache, use sys_alloc() and
- define it accordingly.
-*/
-
-#if defined(macintosh)
-#define sys_alloc(size) NewSafePtrSys(size)
-#else
-#define sys_alloc(size) malloc(size)
-#endif
-
-#if defined(macintosh)
-//stolen from CCacheUtils.c
-// -- NewSafePtrSys -----------------
-// - analagous to NewSafePtr but memory is allocated in the system heap
-Ptr NewSafePtrSys(long size) {
-
- Ptr retPtr;
-
- retPtr = NewPtrSys(size);
-
- if (retPtr != NULL)
- HoldMemory(retPtr, size);
-
- return retPtr;
-}
-#endif
-
-// CopyCCDataArrayToK5
-// - copy and translate the null terminated arrays of data records
-// used in k5 tickets
-int copyCCDataArrayToK5(cc_creds *cc, krb5_creds *kc, char whichArray) {
-
- cc_data *ccAdr, **cbase;
- krb5_address *kAdr, **kbase, **constKBase;
- int numRecords = 0;
-
-
- if (whichArray == kAddressArray) {
- //check pointer
- if (cc->addresses == NULL) {
- kc->addresses = NULL;
- return 0; }
- } else if (whichArray == kAuthDataArray) {
- //check pointer
- if (cc->authdata == NULL) {
- kc->authdata = NULL;
- return 0; }
- } else return -1;
-
-
- cbase = (whichArray == kAddressArray) ? cc->addresses : cc->authdata;
- //calc number of records
- while (*cbase++ != NULL) numRecords++;
- //allocate new array
- constKBase = kbase = (krb5_address **)malloc((numRecords+1)*sizeof(char *));
- //reset base
- cbase = (whichArray == kAddressArray) ? cc->addresses : cc->authdata;
-
-
- //copy records
- while (*cbase != NULL) {
- *kbase = (krb5_address *)malloc(sizeof(krb5_address));
- kAdr = *kbase;
- ccAdr = *cbase;
- kAdr->magic = (whichArray == kAddressArray) ? KV5M_ADDRESS : KV5M_AUTHDATA;
- kAdr->addrtype = ccAdr->type;
- kAdr->length = ccAdr->length;
- kAdr->contents = (krb5_octet *)malloc(kAdr->length);
- memcpy(kAdr->contents, ccAdr->data, kAdr->length);
- //next element please
- kbase++; cbase++;
- }
-
- //write terminator
- *kbase = NULL;
- if (whichArray == kAddressArray) kc->addresses = constKBase;
- else kc->authdata = (krb5_authdata **)constKBase;
-
- return 0;
-}
-
-// copyK5DataArrayToCC
-// - analagous to above, but in the other direction
-int copyK5DataArrayToCC(krb5_creds *kc, cc_creds *cc, char whichArray) {
-
- cc_data *ccAdr, **cbase, **constCBase;
- krb5_address *kAdr, **kbase;
- int numRecords = 0;
-
-
- if (whichArray == kAddressArray) {
- //check pointer
- if (kc->addresses == NULL) {
- cc->addresses = NULL;
- return 0; }
- } else if (whichArray == kAuthDataArray) {
- //check pointer
- if (kc->authdata == NULL) {
- cc->authdata = NULL;
- return 0; }
- } else return -1;
-
-
- kbase = (whichArray == kAddressArray) ? kc->addresses : (krb5_address **)kc->authdata;
- //calc number of records
- while (*kbase++ != NULL) numRecords++;
- //allocate new array
- constCBase = cbase = (cc_data **)sys_alloc((numRecords+1)*sizeof(char *));
- //reset base
- kbase = (whichArray == kAddressArray) ? kc->addresses : (krb5_address **)kc->authdata;
-
-
- //copy records
- while (*kbase != NULL) {
- *cbase = (cc_data *)sys_alloc(sizeof(krb5_address));
- kAdr = *kbase;
- ccAdr = *cbase;
- ccAdr->type = kAdr->addrtype;
- ccAdr->length = kAdr->length;
- ccAdr->data = (unsigned char *)sys_alloc(ccAdr->length);
- memcpy(ccAdr->data, kAdr->contents, kAdr->length);
- //next element please
- kbase++; cbase++;
- }
-
- //write terminator
- *cbase = NULL;
- if (whichArray == kAddressArray) cc->addresses = (cc_data **)constCBase;
- else cc->authdata = (cc_data **)constCBase;
-
- return 0;
-}
-
-
-// dupcctok5
-// - allocate an empty k5 style ticket and copy info from the cc_creds ticket
-void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest) {
-
- int err;
-
- //allocate and copy
- //copy all of those damn fields back
- err = krb5_parse_name(context, src->client, &(dest->client));
- err = krb5_parse_name(context, src->server, &(dest->server));
- if (err) return; //parsename fails w/o krb5.ini for example
-
- //copy keyblock
- dest->keyblock.enctype = src->keyblock.type;
- dest->keyblock.length = src->keyblock.length;
- dest->keyblock.contents = (krb5_octet *)malloc(dest->keyblock.length);
- memcpy(dest->keyblock.contents, src->keyblock.data, dest->keyblock.length);
-
- //copy times
- dest->times.authtime = src->authtime;
- dest->times.starttime = src->starttime;
- dest->times.endtime = src->endtime;
- dest->times.renew_till = src->renew_till;
- dest->is_skey = src->is_skey;
- dest->ticket_flags = src->ticket_flags;
-
- //more branching fields
- copyCCDataArrayToK5(src, dest, kAddressArray);
- dest->ticket.length = src->ticket.length;
- dest->ticket.data = (char *)malloc(src->ticket.length);
- memcpy(dest->ticket.data, src->ticket.data, src->ticket.length);
- dest->second_ticket.length = src->second_ticket.length;
- (dest->second_ticket).data = ( char *)malloc(src->second_ticket.length);
- memcpy(dest->second_ticket.data, src->second_ticket.data, src->second_ticket.length);
-
- //zero out magic number
- dest->magic = 0;
- //later
- //copyCCDataArrayToK5(src, dest, kAuthDataArray);
- //krb5 docs say that authdata can be nulled out if we
- //only want default behavior
- dest->authdata = NULL;
-
- return;
-}
-
-// dupK52CC
-// - analagous to above but in the reverse direction
-void dupK52cc(krb5_context context, krb5_creds *creds, cred_union **cu) {
-
- krb5_address **tA;
- krb5_authdata **tAd;
- cc_creds *c;
- int err;
- #ifdef macintosh
- char *tempname = NULL;
- #endif
-
- if (cu == NULL) return;
-
- //allocate the cred_union
- *cu = (cred_union *)sys_alloc(sizeof(cred_union));
- if ((*cu) == NULL) return;
- (*cu)->cred_type = CC_CRED_V5;
-
- //allocate creds structure (and install)
- c = (cc_creds *)sys_alloc(sizeof(cc_creds));
- if (c == NULL) return;
- (*cu)->cred.pV5Cred = c;
-
- //convert krb5 principals to flat principals
- #ifdef macintosh
- //and make sure the memory for c->client and c->server is on the system heap with NewPtr
- //for the Mac (krb5_unparse_name puts it in appl heap with malloc)
- err = krb5_unparse_name(context, creds->client, &tempname);
- c->client = sys_alloc(strlen(tempname));
- if (c->client != NULL)
- strcpy(c->client,tempname);
- free(tempname);
- tempname = NULL;
-
- err = krb5_unparse_name(context, creds->server, &tempname);
- c->server = sys_alloc(strlen(tempname));
- if (c->server != NULL)
- strcpy(c->server,tempname);
- free(tempname);
- #else
- err = krb5_unparse_name(context, creds->client, &(c->client));
- err = krb5_unparse_name(context, creds->server, &(c->server));
- #endif
- if (err) return;
-
- //copy more fields
- c->keyblock.type = creds->keyblock.enctype;
- c->keyblock.length = creds->keyblock.length;
-
- if (creds->keyblock.contents != NULL) {
- c->keyblock.data = (unsigned char *)sys_alloc(creds->keyblock.length);
- memcpy(c->keyblock.data, creds->keyblock.contents, creds->keyblock.length);
- } else {
- c->keyblock.data = NULL;
- }
-
- c->authtime = creds->times.authtime;
- c->starttime = creds->times.starttime;
- c->endtime = creds->times.endtime;
- c->renew_till = creds->times.renew_till;
- c->is_skey = creds->is_skey;
- c->ticket_flags = creds->ticket_flags;
-
- copyK5DataArrayToCC(creds, c, kAddressArray);
-
- c->ticket.length = creds->ticket.length;
- if (creds->ticket.data != NULL) {
- c->ticket.data = (unsigned char *)sys_alloc(creds->ticket.length);
- memcpy(c->ticket.data, creds->ticket.data, creds->ticket.length);
- } else {
- c->ticket.data = NULL;
- }
-
- c->second_ticket.length = creds->second_ticket.length;
- if (creds->second_ticket.data != NULL) {
- c->second_ticket.data = (unsigned char *)sys_alloc(creds->second_ticket.length);
- memcpy(c->second_ticket.data, creds->second_ticket.data, creds->second_ticket.length);
- } else {
- c->second_ticket.data = NULL;
- }
-
- c->authdata = NULL;
-
- return;
-}
-
-
-// bitTst
-// - utility function for below function
-int bitTst(int var, int mask) {
-
- return var & mask;
-}
-
-// stdccCredsMatch
-// - check to see if the creds match based on the whichFields variable
-// NOTE: if whichfields is zero we are now comparing 'standard fields.'
-// This is the bug that was killing fetch for a week. The behaviour
-// is what krb5 expects, however.
-int stdccCredsMatch(krb5_context context, krb5_creds *base, krb5_creds *match, int whichfields) {
-
- krb5_ticket_times b, m;
- krb5_authdata **bp, **mp;
- krb5_boolean retval;
- krb5_principal_data p1, p2;
-
-
- //always check the standard fields
- if ((krb5_principal_compare(context, base->client, match->client) &&
- krb5_principal_compare(context, base->server, match->server)) == false)
- return FALSE;
-
- if (bitTst(whichfields, KRB5_TC_MATCH_TIMES)) {
- //test for matching times
- //according to the file cache implementation we do:
- if (match->times.renew_till) {
- if (match->times.renew_till > base->times.renew_till)
- return FALSE; /* this one expires too late */
- }
- if (match->times.endtime) {
- if (match->times.endtime > base->times.endtime)
- return FALSE; /* this one expires too late */
- }
- } //continue search
-
- if (bitTst(whichfields, KRB5_TC_MATCH_IS_SKEY))
- if (base->is_skey != match->is_skey) return false;
-
- if (bitTst(whichfields, KRB5_TC_MATCH_FLAGS))
- if (base->ticket_flags != match->ticket_flags) return false;
-
- if (bitTst(whichfields, KRB5_TC_MATCH_TIMES_EXACT)) {
- b = base->times; m = match->times;
- if ((b.authtime != m.authtime) ||
- (b.starttime != m.starttime) ||
- (b.endtime != m.endtime) ||
- (b.renew_till != m.renew_till)) return false;
- }
-
- if (bitTst(whichfields, KRB5_TC_MATCH_AUTHDATA)) {
- bp = base->authdata;
- mp = match->authdata;
- if ((bp != NULL) && (mp != NULL)) {
- while ( (bp) && (*bp != NULL) ){
- if (( (*bp)->ad_type != (*mp)->ad_type) ||
- ( (*bp)->length != (*mp)->length) ||
- ( memcmp( (*bp)->contents, (*mp)->contents, (*bp)->length) != 0)) return false;
- mp++; bp++;
- }
- }
- }
-
- if (bitTst(whichfields, KRB5_TC_MATCH_SRV_NAMEONLY)) {
- //taken from cc_retrv.c
- retval = krb5_principal_compare(context, base->client,match->client);
- if (!retval) return false;
-
- }
-
- if (bitTst(whichfields, KRB5_TC_MATCH_2ND_TKT))
- if ( (base->second_ticket.length != match->second_ticket.length) ||
- (memcmp(base->second_ticket.data, match->second_ticket.data, base->second_ticket.length) != 0))
- return false;
-
- if (bitTst(whichfields, KRB5_TC_MATCH_KTYPE))
- if (base->keyblock.enctype != match->keyblock.enctype) return false;
-
- //if we fall through to here, they must match
- return true;
-}
+++ /dev/null
-//stdcc_util.h
-//
-// Frank Dabek, July 1998
-
-#if defined(macintosh)
-#include "CCache.h"
-#endif
-
-#if defined(_MSDOS) || defined(_WIN32)
-#include "cacheapi.h"
-#endif
-
-#include "krb5.h"
-
-//protoypes for private functions declared in stdcc_util.c
-int copyCCDataArrayToK5(cc_creds *cc, krb5_creds *kc, char whichArray);
-int copyK5DataArrayToCC(krb5_creds *kc, cc_creds *cc, char whichArray);
-void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest);
-void dupK52cc(krb5_context context, krb5_creds *creds, cred_union **cu);
-int stdccCredsMatch(krb5_context context, krb5_creds *base, krb5_creds *match, int whichfields);
-int bitTst(int var, int mask);
-void typeK52cc(krb5_context context, krb5_creds *creds, cc_creds *c, char **client, char **server);
-#define kAddressArray 4
-#define kAuthDataArray 5
-
krb5_cc_ops *ops;
struct krb5_cc_typelist *next;
};
-static struct krb5_cc_typelist *cc_typehead = 0;
+extern krb5_cc_ops krb5_mcc_ops;
+
+static struct krb5_cc_typelist cc_entry = { &krb5_mcc_ops, NULL };
+
+static struct krb5_cc_typelist *cc_typehead = &cc_entry;
/*
* Register a new credentials cache type
AC_REPLACE_FUNCS(vfprintf vsprintf strdup strcasecmp strerror memmove daemon getuid sscanf syslog)
KRB5_AC_REGEX_FUNCS
dnl
+KRB5_SOCKADDR_SA_LEN
KRB5_BUILD_LIBRARY_WITH_DEPS
KRB5_BUILD_LIBOBJS
KRB5_BUILD_PROGRAM
error_code KRB5_CHPW_FAIL, "Password change failed"
error_code KRB5_KT_FORMAT, "Bad format in keytab"
+error_code KRB5_NOPERM_ETYPE, "Encryption type not permitted"
+
end
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * ktf_g_ent.c (krb5_ktfile_get_entry): restructure the code to use
+ the compare_enctypes function and not leak memory
+
Fri Feb 27 18:03:33 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
* Makefile.in: Changed thisconfigdir to point at the lib/krb5
krb5_keytab_entry cur_entry, new_entry;
krb5_error_code kerror = 0;
int found_wrong_kvno = 0;
+ krb5_boolean similar;
/* Open the keyfile for reading */
if ((kerror = krb5_ktfileint_openr(context, id)))
cur_entry.principal = 0;
cur_entry.vno = 0;
cur_entry.key.contents = 0;
+
while (TRUE) {
- krb5_enctype entry_type;
-
if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry)))
break;
- switch (enctype) {
- case ENCTYPE_DES_CBC_CRC:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_RAW:
- enctype = ENCTYPE_DES_CBC_CRC;
- break;
+ /* by the time this loop exits, it must either free cur_entry,
+ and copy new_entry there, or free new_entry. Otherwise, it
+ leaks. */
+
+ /* if the enctype is not ignored and doesn't match, free new_entry
+ and continue to the next */
+
+ if (enctype != IGNORE_ENCTYPE) {
+ if ((kerror = krb5_c_enctype_compare(context, enctype,
+ new_entry.key.enctype,
+ &similar))) {
+ krb5_kt_free_entry(context, &new_entry);
+ break;
+ }
+
+ if (!similar) {
+ krb5_kt_free_entry(context, &new_entry);
+ continue;
+ }
}
- entry_type = new_entry.key.enctype;
- switch(entry_type) {
- case ENCTYPE_DES_CBC_CRC:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_RAW:
- entry_type = ENCTYPE_DES_CBC_CRC;
- break;
+ /* if the principal isn't the one requested, free new_entry
+ and continue to the next. */
+
+ if (!krb5_principal_compare(context, principal, new_entry.principal)) {
+ krb5_kt_free_entry(context, &new_entry);
+ continue;
}
- if (((enctype == IGNORE_ENCTYPE)||
- (entry_type == enctype))&&
- krb5_principal_compare(context, principal, new_entry.principal)) {
- if (kvno == IGNORE_VNO) {
- if (! cur_entry.principal ||
- (cur_entry.vno < new_entry.vno))
- {
- krb5_kt_free_entry(context, &cur_entry);
- cur_entry = new_entry;
- }
- } else {
- if (new_entry.vno == kvno) {
- krb5_kt_free_entry(context, &cur_entry);
- cur_entry = new_entry;
- break;
- } else
- found_wrong_kvno++;
- }
+ if (kvno == IGNORE_VNO) {
+ /* if this is the first match, or if the new vno is
+ bigger, free the current and keep the new. Otherwise,
+ free the new. */
+
+ if (! cur_entry.principal ||
+ (new_entry.vno > cur_entry.vno)) {
+ krb5_kt_free_entry(context, &cur_entry);
+ cur_entry = new_entry;
+ } else {
+ krb5_kt_free_entry(context, &new_entry);
+ }
} else {
+ /* if this kvno matches, free the current (will there ever
+ be one?), keep the new, and break out. Otherwise, remember
+ that we were here so we can return the right error, and
+ free the new */
+
+ if (new_entry.vno == kvno) {
+ krb5_kt_free_entry(context, &cur_entry);
+ cur_entry = new_entry;
+ break;
+ } else {
+ found_wrong_kvno++;
krb5_kt_free_entry(context, &new_entry);
+ }
}
}
+
if (kerror == KRB5_KT_END) {
if (cur_entry.principal)
kerror = 0;
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * vfy_increds.c: rearrange the code a bit to make it more clear
+ that the logic is correct.
+
+ * str_conv.c: remove enctype and cksumtype string converstions.
+ They're in the crypto library now, since the information drops
+ right into the enctype table.
+
+ * ser_eblk.c: ifdef the whole file out, since it's not used
+ anywhere. it should probably be deleted, but I'm not sure about
+ backward-compatibility issues yet.
+
+ * rd_req_dec.c: check the auth_context permit-all flag and
+ permitted_enctypes list, and reject the request if the policy
+ check fails.
+
+ * init_ctx.c: add code to initialize the prng. It's not great,
+ but can be improved, and the prng is reseeded when new keys are
+ processed. Read permitted_enctypes from the krb5.conf file, and
+ provide accessor functions for it. Make the various etype list
+ parsers share code as a side effect.
+
+ * get_creds.c: add krb5_get_{validat,renew}ed_creds functions,
+ which are part of the new init_creds api. The prototypes were
+ already in, krb5.hin but there was no implementing code.
+
+ * auth_con.c, auth_con.h: add a list of permitted enctypes to the
+ auth_context for rd_req to check, and create accessor functions
+ for this list.
+
+ * Makefile.in, enc_helper.c: add enc_helper.c. This provides a
+ wrapper around the conventional way the library encrypts and wraps
+ encoded asn.1 structures, so the code isn't repeated in a dozen
+ places.
+
Wed Aug 19 17:27:51 1998 Tom Yu <tlyu@mit.edu>
* conv_princ.c: Add some additional entries to sconv_list that
cp_key_cnt.o \
decode_kdc.o \
decrypt_tk.o \
+ enc_helper.o \
encode_kdc.o \
encrypt_tk.o \
free_rtree.o \
cp_key_cnt.$(OBJEXT) \
decode_kdc.$(OBJEXT) \
decrypt_tk.$(OBJEXT) \
+ enc_helper.$(OBJEXT) \
encode_kdc.$(OBJEXT) \
encrypt_tk.$(OBJEXT) \
free_rtree.$(OBJEXT) \
$(srcdir)/cp_key_cnt.c \
$(srcdir)/decode_kdc.c \
$(srcdir)/decrypt_tk.c \
+ $(srcdir)/enc_helper.c \
$(srcdir)/encode_kdc.c \
$(srcdir)/encrypt_tk.c \
$(srcdir)/free_rtree.c \
-
#include "k5-int.h"
#include "auth_con.h"
krb5_free_keyblock(context, auth_context->remote_subkey);
if (auth_context->rcache)
krb5_rc_close(context, auth_context->rcache);
+ if (auth_context->permitted_etypes)
+ krb5_xfree(auth_context->permitted_etypes);
free(auth_context);
return 0;
}
krb5_context context;
krb5_auth_context auth_context;
{
+ krb5_error_code ret;
+
if (auth_context->keyblock) {
- int size = krb5_enctype_array[auth_context->keyblock->enctype]->
- system->block_length;
+ size_t blocksize;
- if ((auth_context->i_vector = (krb5_pointer)malloc(size))) {
- memset(auth_context->i_vector, 0, size);
+ if ((ret = krb5_c_block_size(context, auth_context->keyblock->enctype,
+ &blocksize)))
+ return(ret);
+ if ((auth_context->i_vector = (krb5_pointer)malloc(blocksize))) {
+ memset(auth_context->i_vector, 0, blocksize);
return 0;
}
return ENOMEM;
return 0;
}
+krb5_error_code
+krb5_auth_con_setpermetypes(context, auth_context, permetypes)
+ krb5_context context;
+ krb5_auth_context auth_context;
+ const krb5_enctype * permetypes;
+{
+ krb5_enctype * newpe;
+ int i;
+
+ for (i=0; permetypes[i]; i++)
+ ;
+ i++; /* include the zero */
+
+ if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
+ == NULL)
+ return(ENOMEM);
+
+ if (auth_context->permitted_etypes)
+ krb5_xfree(auth_context->permitted_etypes);
+
+ auth_context->permitted_etypes = newpe;
+
+ memcpy(newpe, permetypes, i*sizeof(krb5_enctype));
+
+ return 0;
+}
+
+krb5_error_code
+krb5_auth_con_getpermetypes(context, auth_context, permetypes)
+ krb5_context context;
+ krb5_auth_context auth_context;
+ krb5_enctype ** permetypes;
+{
+ krb5_enctype * newpe;
+ int i;
+
+ if (! auth_context->permitted_etypes) {
+ *permetypes = NULL;
+ return(0);
+ }
+
+ for (i=0; auth_context->permitted_etypes[i]; i++)
+ ;
+ i++; /* include the zero */
+
+ if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
+ == NULL)
+ return(ENOMEM);
+
+ *permetypes = newpe;
+
+ memcpy(newpe, auth_context->permitted_etypes, i*sizeof(krb5_enctype));
+
+ return(0);
+}
krb5_cksumtype safe_cksumtype; /* mk_safe, ... */
krb5_pointer i_vector; /* mk_priv, rd_priv only */
krb5_rcache rcache;
+ krb5_enctype * permitted_etypes; /* rd_req */
};
{
krb5_error_code retval;
krb5_kdc_rep *local_dec_rep;
+ krb5_keyusage usage;
- if (krb5_is_as_rep(enc_rep))
+ if (krb5_is_as_rep(enc_rep)) {
+ usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
retval = decode_krb5_as_rep(enc_rep, &local_dec_rep);
- else if (krb5_is_tgs_rep(enc_rep))
+ } else if (krb5_is_tgs_rep(enc_rep)) {
+ usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY;
+ /* KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY would go here, except
+ that this client code base doesn't ever put a subkey in the
+ tgs_req authenticator, so the tgs_rep is never encrypted in
+ one. (Check send_tgs.c:krb5_send_tgs_basic(), near the top
+ where authent.subkey is set to 0) */
retval = decode_krb5_tgs_rep(enc_rep, &local_dec_rep);
- else
+ } else {
return KRB5KRB_AP_ERR_MSG_TYPE;
+ }
if (retval)
return retval;
- if (retval = krb5_kdc_rep_decrypt_proc(context, key, 0, local_dec_rep))
+ if (retval = krb5_kdc_rep_decrypt_proc(context, key, &usage,
+ local_dec_rep))
krb5_free_kdc_rep(context, local_dec_rep);
else
*dec_rep = local_dec_rep;
register krb5_ticket FAR *ticket;
{
krb5_enc_tkt_part *dec_tkt_part;
- krb5_encrypt_block eblock;
krb5_data scratch;
krb5_error_code retval;
if (!valid_enctype(ticket->enc_part.enctype))
return KRB5_PROG_ETYPE_NOSUPP;
- /* put together an eblock for this encryption */
- krb5_use_enctype(context, &eblock, ticket->enc_part.enctype);
-
scratch.length = ticket->enc_part.ciphertext.length;
if (!(scratch.data = malloc(ticket->enc_part.ciphertext.length)))
return(ENOMEM);
- /* do any necessary key pre-processing */
- if (retval = krb5_process_key(context, &eblock, srv_key)) {
- free(scratch.data);
- return(retval);
- }
-
/* call the encryption routine */
- if (retval = krb5_decrypt(context,
- (krb5_pointer) ticket->enc_part.ciphertext.data,
- (krb5_pointer) scratch.data, scratch.length,
- &eblock, 0)) {
- (void) krb5_finish_key(context, &eblock);
+ if (retval = krb5_c_decrypt(context, srv_key,
+ KRB5_KEYUSAGE_KDC_REP_TICKET, 0,
+ &ticket->enc_part, &scratch)) {
free(scratch.data);
return retval;
}
+
#define clean_scratch() {memset(scratch.data, 0, scratch.length); \
free(scratch.data);}
- retval = krb5_finish_key(context, &eblock);
- if (retval) {
- clean_scratch();
- return retval;
- }
/* now decode the decrypted stuff */
retval = decode_krb5_enc_tkt_part(&scratch, &dec_tkt_part);
if (!retval) {
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code
+krb5_encrypt_helper(context, key, usage, plain, cipher)
+ krb5_context context;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *plain;
+ krb5_enc_data *cipher;
+{
+ krb5_error_code ret;
+ size_t enclen;
+
+ if (ret = krb5_c_encrypt_length(context, key->enctype, plain->length,
+ &enclen))
+ return(ret);
+
+ cipher->ciphertext.length = enclen;
+ if ((cipher->ciphertext.data = (char *) malloc(enclen)) == NULL)
+ return(ret);
+
+ if (ret = krb5_c_encrypt(context, key, usage, 0, plain, cipher))
+ free(cipher->ciphertext.data);
+
+ return(ret);
+}
+
/* due to argument promotion rules, we need to use the DECLARG/OLDDECLARG
stuff... */
krb5_error_code
-krb5_encode_kdc_rep(context, type, encpart, client_key, dec_rep, enc_rep)
+krb5_encode_kdc_rep(context, type, encpart, using_subkey, client_key,
+ dec_rep, enc_rep)
krb5_context context;
const krb5_msgtype type;
const krb5_enc_kdc_rep_part * encpart;
+ int using_subkey;
const krb5_keyblock * client_key;
krb5_kdc_rep * dec_rep;
krb5_data ** enc_rep;
krb5_data *scratch;
krb5_error_code retval;
krb5_enc_kdc_rep_part tmp_encpart;
- krb5_encrypt_block eblock;
+ krb5_keyusage usage;
if (!valid_enctype(dec_rep->enc_part.enctype))
return KRB5_PROG_ETYPE_NOSUPP;
switch (type) {
case KRB5_AS_REP:
+ usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
+ break;
case KRB5_TGS_REP:
+ if (using_subkey)
+ usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY;
+ else
+ usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY;
break;
default:
return KRB5_BADMSGTYPE;
#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
krb5_free_data(context, scratch); }
- krb5_use_enctype(context, &eblock, client_key->enctype);
- dec_rep->enc_part.ciphertext.length =
- krb5_encrypt_size(scratch->length, eblock.crypto_entry);
- /* add padding area, and zero it */
- if (!(scratch->data = realloc(scratch->data,
- dec_rep->enc_part.ciphertext.length))) {
- /* may destroy scratch->data */
- krb5_xfree(scratch);
- return ENOMEM;
- }
- memset(scratch->data + scratch->length, 0,
- dec_rep->enc_part.ciphertext.length - scratch->length);
- if (!(dec_rep->enc_part.ciphertext.data =
- malloc(dec_rep->enc_part.ciphertext.length))) {
- retval = ENOMEM;
- goto clean_scratch;
- }
+ retval = krb5_encrypt_helper(context, client_key, usage, scratch,
+ &dec_rep->enc_part);
#define cleanup_encpart() { \
(void) memset(dec_rep->enc_part.ciphertext.data, 0, \
dec_rep->enc_part.ciphertext.length = 0; \
dec_rep->enc_part.ciphertext.data = 0;}
- retval = krb5_process_key(context, &eblock, client_key);
- if (retval) {
- goto clean_encpart;
- }
-
-#define cleanup_prockey() {(void) krb5_finish_key(context, &eblock);}
-
- retval = krb5_encrypt(context, (krb5_pointer) scratch->data,
- (krb5_pointer) dec_rep->enc_part.ciphertext.data,
- scratch->length, &eblock, 0);
- if (retval) {
- goto clean_prockey;
- }
-
- dec_rep->enc_part.enctype = krb5_eblock_enctype(context, &eblock);
-
- /* do some cleanup */
cleanup_scratch();
- retval = krb5_finish_key(context, &eblock);
- if (retval) {
- cleanup_encpart();
- return retval;
- }
+ if (retval)
+ return(retval);
/* now it's ready to be encoded for the wire! */
retval = encode_krb5_tgs_rep(dec_rep, enc_rep);
break;
}
+
if (retval)
cleanup_encpart();
- return retval;
-
- clean_prockey:
- cleanup_prockey();
- clean_encpart:
- cleanup_encpart();
- clean_scratch:
- cleanup_scratch();
return retval;
}
-
-
const krb5_keyblock *srv_key;
register krb5_ticket *dec_ticket;
{
- krb5_encrypt_block eblock;
krb5_data *scratch;
krb5_error_code retval;
register krb5_enc_tkt_part *dec_tkt_part = dec_ticket->enc_part2;
#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
krb5_free_data(context, scratch); }
- krb5_use_enctype(context, &eblock, srv_key->enctype);
-
- dec_ticket->enc_part.ciphertext.length =
- krb5_encrypt_size(scratch->length, eblock.crypto_entry);
- /* add padding area, and zero it */
- if (!(scratch->data = realloc(scratch->data,
- dec_ticket->enc_part.ciphertext.length))) {
- /* may destroy scratch->data */
- krb5_xfree(scratch);
- return ENOMEM;
- }
- memset(scratch->data + scratch->length, 0,
- dec_ticket->enc_part.ciphertext.length - scratch->length);
- if (!(dec_ticket->enc_part.ciphertext.data =
- malloc(dec_ticket->enc_part.ciphertext.length))) {
- retval = ENOMEM;
- goto clean_scratch;
- }
-
-#define cleanup_encpart() {\
-(void) memset(dec_ticket->enc_part.ciphertext.data, 0,\
- dec_ticket->enc_part.ciphertext.length); \
-free(dec_ticket->enc_part.ciphertext.data); \
-dec_ticket->enc_part.ciphertext.length = 0; \
-dec_ticket->enc_part.ciphertext.data = 0;}
-
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, srv_key))) {
- goto clean_encpart;
- }
-
-#define cleanup_prockey() {(void) krb5_finish_key(context, &eblock);}
-
/* call the encryption routine */
- if ((retval = krb5_encrypt(context, (krb5_pointer) scratch->data,
- (krb5_pointer) dec_ticket->enc_part.ciphertext.data,
- scratch->length, &eblock, 0))) {
- goto clean_prockey;
- }
-
- dec_ticket->enc_part.enctype = srv_key->enctype;
-
- /* ticket is now assembled-- do some cleanup */
- cleanup_scratch();
-
- if ((retval = krb5_finish_key(context, &eblock))) {
- cleanup_encpart();
- return retval;
- }
-
- return 0;
+ retval = krb5_encrypt_helper(context, srv_key,
+ KRB5_KEYUSAGE_KDC_REP_TICKET, scratch,
+ &dec_ticket->enc_part);
- clean_prockey:
- cleanup_prockey();
- clean_encpart:
- cleanup_encpart();
- clean_scratch:
cleanup_scratch();
- return retval;
+ return(retval);
}
const krb5_keyblock *key;
krb5_int32 *seqno;
{
- krb5_pointer random_state;
- krb5_encrypt_block eblock;
- krb5_keyblock *subkey = 0;
+ krb5_data seed;
krb5_error_code retval;
- struct tval {
- krb5_int32 seconds;
- krb5_int32 microseconds;
- } timenow;
- krb5_octet *intmp = 0, *outtmp = 0;
- int esize;
- if (!valid_enctype(key->enctype))
- return KRB5_PROG_ETYPE_NOSUPP;
-
- krb5_use_enctype(context, &eblock, key->enctype);
-
- if ((retval = krb5_init_random_key(context, &eblock, key, &random_state)))
+ seed.length = key->length;
+ seed.data = key->contents;
+ if ((retval = krb5_c_random_seed(context, &seed)))
return(retval);
-
- if ((retval = krb5_random_key(context, &eblock, random_state, &subkey))) {
- (void) krb5_finish_random_key(context, &eblock, &random_state);
- return retval;
- }
- /* ignore the error if any, since we've already gotten the key out */
- if ((retval = krb5_finish_random_key(context, &eblock, &random_state))) {
- krb5_free_keyblock(context, subkey);
- return retval;
- }
-
- esize = krb5_encrypt_size(sizeof(timenow), eblock.crypto_entry);
- intmp = (krb5_octet *)malloc(esize);
- if (!intmp) {
- retval = ENOMEM;
- goto cleanup;
- }
- outtmp = (krb5_octet *)malloc(esize);
- if (!outtmp) {
- retval = ENOMEM;
- goto cleanup;
- }
- if ((retval = krb5_process_key(context, &eblock, subkey))) {
- goto cleanup;
- }
- if ((retval = krb5_us_timeofday(context, &timenow.seconds,
- &timenow.microseconds))) {
- goto cleanup;
- }
- memcpy((char *)intmp, (char *)&timenow, sizeof(timenow));
-
- retval = krb5_encrypt(context, (krb5_pointer)intmp, (krb5_pointer)outtmp,
- sizeof(timenow), &eblock, 0);
- (void) krb5_finish_key(context, &eblock);
- if (retval)
- goto cleanup;
-
- memcpy((char *) seqno, (char *)outtmp, sizeof(krb5_int32));
-
-cleanup:
- if (subkey)
- krb5_free_keyblock(context, subkey);
- if (intmp)
- krb5_xfree(intmp);
- if (outtmp)
- krb5_xfree(outtmp);
- return retval;
+ seed.length = sizeof(*seqno);
+ seed.data = (char *) seqno;
+ return(krb5_c_random_make_octets(context, &seed));
}
-
const krb5_keyblock *key;
krb5_keyblock **subkey;
{
- krb5_pointer random_state;
- krb5_encrypt_block eblock;
krb5_error_code retval;
+ krb5_data seed;
- if (!valid_enctype(key->enctype))
- return KRB5_PROG_ETYPE_NOSUPP;
+ seed.length = key->length;
+ seed.data = key->contents;
+ if ((retval = krb5_c_random_seed(context, &seed)))
+ return(retval);
- krb5_use_enctype(context, &eblock, key->enctype);
+ if ((*subkey = (krb5_keyblock *) malloc(sizeof(krb5_keyblock))) == NULL)
+ return(ENOMEM);
- if ((retval = krb5_init_random_key(context, &eblock, key, &random_state)))
- return(retval);
- if ((retval = krb5_random_key(context, &eblock, random_state, subkey))) {
- (void) krb5_finish_random_key(context, &eblock, &random_state);
+ if ((retval = krb5_c_make_random_key(context, key->enctype, *subkey))) {
krb5_xfree(*subkey);
- return retval;
- }
- /* ignore the error if any, since we've already gotten the key out */
- (void) krb5_finish_random_key(context, &eblock, &random_state);
- return 0;
-}
+ return(retval);
+ }
+ return(0);
+}
krb5_creds **tgts = 0;
krb5_flags fields;
- retval = krb5_get_credentials_core(context, options, ccache,
- in_creds, out_creds,
- &mcreds, &fields);
-
- if (retval) return retval;
-
switch(which) {
case INT_GC_VALIDATE:
retval = krb5_get_cred_from_kdc_validate(context, ccache,
in_creds, out_creds,
INT_GC_RENEW));
}
+
+static krb5_error_code
+krb5_validate_or_renew_creds(context, creds, client, ccache, in_tkt_service,
+ validate)
+ krb5_context context;
+ krb5_creds *creds;
+ krb5_principal client;
+ krb5_ccache ccache;
+ char *in_tkt_service;
+ int validate;
+{
+ krb5_error_code ret;
+ krb5_creds in_creds; /* only client and server need to be filled in */
+ krb5_creds *out_creds;
+ krb5_creds **tgts;
+
+ memset((char *)&in_creds, 0, sizeof(krb5_creds));
+
+ in_creds.server = NULL;
+ tgts = NULL;
+
+ in_creds.client = client;
+
+ if (in_tkt_service) {
+ /* this is ugly, because so are the data structures involved. I'm
+ in the library, so I'm going to manipulate the data structures
+ directly, otherwise, it will be worse. */
+
+ if (ret = krb5_parse_name(context, in_tkt_service, &in_creds.server))
+ goto cleanup;
+
+ /* stuff the client realm into the server principal.
+ realloc if necessary */
+ if (in_creds.server->realm.length < in_creds.client->realm.length)
+ if ((in_creds.server->realm.data =
+ (char *) realloc(in_creds.server->realm.data,
+ in_creds.client->realm.length)) == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+
+ in_creds.server->realm.length = in_creds.client->realm.length;
+ memcpy(in_creds.server->realm.data, in_creds.client->realm.data,
+ in_creds.client->realm.length);
+ } else {
+ if (ret = krb5_build_principal_ext(context, &in_creds.server,
+ in_creds.client->realm.length,
+ in_creds.client->realm.data,
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME,
+ in_creds.client->realm.length,
+ in_creds.client->realm.data,
+ 0))
+ goto cleanup;
+ }
+
+ if (validate)
+ ret = krb5_get_cred_from_kdc_validate(context, ccache,
+ &in_creds, &out_creds, &tgts);
+ else
+ ret = krb5_get_cred_from_kdc_renew(context, ccache,
+ &in_creds, &out_creds, &tgts);
+
+ /* ick. copy the struct contents, free the container */
+
+ *creds = *out_creds;
+ krb5_xfree(out_creds);
+
+cleanup:
+
+ if (in_creds.server)
+ krb5_free_principal(context, in_creds.server);
+ if (tgts)
+ krb5_free_tgt_creds(context, tgts);
+
+ return(ret);
+}
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_get_validated_creds(context, creds, client, ccache, in_tkt_service)
+ krb5_context context;
+ krb5_creds *creds;
+ krb5_principal client;
+ krb5_ccache ccache;
+ char *in_tkt_service;
+{
+ return(krb5_validate_or_renew_creds(context, creds, client, ccache,
+ in_tkt_service, 1));
+}
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_get_renewed_creds(context, creds, client, ccache, in_tkt_service)
+ krb5_context context;
+ krb5_creds *creds;
+ krb5_principal client;
+ krb5_ccache ccache;
+ char *in_tkt_service;
+{
+ return(krb5_validate_or_renew_creds(context, creds, client, ccache,
+ in_tkt_service, 0));
+}
krb5_data *password;
krb5_error_code ret;
krb5_data defsalt;
- krb5_encrypt_block eblock;
char *clientstr;
char promptstr[1024];
krb5_prompt prompt;
as_key->length = 0;
}
- if (!valid_enctype(etype))
- return(KRB5_PROG_ETYPE_NOSUPP);
-
- krb5_use_enctype(context, &eblock, etype);
-
if (password->data[0] == '\0') {
if (prompter == NULL)
return(EIO);
defsalt.length = 0;
}
- ret = krb5_string_to_key(context, &eblock, as_key, password, salt);
+ ret = krb5_c_string_to_key(context, etype, password, salt, as_key);
if (defsalt.length)
krb5_xfree(defsalt.data);
krb5_keyblock ** key;
{
krb5_error_code retval;
- krb5_encrypt_block eblock;
krb5_data * password;
int pwsize;
- if (!valid_enctype(type))
- return KRB5_PROG_ETYPE_NOSUPP;
-
- krb5_use_enctype(context, &eblock, type);
-
password = (krb5_data *)keyseed;
if (!password->length) {
if (!(*key = (krb5_keyblock *)malloc(sizeof(**key))))
return ENOMEM;
- if ((retval = krb5_string_to_key(context, &eblock, *key, password, salt)))
+ if ((retval = krb5_c_string_to_key(context, type, password, salt, *key)))
krb5_xfree(*key);
+
return(retval);
}
* krb5_init_contex()
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
#include <ctype.h>
#include "brand.c"
{
krb5_context ctx = 0;
krb5_error_code retval;
+ krb5_timestamp now;
+ krb5_data seed;
int tmp;
/* Initialize error tables */
if ((retval = krb5_os_init_context(ctx)))
goto cleanup;
+ /* initialize the prng (not well, but passable) */
+ if ((retval = krb5_timeofday(ctx, &now)))
+ goto cleanup;
+ seed.length = sizeof(now);
+ seed.data = (char *) &now;
+ if ((retval = krb5_c_random_seed(ctx, &seed)))
+ goto cleanup;
+
ctx->default_realm = 0;
profile_get_integer(ctx->profile, "libdefaults", "clockskew",
0, 5 * 60, &tmp);
return 0;
}
-krb5_error_code
-krb5_get_default_in_tkt_ktypes(context, ktypes)
- krb5_context context;
- krb5_enctype **ktypes;
+static krb5_error_code
+get_profile_etype_list(context, ktypes, profstr, ctx_count, ctx_list)
+ krb5_context context;
+ krb5_enctype **ktypes;
+ char *profstr;
+ int ctx_count;
+ krb5_enctype FAR *ctx_list;
{
- krb5_enctype * old_ktypes;
+ krb5_enctype *old_ktypes;
if (context->in_tkt_ktype_count) {
- /* application-set defaults */
- if ((old_ktypes =
- (krb5_enctype *)malloc(sizeof(krb5_enctype) *
- (context->in_tkt_ktype_count + 1)))) {
- memcpy(old_ktypes, context->in_tkt_ktypes, sizeof(krb5_enctype) *
- context->in_tkt_ktype_count);
- old_ktypes[context->in_tkt_ktype_count] = 0;
- } else {
- return ENOMEM;
- }
+ /* application-set defaults */
+ if ((old_ktypes =
+ (krb5_enctype *)malloc(sizeof(krb5_enctype) *
+ (ctx_count + 1)))) {
+ memcpy(old_ktypes, ctx_list, sizeof(krb5_enctype) * ctx_count);
+ old_ktypes[ctx_count] = 0;
+ } else {
+ return ENOMEM;
+ }
} else {
- /* taken directly from krb5_get_tgs_ktypes... */
/*
XXX - For now, we only support libdefaults
Perhaps this should be extended to allow for per-host / per-realm
int i, j, count;
krb5_error_code code;
- code = profile_get_string(context->profile,
- "libdefaults", "default_tkt_enctypes", NULL,
- "des-cbc-md5 des-cbc-crc",
+ code = profile_get_string(context->profile, "libdefaults", profstr,
+ NULL,
+ "des3-hmac-sha1 des-cbc-md5 des-cbc-crc",
&retval);
if (code)
return code;
return 0;
}
+krb5_error_code
+krb5_get_default_in_tkt_ktypes(context, ktypes)
+ krb5_context context;
+ krb5_enctype **ktypes;
+{
+ return(get_profile_etype_list(context, ktypes, "default_tkt_enctypes",
+ context->in_tkt_ktype_count,
+ context->in_tkt_ktypes));
+}
+
krb5_error_code
krb5_set_default_tgs_ktypes(context, ktypes)
krb5_context context;
krb5_const_principal princ;
krb5_enctype **ktypes;
{
- krb5_enctype * old_ktypes;
-
- if (context->tgs_ktype_count) {
-
- /* Application-set defaults */
-
- if ((old_ktypes =
- (krb5_enctype *)malloc(sizeof(krb5_enctype) *
- (context->tgs_ktype_count + 1)))) {
- memcpy(old_ktypes, context->tgs_ktypes, sizeof(krb5_enctype) *
- context->tgs_ktype_count);
- old_ktypes[context->tgs_ktype_count] = 0;
- } else {
- return ENOMEM;
- }
- } else {
- /*
- XXX - For now, we only support libdefaults
- Perhaps this should be extended to allow for per-host / per-realm
- session key types.
- */
-
- char *retval;
- char *sp, *ep;
- int i, j, count;
- krb5_error_code code;
+ return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
+ context->tgs_ktype_count,
+ context->tgs_ktypes));
+}
- code = profile_get_string(context->profile,
- "libdefaults", "default_tgs_enctypes", NULL,
- "des-cbc-md5 des-cbc-crc",
- &retval);
- if (code)
- return code;
+krb5_error_code
+krb5_get_permitted_enctypes(context, ktypes)
+ krb5_context context;
+ krb5_enctype **ktypes;
+{
+ return(get_profile_etype_list(context, ktypes, "permitted_enctypes",
+ context->tgs_ktype_count,
+ context->tgs_ktypes));
+}
- count = 0;
- sp = retval;
- while (sp) {
- for (ep = sp; *ep && (*ep != ',') && !isspace(*ep); ep++)
- ;
- if (*ep) {
- *ep++ = '\0';
- while (isspace(*ep))
- ep++;
- } else
- ep = (char *) NULL;
+krb5_boolean
+krb5_is_permitted_enctype(context, etype)
+ krb5_context context;
+ krb5_enctype etype;
+{
+ krb5_enctype *list, *ptr;
+ krb5_boolean ret;
- count++;
- sp = ep;
- }
-
- if ((old_ktypes =
- (krb5_enctype *)malloc(sizeof(krb5_enctype) * (count + 1))) ==
- (krb5_enctype *) NULL)
- return ENOMEM;
-
- sp = retval;
- j = 0;
- i = 1;
- while (1) {
- if (! krb5_string_to_enctype(sp, &old_ktypes[j]))
- j++;
+ if (krb5_get_permitted_enctypes(context, &list))
+ return(0);
- if (i++ >= count)
- break;
+
+ ret = 0;
- /* skip to next token */
- while (*sp) sp++;
- while (! *sp) sp++;
- }
+ for (ptr = list; *ptr; ptr++)
+ if (*ptr == etype)
+ ret = 1;
- old_ktypes[j] = (krb5_enctype) 0;
- free(retval);
- }
+ krb5_xfree(list);
- *ktypes = old_ktypes;
- return 0;
+ return(ret);
}
krb5_kdc_rep * dec_rep;
{
krb5_error_code retval;
- krb5_encrypt_block eblock;
krb5_data scratch;
krb5_enc_kdc_rep_part *local_encpart;
+ krb5_keyusage usage;
- if (!valid_enctype(dec_rep->enc_part.enctype))
- return KRB5_PROG_ETYPE_NOSUPP;
+ if (decryptarg) {
+ usage = *(const krb5_keyusage *) decryptarg;
+ } else {
+ usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
+ }
/* set up scratch decrypt/decode area */
return(ENOMEM);
}
- /* put together an eblock for this encryption */
-
- krb5_use_enctype(context, &eblock, dec_rep->enc_part.enctype);
+ dec_rep->enc_part.enctype;
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, key))) {
+ if ((retval = krb5_c_decrypt(context, key, usage, 0, &dec_rep->enc_part,
+ &scratch))) {
free(scratch.data);
return(retval);
}
- /* call the decryption routine */
- if ((retval = krb5_decrypt(context, (krb5_pointer) dec_rep->enc_part.ciphertext.data,
- (krb5_pointer) scratch.data,
- scratch.length, &eblock, 0))) {
- (void) krb5_finish_key(context, &eblock);
- free(scratch.data);
- return retval;
- }
#define clean_scratch() {memset(scratch.data, 0, scratch.length); \
free(scratch.data);}
- if ((retval = krb5_finish_key(context, &eblock))) {
- clean_scratch();
- return retval;
- }
/* and do the decode */
retval = decode_krb5_enc_kdc_rep_part(&scratch, &local_encpart);
return;
}
+KRB5_DLLIMP void KRB5_CALLCONV
+krb5_free_checksum_contents(context, val)
+ krb5_context context;
+ register krb5_checksum *val;
+{
+ if (val->contents)
+ krb5_xfree(val->contents);
+ return;
+}
+
KRB5_DLLIMP void KRB5_CALLCONV
krb5_free_cred(context, val)
krb5_context context;
krb5_xfree(val);
return;
}
+
krb5_enc_data * pencdata;
{
krb5_error_code retval;
- krb5_encrypt_block eblock;
krb5_data * scratch;
- if (pkeyblock && !valid_enctype(pkeyblock->enctype))
- return KRB5_PROG_ETYPE_NOSUPP;
-
/* start by encoding to-be-encrypted part of the message */
if ((retval = encode_krb5_enc_cred_part(pcredpart, &scratch)))
return retval;
return 0;
}
- /* put together an eblock for this encryption */
-
- pencdata->kvno = 0;
- pencdata->enctype = pkeyblock->enctype;
-
- krb5_use_enctype(context, &eblock, pkeyblock->enctype);
- pencdata->ciphertext.length = krb5_encrypt_size(scratch->length,
- eblock.crypto_entry);
-
- /* add padding area, and zero it */
- if (!(scratch->data = (char *)realloc(scratch->data,
- pencdata->ciphertext.length))) {
- /* may destroy scratch->data */
- krb5_xfree(scratch);
- return ENOMEM;
- }
-
- memset(scratch->data + scratch->length, 0,
- pencdata->ciphertext.length - scratch->length);
- if (!(pencdata->ciphertext.data =
- (char *)malloc(pencdata->ciphertext.length))) {
- retval = ENOMEM;
- goto clean_scratch;
- }
-
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, pkeyblock))) {
- goto clean_encpart;
- }
-
/* call the encryption routine */
- if ((retval = krb5_encrypt(context, (krb5_pointer)scratch->data,
- (krb5_pointer)pencdata->ciphertext.data,
- scratch->length, &eblock, 0))) {
- krb5_finish_key(context, &eblock);
- goto clean_encpart;
- }
-
- retval = krb5_finish_key(context, &eblock);
+ retval = krb5_encrypt_helper(context, pkeyblock,
+ KRB5_KEYUSAGE_KRB_CRED_ENCPART,
+ scratch, pencdata);
-clean_encpart:
if (retval) {
memset(pencdata->ciphertext.data, 0, pencdata->ciphertext.length);
free(pencdata->ciphertext.data);
pencdata->ciphertext.data = 0;
}
-clean_scratch:
memset(scratch->data, 0, scratch->length);
krb5_free_data(context, scratch);
krb5_data * outbuf;
{
krb5_error_code retval;
- krb5_encrypt_block eblock;
krb5_priv privmsg;
krb5_priv_enc_part privmsg_enc_part;
- krb5_data *scratch1, *scratch2;
-
- if (!valid_enctype(keyblock->enctype))
- return KRB5_PROG_ETYPE_NOSUPP;
+ krb5_data *scratch1, *scratch2, ivdata;
+ size_t blocksize, enclen;
privmsg.enc_part.kvno = 0; /* XXX allow user-set? */
privmsg.enc_part.enctype = keyblock->enctype;
return retval;
/* put together an eblock for this encryption */
- krb5_use_enctype(context, &eblock, keyblock->enctype);
- privmsg.enc_part.ciphertext.length = krb5_encrypt_size(scratch1->length,
- eblock.crypto_entry);
- /* add padding area, and zero it */
- if (!(scratch1->data = realloc(scratch1->data,
- privmsg.enc_part.ciphertext.length))) {
- /* may destroy scratch1->data */
- krb5_xfree(scratch1);
- return ENOMEM;
- }
+ if ((retval = krb5_c_encrypt_length(context, keyblock->enctype,
+ scratch1->length, &enclen)))
+ goto clean_scratch;
- memset(scratch1->data + scratch1->length, 0,
- privmsg.enc_part.ciphertext.length - scratch1->length);
+ privmsg.enc_part.ciphertext.length = enclen;
if (!(privmsg.enc_part.ciphertext.data =
malloc(privmsg.enc_part.ciphertext.length))) {
retval = ENOMEM;
goto clean_scratch;
}
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, keyblock)))
- goto clean_encpart;
-
/* call the encryption routine */
- if ((retval = krb5_encrypt(context, (krb5_pointer) scratch1->data,
- (krb5_pointer) privmsg.enc_part.ciphertext.data,
- scratch1->length, &eblock, i_vector))) {
- krb5_finish_key(context, &eblock);
- goto clean_encpart;
+ if (i_vector) {
+ if ((retval = krb5_c_block_size(context, keyblock->enctype,
+ &blocksize)))
+ goto clean_encpart;
+
+ ivdata.length = blocksize;
+ ivdata.data = i_vector;
}
+ if ((retval = krb5_c_encrypt(context, keyblock,
+ KRB5_KEYUSAGE_KRB_PRIV_ENCPART,
+ i_vector?&ivdata:0,
+ scratch1, &privmsg.enc_part)))
+ goto clean_encpart;
+
/* put last block into the i_vector */
+
if (i_vector)
memcpy(i_vector,
privmsg.enc_part.ciphertext.data +
- (privmsg.enc_part.ciphertext.length -
- eblock.crypto_entry->block_length),
- eblock.crypto_entry->block_length);
+ (privmsg.enc_part.ciphertext.length - blocksize),
+ blocksize);
- if ((retval = encode_krb5_priv(&privmsg, &scratch2))) {
- krb5_finish_key(context, &eblock);
- goto clean_encpart;
- }
-
- /* encode private message */
- if ((retval = krb5_finish_key(context, &eblock)))
+ if ((retval = encode_krb5_priv(&privmsg, &scratch2)))
goto clean_encpart;
*outbuf = *scratch2;
krb5_error_code retval;
krb5_enctype enctype;
krb5_ap_rep_enc_part repl;
- krb5_encrypt_block eblock;
krb5_ap_rep reply;
krb5_data * scratch;
krb5_data * toutbuf;
- /* verify a valid enctype is available */
- if (!valid_enctype(enctype = auth_context->keyblock->enctype))
- return KRB5_PROG_ETYPE_NOSUPP;
+ enctype = auth_context->keyblock->enctype;
/* Make the reply */
if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
if ((retval = encode_krb5_ap_rep_enc_part(&repl, &scratch)))
return retval;
- /* put together an eblock for this encryption */
- krb5_use_enctype(context, &eblock, enctype);
- reply.enc_part.enctype = enctype;
- reply.enc_part.kvno = 0; /* XXX user set? */
-
- reply.enc_part.ciphertext.length = krb5_encrypt_size(scratch->length,
- eblock.crypto_entry);
- /* add padding area, and zero it */
- if (!(scratch->data = realloc(scratch->data,
- reply.enc_part.ciphertext.length))) {
- /* may destroy scratch->data */
- krb5_xfree(scratch);
- return ENOMEM;
- }
- memset(scratch->data + scratch->length, 0,
- reply.enc_part.ciphertext.length - scratch->length);
- if (!(reply.enc_part.ciphertext.data =
- malloc(reply.enc_part.ciphertext.length))) {
- retval = ENOMEM;
+ if ((retval = krb5_encrypt_helper(context, auth_context->keyblock,
+ KRB5_KEYUSAGE_AP_REP_ENCPART,
+ scratch, &reply.enc_part)))
goto cleanup_scratch;
- }
-
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, auth_context->keyblock)))
- goto cleanup_encpart;
-
- /* call the encryption routine */
- if ((retval = krb5_encrypt(context, (krb5_pointer) scratch->data,
- (krb5_pointer) reply.enc_part.ciphertext.data,
- scratch->length, &eblock, 0))) {
- krb5_finish_key(context, &eblock);
- goto cleanup_encpart;
- }
-
- if ((retval = krb5_finish_key(context, &eblock)))
- goto cleanup_encpart;
if (!(retval = encode_krb5_ap_rep(&reply, &toutbuf))) {
*outbuf = *toutbuf;
krb5_xfree(toutbuf);
}
-cleanup_encpart:
memset(reply.enc_part.ciphertext.data, 0, reply.enc_part.ciphertext.length);
free(reply.enc_part.ciphertext.data);
reply.enc_part.ciphertext.length = 0;
krb5_ap_req request;
krb5_data *scratch = 0;
- krb5_encrypt_block eblock;
krb5_data *toutbuf;
request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
return(retval);
- /* verify a valid enctype is available */
- if (!valid_enctype(in_creds->keyblock.enctype)) {
- retval = KRB5_PROG_ETYPE_NOSUPP;
- goto cleanup;
- }
-
/* verify that the ticket is not expired */
if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
goto cleanup;
&(*auth_context)->local_subkey)))
goto cleanup;
-
if (in_data) {
if ((*auth_context)->req_cksumtype == 0x8003) {
/* XXX Special hack for GSSAPI */
checksum.checksum_type = 0x8003;
checksum.length = in_data->length;
checksum.contents = (krb5_octet *) in_data->data;
- } else {
- /* Generate checksum, XXX What should the seed be? */
- checksum.length =
- krb5_checksum_size(context, (*auth_context)->req_cksumtype);
- if ((checksum.contents = (krb5_octet *)malloc(checksum.length)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- if ((retval = krb5_calculate_checksum(context,
- (*auth_context)->req_cksumtype,
- in_data->data, in_data->length,
- (*auth_context)->keyblock->contents,
- (*auth_context)->keyblock->length,
- &checksum)))
+ } else {
+ if ((retval = krb5_c_make_checksum(context,
+ (*auth_context)->req_cksumtype,
+ (*auth_context)->keyblock,
+ KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
+ in_data, &checksum)))
goto cleanup_cksum;
}
checksump = &checksum;
(*auth_context)->authentp->checksum = NULL;
(*auth_context)->authentp->authorization_data = NULL;
- /* put together an eblock for this encryption */
-
- krb5_use_enctype(context, &eblock, in_creds->keyblock.enctype);
- request.authenticator.enctype = in_creds->keyblock.enctype;
- request.authenticator.kvno = 0;
- request.authenticator.ciphertext.length =
- krb5_encrypt_size(scratch->length, eblock.crypto_entry);
- /* add padding area, and zero it */
- if (!(scratch->data = realloc(scratch->data,
- request.authenticator.ciphertext.length))) {
- /* may destroy scratch->data */
- retval = ENOMEM;
- goto cleanup_cksum;
- }
- memset(scratch->data + scratch->length, 0,
- request.authenticator.ciphertext.length - scratch->length);
- if (!(request.authenticator.ciphertext.data =
- malloc(request.authenticator.ciphertext.length))) {
- retval = ENOMEM;
- goto cleanup_cksum;
- }
-
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, &(in_creds)->keyblock)))
- goto cleanup;
-
/* call the encryption routine */
- if ((retval = krb5_encrypt(context, (krb5_pointer) scratch->data,
- (krb5_pointer) request.authenticator.ciphertext.data,
- scratch->length, &eblock, 0))) {
- krb5_finish_key(context, &eblock);
+ if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
+ KRB5_KEYUSAGE_AP_REQ_AUTH,
+ scratch, &request.authenticator)))
goto cleanup_cksum;
- }
- if ((retval = krb5_finish_key(context, &eblock)))
- goto cleanup_cksum;
-
if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
goto cleanup_cksum;
#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
if ((retval = encode_krb5_safe(&safemsg, &scratch1)))
return retval;
- safe_checksum.length = krb5_checksum_size(context, sumtype);
- if (!(safe_checksum.contents = (krb5_octet *) malloc(safe_checksum.length))) {
-
- retval = ENOMEM;
- goto cleanup_scratch;
- }
- if ((retval = krb5_calculate_checksum(context, sumtype, scratch1->data,
- scratch1->length,
- (krb5_pointer) keyblock->contents,
- keyblock->length, &safe_checksum))) {
+ if ((retval = krb5_c_make_checksum(context, sumtype, keyblock,
+ KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
+ scratch1, &safe_checksum)))
goto cleanup_checksum;
- }
+
safemsg.checksum = &safe_checksum;
if ((retval = encode_krb5_safe(&safemsg, &scratch2))) {
goto cleanup_checksum;
for (pa = preauth_to_use, size=0; *pa; pa++, size++) {
if ((*pa)->pa_type == KRB5_PADATA_ETYPE_INFO) {
+ /* XXX use the first one. Is there another way to disambiguate? */
+ if (etype_info)
+ continue;
+
scratch.length = (*pa)->length;
scratch.data = (char *) (*pa)->contents;
retval = decode_krb5_etype_info(&scratch, &etype_info);
}
cleanup:
+ if (etype_info)
+ krb5_free_etype_info(context, etype_info);
if (f_salt)
krb5_xfree(salt.data);
if (send_pa_list)
krb5_data * scratch;
krb5_enc_data enc_data;
krb5_pa_data * pa;
-
-
- enc_data.ciphertext.data = 0;
retval = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
if (retval)
if ((retval = encode_krb5_pa_enc_ts(&pa_enc, &scratch)) != 0)
return retval;
- if ((retval = krb5_encrypt_data(context, def_enc_key, 0, scratch,
- &enc_data)))
+ enc_data.ciphertext.data = 0;
+
+ if ((retval = krb5_encrypt_helper(context, def_enc_key,
+ KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
+ scratch, &enc_data)))
goto cleanup;
krb5_free_data(context, scratch);
if (ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp))
return(ret);
- ret = krb5_encrypt_data(context, as_key, 0, tmp, &enc_data);
+ ret = krb5_encrypt_helper(context, as_key,
+ KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
+ tmp, &enc_data);
krb5_free_data(context, tmp);
- if (ret)
+ if (ret) {
+ krb5_xfree(enc_data.ciphertext.data);
return(ret);
+ }
ret = encode_krb5_enc_data(&enc_data, &tmp);
char banner[100], prompt[100], response[100];
krb5_data response_data;
krb5_prompt kprompt;
- krb5_encrypt_block eblock;
krb5_data defsalt;
krb5_sam_challenge *sam_challenge = 0;
krb5_sam_response sam_response;
as_key->length = 0;
}
- /* XXX the server uses this fixed enctype, so we will, too. */
-
- if (!valid_enctype(ENCTYPE_DES_CBC_MD5))
- return(KRB5_PROG_ETYPE_NOSUPP);
-
- krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_MD5);
-
#if 0
if ((salt->length == -1) && (salt->data == NULL)) {
if (ret = krb5_principal2salt(context, request->client,
salt = NULL;
#endif
- ret = krb5_string_to_key(context, &eblock, as_key,
- &response_data, salt);
+ /* XXX the server uses this fixed enctype, so we will, too. */
+
+ ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
+ &response_data, salt, as_key);
+
if (defsalt.length)
krb5_xfree(defsalt.data);
krb5_cred_enc_part * pcredenc;
{
krb5_cred_enc_part * ppart;
- krb5_encrypt_block eblock;
krb5_error_code retval;
krb5_data scratch;
return ENOMEM;
if (pkeyblock != NULL) {
- if (!valid_enctype(pcred->enc_part.enctype)) {
- free(scratch.data);
- return KRB5_PROG_ETYPE_NOSUPP;
- }
-
- /* put together an eblock for this decryption */
- krb5_use_enctype(context, &eblock, pcred->enc_part.enctype);
-
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, pkeyblock)))
- goto cleanup;
-
- /* call the decryption routine */
- if ((retval = krb5_decrypt(context,
- (krb5_pointer) pcred->enc_part.ciphertext.data,
- (krb5_pointer) scratch.data,
- scratch.length, &eblock, 0))) {
- (void)krb5_finish_key(context, &eblock);
- goto cleanup;
- }
-
- if ((retval = krb5_finish_key(context, &eblock)))
+ if ((retval = krb5_c_decrypt(context, pkeyblock,
+ KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0,
+ &pcred->enc_part, &scratch)))
goto cleanup;
} else {
memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length);
krb5_error_code retval;
krb5_priv * privmsg;
krb5_data scratch;
- krb5_encrypt_block eblock;
krb5_priv_enc_part * privmsg_enc_part;
+ size_t blocksize;
+ krb5_data ivdata;
if (!krb5_is_krb_priv(inbuf))
return KRB5KRB_AP_ERR_MSG_TYPE;
if ((retval = decode_krb5_priv(inbuf, &privmsg)))
return retval;
- if (!valid_enctype(privmsg->enc_part.enctype)) {
- retval = KRB5_PROG_ETYPE_NOSUPP;
- goto cleanup_privmsg;
+ if (i_vector) {
+ if ((retval = krb5_c_block_size(context, keyblock->enctype,
+ &blocksize)))
+ goto cleanup_privmsg;
+
+ ivdata.length = blocksize;
+ ivdata.data = i_vector;
}
-
- /* put together an eblock for this decryption */
- krb5_use_enctype(context, &eblock, privmsg->enc_part.enctype);
+
scratch.length = privmsg->enc_part.ciphertext.length;
-
if (!(scratch.data = malloc(scratch.length))) {
retval = ENOMEM;
goto cleanup_privmsg;
}
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, keyblock)))
+ if ((retval = krb5_c_decrypt(context, keyblock,
+ KRB5_KEYUSAGE_KRB_PRIV_ENCPART,
+ i_vector?&ivdata:0,
+ &privmsg->enc_part, &scratch)))
goto cleanup_scratch;
- /* call the decryption routine */
- if ((retval = krb5_decrypt(context,
- (krb5_pointer) privmsg->enc_part.ciphertext.data,
- (krb5_pointer) scratch.data,
- scratch.length, &eblock, i_vector))) {
- krb5_finish_key(context, &eblock);
- goto cleanup_scratch;
- }
-
/* if i_vector is set, put last block into the i_vector */
if (i_vector)
memcpy(i_vector,
privmsg->enc_part.ciphertext.data +
- (privmsg->enc_part.ciphertext.length -
- eblock.crypto_entry->block_length),
- eblock.crypto_entry->block_length);
-
- if ((retval = krb5_finish_key(context, &eblock)))
- goto cleanup_scratch;
+ (privmsg->enc_part.ciphertext.length - blocksize),
+ blocksize);
/* now decode the decrypted stuff */
if ((retval = decode_krb5_enc_priv_part(&scratch, &privmsg_enc_part)))
{
krb5_error_code retval;
krb5_ap_rep * reply;
- krb5_encrypt_block eblock;
krb5_data scratch;
if (!krb5_is_ap_rep(inbuf))
/* put together an eblock for this encryption */
- if (!valid_enctype(reply->enc_part.enctype)) {
- krb5_free_ap_rep(context, reply);
- return KRB5_PROG_ETYPE_NOSUPP;
- }
- krb5_use_enctype(context, &eblock, reply->enc_part.enctype);
-
scratch.length = reply->enc_part.ciphertext.length;
if (!(scratch.data = malloc(scratch.length))) {
krb5_free_ap_rep(context, reply);
return(ENOMEM);
}
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock,
- auth_context->keyblock))) {
- goto errout;
- }
-
- /* call the encryption routine */
- if ((retval = krb5_decrypt(context,
- (krb5_pointer) reply->enc_part.ciphertext.data,
- (krb5_pointer) scratch.data,
- scratch.length, &eblock, 0))) {
- (void) krb5_finish_key(context, &eblock);
- goto errout;
- }
-
- /* finished with the top-level encoding of the ap_rep */
- if ((retval = krb5_finish_key(context, &eblock)))
+ if ((retval = krb5_c_decrypt(context, auth_context->keyblock,
+ KRB5_KEYUSAGE_AP_REP_ENCPART, 0,
+ &reply->enc_part, &scratch)))
goto clean_scratch;
/* now decode the decrypted stuff */
*/
static krb5_error_code decrypt_authenticator
- PROTOTYPE((krb5_context, const krb5_ap_req *, krb5_authenticator **));
+ PROTOTYPE((krb5_context, const krb5_ap_req *, krb5_authenticator **,
+ int));
#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
return retval;
}
+ /* XXX this is an evil hack. check_valid_flag is set iff the call
+ is not from inside the kdc. we can use this to determine which
+ key usage to use */
if ((retval = decrypt_authenticator(context, req,
- &((*auth_context)->authentp))))
+ &((*auth_context)->authentp),
+ check_valid_flag)))
goto cleanup;
if (!krb5_principal_compare(context, (*auth_context)->authentp->client,
}
}
+ /* check if the various etypes are permitted */
+
+ if ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) {
+ /* no etype check needed */;
+ } else if ((*auth_context)->permitted_etypes == NULL) {
+ /* check against the default set */
+ if ((!krb5_is_permitted_enctype(context,
+ req->ticket->enc_part.enctype)) ||
+ (!krb5_is_permitted_enctype(context,
+ req->ticket->enc_part2->session->enctype)) ||
+ (((*auth_context)->authentp->subkey) &&
+ !krb5_is_permitted_enctype(context,
+ (*auth_context)->authentp->subkey->enctype))) {
+ retval = KRB5_NOPERM_ETYPE;
+ goto cleanup;
+ }
+ } else {
+ /* check against the set in the auth_context */
+ int i;
+
+ for (i=0; (*auth_context)->permitted_etypes[i]; i++)
+ if ((*auth_context)->permitted_etypes[i] ==
+ req->ticket->enc_part.enctype)
+ break;
+ if (!(*auth_context)->permitted_etypes[i]) {
+ retval = KRB5_NOPERM_ETYPE;
+ goto cleanup;
+ }
+
+ for (i=0; (*auth_context)->permitted_etypes[i]; i++)
+ if ((*auth_context)->permitted_etypes[i] ==
+ req->ticket->enc_part2->session->enctype)
+ break;
+ if (!(*auth_context)->permitted_etypes[i]) {
+ retval = KRB5_NOPERM_ETYPE;
+ goto cleanup;
+ }
+
+ if ((*auth_context)->authentp->subkey) {
+ for (i=0; (*auth_context)->permitted_etypes[i]; i++)
+ if ((*auth_context)->permitted_etypes[i] ==
+ (*auth_context)->authentp->subkey->enctype)
+ break;
+ if (!(*auth_context)->permitted_etypes[i]) {
+ retval = KRB5_NOPERM_ETYPE;
+ goto cleanup;
+ }
+ }
+ }
+
(*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number;
if ((*auth_context)->authentp->subkey) {
if ((retval = krb5_copy_keyblock(context,
(*auth_context)->authentp->subkey,
&((*auth_context)->remote_subkey))))
goto cleanup;
- } else
+ } else {
(*auth_context)->remote_subkey = 0;
+ }
+
if ((retval = krb5_copy_keyblock(context, req->ticket->enc_part2->session,
&((*auth_context)->keyblock))))
goto cleanup;
}
static krb5_error_code
-decrypt_authenticator(context, request, authpp)
+decrypt_authenticator(context, request, authpp, is_ap_req)
krb5_context context;
const krb5_ap_req *request;
krb5_authenticator **authpp;
+ int is_ap_req;
{
krb5_authenticator *local_auth;
krb5_error_code retval;
- krb5_encrypt_block eblock;
krb5_data scratch;
krb5_keyblock *sesskey;
sesskey = request->ticket->enc_part2->session;
- if (!valid_enctype(sesskey->enctype))
- return KRB5_PROG_ETYPE_NOSUPP;
-
- /* put together an eblock for this encryption */
-
- krb5_use_enctype(context, &eblock, request->authenticator.enctype);
-
scratch.length = request->authenticator.ciphertext.length;
if (!(scratch.data = malloc(scratch.length)))
return(ENOMEM);
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, sesskey))) {
+ if ((retval = krb5_c_decrypt(context, sesskey,
+ is_ap_req?KRB5_KEYUSAGE_AP_REQ_AUTH:
+ KRB5_KEYUSAGE_TGS_REQ_AUTH, 0,
+ &request->authenticator, &scratch))) {
free(scratch.data);
return(retval);
}
- /* call the encryption routine */
- if ((retval = krb5_decrypt(context,
- (krb5_pointer)request->authenticator.ciphertext.data,
- (krb5_pointer)scratch.data,
- scratch.length, &eblock, 0))) {
- (void) krb5_finish_key(context, &eblock);
- free(scratch.data);
- return retval;
- }
#define clean_scratch() {memset(scratch.data, 0, scratch.length); \
free(scratch.data);}
- if ((retval = krb5_finish_key(context, &eblock))) {
- clean_scratch();
- return retval;
- }
/* now decode the decrypted stuff */
if (!(retval = decode_krb5_authenticator(&scratch, &local_auth))) {
*authpp = local_auth;
krb5_checksum our_cksum, *his_cksum;
krb5_octet zero_octet = 0;
krb5_data *scratch;
+ krb5_boolean valid;
if (!krb5_is_krb_safe(inbuf))
return KRB5KRB_AP_ERR_MSG_TYPE;
message->checksum = his_cksum;
- retval = krb5_verify_checksum(context, his_cksum->checksum_type,
- his_cksum, scratch->data, scratch->length,
- (krb5_pointer) keyblock->contents,
- keyblock->length);
+ retval = krb5_c_verify_checksum(context, keyblock,
+ KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
+ scratch, his_cksum, &valid);
+
(void) memset((char *)scratch->data, 0, scratch->length);
krb5_free_data(context, scratch);
- if (retval) {
+ if (!valid) {
retval = KRB5KRB_AP_ERR_MODIFIED;
goto cleanup;
}
krb5_checksum checksum;
krb5_authenticator authent;
krb5_ap_req request;
- krb5_encrypt_block eblock;
krb5_data * scratch;
krb5_data * toutbuf;
/* Generate checksum */
- checksum.length = krb5_checksum_size(context, context->kdc_req_sumtype);
- if ((checksum.contents = (krb5_octet *) malloc(checksum.length)) == NULL)
- return(ENOMEM);
-
- if ((retval = krb5_calculate_checksum(context, context->kdc_req_sumtype,
- in_data->data, in_data->length,
- (krb5_pointer) in_cred->keyblock.contents,
- in_cred->keyblock.length,
- &checksum))) {
- free(checksum.contents);
+ if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype,
+ &in_cred->keyblock,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
+ in_data, &checksum))) {
+ free(checksum.contents);
return(retval);
}
/* Cleanup scratch and scratch data */
goto cleanup_data;
- /* put together an eblock for this encryption */
- krb5_use_enctype(context, &eblock, in_cred->keyblock.enctype);
- request.authenticator.enctype = in_cred->keyblock.enctype;
- request.authenticator.ciphertext.length =
- krb5_encrypt_size(scratch->length, eblock.crypto_entry);
-
- /* add padding area, and zero it */
- if (!(scratch->data = realloc(scratch->data,
- request.authenticator.ciphertext.length))) {
- /* may destroy scratch->data */
- krb5_free_ticket(context, request.ticket);
- retval = ENOMEM;
- goto cleanup_scratch;
- }
- memset(scratch->data + scratch->length, 0,
- request.authenticator.ciphertext.length - scratch->length);
-
- if (!(request.authenticator.ciphertext.data =
- malloc(request.authenticator.ciphertext.length))) {
- retval = ENOMEM;
- goto cleanup_ticket;
- }
-
- /* do any necessary key pre-processing */
- if ((retval = krb5_process_key(context, &eblock, &(in_cred)->keyblock)))
- goto cleanup;
-
/* call the encryption routine */
- if ((retval=krb5_encrypt(context, (krb5_pointer) scratch->data,
- (krb5_pointer)request.authenticator.ciphertext.data,
- scratch->length, &eblock, 0))) {
- krb5_finish_key(context, &eblock);
- goto cleanup;
- }
-
- if ((retval = krb5_finish_key(context, &eblock)))
- goto cleanup;
+ if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH,
+ scratch, &request.authenticator)))
+ goto cleanup_ticket;
retval = encode_krb5_ap_req(&request, &toutbuf);
*outbuf = *toutbuf;
krb5_timestamp time_now;
krb5_pa_data **combined_padata;
krb5_pa_data ap_req_padata;
+ size_t enclen;
/*
* in_creds MUST be a valid credential NOT just a partially filled in
if (authorization_data) {
/* need to encrypt it in the request */
- krb5_encrypt_block eblock;
if ((retval = encode_krb5_authdata((const krb5_authdata**)authorization_data,
&scratch)))
return(retval);
- krb5_use_enctype(context, &eblock, in_cred->keyblock.enctype);
- tgsreq.authorization_data.enctype = in_cred->keyblock.enctype;
- tgsreq.authorization_data.kvno = 0; /* ticket session key has */
- /* no version */
- tgsreq.authorization_data.ciphertext.length =
- krb5_encrypt_size(scratch->length, eblock.crypto_entry);
- /* add padding area, and zero it */
- if (!(scratch->data = realloc(scratch->data,
- tgsreq.authorization_data.ciphertext.length))) {
- /* may destroy scratch->data */
- krb5_xfree(scratch);
- return ENOMEM;
- }
- memset(scratch->data + scratch->length, 0,
- tgsreq.authorization_data.ciphertext.length - scratch->length);
- if (!(tgsreq.authorization_data.ciphertext.data =
- malloc(tgsreq.authorization_data.ciphertext.length))) {
- krb5_free_data(context, scratch);
- return ENOMEM;
- }
- if ((retval = krb5_process_key(context, &eblock,
- &in_cred->keyblock))) {
- krb5_free_data(context, scratch);
- return retval;
- }
- /* call the encryption routine */
- if ((retval = krb5_encrypt(context, (krb5_pointer) scratch->data,
- (krb5_pointer) tgsreq.authorization_data.ciphertext.data,
- scratch->length, &eblock, 0))) {
- (void) krb5_finish_key(context, &eblock);
+
+ if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
+ KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
+ scratch,
+ &tgsreq.authorization_data))) {
krb5_xfree(tgsreq.authorization_data.ciphertext.data);
krb5_free_data(context, scratch);
return retval;
- }
- krb5_free_data(context, scratch);
- if ((retval = krb5_finish_key(context, &eblock))) {
- krb5_xfree(tgsreq.authorization_data.ciphertext.data);
- return retval;
}
+
+ krb5_free_data(context, scratch);
}
/* Get the encryption types list */
krb5_error_code krb5_ser_address_init KRB5_PROTOTYPE((krb5_context));
krb5_error_code krb5_ser_authenticator_init KRB5_PROTOTYPE((krb5_context));
krb5_error_code krb5_ser_checksum_init KRB5_PROTOTYPE((krb5_context));
-krb5_error_code krb5_ser_encrypt_block_init KRB5_PROTOTYPE((krb5_context));
krb5_error_code krb5_ser_keyblock_init KRB5_PROTOTYPE((krb5_context));
krb5_error_code krb5_ser_principal_init KRB5_PROTOTYPE((krb5_context));
*/
kret = EINVAL;
if ((auth_context = (krb5_auth_context) arg)) {
- required = sizeof(krb5_int32)*8;
-
kret = 0;
+
/* Calculate size required by i_vector - ptooey */
- if (auth_context->i_vector && auth_context->keyblock)
- required += (size_t)
- krb5_enctype_array[auth_context->keyblock->enctype]->
- system->block_length;
+ if (auth_context->i_vector && auth_context->keyblock) {
+ kret = krb5_c_block_size(kcontext, auth_context->keyblock->enctype,
+ &required);
+ } else {
+ required = 0;
+ }
+
+ required += sizeof(krb5_int32)*8;
/* Calculate size required by remote_addr, if appropriate */
- if (auth_context->remote_addr) {
+ if (!kret && auth_context->remote_addr) {
kret = krb5_size_opaque(kcontext,
KV5M_ADDRESS,
(krb5_pointer) auth_context->remote_addr,
(void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype,
&bp, &remain);
+ kret = 0;
+
/* Now figure out the number of bytes for i_vector and write it */
- obuf = (!auth_context->i_vector) ? 0 : (krb5_int32)
- krb5_enctype_array[auth_context->keyblock->enctype]->
- system->block_length;
- (void) krb5_ser_pack_int32(obuf, &bp, &remain);
+ if (auth_context->i_vector) {
+ kret = krb5_c_block_size(kcontext,
+ auth_context->keyblock->enctype,
+ &obuf);
+ } else {
+ obuf = 0;
+ }
+
+ if (!kret)
+ (void) krb5_ser_pack_int32(obuf, &bp, &remain);
/* Now copy i_vector */
- if (auth_context->i_vector)
+ if (!kret && auth_context->i_vector)
(void) krb5_ser_pack_bytes(auth_context->i_vector,
(size_t) obuf,
&bp, &remain);
- kret = 0;
/* Now handle remote_addr, if appropriate */
if (!kret && auth_context->remote_addr) {
kret = krb5_ser_authenticator_init(kcontext);
if (!kret)
kret = krb5_ser_checksum_init(kcontext);
- if (!kret)
- kret = krb5_ser_encrypt_block_init(kcontext);
if (!kret)
kret = krb5_ser_keyblock_init(kcontext);
if (!kret)
*
*/
+#if 0 /* i don't believe this is used anywhere --marc */
+
/*
* ser_eblk.c - Serialize a krb5_encblock structure.
*/
{
return(krb5_register_serializer(kcontext, &krb5_encrypt_block_ser_entry));
}
+
+#endif
*
* String decoding:
* ----------------
- * krb5_string_to_enctype() - Convert string to krb5_enctype.
* krb5_string_to_salttype() - Convert string to salttype (krb5_int32)
- * krb5_string_to_cksumtype() - Convert string to krb5_cksumtype;
* krb5_string_to_timestamp() - Convert string to krb5_timestamp.
* krb5_string_to_deltat() - Convert string to krb5_deltat.
*
* String encoding:
* ----------------
- * krb5_enctype_to_string() - Convert krb5_enctype to string.
* krb5_salttype_to_string() - Convert salttype (krb5_int32) to string.
- * krb5_cksumtype_to_string() - Convert krb5_cksumtype to string.
* krb5_timestamp_to_string() - Convert krb5_timestamp to string.
* krb5_timestamp_to_sfstring() - Convert krb5_timestamp to short filled string
* krb5_deltat_to_string() - Convert krb5_deltat to string.
/*
* Local data structures.
*/
-struct enctype_lookup_entry {
- krb5_enctype ktt_enctype; /* Keytype */
- const char * ktt_specifier; /* How to recognize it */
- const char * ktt_output; /* How to spit it out */
-};
-
struct salttype_lookup_entry {
krb5_int32 stt_enctype; /* Salt type */
const char * stt_specifier; /* How to recognize it */
const char * stt_output; /* How to spit it out */
};
-struct cksumtype_lookup_entry {
- krb5_cksumtype cst_cksumtype; /* Checksum type */
- const char * cst_specifier; /* How to recognize it */
- const char * cst_output; /* How to spit it out */
-};
-
struct deltat_match_entry {
const char * dt_scan_format; /* sscanf format */
int dt_nmatch; /* Number to match */
* Local strings
*/
-/* Keytype strings */
-static const char enctype_des_in[] = "des";
-static const char enctype_null_in[] = "null";
-static const char enctype_descbccrc_in[] = "des-cbc-crc";
-static const char enctype_descbcmd4_in[] = "des-cbc-md4";
-static const char enctype_descbcmd5_in[] = "des-cbc-md5";
-static const char enctype_des3cbcsha_in[] = "des3-cbc-sha";
-static const char enctype_descbcraw_in[] = "des-cbc-raw";
-static const char enctype_null_out[] = "Null";
-static const char enctype_descbccrc_out[] = "DES cbc mode with CRC-32";
-static const char enctype_descbcmd4_out[] = "DES cbc mode with RSA-MD4";
-static const char enctype_descbcmd5_out[] = "DES cbc mode with RSA-MD5";
-static const char enctype_des3cbcsha_out[] = "DES-3 cbc mode with NIST-SHA";
-static const char enctype_descbcraw_out[] = "DES cbc mode raw";
-
/* Salttype strings */
static const char stype_v5_in[] = "normal";
static const char stype_v4_in[] = "v4";
static const char stype_special_out[] = "Special";
static const char stype_afs3_out[] = "AFS version 3";
-/* Checksum type strings */
-static const char cstype_crc32_in[] = "crc32";
-static const char cstype_md4_in[] = "md4";
-static const char cstype_md4des_in[] = "md4-des";
-static const char cstype_descbc_in[] = "des-cbc";
-static const char cstype_md5_in[] = "md5";
-static const char cstype_md5des_in[] = "md5-des";
-static const char cstype_sha_in[] = "sha";
-static const char cstype_hmacsha_in[] = "hmac-sha";
-static const char cstype_crc32_out[] = "CRC-32";
-static const char cstype_md4_out[] = "RSA-MD4";
-static const char cstype_md4des_out[] = "RSA-MD4 with DES cbc mode";
-static const char cstype_descbc_out[] = "DES cbc mode";
-static const char cstype_md5_out[] = "RSA-MD5";
-static const char cstype_md5des_out[] = "RSA-MD5 with DES cbc mode";
-static const char cstype_sha_out[] = "NIST-SHA";
-static const char cstype_hmacsha_out[] = "HMAC-SHA";
-
/* Absolute time strings */
static const char atime_full_digits[] = "%y%m%d%H%M%S";
static const char atime_full_digits_d[] = "%y.%m.%d.%H.%M.%S";
* Lookup tables.
*/
-static const struct enctype_lookup_entry enctype_table[] = {
-/* krb5_enctype input specifier output string */
-/*------------- ----------------------- ------------------------*/
-{ ENCTYPE_NULL, enctype_null_in, enctype_null_out },
-{ ENCTYPE_DES_CBC_MD5, enctype_des_in, enctype_descbcmd5_out },
-{ ENCTYPE_DES_CBC_CRC, enctype_descbccrc_in, enctype_descbccrc_out },
-{ ENCTYPE_DES_CBC_MD4, enctype_descbcmd4_in, enctype_descbcmd4_out },
-{ ENCTYPE_DES_CBC_MD5, enctype_descbcmd5_in, enctype_descbcmd5_out },
-{ ENCTYPE_DES3_CBC_SHA, enctype_des3cbcsha_in, enctype_des3cbcsha_out },
-{ ENCTYPE_DES_CBC_RAW, enctype_descbcraw_in, enctype_descbcraw_out }
-};
-static const int enctype_table_nents = sizeof(enctype_table)/
- sizeof(enctype_table[0]);
-
static const struct salttype_lookup_entry salttype_table[] = {
/* salt type input specifier output string */
/*----------------------------- ----------------------- ------------------*/
static const int salttype_table_nents = sizeof(salttype_table)/
sizeof(salttype_table[0]);
-static const struct cksumtype_lookup_entry cksumtype_table[] = {
-/* krb5_cksumtype input specifier output string */
-/*----------------------- --------------------- ------------------------*/
-{ CKSUMTYPE_CRC32, cstype_crc32_in, cstype_crc32_out },
-{ CKSUMTYPE_RSA_MD4, cstype_md4_in, cstype_md4_out },
-{ CKSUMTYPE_RSA_MD4_DES, cstype_md4des_in, cstype_md4des_out },
-{ CKSUMTYPE_DESCBC, cstype_descbc_in, cstype_descbc_out },
-{ CKSUMTYPE_RSA_MD5, cstype_md5_in, cstype_md5_out },
-{ CKSUMTYPE_RSA_MD5_DES, cstype_md5des_in, cstype_md5des_out },
-{ CKSUMTYPE_NIST_SHA, cstype_sha_in, cstype_sha_out },
-{ CKSUMTYPE_HMAC_SHA, cstype_hmacsha_in, cstype_hmacsha_out }
-};
-static const int cksumtype_table_nents = sizeof(cksumtype_table)/
- sizeof(cksumtype_table[0]);
-
static const char * const atime_format_table[] = {
atime_full_digits_Y, /* yyyymmddhhmmss */
atime_full_digits_Yd, /* yyyy.mm.dd.hh.mm.ss */
}
#endif /* HAVE_STRPTIME */
\f
-/*
- * String to internal datatype routines.
- *
- * These routines return 0 for success, EINVAL for invalid entry.
- */
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_string_to_enctype(string, enctypep)
- char FAR * string;
- krb5_enctype FAR * enctypep;
-{
- int i;
- int found;
-
- found = 0;
- for (i=0; i<enctype_table_nents; i++) {
- if (!strcasecmp(string, enctype_table[i].ktt_specifier)) {
- found = 1;
- *enctypep = enctype_table[i].ktt_enctype;
- break;
- }
- }
- return((found) ? 0 : EINVAL);
-}
-
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
krb5_string_to_salttype(string, salttypep)
char FAR * string;
return((found) ? 0 : EINVAL);
}
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_string_to_cksumtype(string, cksumtypep)
- char FAR * string;
- krb5_cksumtype FAR * cksumtypep;
-{
- int i;
- int found;
-
- found = 0;
- for (i=0; i<cksumtype_table_nents; i++) {
- if (!strcasecmp(string, cksumtype_table[i].cst_specifier)) {
- found = 1;
- *cksumtypep = cksumtype_table[i].cst_cksumtype;
- break;
- }
- }
- return((found) ? 0 : EINVAL);
-}
-
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
krb5_string_to_timestamp(string, timestampp)
char FAR * string;
* These routines return 0 for success, EINVAL for invalid parameter, ENOMEM
* if the supplied buffer/length will not contain the output.
*/
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_enctype_to_string(enctype, buffer, buflen)
- krb5_enctype enctype;
- char FAR * buffer;
- size_t buflen;
-{
- int i;
- const char *out;
-
- out = (char *) NULL;
- for (i=0; i<enctype_table_nents; i++) {
- if (enctype == enctype_table[i].ktt_enctype) {
- out = enctype_table[i].ktt_output;
- break;
- }
- }
- if (out) {
- if (buflen > strlen(out))
- strcpy(buffer, out);
- else
- out = (char *) NULL;
- return((out) ? 0 : ENOMEM);
- }
- else
- return(EINVAL);
-}
-
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
krb5_salttype_to_string(salttype, buffer, buflen)
krb5_int32 salttype;
krb5_creds in_creds, *out_creds;
krb5_auth_context authcon;
krb5_data ap_req;
- int keytab_key_exists, rd_req_succeeds, nofail;
- keytab_key_exists = 0;
- rd_req_succeeds = 0;
- nofail = 0;
-
/* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */
server = NULL;
goto cleanup;
}
- if (ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))
- goto cleanup;
+ if (ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte)) {
+ /* this means there is no keying material. This is ok, as long as
+ it is not prohibited by the configuration */
+
+ krb5_error_code ret2;
+ int nofail;
+
+ if (options &&
+ (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL)) {
+ if (options->ap_req_nofail)
+ goto cleanup;
+ } else if ((ret2 = krb5_appdefault_boolean(context,
+ &creds->client->realm,
+ "verify_ap_req_nofail",
+ &nofail))
+ == 0) {
+ if (nofail)
+ goto cleanup;
+ }
+
+ ret = 0;
+ goto cleanup;
+ }
krb5_kt_free_entry(context, &kte);
- keytab_key_exists = 1;
/* If the creds are for the server principal, we're set, just do
a mk_req. Otherwise, do a get_credentials first. */
NULL, NULL))
goto cleanup;
- rd_req_succeeds = 1;
-
-cleanup:
- /* I could test the error case first, but then there would be a
- chance that the verification would succeed when there was
- actually a significant failure (some transient condition could
- make rd_req fail, and this would not be a problem if nofail was
- not set */
-
- if (!keytab_key_exists) {
- krb5_error_code ret2;
-
- if (options &&
- (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL))
- nofail = options->ap_req_nofail;
- else if ((ret2 = krb5_appdefault_boolean(context, &creds->client->realm,
- "verify_ap_req_nofail",
- &nofail))
- == 0)
- ;
- else
- nofail = 0;
- }
-
- if ((keytab_key_exists && rd_req_succeeds) ||
- (!keytab_key_exists && !nofail)) {
- ret = 0;
+ /* if we get this far, then the verification succeeded. We can
+ still fail if the library stuff here fails, but that's it */
- if (ccache_arg && ccache) {
- if (*ccache_arg == NULL) {
- krb5_ccache retcc;
+ if (ccache_arg && ccache) {
+ if (*ccache_arg == NULL) {
+ krb5_ccache retcc;
- retcc = NULL;
+ retcc = NULL;
- if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) ||
- (ret = krb5_cc_initialize(context, retcc, creds->client)) ||
- (ret = krb5_cc_copy_creds_except(context, ccache, retcc,
- creds->server))) {
+ if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) ||
+ (ret = krb5_cc_initialize(context, retcc, creds->client)) ||
+ (ret = krb5_cc_copy_creds_except(context, ccache, retcc,
+ creds->server))) {
if (retcc)
- krb5_cc_destroy(context, retcc);
- } else {
+ krb5_cc_destroy(context, retcc);
+ } else {
*ccache_arg = retcc;
- }
- } else {
- /* if this returns an error, then that's the return
- from this function */
- ret = krb5_cc_copy_creds_except(context, ccache, *ccache_arg,
- server);
- }
- }
+ }
+ } else {
+ ret = krb5_cc_copy_creds_except(context, ccache, *ccache_arg,
+ server);
+ }
}
- if (!server_arg)
+ /* if any of the above paths returned an errors, then ret is set
+ accordingly. either that, or it's zero, which is fine, too */
+
+cleanup:
+ if (!server_arg && server)
krb5_free_principal(context, server);
- if (!keytab_arg)
+ if (!keytab_arg && keytab)
krb5_kt_close(context, keytab);
if (ccache)
krb5_cc_destroy(context, ccache);
return(ret);
}
-
-
-
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * c_ustime.c, localaddr.c: moved here from lib/crypto
+
+ * ktdefname.c (krb5_kt_default_name): there is code in the tree
+ (notably, the admin server code) which uses globals to set the
+ keytab which will be used by gssapi. this is gross, and we need a
+ better answer. However, even that didn't work if there was an env
+ var or krb5.conf variable, since those override krb5_defkeyname.
+ Add a new global, krb5_overridekeyname, which really does override
+ all the other keytab locators. While I'm at it, make the buffer
+ overflow checks sane.
+
Fri Sep 25 22:32:16 1998 Theodore Y. Ts'o <tytso@mit.edu>
* ccdefname.c: We shouldn't try to use the CCache API on Unix
STLIBOBJS= \
an_to_ln.o \
+ c_ustime.o \
def_realm.o \
DNR.o \
ccdefname.o \
OBJS= \
an_to_ln.$(OBJEXT) \
+ c_ustime.$(OBJEXT) \
def_realm.$(OBJEXT) \
DNR.$(OBJEXT) \
ccdefname.$(OBJEXT) \
SRCS= \
$(srcdir)/an_to_ln.c \
+ $(srcdir)/c_ustime.c \
$(srcdir)/def_realm.c \
$(srcdir)/DNR.c \
$(srcdir)/ccdefname.c \
#define NEED_SOCKETS
#include "k5-int.h"
-#ifdef macintosh
+#ifdef _MACINTOSH
/* We're a Macintosh -- do Mac time things. */
extern char *krb5_defkeyname;
+/* this is a an exceedinly gross thing. */
+char *krb5_overridekeyname = NULL;
+
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
krb5_kt_default_name(context, name, namesize)
krb5_context context;
krb5_error_code code;
char *retval;
- if ((context->profile_secure == FALSE) &&
+ if (krb5_overridekeyname) {
+ if ((size_t) namesize < (strlen(krb5_overridekeyname)+1))
+ return KRB5_CONFIG_NOTENUFSPACE;
+ strcpy(name, krb5_overridekeyname);
+ } else if ((context->profile_secure == FALSE) &&
(cp = getenv("KRB5_KTNAME"))) {
- strncpy(name, cp, namesize);
- if (strlen(cp) >= (size_t) namesize)
+ if ((size_t) namesize < (strlen(cp)+1))
return KRB5_CONFIG_NOTENUFSPACE;
+ strcpy(name, cp);
} else if (((code = profile_get_string(context->profile,
"libdefaults",
"default_keytab_name", NULL,
NULL, &retval)) == 0) &&
retval) {
- strncpy(name, retval, namesize);
- if ((size_t) namesize < strlen(retval))
+ if ((size_t) namesize < (strlen(retval)+1))
return KRB5_CONFIG_NOTENUFSPACE;
+ strcpy(name, retval);
+ free(retval);
} else {
#if defined (_MSDOS) || defined(_WIN32)
{
sprintf(name, krb5_defkeyname, defname);
}
#else
- strncpy(name, krb5_defkeyname, namesize);
- if ((size_t) namesize < strlen(krb5_defkeyname))
+ if ((size_t) namesize < (strlen(krb5_defkeyname)+1))
return KRB5_CONFIG_NOTENUFSPACE;
+ strcpy(name, krb5_defkeyname);
#endif
}
return 0;
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
- * Just a stub that calls krb5_crypto_os_localaddr().
*
+ * Return the protocol addresses supported by this host.
+ *
+ * XNS support is untested, but "Should just work".
*/
+#define NEED_SOCKETS
#include "k5-int.h"
+#if !defined(HAVE_MACSOCK_H) && !defined(_MSDOS) && !defined(_WIN32)
+
+/* needed for solaris, harmless elsewhere... */
+#define BSD_COMP
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <errno.h>
+
+/*
+ * The SIOCGIF* ioctls require a socket.
+ * It doesn't matter *what* kind of socket they use, but it has to be
+ * a socket.
+ *
+ * Of course, you can't just ask the kernel for a socket of arbitrary
+ * type; you have to ask for one with a valid type.
+ *
+ */
+#ifdef HAVE_NETINET_IN_H
+
+#include <netinet/in.h>
+
+#ifndef USE_AF
+#define USE_AF AF_INET
+#define USE_TYPE SOCK_DGRAM
+#define USE_PROTO 0
+#endif
+
+#endif
+
+#ifdef KRB5_USE_NS
+
+#include <netns/ns.h>
+
+#ifndef USE_AF
+#define USE_AF AF_NS
+#define USE_TYPE SOCK_DGRAM
+#define USE_PROTO 0 /* guess */
+#endif
+
+#endif
+/*
+ * Add more address families here.
+ */
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+ sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN*/
+
+
+
+extern int errno;
+
+/*
+ * Return all the protocol addresses of this host.
+ *
+ * We could kludge up something to return all addresses, assuming that
+ * they're valid kerberos protocol addresses, but we wouldn't know the
+ * real size of the sockaddr or know which part of it was actually the
+ * host part.
+ *
+ * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
+ */
+
KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
krb5_os_localaddr(context, addr)
krb5_context context;
krb5_address FAR * FAR * FAR *addr;
{
- return krb5_crypto_os_localaddr(addr);
+ struct ifreq *ifr, ifreq;
+ struct ifconf ifc;
+ int s, code, n, i;
+ char buf[1024];
+ krb5_address *addr_temp [ 1024/sizeof(struct ifreq) ];
+ int n_found;
+ int mem_err = 0;
+
+ memset(buf, 0, sizeof(buf));
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+
+ s = socket (USE_AF, USE_TYPE, USE_PROTO);
+ if (s < 0)
+ return errno;
+
+ code = ioctl (s, SIOCGIFCONF, (char *)&ifc);
+ if (code < 0) {
+ int retval = errno;
+ closesocket (s);
+ return retval;
+ }
+ n = ifc.ifc_len;
+
+n_found = 0;
+ for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
+ krb5_address *address;
+ ifr = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
+
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
+ if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0)
+ continue;
+
+#ifdef IFF_LOOPBACK
+ if (ifreq.ifr_flags & IFF_LOOPBACK)
+ continue;
+#endif
+
+ if (!(ifreq.ifr_flags & IFF_UP))
+ /* interface is down; skip */
+ continue;
+
+ /* ifr->ifr_addr has what we want! */
+ switch (ifr->ifr_addr.sa_family) {
+#ifdef HAVE_NETINET_IN_H
+ case AF_INET:
+ {
+ struct sockaddr_in *in =
+ (struct sockaddr_in *)&ifr->ifr_addr;
+
+ address = (krb5_address *)
+ malloc (sizeof(krb5_address));
+ if (address) {
+ address->magic = KV5M_ADDRESS;
+ address->addrtype = ADDRTYPE_INET;
+ address->length = sizeof(struct in_addr);
+ address->contents = (unsigned char *)malloc(address->length);
+ if (!address->contents) {
+ krb5_xfree(address);
+ address = 0;
+ mem_err++;
+ } else {
+ memcpy ((char *)address->contents,
+ (char *)&in->sin_addr,
+ address->length);
+ break;
+ }
+ } else mem_err++;
+ }
+#endif
+#ifdef KRB5_USE_NS
+ case AF_XNS:
+ {
+ struct sockaddr_ns *ns =
+ (struct sockaddr_ns *)&ifr->ifr_addr;
+ address = (krb5_address *)
+ malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
+ if (address) {
+ address->magic = KV5M_ADDRESS;
+ address->addrtype = ADDRTYPE_XNS;
+
+ /* XXX should we perhaps use ns_host instead? */
+
+ address->length = sizeof(struct ns_addr);
+ address->contents = (unsigned char *)malloc(address->length);
+ if (!address->contents) {
+ krb5_xfree(address);
+ address = 0;
+ mem_err++;
+ } else {
+ memcpy ((char *)address->contents,
+ (char *)&ns->sns_addr,
+ address->length);
+ break;
+ }
+ } else mem_err++;
+ break;
+ }
+#endif
+ /*
+ * Add more address families here..
+ */
+ default:
+ continue;
+ }
+ if (address)
+ addr_temp[n_found++] = address;
+ address = 0;
+ }
+ closesocket(s);
+
+ *addr = (krb5_address **)malloc (sizeof (krb5_address *) * (n_found+1));
+ if (*addr == 0)
+ mem_err++;
+
+ if (mem_err) {
+ for (i=0; i<n_found; i++) {
+ krb5_xfree(addr_temp[i]);
+ addr_temp[i] = 0;
+ }
+ return ENOMEM;
+ }
+
+ for (i=0; i<n_found; i++) {
+ (*addr)[i] = addr_temp[i];
+ }
+ (*addr)[n_found] = 0;
+ return 0;
+}
+
+#else /* Windows/Mac version */
+
+/*
+ * Hold on to your lunch! Backup kludge method of obtaining your
+ * local IP address, courtesy of Windows Socket Network Programming,
+ * by Robert Quinn
+ */
+#if defined(_MSDOS) || defined(_WIN32)
+static struct hostent *local_addr_fallback_kludge()
+{
+ static struct hostent host;
+ static SOCKADDR_IN addr;
+ static char * ip_ptrs[2];
+ SOCKET sock;
+ int size = sizeof(SOCKADDR);
+ int err;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET)
+ return NULL;
+
+ /* connect to arbitrary port and address (NOT loopback) */
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(IPPORT_ECHO);
+ addr.sin_addr.s_addr = inet_addr("204.137.220.51");
+
+ err = connect(sock, (LPSOCKADDR) &addr, sizeof(SOCKADDR));
+ if (err == SOCKET_ERROR)
+ return NULL;
+
+ err = getsockname(sock, (LPSOCKADDR) &addr, (int FAR *) size);
+ if (err == SOCKET_ERROR)
+ return NULL;
+
+ closesocket(sock);
+
+ host.h_name = 0;
+ host.h_aliases = 0;
+ host.h_addrtype = AF_INET;
+ host.h_length = 4;
+ host.h_addr_list = ip_ptrs;
+ ip_ptrs[0] = (char *) &addr.sin_addr.s_addr;
+ ip_ptrs[1] = NULL;
+
+ return &host;
+}
+#endif
+
+/* No ioctls in winsock so we just assume there is only one networking
+ * card per machine, so gethostent is good enough.
+ */
+krb5_error_code
+krb5_os_localaddr (krb5_context context, krb5_address ***addr) {
+ char host[64]; /* Name of local machine */
+ struct hostent *hostrec;
+ int err;
+
+ *addr = calloc (2, sizeof (krb5_address *));
+ if (*addr == NULL)
+ return ENOMEM;
+
+#ifdef HAVE_MACSOCK_H
+ hostrec = getmyipaddr();
+#else /* HAVE_MACSOCK_H */
+ err = 0;
+
+ if (gethostname (host, sizeof(host))) {
+ err = WSAGetLastError();
+ }
+
+ if (!err) {
+ hostrec = gethostbyname (host);
+ if (hostrec == NULL) {
+ err = WSAGetLastError();
+ }
+ }
+
+ if (err) {
+ hostrec = local_addr_fallback_kludge();
+ if (!hostrec)
+ return err;
+ }
+#endif /* HAVE_MACSOCK_H */
+
+ (*addr)[0] = calloc (1, sizeof(krb5_address));
+ if ((*addr)[0] == NULL) {
+ free (*addr);
+ return ENOMEM;
+ }
+ (*addr)[0]->magic = KV5M_ADDRESS;
+ (*addr)[0]->addrtype = hostrec->h_addrtype;
+ (*addr)[0]->length = hostrec->h_length;
+ (*addr)[0]->contents = (unsigned char *)malloc((*addr)[0]->length);
+ if (!(*addr)[0]->contents) {
+ free((*addr)[0]);
+ free(*addr);
+ return ENOMEM;
+ } else {
+ memcpy ((*addr)[0]->contents,
+ hostrec->h_addr,
+ (*addr)[0]->length);
+ }
+ /* FIXME, deal with the case where gethostent returns multiple addrs */
+
+ return(0);
}
+#endif
const char *realm_kdc_names[4];
char **masterlist, **hostlist, *host, *port, *cp;
krb5_error_code code;
- int i, j, out, count;
+ int i, j, out, count, ismaster;
struct sockaddr *addr_p;
struct sockaddr_in *sin_p;
struct hostent *hp;
}
if (master_index) {
+ *master_index = 0;
+ *nmasters = 0;
+
realm_kdc_names[0] = "realms";
realm_kdc_names[1] = host;
realm_kdc_names[2] = "admin_server";
krb5_xfree(host);
- if (code) {
- *master_index = 0;
- *nmasters = 0;
- } else {
+ if (code == 0) {
for (i=0; masterlist[i]; i++) {
host = masterlist[i];
krb5_xfree(host);
}
- /* at this point, is master is non-NULL, then either the master kdc
+ /* at this point, if master is non-NULL, then either the master kdc
is required, and there is one, or the master kdc is not required,
and there may or may not be one. */
-
#ifdef HAVE_NETINET_IN_H
if (sec_udpport)
count = count * 2;
continue;
}
- if (masterlist)
- for (j=0; masterlist[j]; j++)
- if (strcasecmp(hostlist[i], masterlist[j]) == 0)
+ ismaster = 0;
+ if (masterlist) {
+ for (j=0; masterlist[j]; j++) {
+ if (strcasecmp(hostlist[i], masterlist[j]) == 0) {
*master_index = out;
+ ismaster = 1;
+ }
+ }
+ }
switch (hp->h_addrtype) {
default:
break;
}
- if (masterlist)
+ if (ismaster)
*nmasters = out - *master_index;
/* Free the hostlist entry we are looping over. */
hostlist[i] = 0;
}
+ if (masterlist) {
+ for (i=0; masterlist[i]; i++)
+ free(masterlist[i]);
+ free(masterlist);
+ }
free ((char *)hostlist);
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * svc_auth_gssapi.c, auth_gssapi.h: fix the set_name prototype,
+ add a new unset_names function
+
+Sun Jul 26 18:13:39 1998 Sam Hartman <hartmans@utwig.mesas.com>
+
+ * Makefile.in (LIBMAJOR): bump libmajor
+
Wed Apr 15 18:07:38 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in (SHLIB_EXPDEPS):
##DOSLIBNAME=libgssrpc.lib
LIB=gssrpc
-LIBMAJOR=2
+LIBMAJOR=3
LIBMINOR=0
STOBJLISTS=OBJS.ST
SHLIB_EXPDEPS= \
void auth_gssapi_display_status
PROTOTYPE((char *msg, OM_uint32 major,
OM_uint32 minor));
-bool_t _svcauth_gssapi_set_name
-PROTOTYPE((char *name, gss_OID name_type));
+bool_t _svcauth_gssapi_set_names
+PROTOTYPE((auth_gssapi_name *names, int num));
+void _svcauth_gssapi_unset_names
+PROTOTYPE(());
void _svcauth_set_log_badauth_func
PROTOTYPE((auth_gssapi_log_badauth_func func,
}
/*
- * Function: _svcauth_gssapi_set_name
+ * Function: _svcauth_gssapi_set_names
*
* Purpose: Sets the list of service names for which incoming
* authentication requests should be honored.
if (server_name_list == NULL)
goto fail;
+ for (i = 0; i < num; i++) {
+ server_name_list[i] = 0;
+ server_creds_list[i] = 0;
+ }
+
+ server_creds_count = num;
+
for (i = 0; i < num; i++) {
in_buf.value = names[i].name;
in_buf.length = strlen(in_buf.value) + 1;
}
}
- server_creds_count = num;
-
return TRUE;
fail:
- /* memory leak: not releasing names/creds already acquired */
- if (server_creds_list)
+ _svcauth_gssapi_unset_names();
+
+ return FALSE;
+}
+
+/* Function: _svcauth_gssapi_unset_names
+ *
+ * Purpose: releases the names and credentials allocated by
+ * _svcauth_gssapi_set_names
+ */
+
+void _svcauth_gssapi_unset_names()
+{
+ int i;
+ OM_uint32 minor_stat;
+
+ if (server_creds_list) {
+ for (i = 0; i < server_creds_count; i++)
+ if (server_creds_list[i])
+ gss_release_cred(&minor_stat, &server_creds_list[i]);
free(server_creds_list);
- if (server_name_list)
+ }
+
+ if (server_name_list) {
+ for (i = 0; i < server_creds_count; i++)
+ if (server_name_list[i])
+ gss_release_name(&minor_stat, &server_name_list[i]);
free(server_name_list);
- return FALSE;
+ }
}
+
/*
* Function: _svcauth_gssapi_set_log_badauth_func
*
+++ /dev/null
-Tue Jul 7 17:00:00 1998 Miro Jurisic <meeroh@mit.edu>
-
- * initTestTrackGlue.c renamed to ShlibTestTrack.c. removed CFM initialization code from
- there, since we are calling ShlibTestTrack from CFM initializers in *.CFM.c. Also updated
- to fix the bug where we were closing application's resource fork (oops).
-
-Fri Dec 20 12:35:32 1996 Marshall Vale <mjv@mit.edu>
-
- * GSSforSAP.r: Moved resources for the timebomb out to Rez
- format for easier CVSing
- * macSAPglue.c (__initializeSAPglue): Added new conditions to the
- timebomb code so that it can identify individual applications
- and not just fail globally.
-
-Tue Dec 17 13:53:36 1996 Theodore Y. Ts'o <tytso@mit.edu>
-
- * GSSforSAP.r: Fix expire time in the text resource to be June 1,
- 1997.
-
-Fri Dec 13 14:58:20 1996 Theodore Y. Ts'o <tytso@mit.edu>
-
- * macSAPglue.c (__initializeSAPglue): Change the timebomb date to
- be June 1, 1997.
-
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:$%e*9%&dD'9ZB8aTBJ"cD'aL2j!%!*!%b$d!!!*A#-K+EhNKF'9QCQdf1'X!!!!\r"XG%Hb!#3$3-!!J#3$NXd!!",0!!!5c3!!!#8!!%#!*!%"3#3"LFJ!!!R)!!!"GJ\r!!%[)!J%#!*!%$J#3$J9)!!"4S!3"!J"0B@PZ!#9"09G[FQaN!%a[B@4PFJ#3"#T\r46PErp#m0F!%[!$!mUQi[!#*YrC3J@8k3!#TZrr!Y32rdF!%[!$!mU'i[!#*YrC3\rJ@8k3!#TZrr#`V[rdCJB`2!)!B!3`2!3!6Pj1GBp1G@e8EfpXBQpi9(*KF(-!!#T\r46PErq$!Z!!S#J!!!#!"Q"(!!B!*`!8jH6R3!")Y(CA48FQ&`9(P`C3!!+P&19[r\rd51FB"$BZ!!S[!f(rN!6%'!!-"!!"CK*Krj!%@!*$"rqf3'd%0MbSRbm%,`-LEIf\r8)&P1N!!UE[r`,8$rp(!",`!`2+LI,`!LEIf8)&P1N!!UE[r`X+lrp&E!4!"*`%c\rI!"K1ANjd!!5+9(*KF%9iDA0dF`!!!#T46PErj#m05'lrk(!",`!LEIcB)&P1N!!\rUE[rJ5'lrj#mZ!!`[,J!)-#lrpLm!)Qhmc#"C6T!!+Qlri%M!C``JEJ!)3P!JEJ!\r-3T!!6Pj1G!!)MdGPG&0jFh4PE8C[E'4PFJ!!+P&19[rd51F30#CZ!!JNEJ!-GJ!\r`2+'Y,`"Krj!%#%S!Caa)E[rd,caQEfaN)QhpN!!J@8k3!#TZrr")`'B#GJ&+!fB\r-,`S[#f(rN!4@B#J[#Lm,F!![!#mmBh4bE$!mJ!![!#*YrB`J@8k3!#TZrr")`'F\r%3P0#NNcI$!K1ANjd!!L24f9d3e"KEQ9X4QpXC'9b!!!U88j@rRa)jam%,Li!##`\rZ!!`k,J!5+#i!&%+ZriT"l[jq,8MrN!!p4Iq8,86rVMem!!(rQQ"F[UlrRQC1[+l\rrSQC)F!%[!%KZrRi["#m&)QhpV#"C6T!!+QlqH$B!F!%[!#mmC'jbF#*YrA`J@8k\r3!#TZrRK+J'B3,`-LEIeB)&P1N!!UE[jiB!3`!f!H8QlrQLe%rkj)E[pq)Qhmr#"\rC6T!!+QlqH%M!Cj!!F2p-h`$i6Pj1G!!3Ne0PBA*MD%C[E'4PFNC[FN418P!!!#T\r46PErm#m$5'lrmNKZrrCKrrrrrT3[,[rb-#lrpLm!,cakG'0`,caMC'9fBIq3"!`\rf!!a$rrpR"$!$B'j)E[rb5'lrpQ(rrrrpr#mZrr)`,[rf,`![2'edBh![2'0NCAC\rKrrrrrYBf!!a$rrpR"$!$B$K)E[rb5'lrpQ(rrrrq+#mZrr)`,[rf,`![2'edBh!\r[2'0NCACKrrrrrU!f!!a$rrpR"$!$B!*`rbBI6Pj1GBP2F'9Z6h9b8NB!!#T46PE\rrq%MR%!4+VISSC`C`!'!!!04Krj!%,$B!F!%[!#mmC'jbF#*YrA`J@8k3!#TZrr3\rV32SN5Uhk*'B3)QhpL#"C6T!!+Qlrp'!!!*`[,ISN)Qhp##"C6T!!+Qlrp!a$rrp\rR$Lm$)Qhp@#"C6T!!+Qlrp#mYqL3LEIc8)&P1N!!UE[rd,bhk*#*YrE`J@8k3!#T\rZrr3JEISN+e$k+#mZ!!K)H!!"5(J$i5mYqLJLEIcX)&P1N!!UE[rd0J!`!dM!6qm\r!%'FN,bhk*#*Yr0`J@8k3!#TZrr3[,ISN)QhpZ#"C6T!!+Qlrp%+YqLJ`!bBI6Pj\r1G!!%M%p`C@j5CA0[E(CPFJ!!!#T46PErq#m05Uhk+'B%F14J+LmZ!"3[,J!3,bi\r!$#mZ!!K)H!!$,c`!!2rK,bhk+#*Yr1`J@8k3!#TZrr41ANjd!"#*8h4b9'p"C'4\rb!!!U88j@rrK)EIT)5'hk6#mZ!!KKr`!!!SK+J'F%F!"J-N(YqNJV52T!3Uhk4%(\rYqN`V52SX3Uhk-(!#+d$k0(!%+d$k1%(YqN!V52Sm3Hhk,#!)6Pj1G!!%M@GPG'K\r[Fh4LH@jKE@8!!#T46PErp#m05'hl6%KYr[`LEIcS)&P1N!!UE[r`5-!Y32rd)#l\rrp%jH6R@,Eh"PEPpNFQPfCA)!!#T46PErq#m05Uhl8'F1)Qhl8#"C6T!!+Qlrp'!\r#F!"1ANjeMh9cCA*IB@*[FR4IC'PcF!!!+P&19[ri51F3*#4Z!!Kf!!a5!!&R"M!\r55-"J('(rN!5`*J"R"#!$B!iLEIe`)&P1N!!UE[rdB0K-h`3)6Pj1G!!%L(GKDA4\rICQpb!!!!+P&19[ri51F3"%TYqdaQ%Q(rN!3f*J"+JfF')!0J!!#`5(J!CN+R5'h\rla#*YrM3J@8k3!#TZrr3lEIY-qp`lI!!QqpiVEJ!)qq!EI!!Hqq4#,I[P'hcr`2[\rQ5'hla#*Yr@`J@8k3!#TZrr4)EI[8BIq3"%3Q!%Ki!'C#TdKYqm3LEIid)&P1N!!\rUE[rd1fhl62[F1h`!+[[H+fi!#2[J5'hla#*YrC`J@8k3!#TZrr4+EI[8CK![,I[\rN)QhqQ#"C6T!!+Qlrp%U$CJBf,I[85--J!bBI6Pj1G!!%N!"dBh"IBfa[Ff9IFh4\rbC@&Y!!!!+P&19[ri51F3"%TYqdaQ%'(rrrrq5LB!5S0R"(!!B&C)H!"Q3UG)EIY\rH)Qhq0#"C6T!!+Qlrp$YYqdclGMYm!#MlH#YZ!!MlHNKYqeiLEIeX)&P1N!!UE[r\rd5'hlEQ(rrrrqDLB!5S0R"(!!B!T+EIZD9X"%!%R!*Kp1ANjd!!5,G'0`Af0KER*\rPB@3!!#T46PErq%MR%$3QEJ!-5Uhl9'BN5'hr!L*Yr[JJ@8k3!#TZrr4)`#B!5S0\rR"L!$B!!!RR!"+d$l9(!3,`")H!2!,bhqk#*Yr8JJ@8k3!#TZrr3N3$Ym!!(lA%K\rYqe`[#LmYrZ`[,J!))Qhqp#"C6T!!+Qlrp#"YrZ`-N!$rrkAqCK")EIYFBIrrrrf\ri)'hql##!,`SLEIdS)&P1N!!UE[rd)'hql%U3!'F))'hql#!3B#)JEIlX)Qi!%#+\rS!33J#fF3)%XLEIlX3qN!"#!)%0PQr(!!60m-#%jH6R3!$)pZFepbCA0[E(CPAfj\rKE@8!!#T46PErq#"Z!!JLEJ!--UJ!!NjH6R3!#)abCA0[E(CPAh"bEf-!!!!U88j\r@rrK)j`!N$'i!!3!1CKJNEJ!3,bS!##mZ!"!LDJ!%)&P1N!!UE[rd*&p1ANjd!"#\r+G@4`Afj[G'PQH3!!!#T46PEr[%MR%$3QEJ!)GJ"+EIY-CK*Krrrrr'BQ!%U$C`B\rJ!f!!!-4)H!!k3UG)E[qq)Qhq0#"C6T!!+QlrZ%Ki!!`LEIkF)&P1N!!UE[qi*%!\rJ#QB'F!aJ!!#52A`!&2rB2@hl62r@,@i!%2rH,@i!&2rL5Uhl@'BFF"![!%Ki2X!\r[,IlN)Qhp5#"C6T!!+QlrZ#Y!qeJYEIYBrqBp8rrU,8Vrl%KZrliLEIeX)&P1N!!\rUE[qi5QlrcQF@,`SLEIkB)&P1N!!UE[qi-#lrcNM!B"`NV[rD*@i!(!!%*@i!$!!\r))'i!'##+0UlrkL!$60m-#%jH6R3!')aeC("IFQ9RDA0dCA)!!!!U88j@rkJ[$8K\ri!$T#TdKZrliLEIid)&P1N!!UE[qN2@i!'[qb,@i!&2qd3QlrZ#eZ!!MrUMem!"I\rrf$eYqdcreL"ZrkSY82rD,@i!$2rJ2@i!%[rN(A`!!IrU3HlrXLe)rqC)E[qq)Qh\rpE#"C6T!!+QlrT%KZrmjKrrrrqfiY32qZ)#lrVNjH6R3!&)jeC("IFf9ZC&pNCh*\rKE3!!!#T46PEr[%MR'#3S,J!B5(J!1N+R5'lr[L*YrM3J@8k3!#TZrlJNEJ!)2A`\r!&IrB2@hl62r@,9,rfR!!%#hl6Me!rpj)E[qq)QhpE#"C6T!!+QlrZ%KZrmjKrrr\rrq[)Q!%U$C`3J!f"dF!!`,[rUZ)"X"#!%B!C`!$!ZrqSLEJ!8)'lrjR)JX)&P"+)\rZB!j+J'F+)JN5f&1!C[SL3A!!-#lrkL"Z!"`JJ#"Z!!`JV[rJ)'i!%$#Zrq3pI!!\r@rpK)E[qq)QhpE#"C6T!!+QlrZ%KZrmjKrrrrqRJQ!#!$60m%'%jH6R3!')eeC("\rICf9dAf4RFQ&Y!!!U88j@rlK)j`!N5(J!1N+R5'lr[L*YrM3J@8k3!#TZrl3NEJ!\r)2A`!'2rB2@hl62r@,9,rfNKZrliLEIeX)&P1N!!UE[qd5'lrcQ(rrrrk$#e!rlS\r[#L*YrTJJ@8k3!#TZrl3NAdjH6R3!")YeC("IFQ9XC@&cC3!!+P&19[r851F3"(B\r!5Qhl6'B-BIrrrrPJ*J"+JfC!5(J!*%+R5'lre#*YrM3J@8k3!#TZrp!pI!!2rqi\rpEIY-rqa)E[r8)QhpE#"C6T!!+Qlrd%TZrq4Q##"Z!!JJV[r`*Kp1ANjd!!51Cf9\rdAfejAfP`Af&NC()!!!!U88j@rrK1ANjeL'jPG&pTC'aP!!!!+P&19[ri51F3"%U\rYr#TR"(!!B'4)H!N!)QhqR#"C6T!!+Qlrp#Y!r#T+VI`UCK"`$#Y!m%JlI!!-r,j\r`rf!k5(J*!%+R,bhm+L*YrM3J@8k3!#TZrr4f!'!B)!-'J!!!!)"b5%`$'!!JEI`\rU)B!B"&+$F##fJ'hLF!!Q(djH6R@+BfKPBfYID@jTG!!!!#T46PErq#m$BIq3"'a\r+J'F%F!"J-(B!B#4`5%`$#!!JEI`U#$!!"`J!CK"`5%`$#!!JEI`UdF!J#'!+8S0\r`),D!EGC`!#BI6Pj1GC&RCA4IG@jeFf9NAh0[BfYPG!!!+P&19[ri*#i!#()!B#*\r`5%`"#!!JEI`UY,!)"'B3F%K-!3J!)'hm+Y(!)!KJ#P+"F##bJ'hBF!"1ANjd!!5\r,CQPZC&pcEf0VCA3!!#T46PErq%MR!#3NEJ!)5(J!"%+R,`SLEIid)&P1N!!UE[r\rd3US!1%UU!$4R%#mU!$3LEIkB)&P1N!!UE[rd3US!0%+U!$!NAdjH6R3!")jbC@a\rPBA0PAh0[BfYPG!!!!#T46PErq%MR(#3Q,J!)+Li!$#JZ!""`!VD!CJT+K'FBF!+\riJ'F5F"BV32")1h`!&[bqF2pJ!!#bF!+kJ'FBF!'kJ'F5F"BV32")1h`!&[bqF2p\rJ!!#8BIrrrrkJ*%!J#QB3F!`V32")1h`!$2bqF2pJGM9$!!Je3`!B08-!+$9%!#S\rP43!X5US!0'Bb5(J)!#*YrT`J@8k3!#TZrr3P3!!d*A`!!!J!!$"+UJ!dCK"`$#Y\r!m%JlI!!-r,j`rf!U5(J!"%+R,`SLEIid)&P1N!!UE[rd!")!J!*5J(m#+J$[!!&\r#UJ!i)#S!"%cI"$K1ANjd!!b'FfpMDf9d!!!!+P&19[ri51F!*#4Z!!`)%J!(CK"\r)EIm))Qhp4#"C6T!!+Qlrp1R5!%K531r5!%JNAdjH6R3!#*4cEf0VCA4ICACPER4\rID'&ZC'aPFJ!!!#T46PErq%MR'$JS,J!3+'i!'#mZ!!KKrrrrrIBN3#!+CK*`&LY\r!m%JlI!!@r,j`rf!!!-*`!V#U!#aQ#!aU!!)!#'F5F"BV32")1h`!&[bqF2pJ!!#\rJ5US!1'C),bhqi%KU!$J[+J!`,bS!0#m+5'S!#Q(rrrrj&LB!5S0R&Lm+BIrrrrh\rBF"NV32")1d2m[R$rB'")DJ!-BIrrrr[k!#S!%!!"F"#`VJ!FCJB-9!!#Ca"`&LY\r!m%JlI!!@r,j`rf!b*N`["#mZ!!``+`!#,`![+`!%,bS!1'(rrrrjY#B!5S0R$R!\rC+d$`5$Y$r,j`rf!#)!4-ha`B6Pj1G!!BKR0PEQ4dE`!!!#T46PErp%MR%$!QEJ!\rF,bi!#'(rrrrmmL4!)!TQ%R!@+d$`5$Ym!"Em[R$rB!!!LR!#X+S!,'B)$'S!!J!\r)Ca"`&LY!m%JlI!!@r,j`rf"SF"#`Nf-3F"BV32")1h`!&[bqF2pJ8R!3*S!QEJ!\rB0V`!!NKZrr3[,J!3,bi!$%KV!!*)D`!%,bS!1'(rrrrjPLB!kG)!5'F+kG)!5&0\r!lp)!5%U$CJBJ,[rdB!a`'5Y!m%Jl3rbqF2p-h``)6Pj1G!!BL(*PBhCQFQpY!!!\r!+P&19[ri51FI2#SZ!!JSEJ!-*Qi!%#iZ!"3NEJ!B)!TQ"(cqB#3LEId3)&P1N!!\rUE[rdFMa-%K!!dS!J+J!%6(`!N!4"'Y#",!")H!!J3UG)EIb1)Qhq0#"C6T!!+Ql\rrp%Ki!#"#TdKYr'iLEIid)&P1N!!UE[rd5(J!)%+R5'hm6L*YrM3J@8k3!#TZrr4\r)H!!J3UG)EI`Z)Qhq0#"C6T!!+Qlrp(J!)!aQ"%RYr#iJ#fB%4qhm,NU(CJC"lI`\rZ,JKf!'!!!+)J!qU))J0d(m+#G!(MUX5c$!"R(L!$FKr!JA)"iDNJ!qU)3HhmEN(\r`$!!J%)#"))"5K#!$kSJL!h3I`S*d!H1Ua,3-!'GBF)$3Jh)JX)&Z6Lm$BIrrrrX\rJ*%!J#QG!#")!"fFkkG)!5'B@F!'`UJ!XCL`[+J!mBIrrrr5D5S"R(L!$FKr!JA)\r"iDNJ!qU)3HhmMN(`$!!J%)#"))"5K&+$YS9Y!2pF5S4Q*#*YrA!J@8k3!#TZrr4\rKrrrrqESLEId3)&P1N!!UE[rdX)CP!2mZ)!9HJ#B!j)2JLq#,i)[ULpD!jS0`),D\r!B`*f)#*-3HhmML!$FL#`J@8%SLjJ$NU!C`SL#4,B8i"QqL*")NY"lIaZ)!0b),#\r"C35L,Q!15S"R#L)*%YK6J'Ek)N%L4d(Yr%iJ!h)JX)&P"+)ZB!j+J'F+)JN5f&1\r!C[SL35!%60mFq%jH6R3!&)CcC@aPBh3!!!!U88j@rrK)ja!N*Li!#!b$!!!!J'`\r5,`-LEIh3)&P1N!!UE[rdB!!!RLm$BIrrrrRS*%!J#QB'F!"J!!#+)!TR$JJ5!!G\rR#!aU!!)!+'F3F"BV32")1h`!&[bqF2pJCL!U!#a6J'F'8i"R,Q!q5US!2'G),bS\r!2'(rrrrb6LB!5S0R1(!C+d$`5$Y$r,i[#Q(rrrrjd($rB#a+UJ!iCa`[+J!iBIr\rrrrH!B""`&LY!m%JlI!!@r,j`rf!+,`TKrrrrqD*`!%cI"!K1ANjd!!5-FfpMDf9\rdAf0XEh0P!!!!+P&19[ri,`e+VIbZCK4)H!,))QhqR#"C6T!!+Qlrp#Y!r+j+VIb\rbCK4)H!!8)QhqR#"C6T!!+Qlrp#Y!r,*1ANjeLh4dAf&XE'pMBA4P!!!U88j@rrJ\r[$8UYr+jR%#mYr+iLEIkB)&P1N!!UE[rd3UhmVNUYr,*R%#mYr,)LEIkB)&P1N!!\rUE[rd3UhmXNjH6R@(G(4ICR*PC3!!+P&19[[S,`e"l[[i)Qi!%#!)%0PQr%KZqrJ\rLEIeN)&P1N!!UE[[N5'llkNKZqr4)E[[b-#i!$Lm!,bi!##*Yr43J@8k3!#TZqq4\r)E[[i,bllp#*Yr63J@8k3!#TZqq41ANjd!!b3!(4dAh0PG&pTG'9YAh4PH(3!!!!\rU88j@qqJ[$8KZqqT)E[[d5'llmM!Z!!i[!#mZ!!JLEId8)&P1N!!UE[[N5'llq#m\rZqr3LEIdN)&P1N!!UE[[N5'llq#*Yr33J@8k3!#TZqq3JEJ!33qllq#!)%0PQr%j\rH6R3!$*!!G(4ICf9dAfPdC@eIG'9iG!!!!#T46PErj%MR%$`SEJ!)*'i!$#CZ!""\r`!$!59i"R$R!!-"*EJ'F'F!"J!!$Z*LS!!J+$!!!!r`b$!!!!!fF8$)-!!!!0C``\r-J`!!!"YRCQ!!!-Bf[!!"5'lrkNKZrr4)E[rbF!%[!#m-)Qhp&#"C6T!!+Qlri(!\r+,`![,[rd)Qhp'#"C6T!!+Qlri%KZrqC)H!!))Qhp$#"C6T!!+Qlri(!!,`![,[r\rd)Qhp'#"C6T!!+Qlri(!"B'3f[!!#5'lrkNKZrr4)E[rbF!)[!#m-)Qhp&#"C6T!\r!+Qlri(!+,`![,[rd)Qhp'#"C6T!!+Qlri%KZrqC)H!!))Qhp$#"C6T!!+Qlri(!\r!,`![,[rd)Qhp'#"C6T!!+Qlri(!"B!*`!%cI(!K1ANjd!!b0G(4ICA9TAfCTE(4\rPFJ!!+P&19[p),`e#V[p@3UlrA%KZrdSLEIeJ)&P1N!!UE[p%5N"R"($rB#j#V[q\r+3QlrQMeZrf$rP%+Zrj!!5'lrIL*Yr2!J@8k3!#TZrd4+3'F%F2pJ"#!Zrja1ANj\reQ(4dAfGPG&pfEfaIBh*PBA4TEfjIC'&dC3!!!#T46PErj%MR!$`SEJ!)3QlrpNK\rirrp#Tc!m"%`[!#*Yr5`J@8k3!#TZrq!Q3#!,CJC`rf!!!9SJ9%)3)&4#+!"N,a4\r`"#m!,`YKrrrrr53J9%KS!'4`"Lm!,`YKrrrrr4*`%#m!5(J2d#mYrYJLEIe))&P\r1N!!UE[rJ*%")E[rU)Qhp9#"C6T!!+Qlri#m,)Qhp6#"C6T!!+Qlri%KZrqj)E[r\rN5'lrk(!",`![#b*Yr43J@8k3!#TZrq"`!bm!F!-[!#*YrE!J@8k3!#TZrq"`r#m\r!F2`[!%KZrqiLEIh!)&P1N!!UE[rJF"![!(!3,`")E[rZ)Qhmb#"C6T!!+Qlri%K\rZrrB[#L*Yr13J@8k3!#TZrq!-EJ!"rrCR#!aZ!!,rpQEH,`SLEIdS)&P1N!!UE[r\rJ$'i!!IrfCL`[&(!%,`![#f(rrrrmU#"85'J!C(!',`![#f(rrrrmPQ(rrrrq1#"\r8)8!!b#m,)QhpH#"C6T!!+Qlri#m-)QhpD#"C6T!!+Qlri#m-)QhpY#"C6T!!+Ql\rri$!ZrrC)`%cI(!"1ANjd!!54G(4IC@4TG&peFf9bAfPZCQm!!#T46PErq%MR!#3\r`2!4-,`![2(4dG@NLEIdm)&P1N!!UE[rd*%"+J'C85(J!c#*Yr3!J@8k3!#TZrr3\rN3%KYre)`2!4-,`![2(4dG@N[#L*Yr6!J@8k3!#TZrr4)H!$-3UF[%L*YrM3J@8k\r3!#TZrr3[#Q(rrrrpjP1!CbT`rf"D$#i!!3!2C`jKrrrrr9SJ8V#S!-KR%#m+BIr\rrrrh!8i"R"($rB$3LEJ!))&)J2!!!!-ab),#"C35L,Q!15S"R#L)*%YK6J'Ek)N%\r[#L*YrB!J@8k3!#TZrr4`!#4I6Pj1G!!)N!"dG&pRCA4IGA0PFPpTEQC[!!!!+P&\r19[rN,`e)E[rSF!%[!#*Yr0JJ@8k3!#TZrq!p32rQCb)`,[rQ5-![!%KYrfB[,J!\r))Qhpp#"C6T!!+Qlri%r[!!aJ8$!Zrr4)`#m!F!!3,[ra,`"`!"!Zrr![!$!Zrqj\r)`#m!-#lrl%M!,`!`,[rU5-![!$!ZrqK)`#m!5'hrK#mZ!!JLEIhd)&P1N!!UE[r\rJ6qm!*%jH6R3!"*0dG&pRCA4IFhPcAf9ZGQPbEfjc!!!U88j@rr4)j`!N-$`%6#m\r!,ca$8e45)Qhp2#"C6T!!+Qlrm#4!5S"R4Lm+)Qhp[#"C6T!!+Qlrm#m5BIrrrqS\r5,8$rp'F1)'lrp#"S!"!J8#Y3r,B[#L*Yr0`J@8k3!#TZrr![#L*YrB!J@8k3!#T\rZrr!NAdjH6R@8G(4ICf9dAh0PFRCPFPpTF'&NC()!!!!U88j@q"K)jam%&Li!&bJ\rZ!"Kk!(i!)QhpU#"C6T!!+Qli&$e!rYi`,Ibm,`!LEIcd)&P1N!!UE[J8F!'iJ'm\rD)Qhp%#"C6T!!+Qli&%a%!!&+J@F'F!"J!!*L5UhmYQB5BIq3""C+VIbfCJC`!'!\r!!NT)E[VHBIrrrrj3GJ"+!fFX%#i!%bm!5'lqp'(rrrrp5%U!Cb3`,[lH,`!LEIc\rd)&P1N!!UE[J8F2pJ!!)13Llqp%)ZreK#V[qmBIrrrrK#5(J#b%+R,bhmVL*YrM3\rJ@8k3!#TZq"3JEIbZ-,`!!5"Yr+iaI!!"!!)JEIbZ-A`!!3!%5J0R"(!"B!*`!#"\rYr+ia3!!')Qhp%#"C6T!!+Qli&#"Yr+iK3!!)5'lkhNKZreK)E[ld5'hrd%KZq#)\rLEIhd)&P1N!!UE[J8)'hmXL#Z!!JJEIbb)@i!$!!%3HhrfL*Yr,)M5!!)3Hhr8#*\rYr,)M5!!-3Hli)L*Yr,)M5!!3,bhmXLmYr+jKr`!!!PiX!%+R5(J!!NKi!!*Krrr\rrm9)Q!$em!!,r`$em)66r`LeYr,Era%Ki!"")E[r!3UF["LmYr+i[!f(rrrrbF(S\r!6qm!&%Ki!#"#TdKZrp!LEIid)&P1N!!UE[J8)!0b(m#"FJ(KU5!$kSK"l[r33I!\r-!#!3J)%JJ(!&,8$rm%+Zrr4)E[r`3UG#TdKZrp")H!%!BIrrrr2Z+!"+K'BB5(J\r!%%KZrm"#Tbm',bhmVLm$BIrrrr(k5S4Q#&+&F!1kJ'f%F!'iJ'C@F"!Y32JH5'l\ri(NKZrm"#TdKi!XJ[,IbZ,`0KrrrrmY!S!#"Yr+i-D!!%!!CQ+%KZrZ![,IbZBIm\r!!!#L)'lql"!35F!%J!!!!&*R!Q!#I[mYE[l`q"S[!f(rrrreK'(rrrrfUM!ZrYi\r[!#*Yr23J@8k3!#TZq"3J"dcI!2K1ANjd!"5+G'9cG&pdFQ&MD`!!!#T46PErq#m\r-)'i!##*Z!!`SEJ!3)Li!&'!++-Lab@3%5KKQq#!"8i&+J'EZ+&p1ANjd!"#3!(C\rIF'&bFf9IF'YdAf4KG'%!!!!U88j@rrK)H!!&,bi!$#"Z!!K)D!,()'i!#%KS!!a\rKrj!%QNjH6R3!#)YfAh"KFR0PAh"VG!!!+P&19[ri51FB2#4Z!!JSEJ!-*Qi!%#B\rZ!"3S#Q!f5T0Q"%)DB"BJ6*(+,`J[%bm+)Qhpm#"C6T!!+Qlrp%+R,`SLEIhS)&P\r1N!!UE[rd)%"5L#4)@)XJ!e1$5S"Q`L"+NF3J#%cI("K1ANjd!"#6GPpKFh0PE@*\rXC9p`Dh4IC'&dB3!!+P&19[ri,`0f"5m$,bi!$#"Z!!K"k!,)NF0)8#"Z!!K)D!!\r-BIq3"&Tb$0#"*Kp1ANjd!!L1GPpKFh0PE@*XC9p`Dh3!!!!U88j@rrK)jaJN*'i\r!#(B!BIm!!!&`)QhpU#"C6T!!+Qlrp$J!F2mV32bkF!'`UJ!-CM"`!5m!,bS!%#*\rYrD3J@8k3!#TZrr4)`#Y!r,T`rl#Yr,TQ$L*YrBJJ@8k3!#TZrr3f!#m%)Qhmp#"\rC6T!!+Qlrp$!$60m%'%jH6R3!"*&IAfPZDA4TB@aTHQ9I9&466!!!+P&19[ri,`e\r`rl#Yr,TQ%M!Yr,`[!#*Yr9JJ@8k3!#TZrr4Kr`!!!2a1ANjeN!"IAh4PFQeTEQ&\rdC9p89&0-!!!!+P&19[ri-#hm[NjH6R@3!%GPG%*64%eKBdp64A*bEh)!!!!U88j\r@rrK`!%jH6R3!")j*ER0dB@aX3fpZFfpXC3!!!#T46PErq%jH6R@08Q9YEhCP3fp\rZFfpXC3!!+P&19[riF!"1ANjd!!L69h*TG'9$D'&bFe4[3fpZFfpXC3!!+P&19[r\riF!"1ANjd!!L88Q9KC%0SBA*c4R*[E80[ER0[E'8!!!!U88j@rrK1ANje+P&19[r\ri,`dJ$5m!,bhqa#*YrV3J@8k3!#TZrr3V32c!BIq3"0C`!%jH6R3!"#T46PErq#m\r0)Qhq[#"C6T!!+Qlrp#mYr-!LEIk`)&P1N!!UE[rd6Pj1G5T46PErq%MR!#4J'L"\rYrX!JNR$r,`![+J!))QS!"#"C6T!!+Qlrp#"YrX!N8#!+CY`NAdjH6R8U85m-+'m\r!##*[!!a`!#"YrVKJ%%U3!'B)))`K53!%B!j5J&#)$)!!!!#!EHK`rbKI6R3!##T\r4)Lm!"%U"E4J-J3!!!)"X%#!"jiJJEIkidF"#N!"#U!!%6R3!"#"[!!4`!*!!V`!\r-)8!!"(!!)Lm!#*'"))"1G!!-)'m!"#![!!b3!+m!&#&!!!3J,`!))Lm!%*'"))"\r1G!!86PErk%MR(cJU,J!)*'i!$#KZ!"!QEJ!85T*Q#%UU!!4R!!$@GJ"i!#"&,"!\rYD!!%rr3Y8[rX,@S!"2rSIJ"k!%+Zrr"J!!#8eS-J"!+!J!!!!'F%F!''J0L%)!B\r#J)!!!!"R"(!"L)$FKL!Zrr3#J)!!!!"R"(!"M)!J,[rdd)!Y32rdhSFJ"3+!J!!\r!!'F%F!'1J0U&YUlrl')-YUlrl'BdZ+lrk'8ZF!'+J#e$rrJY42rm,bS!"#mU!!!\r[,[rm,blrq%KZrrKKrj!%&LBZrrJS,[rm8Ulrm("!X+lrm'i!rfBJ$'F'+)FT43!\r%)!YR"LD$*d3!"%cI(2K1ANjd!""19J!!,`SNEJ!)3UF[#NKZ!"4)EJ!-BIrrrrl\rQ)!SNAdjH6R3!&%j@!!![#L4Z!!J[#N+R5'i!&%KZ!!aKrrrrrX!J#L4I6Pj1G!!\r8)#m!",#[!!aR#'85F!&1G!!3)#m!#,#[!""R#'6ZF2p1G!!3F!"1G!!3*#m!##!\r[!!3L,`!-P+m!%*'"C`TY"R!"6R3!%($r6R3!%#"[!!3J,`!))8!!"!J!!"pR#($\rr))"1G!!)F!!JJ%jd!!JU88j@rrK)j`!N5(J!!5*YrR!J@8k3!#TZrr3JEIkN5T!\r!CKJ[,IkJ)Qhq)#"C6T!!+Qlrp#"YrU4`!5#!,bi!##mYrU!LEIiF)&P1N!!UE[r\rd*%")H!!")QhqE#"C6T!!+Qlrp#!+*&p1ANjd!!3U88j@rrJ[$5"YrU4+N!"R0%K\ri!!%LEIj`)&P1N!!UE[rd,bi!##mYrU!LEIiB)&P1N!!UE[rd5(J!!5*YrQ`J@8k\r3!#TZrr41ANjd!!3U88j@rrK)ja!d*'i!##CZ!"!Q,J!83T)PEJ!-!!3#+J!I!!J\r#+J$[!!K#+J!-3LS!$8+U!"*+JfFB,`0)H!!#,`X[#L*YrR`J@8k3!#TZrr4J&%+\rR3UG#Tbm+)QhqI#"C6T!!+Qlrp#9U!"B!(N+U!#,TkJ(#!!46J'F'9B"R('!`*@h\rq8!!b*@hq@!!f*@hq9!!k*@hq6!!qB"C#UJ!b*@hph!!f*@hpf!!k*@hpe!!q3US\r!3NcI$!K1ANjd!"!U88j@rrK)ja!N5(J!!L*YrR!J@8k3!#TZrr4f!#4YrYaJ)ZR\rU!F)!"'F8,`SLEIjN)&P1N!!UE[rd!QVqI`!%8S0`4YA!F#1fJ'hB5(J!!L*YrQ`\rJ@8k3!#TZrr4-h`3)6Pj1G5T46PErq%MR'#4i!(B!*'hqh'!LkHS"`J!%Ca3[#L*\rYrQ!J@8k3!#TZrr4+J'F#H2p5Jh"'eF"`)lD!EGJJ"%cI""K1ANje+P%[$#K[!!J\rLE`!-)%`L%@!B$"!!$@B'%,`!#Q!+$"!!#QB%%,`!$9+))!&6J8U!CZ!SAdjd!!J\rU85"[!!3KD!!@!"iKD!!D!#)J+!!5`+J!*T'S!#)KD!!5!#j1G!!%+P&19[ri51F\r30#4Z!!JQEJ!-)'S!(T(U!"BQ#%U$Ce3P3`!L##S!"J!&CK4)DJ!L,bS!&L*YrSJ\rJ@8k3!#TZrr3[+J"#5'S!)LmU!"B[%L*U!$SJ@8k3!#TZrr3Q!#!,C`3QUJ!L5S0\rR"#!$B"JJ+J!LdDS!%Lm+)QhqK#"C6T!!+Qlrp(!!60m-#%jH6R3!##T46PErq%M\rR($3NEJ!)*Qi!$#BZ!"!S,J!8kHT4`J!%kHS!!`!)CJ4+K@B'F2pJ!!$+5S0R%R!\r"YS"R$(!#YS"R"R$rB!!!Y%UU!"CR'!JU!!3!#'F3,bS!&L*YrTJJ@8k3!#TZrr6\r[kM&#!!3#+J$[!!JJ5P#)A)JP5!!@)%T3L&b)*8J!(R!"*8!!'N+U!#*#UJ!Q5S0\rR"R!"Z)"N#L"U!"j#%(!!B&)J#fBH,`3LEIkF)&P1N!!UE[rd*N"+J'B%F2pJ0J!\rU!"!!##9,!"BPDJ!@!"iP4!!D3US!*ZRU!F)!"&1!CK)J"!+!!!!"rfB)*A`!!!(\rr!#C`!%cI$$K1ANjd!"!U88j@rrK)jaJN+#i!##4Z!!cTkM(#!!4#UJ!L5LS!$@B\r%5S0Q"R$rB!!"%(!#YS"Q$#*YrL3J@8k3!#TZrr6TkJ!$!!KQ81RU!)-!"()#`)&\rR41RU!)-!"()%`)&R(NKi!!*#Tbm+)Qhq1#"C6T!!+Qlrp%U!C`C`!'!!!-!#+J!\rI!!J!+J!J!!J[#L*YrS3J@8k3!#TZrr6TkJ!$!!K6!'F3&A`!!3!03US!)R$rB!!\r!M1RU!8)!"&8!C`iJDJ!HNHS!&V(U!"TQ)N+R,`SLEIk!)&P1N!!UE[rd5S"R$K9\rm!!%!$8+U!#*`rf"38kS!)L"U!"j5UJ!H%)6TkJ&#!!49!'FdkHS"3J!%C`C`#VL\r!CL*#Tbm+)QhqJ#"C6T!!+Qlrp%U!C`i9I!!"!!e#UJ!LF2pJ#%+U!#*`!"!%60m\r%'%jH6R3!##T46PErq%MR%!4f!#"YrR4`!E#3!'B%F!&JCNKi!!-LEIj`)&P1N!!\rUE[rd)'hqG%U3!'Bm)Qhq*#"C6T!!+Qlrp(!!,`!LEIl8)&P1N!!UE[rd5N"R#L"\rYrR4`!L#!B")JEIkS)+hqd#"YrR4`!5#!GJ&)H!!$)QhqE#"C6T!!+Qlrp#!$*Kp\r1ANje+P&19[ri51F!*#4Z!""Krj!%E%U!CJ4`!@!d)'hqh%KS!%BLEIjJ)&P1N!!\rUE[rd,a)[,J!-)Qhqb#"C6T!!+Qlrp#5!F2q`NQB%F!&J!R!!*&p1ANjd!"!U88j\r@rrK)j`!N*'i!%'(rN!385S"Q"(!"B#![%LmZ!!`LEIl-)&P1N!!UE[rd*)"`rl#\r5CJ4`!@!#F!!NAdjH6R3!%#T4F!"1G!!%+P&1G!!%+P&1G!!%+P&19[rd51FI2#K\rZ!!JX,J!-+#i!%#4Z!"3Q"N`%-!"+JfF15LS!$@B)kHS"`J!%CJC`!'!!!LETkJ(\r#!!49J'B-)Qhq*#"C6T!!+Qlrm!JU!!B!"@FLkHS"`J!%9i"R'1RU!8)!"&8!C`l\rTkJ&#!!46!'F%F!"J!R!"+J$TkJ!$!!KQ81RU!)-!"()#`)&R41RU!)-!"()%`)&\rR(NKi!!*#Tbm+)Qhq1#"C6T!!+Qlrm%U!C`C`!'!!!D3#+J!I!!J!+J!J!!J[#L*\rYrS3J@8k3!#TZrr$TkJ!$!!K6!'F3&A`!!3!03US!)R!!B!!"F#C-H!"+JfF!!2!\rJDJ!HXHS!&QB'5S9R!!$J)'S!(T(U!"BJ+J!DN!#)*8!!)TR-,@S!)[rdYUlrp'3\r%,82rp1RU!8)!"&-!CLa+V[rdCbB[,[rd5(J!#Lm,)Qhq,#"C6T!!+Qlrm#K!5S"\rR#L"-8SL4bbe)rr4+V[rdCciLDJ!H)%XJ,[rdFL#`J@8%SLjJ$NU!C`SL#4,B8i"\rQqL*"eqlrp0LZrr5@V[rd)#lrp0'U!"iJ,[rdNDS!)NUU!#*R$#!-CJMTkJ&#!!4\rQ*%+R,`SLEIk!)&P1N!!UE[r`,J"+KfF1&A`!!3!03US!)RB!B!T+JfF'5S9Q!2m\rf5S0R@NU&CPBSDJ!@+LS!'L9,!"BP3`!D)%[4`b9)!"j)E[rd,`SLEIk!)&P1N!!\rUE[r`5S"R#K9m!!%!$8+U!#,BV[rd*8`!&L9&!"S[#L*YrS3J@8k3!#TZrr"#UJ!\rLkHS"3J!%93"R"%+U!#)J"0#'8i"-4J!!60mFq%jH6R3!%#T46PErq%MR'#3NEJ!\r))!TQ"($rB&VTkJ(#!!4Q"(!!B%i[#L*YrQ!J@8k3!#TZrr3Q!#m5)QS!2L"C6T!\r!+Qlrp#J!!QVqI`!%3T))+J!%!!KR%#mU!"BLEIkB)&P1N!!UE[rd5S0Q"%U%C`4\r`rf!#F!"-h`3B6Pj1G!!%+P&19[ri51F3*#4Z!!JJ#QB3)QhqM#"C6T!!+Qlrp'!\r!!+"++J!0CJMTkJ(#!!4Q"R$rB!!!M1RU!!-!#!`!!!0P$!)U!"m!#!!U!%!!#1R\rU!!-!#&8!CJ4#UJ!LkHS!!`!)8`"R#J)U!"m!#(!!B&$TkJ(#!!46J'B5,`SLEIj\r!)&P1N!!UE[rd*J"J!RB!3UF[#L*YrS!J@8k3!#TZrr4+J'F1&A`!!3!03US!)R$\rrB"!#+J!I!!JP3`!53US!)R!!60m%#%jH6R3!"#T40#m!"R)!)'hqA'!1Y&"Q"#!\r)B!j5JA")dF"`)l+!EHa`!%jd!!3U88j@rm4)ja!m*Li!##KZ!!`NEJ!3*Qi!&%+\rZrp)p3rrH,8crjLe5rqT#E[rb)!YR*%KZrmBLEIc3)&P1N!!UE[r!B!SL5b"C6T!\r!+Qlr`%TZrpCZm'!35'lraL*Yr1!J@8k3!#TZrm!NV[rZ$'lrfIr@CJa+NQF%F!"\rJ%(!#B!a+E[r@CJ4`!'!#F!&-ha`)6Pj1G!!3+P&19[r%51F32#BZ!!JSEJ!-*'i\r!%#CZ!"4#V[r5282rhLe-rqBY8[rU3QlrmL!,Cb4)E[r')QhpA#"C6T!!+Qlr`'!\r+)NXJ@8k3!#TZrm"+E[r@E["J%%KZrmBLEIfJ)&P1N!!UE[r!*+lrlNTZrpCQ"(!\r!B!*`!8cI(!K1ANjd!"!U88j@rm4)ja`d+Li!##CZ!!`S,J!3*'i!&%+Zrp)p4Ir\rH)!4R$P@!C`*J%$em!!,rmQ!12A`!!IrbB!C`!@!!!4!Y8rrd)!TR*%KZrmBLEIf\r%)&P1N!!UE[r!B!SL5L"C6T!!+Qlr`%TZrpCZm'!35'lraL*YrCJJ@8k3!#TZrm!\rJ%j!!V[rd*J"+J'm!!,BJ,[rdd)-Y32rL)!TR*%KZrmBLEIe!)&P1N!!UE[r!B!S\rL5L"C6T!!+Qlr`%TZrpCZm'!35'lraL*Yr2JJ@8k3!#TZrm"+E[r@CJ4`!'!#F!&\r+J'CL3UlrdMe&rpiJ"'F19B"R!Q!32A`!![rbB!`pI!!"rr*J"(!"B%`Y8rrd)!T\rR*%KZrmBLEIf%)&P1N!!UE[r!B!SL5L"C6T!!+Qlr`%TZrpCZm'!35'lraL*YrCJ\rJ@8k3!#TZrm!QV[rd5QlreQB%F!"J!R!"60m-1%jH6R3!%#T46PErI%MR%#3Q,J!\r),`0Krrrrr9SN3$e$rjC)E[pq)Qhp8#"C6T!!+QlrH$B!CLSJ#QFQ)%T3L#e)rj!\r!2@S!![q8,@S!"2qZ5'lrIL*YrA3J@8k3!#TZrhJf!#!+C`*#8NT$CJ4`!'!#F!&\r-h`3)6Pj1G!!%+P%LE`!%kHN4`J!%$!%!!@F'$!%!!QB'5LN!$@F-)'hq5(!M))"\r`rf!dkHN!!`!)CJBJ+3!5B#BJD3!HNHN!&L)T!#l5L1RT!!-!#!`!!!0P#ZRT!!-\r!#&@!NS!J!8jd!!3U88j@rrJ[$5mZ!!JLEIj%)&P1N!!UE[rd6Pj1G!!%+P&19[r\ri51FB0#4Z!!JQ,J!3kHT"`J!%$!3!!@B'5LS!$@F1)'hq5(!M))"`rf!!!4ETkJ!\r$!!K6!'BX3UF[#L*YrS!J@8k3!#TZrr4+J'FB&A`!!3!03US!)L"YrNK`)b#!F2p\rJ!!$JF!'fJ'B@GJ![#L*YrN3J@8k3!#TZrr3S!0QZ!!a`!VD!CfETkJ#$!!4A!'G\rFkHS!!`!)93"R#ZRU!!-!#&F!CNJJ,J!-X+S!%Q3+)#i!$,#U!#jN#!)U!"m!#'!\rb)#i!$*!!UJ!Z)'S!&Y(!*8J!(L!U!"+3!+i!$#9!!#)#+J!I!!J!+J"!!!KJ"J)\rU!"m!#1RU!!-!#'C'*QS!-L!,Cc![+J"#,`0)EJ!-,a)L5b"C6T!!+Qlrp%U!CaB\r9I!!"!!e#UJ!L)'hq5(!M))"`rf!33LS!$#9Z!!`!%N+U!#*`!%cI$"K1ANjd!!`\rU88j@rrK)ja`N*'i!##SZ!!`S,J!3*J8["#m$,`SLEIim)&P1N!!UE[rd60m%1%j\rH6R3!$#T46PErq%MR'#3NEJ!)+#i!$#BZ!"![!bm%,`SLEIiS)&P1N!!UE[rd)!T\r-h`3B6Pj1G!!-+P%[#bC[!!JN,`!-)#m!%")#)NY5J'!-XKPQ##"*8iJJ#'!'8i"\rQm(!!*Pp1G!!-+P%LE`!%*#m!##![!!`5!L"*dF"5J'!)XL"Q"#!)B!C6J'EdF!"\r1G!!-+P&)ja`!)'m!%#J[!"3U,`!BGJ!@"(!JZS"PAR!$+!K%K-L!5S4R#*U%%-0\r6K'Ek5S0R&L!$FK$MU#)$G"MPUB+!)!2KL)#"KS!S"HU-5S4R&#$$)--J`b$$)--\rJ`b$$)-06K'EXH"r)KH5-5S4R"L$$8i4QqR!$bS"+K@F'%-06K@Ek60m!1%jd!!`\rU85"YrU`JVIk3!%je+P%[#b*[!!JQ58+V!!3J5eL)*dJ!$#G)!!JQL#0YrK3!%#0\rYrK!!�m!!#!!!!B3UN!(%+T!#"#U3!N*Pp1G!!%+P&19[ri51FF2#4Z!!JQ,J!\r-+%T+JfF'F2LfJ'-'F!"J!!$D@)0`r#)$9S(#J#B"YUS!''9!5US!%'Fk5US!('B\rdH"$BJbm+,`3LDJ!3)&P1N!!UE[rd+J![#Lm%,`9Kr`!!!9JQ3#!,CJC`!'!!!)j\rfr-D6B(*`%,D!C!*f%#m$,`aKr`!!!I)Q3#!,C``[#bm-BIm!!!'bB%"+UJ!3Cc+\rfUJ!BBJKi%0LU!"KJ"(J3f)-[#Lm%)QS!%#"C6T!!+Qlrp#S!,`S["#m&BIm!!!$\rX*N!J#fB%F!"J)Lm$,`X[$'(r!!!"`LB!F!%L%i+!*S&`!S'c1!!J5eL))!K-ha`\ri6Pj1G!!)+P&19[ri51FB2#KZ!!JQEJ!-+!`J#fF!!)iN5eQ+F2iL%X+!*)&fr-D\r5*NVA`h$p)K2#J#D"*d2rr#m+,`4Kr`!!!ISN3(EmaT)Q5YI$5U`!&'G)F!,!NQC\r#5UVrr'`m5T0X1#C+8BYCLdU6C`SJ8b&V!!3!"'!'+@X!"!!J5UX!"'F')'X!"##\r6,``[#b*X!"3J@8k3!#TZrr4J#Lm+,`4Kr`!!!(*-ha`B6Pj1G!!)+P&)j`!B*#m\r!$#)[!"!SE`!85S*Q"(!!B%!L3R!3NS!Q58UX!#"R"L"X!#!JLd+6*f`!)!!%+8X\r!)&#*F2`LJ&L*)S%J!9Q!dm!LJ9L*F2`LJ#"#8)KBL#!)60mB!%jd!!`U85m,)Qm\r!##C[!!`J59L)*dJ!"#GT!!`!##"T!!`K5`!%)dX!$#CI6R3!##T4,`XQE`!))Qm\r!$,26CJBJ8bDS!!JJD3!))@N!"!!%)'N!"#&T!!J!##CI6R3!##T4,``LE`!))Lm\r!$#"4+%K`r-#3!,#"C3BLL#!)B!SJD!!)XFaQkR!!+&p1G!!)+P&)jami*Qm!+#B\r[!#a`r#)$9S(#J#B"+K0qr-k&+!HBJb4,eFFX%NU'E4a`!F#'CKB[#Lm[!#KKrj!\r%DRlmcSEBKpA(B!T`%,L!C!3J"f"#F!2!KB#$*S!S5pR$F!(!K@B%+82rr(!"`)9\r+J'F%F!*J!R!!J)3SJ#9%rra`r5)5`S!NJ5m-,bm!+'(rrrrqkL!$60mFq%jd!!`\rU88MR($JSE`!F*'m!)(Mmb*)Q5YI%+K0fr-D&5S9Y'R!"`)9Q&#m,,`aKrrrrrYc\rBJh!$`*+!K#5!*LVrr(!#`**Q"%U$E!BPK%MmB"iQ5TI$,`X[$'(rrrrqX0D%F!2\r!Ni#$*S!RJcMm*%XJ#NcI($K1G!!)+P&19[ri,`d[,J!))Qhpa#"C6T!!+Qlrp%j\rH6R3!##T46PErq#m0,bi!##*Yr4`J@8k3!#TZrr41ANjd!!JU88MR'$K2lrr`*Lm\r!+#K[!#`QE`!`*%-II!!"!!*#,`!$3Lm!"%)[!!9#,`!'3Um!#%+[!!a5LK!55F!\rQ!()PX)&Q("p$!!G"l`!#3p-Lf#,B)YJbf#"+8SJJ#'!!!U*i!5!$")!!!!!JCb"\rAJ'FX8B"R%&@!C`CAJ'FSB$4#,`!#B$!II!!"!!0J+!`[!!%!!fFJ(h`!!J!$B"J\rII!!"!!9J%%S[!!*R#Kpm!!)!!Q!#H!"+K'F)8SS@%NR$B+"`+VD!CMjBP#"8,fM\rrr!!)5UMrr'`13Lm!!L![!!K%J#p!!!K5LKB55F0J+R!+6#m)!!!)FY$5Jp+!,d%\r!#&++&K**`h!!%!-JEIl`%$!)!()3`)&QeJb[!!!"r3!)EaiII!$r!!G"l`!#3p-\rLf#,B)YJbf#"+8SJJ#'!!!F4`,VD!CPSII!!"!!45LK!55F!Q!()UX)&Q0&L8)&3\r[D2rm!!a+U2rmE!4#,`!%8SS@%NR$B#T`#N`[#!!!$(,3dS25J#p"!!a5LKB55F0\r`!"!$)'hqm"!`#!"b%-#"CYCi!3b$!!!!D'F5$)-!!!"XCa)-J`!!!%aR%Q!B(h`\r!!3!'B")II!!#!!CJ#Kpm!!3!"Q!#H!"+K'F'8SS@%NR$(d-!"b!$")!!!!"&C`!\r!L&@!ChB%J!!!!"&R2&'!9i"R!!#d8i"R-&1!CfT6J'GQ8i"R9P@!Cb"EJ'F!!,a\r6J'F@8i"RGPH!C`!!S&@!C`KAJ'F%B!!!XJ`[!!3!"QB'(h`!!`!'5Lm!"'B+F!%\r[3!!-B!!!QJ`[!!)!!QB!!*!!(h`!!3!#B!!!KNU[!!aQ"R!",d!!$!`[!!%!"QF\r)$#m!!J!'CJJII!$r!!GJB%S[!!4Q@R!',d!!$'"5(h`!!J!'(h`!!3!&(h`!H!!\r(F!J[3!!-B$K+,`!%CJC+,`!'Cb`II!$r!!GJ*%S[!!CR(Kpm!2m!"f!@$#m!"!!\r'CJiII!!$!!CJ"Kpm!2m!"d([!!*$db,B)YJLf$,B)%T5L#!)6qm!%%cI("K1G!!\r-+P&)jam`+#m!)#C[!#4q!#S%*%Y#)R`!5S4Q'NU[!$*Q&%S[!#YR#!`[!'m!,@F\r')!TJ!!%JF!!3,`!Y")!!!!"BCc44J&Q!Ca*EJ'F1AB"R&Pf!CaTAJ'FHB#*f#NU\r%E"a%KAi"B"Cf#%)[!#PJ$RB+3Lm!+@!'GK"#,`!T)!9-3`!"+!&-3e!&F!UiJ'`\r'F$$BJ'!@F!UBJ!`[!(J!,@B'F'(BJ'!%F%(BJ"8%8SC+K@E+F!LfJ'B55Lm!+fF\r-$")!-'F'&6`!-&+'$#m!!J!SCL3[E`!Z!$*+KfB'5Lm!+@F%8km!-R!3YS"Q#NS\r[!#YR"&@[!$)J5j(+)#m!-Y#)$)!!!!(pE`T`!'"'&6`!-&+'[+m!-QhdF"#fJ'B\r15Lm!+fF)&5m!,48m!$"+KfF'&6`!,@!D$#m!!3!TCJB92!!VB!`-,`!#!#PQ""8\rm!#!J#NcI$2K1G!!B+P&)ja``6qrrk#C[!$Kk!#p[!$!!##p[!$3!$#4,3L*i!%+\rR3UF[,`!m,bm!2'(rrrrQC%T!CKT+V`"'CK4+,`!rC`J-,`"[!%&R"L!+B!!"hR!\r!%#m!335!!!!!@'Gd8B"CJ'F5@i"R$Pf!Cd*GJ'G39i"RAQ"X3Um!%#pm!!!!#J!\r83UG#Tbm[!$`[,`!mBIrrrqBX5N"X5Lm[!!`[,`!-5'm!%'(rrrrNBRS"B$4#V`!\r3,h`!!!!)!"4#,`!pB#*#V`!3,h`!!!!+!"4#,`!pB""#V`!3,h`!!!!3!"4#,`!\rp,bm!&#m[!"3[,`!8,bm!&%K[!""KrrrrjA3Q+!!%,bm!&#m[!"3[,`!8,bm!&%K\r[!"KKrrrrj6"`#VD!E!C`-0D!B"C`#TD!$#m!H!""CJC`BGD!B!4`3GD!&305K%+\rR3UF[,`!8,bm!&'(rrrrP4%T!CSa)H!!)3UF[,`!F,bm!('(rrrrP,%T!CK*+,`!\rrC``-%J!`C`B92!!`8S3-,`!#!$aQ0Lp[!%)!4NU&CJC+,`!pC`46V`"'5(J!%%+\rR,bm!(#m[!"aKrrrrj1C+3'B+5Lm!2fF%9Dm!4L",NFSJ,`"'d)J-J!!!!Ie[#R!\r!B&J92!!`8S5iV`"'EI4)H!!33UF[,`!F,bm!('(rrrrNSNT!CJj+,`!rC`J9,`"\r"&6`!-%U&C`B92!!YB"S-,`!"!$eQ"K8m!#YJ$!`[!!)!2@B%&6`!)#!+6qm!'%c\rI$$K1G!!F+P&)ja`i*'m!(#B[!#"+Jf`@3K*#DJ!#&A`!!3!%&A`!-!!&B!!!VR!\r!%#S!",D!E!!!SLC+@S[A`e+,'#0*a(,3f)%-"!!&CLa`!"!U!!3S5PU-f-"6M,R\r,B`B-&!!`Cr5jbfB+%#[rrh)"`)&J!R!"+J"J1J`%!!9H`%3!5F!U!'!X'#0*a(,\r3f)(BK3`%!!PH`%3!5F!U!'B%5J4Q"&1$B!`3"%R!FM$3J4D!B!4+JfE35S9R%P*\rU!!)9I!!"!!39I!!a!!9J#NU$C`$r4"9$!!4-ha`i6R3!##T46PEra%MR($3QEJ!\r8$+i!!!(p!#*["R!!B!!$`%)ZrmipI!!Jrp")E[r5,bi!%#mZ!!`[,J!)5'lrcL*\rYrF`J@8k3!#TZrm"`!"!ZrpC&l[r5@SV8`'!)8blreP*Zrp3-,J!"rpCM"J`L!$"\rRkR!!%#lre`5!!!!!-'F1")!!!!!CCa"EJ'G3B'4#,[r53Qlre'"D3Ulra%+ZrmK\r#E[r-5'lra%KZ!!Jr2!!)UHYX%L4,@iSJ5L*YrJ`J#"$CC[aJ%#4,@BSJ5L*YrJJ\rJ#"$CC[`J#Q!!!`BN5eQ+)%SLEIi%)!J3f@Em)!TJ!!,`F!!3,[r@8i$4E[r8*%Y\r#)R!!%#i!(35!!!!!4@F!!,49J'FB")!!!!!HC`!!TP1!C`!"RP1!C`4J!!+bF!!\r3,[r@X+i!)Qm1,bi!)NKZrp*KrrrrrHB-E[rmrp4Y$$!Zrp4)`,#Z!#*Y-%SZ!"Y\rR"P1Z!#*J$(!!%#lreP1!,8!!)J`Z!'F!(@B)(A`!C3!GB%!GI!"&!"eJ1%SZ!"Y\rR%$!Zrp4)`&+!NDi!)Q!!!5)`,[r85-"5J()!%LlreT+!,8%!)NU"E!!"#%+Z!#*\rJ!!%!)#i!)P+!FJ!5,[r@XS"[%L!Z!#*5J#m!5'lrdQ(rrrrp5$JZrp4)a(SV5S4\rX"%5%HLef!'!D)!4-I!J"!!!!#R!`dS!9!8am5!3!!!!+8S0+K'ELF!+fJ'hF&38\r9,J!G)%Z4bL!Z!#,3L!b!!!!"r@m'F!"J!!'Q)#i!)P+!FJ!5,[r@XS"X'(!!%#l\rreLJZ!#*8K*L!B!392!!`8i4Qq(J!'#lreR!!%!4(l[r5@S[@`'!#&506K'Ek5Ui\r!)QB'5Li!'fF%&6`!,K8ZrpG+,[r5C`J92!!YB!!"3!`Z!!%!'@B)&6`!+f!!!6!\r-,J!#!"PQ!!%Q&6`!)'!!!4j`!"!ZrpBb,[r85-&%JG+!8i%S!8U"E!*i!,LZ!#*\r[0#!%N!#Z!#*b!")ZrpD5J#m"5'lrdQ(rrrrm-R!!%#lreM)Zrp4)`85"dS"6J5J\r"5S&X!RJ!-#lre%M!8S!U!%U!E!*k!#!&d)3-J!!!!Ie["R!!B!!!UR!!%#lreNI\rZrp*DLpE!GJ"J"K8m!$"5Jb!Z!#+3!)5fJ'h`GJ"J""8M8S1fK'`5F!!3,[r@YS"\rYlQ!'&6`!-&+$YS4YpNUZ!#*Q"NSZ!"YR""8m!#j+K@FNGJ"J"K8m!$"5Jh!!%#l\rreL)&NS#fJ@hXB!39)e+$YS9Yq'!%&6`!-%SZrp*R"K8m!#eJ'J`Z!!%!'@B'&6`\r!+f!-$#i!!J!CCJ392!!J)!T-h``i6Pj1G!!J+P&19[h-51FI2#CZ!!JNEJ!-IL!\rS5RJ!B!!&%%Ki!#8[$#*YrH`J@8k3!#TZrFJX!'Bf)%a`re+!5KKQqLB!f)0+JfF\r!"1`[#dKi!!%[!bm-)QhqD#"C6T!!+Qlpb%U!CJ!%d($rB!!%c#"'NF`Q#0L$5S0\rR)#m,5(J!!5m$,``LEIjS)&P1N!!UE[h)5S"Q"R$rB!!%S#K'5'lrkNKZ!"![$'(\rrrrrcr#K!F!!3,[r[")!!!!!PC`!$&J5!!!!!)'F!!ET9J'F!!E3%J!!!!"&R!!$\rm8B"AJ'F!!Z"6J'G#8i"R!!'B8i"R!!'58i"R!!'-9B"R,&Z!C`!#I&1!C`!!cPQ\r!C`!"rP@!C`!!`PH!C`!![!5!!!!!KfF!!VjJ!!+k$#i!![rZCJjBVJ!3)'i!%#S\rSrraJ+J`Z!!2rlQB@8+i!%#"Z!"!YD2rirH)YD2rmrHCJ$&LZ!"!JEJ!3+LMrr!`\rZ!!(rlQB%-%8U#!`Z!!2rlQBS3HlrqLmJ,b![)#mJ5'lrkLmZrHB[,[hLBIrrrrG\ri*%"+J'BNB!!#2N(ZrrS[)#mJ,b![)%KZrqS["@(rrrreqL4!5S"R!!)H3HlpkN(\rS!Iq4bLB)B!!#4J`Z!!,rlQB1@+i!%#"Z!"!U+2rmB#S-,J!$rqjQ&P#Z!"!JEJ!\r3,@Mrq2hL,@Mrr2hQB!aBVJ!3)'i!%#SSrr`-,J!"rqjQ"R!!-!8U!!`Z!!2rlQB\rS3HlrqLmJ,b![)#mJ5'lrkLmZrHB[,[hLBIrrrrE+*%"+J'BNB!!"N!""l[rk,b!\r[)#mJ,b")E[rU,`9Krrrrp8`N3%U!C`!"F%(ZrHT"k!(rNFSQ#'!!!CJ-,J!%rqj\rQ(R!+dDi!%#"Z!"!YD2rfrGJYD2rkrG`pD2rqrH"J+&#Z!"!JEJ!35'Mrq%KZrFi\rr2!J1UHXYE[h1rGJYE[h5rG`pE[h@rH""l[rk,b![)#mJ,b")E[rU,blpi#mZrG`\r[,[hBBIrrrrNf*%"+J'F!!1K"l[hU3HJ"rj(+*JKJ!!%3@+i!%#"Z!"!ND2rm)!T\rQ"#4YrJ"+,[rYCaaf!"BD5Llrl'F!!1UfV[rdE`!!iLBZrr4J!!$D5Llrl'FQ*Ll\rrp#m$3UF[#L*YrM!J@8k3!#TZrFJX!'F!!,JJ4T(+*JKJ!!#Z)%T`re+!5KKQqLB\r!B!!!RPLZ!"!JEJ!3*'Mrr(!!%#lrlQF38i"R%P1!Ca46J'F@B!!"P#5%B!!"MM5\r%B!!"L#5%B!!"JLm%,`TKrrrrh$4J!!&d4HlpkPLZ!"!JEJ!3&+MrrhB"B%4&l[h\rU&,`!*AB"B$JJ4R$r8S"+''Ek*J$BJdU$Cb![#dKi!!%[!bm')QhqD#"C6T!!+Ql\rpb%U!CJC`rf!!!5SJ"'!!!53X!dSZrqTR!!#Q$#i!![rUCJ4`-'!#F#!H!!`5!#Y\rR#!`5!#eQ!!##$!F!-'Ck)#X!)P1V!#*+J'F3)'X!(P+V!"i3NR!!%"*J&#m,%"*\r*`#m!)QhqH#"C6T!!+Qlpb&+!CJC`rf!!!,a5LP1$B$SJ+`!L8kX!)NU!Ca!JD`!\rH8UX!(K#(F!!3"f!8,`X3"dR!,`!LEIji)&P1N!!UE[h)8S"Q"($rB(a5KVbZrr"\rY`%U$Cai[#dKi!!%[!bm+)QhqD#"C6T!!+Qlpb%U!CJ4`rf"55LlrkQC#B$SJ+`!\rL8kX!)NU!Ca)JD`!H8UX!(K#m!#"`!(!JB")[#dKi!#!LEIji)&P1N!!UE[h)8S"\rQ"($rB"*5KVbZrr"Y`0L'5K4Q!2VZ)!4-haci6Pj1G!!-+P&19[q`51F32#4Z!!J\rSEJ!-*Qi!%%Ki!!&)H2rr,`T)E[qb)Qhpi#"C6T!!+QlrV#m,,`a)E[qb)Qhpr#"\rC6T!!+QlrV#B!5S0Y"%)b1!!J!dcI(!K1ANjd!!`U88j@rrJ[$8KZ!"![,J!-,bi\r!##*YrIJJ@8k3!#TZrr41ANje+P%[$#K[!!JJE`!-)#m!%#*))%a5J'!1%0PQ#Q!\r#3KK6J'EkB!46J'EZ)!`SAdjd!!`U88MR'$!QE`!8+#m!'#4,&J4J$,J$CJJJ5P1\r))!KJ%KJDC["+!fF%NFKJ"#"+8iJJ#%cI$"K1G!!)+P&)jaJ`*Qm!&#J[!"JN5jI\r,&J4J#,J$CJ3Q5P1,'"TQp#!,C`3J#f!15J0R"*()B!3J5P1))!K-h``B6R3!##T\r46PErq%MR'$3NEJ!)*Qi!$#JZ!"!Q,J!8,`3[#b"YrH3[%#m+)QhqP#"C6T!!+Ql\rrp1rU-!-!##m+)QhqK#"C6T!!+Qlrp(!!60m-'%jH6R3!%#T4F!*1G!!3+P&`!%j\rd!"!U8A!!6R3!"#T46PEr3%MR'!3S,J!)5S4Y#R!#Z)"Z"(!!B(T#E[pF286r@%+\rZre*)E[p!)Qhp1#"C6T!!+Qlr2$B!-!0)`'Bm2@lr9[q8286rPNKZrhiLEIe3)&P\r1N!!UE[mm0J!`!dM!CKT#V[q3!$eZreErP%KZrhiLEIdJ)&P1N!!UE[mm-!0)`'F\r+-!0)`#"YrNJJJ%T$CJ4`!'!#F2p-h`!B6Pj1G!!%+P&2lrrd,fm!&!!#,fm!'!!\r'2fm!(!!+,bm!)%K[!!B[,`!B,aF[,`!),bm!%$mm!!ZTke"2@%p2l`!-6R3!&!J\rN!4q"K!)K!3%LK"J#)3%")S3B!L%"!5+!Z!)N!4q(k)B#!3X!$#)5&!)K!3-L%K3\r@)L3i!L)N-!)L*#J))4-6)K%8!L%"!b)4&"BL*$J#)L3`!L)N+!JK%4-L%"3#)3%\r$)K!8&L)N1!)L*$!#)L3S!*&%))&r!C!*!T!&!C!5"!L3$c#3#JL3"k#3"S#3&!L\r3"Q#3"N#3&!L3"!'!N!G!N"N)N!G!#*!'J)!)N!j!3!L3#i#3"%!)N!K!J!L3"%"\r!#*!&J*!,#)#3"!L3#J%N,8PZCJ)M5@jQ!501B8i$)Kh!!+Y3)L-)JJ*,)a!M'#-\rJ)bJM-#-i#XJM3#0))e!M@#0J)fJ+aJV##Vi+Z#0`)hJMJ#1))j!!)jJMS#1S)l!\rMZ#2!)mJMd#2B%aJMi#2S)r!Mq"-F*!!N##33*"JN)"-8*%!N5#43*&JNB#4S*(!\rNH#5!*)J2l!rS$q32i#53!#5B#q!NS"q8*4JNU#5`*,JN`#6S!#BNm#6i*3!+c!Q\ri*3JR*4!%,NP38!%J-39SEh0dFbGcEf0VCA4ICACPER4ID'&ZC'aPFMSJFfpMDf9\rd)'j[G#"TEL"eFf@UrJF,)YIe!5%3!5%%!L)Ni!JK2`%J-408CA0d9(*KBfXJ9A0\rPFL"*EQC[4A*bEh)J*@3J4f9dG'PZCb"6HA-J4@jfDA*[ER-")%T&ERC@CA)J*@3\rJE@&MD&4jF'8J*@3JFhPc9Q9b)#9N)("bEf-J*@3J4P"9)#9N)%0[E'pb883J*@3\rJDf*N)#9N)'&d9Q9bFb!PC!)S*A-k*A-k*A-#*8eKBdp6!51UrJF-)58")4!")33\r#)L6)!#SL2c`")`DTm!)Lrrd5)L,3JJ+""NVd)Y"+9#,35N`Ld%T%)Y"+2#,35HS\rLd%QU)Y"*F#,356iLd%ND)Y")`#,33i3Ld$J#)Y!hj#,306BLd$3`)Y!clL,3-q)\rLd$0@)Y!c,#,3-[`Ld$,))Y!bP#,3-83Ld$%Q)Y!`a#,3-&!Ld#lf)Y!ZGL,3,H)\rLd#c`)Y!XGL,3+K!Ld#S+)Y!U"#,3+I`Ld#Qi)Y!TB#,3*jBLd#D5)Y!Q"#,3*G`\rLd#@N)Y!PAL,3*2`Ld#3q)Y!Mp#,3)iSLd#&X)Y!K1#,3)3)Ld#"m)Y!J@#,3)$i\rLd#!H)Y!Ir#,3(l`Ld"mX)Y!E%L,3&C!!)Y!1jL,3#(`Ld!K8)Y!%JL,3!i)Ld##\rB5c3#D!(J%L%"!5%-"#&H"b5+!3--!b-""J%")4`$*3&S!@%-!bB"r2rrh6J#)J,\r%!5)"%!-P!i)"!3J$)`5#!B%$"`J!!!63!!J!!!8i!3`!!!9`!3J!!#8&T!%K#!-\rP"I)"!3J$*3EH!3%)!b8(DJ&K#!-L#&3'*3Km!5!)!b8)[!&K4!-M#F!"!5&B!b8\r+A!%M4!-P#e!")%J$*3['!3%X!b)-2JBP$&3"!3J$)JcJ!5)"#!-L$8!'*3f-!5!\r)!b80kJ%R#!-P$ZB")!J$)Jmd!5,M#!-L%$`")Q%-!b84#J(r#!-P%bi")3J$)a3\r-!3%K#!-M&&S"!5%)!bB8T2rrh6i#*K8DrrrG4!)P&C!!!H%F!bB@`[rrh8S#*4F\ri!H!F!b8Bj!%J#!-M'GB"!5%F!b8DKJ%J$!-Q'a,rrpe3!L)GiJBL(LS#)3J$*4j\rL!H-)!b)Hj!%L!3J$*4mX!5-)!b-I[!%")3J$)Krm"L-JV!%")3J$)b$D!3%K#!-\rP)3)")!J$)L%i"L)KcS%$"[mB!!!Ld#!!!!!LpL!!!!!M(![rN!3!N!F"!!!Nf!!\r!!!%!!#63!!!!!3!!!%!!!!!"!!!"A!!!!C3!!!8)!!!!!3!!!!3!N!p!!*!)!J!\r!$3)!!"`#!!!Q!J!!-J)!!$S#!!"'!J!!6J)!!&N#!!"P!J!!F!)!!))#!!#5!J!\r!R3)!!+S#!!#k!J!!a!)!!-X#!!$D!J!!i!)!!1S#!!$i!J!""J)!!4%#!!%J!J!\r"-J)!!8X#!!&B!J!"C!)!!AB#!!'(!J!"N`)!!D%#!!'U!J!"[`)!!FF#!!(6!J!\r"f`)!!HJ#!!(e!J!#!`)!!JS#!!)D!J!#+3)!!M3#!!*#!J!#8!)!!Pm#!!*[!J!\r#IJ)!!SF#!!+5!J!#QJ)!!US#!!+i!J!#aJ)!!Y)#!!,K!J!#l!)!![N#!!-"!J!\r$$`)!!ad#!!-M!J!$,3!"!*!&(!#3"!4"S!!!2%)!!F1!)8)!S!!!JN)!!F1!)8)\r!S!!!b%)!!F1J!"qB5Mp#6!q"S!!L&%)!J1p'38)!5@jdCA*QB@0P6'PL!%CbB@e\rP8QpeEQ45C@0d!%GPG&G%5@jQE`"33P*PB@4"FhPZB`"0EhCP5%KT!&0jFd9ZGQP\rbEfjc!%K9EQa[BfX!8%*5C@&N8hPZB`"0Ef4KE%4TB@a[C`"2F'9Z4(*TGQ9b!%0\rKE'a9EQPfCA*cB@a3FQpM!&"#5%GPG&C*EQC[8hPZB`"9Ff95CA0'D@aP!&"#8f9\rd48p'8hPZB`"33NK(CA4'5@jQEe0jEQ-!6Q9h5'&ZC'aP!(!bBh0dFJ"%CA4KBfK\r5CA0[GA*MC3"%C@aKH3"8D@0V3fpeER3!4f9d4'PKE'pR5A4PE3")D@aTG'9$Efj\rdFQpX!%4TFh"[Ff93G()!8%*'E(9cD&C[E&0jEQ-!4f9d4'PKE'pR5A4PE94PH(3\r!4'PcF'pcC9*[GA4TEQ9%CA0MFQP`G'pb!%GPG%jPGd4TB@a[C`""C'45CA0[GA*\rMC3"6CA4%D@&XEfG*G'9Y9'9iG!"33NGPG%C$3NPZCQp6H@jM!%GPG&*PFfpeFQ0\rP!&"#8f9d48p'3A0jEQ-!4'9LG@G6G()!6Q9h8QpeG'PZC84PFf0bDA"dEh)!8f9\rd8'pbG!"33N0XEh0P8hPZB`"(CA43Eh*d!%0XEh0P8Q9c4QPXC3"33PGbDA4P3A0\rjEQ-!8%*)4f9d9QpX8hPZB`"M-R"cG()!3fKKEQGPC&*PFfpeFQ0P!&"#3fpZG(*\r[E%&cH@jM!&0jFh4PE94KFfX!8%*)4'9XCA4P8hPZB`"%DA0`Eh0P4'PKE'pR!%G\rPG%PZC&*PFfpeFQ0P!&*PE'9KFf95CA0[GA*MC3"33P0PG%C3Eh0"FhPZB`"5CA0\r&FR*[FJ"'D@jN4QpXC'9b!%GPFh4KE(3!6NGPG&4bBA""C'4bCA0c!&"#8f9d4P"\r[Fe0jEQ-!8%*$EfjdFQpX8hPZB`"33PGbDA4P8hPZB`"'8h"2F'9Z8Q9c4QPXC3"\r$GA*5CA0'D@aP!%K2F'9Z8Q9c4QPXC3"3C@j6DATP!&GbDA4P8Q9cEh9bBf8!4'P\rcF'pcC8KKEQ4XC3")6'pMD`"*ER0PG&*PBh3!6Q9h8(4b!%GPG%*64%eKBdp64A*\rbEh*(E(9P!%GPG%*64%eKBdp64A*bEh)!G'9cG&pdFQ&MDdGXG@8!G'9cG&pdFQ&\rMD`!!#!!!!!J!!J!8a+F!%$dd!!jkQJ!+TjN"!!-d!!!LX!!"!J!$53!!*-J!!3%\r!!eS!!#)!!!%#!!0T!!!Ni!!"!*!)5Qpj)A"PCQC`Gh"M!!!!!E(413S!N!d$!!)\r!N!6rN!3!N!CR+!!!CbJ!!'FS!!!'!!!%"!$rN!3!N!BP&!!!%2%!!!3G!!"Y-!)\r""!$rN!3!N!i&H!!!!)!%"!3!N!ArN!3!N!F"!!!#H!!!!!%!!!*`!!!!!J!!!%)\r!!!!"!!!"I!!!!DJ!!!8i!!!!!3!!!!3!N!p"!*!,$3#3#`%!!!""!*!%!J!!&3)\r!!#3#!!!Z!J!!1J)!!%)#!!"1!J!!9J)!!'%#!!"Y!J!!H!)!!)S#!!#D!J!!T3)\r!!,)#!!$#!J!!c!)!!0-#!!$L!J!!k!)!!2)#!!%!!J!"$J)!!4N#!!%S!J!"1J)\r!!9-#!!&J!J!"E!)!!Ai#!!'2!J!"Q`)!!DN#!!'b!J!"a`)!!Fm#!!(E!J!"i`)\r!!I!#!!(q!J!##`)!!KN#!!)J!J!#-!)!!Mm#!!*+!J!#@!)!!QB#!!*e!J!#K3)\r!!T3#!!+G!J!#U!)!!V!#!!,!!J!#cJ)!!Y`#!!,S!J!#p`)!!`3#!!-2!J!$&`)\r!!b8#!!-V!J!$13)!!d-#!!0+!!%!N!89!*!%5N&#&%!"3J&!!8)IJ&0'&35"#S%\r#!3""!8-"`3""!8-"`3""!81+!d#'!!"*ER4PFQCKBf9-D@)!6@&dD%aTBJ"'FQ&\rYC9*[G@jN8Q9MG!"(CA4A4%PZCQm!8%*5C@&N3A0jEQ-!6@pfC8K)D3"6HA0&ERC\rTFQpZF`")9@jXEf0V!&"#8Q9KC&0jEQ-!6@pNB@a%D@&XEfF!6h"PEN4bDACPFJ"\r$B@aX9@jTGQ9bFf&X8(*[B`"33NK(CA4@5@jQEe0jEQ-!9A0P8Q9c4QPXC3"33P0\rPG%924P0jEQ-!8%*)4f9d4NPZCQp6H@jM!%jPGdKKEQ4XC3"`-Q0cG()!4'9dB@0\rS8Q9cEh9bBf8!4'9XBAN!9'PMDd0[G@jd!%GPG%4TB@a[CdPdC@d!5'PXDA4P3fp\rZG(*[E!"%DA0`Eh0P8(4b!&"#4QaeFfK@Efa6H@jM!%GPG%4TB@a[CdPdC@e8CAK\rd!%4TFh"[Ff95Eh9dD@jP4'9cBh*TF(4[FJ"(CA41CAG%D@&XEfF!3@4N8Q9cEh9\rbBf8!8f9d4'PKE'pR5A4PE94PH(3!8%*(CA4'3d**EQC[8hPZB`"(CA45CA0[GA*\rMC3"33P0PG%924N&cH@jM!%4PBR9R8h4b!%jPGe*[GA4TEQ9%CA0MFQP`G'pb!&0\rPG&"[FR3!8%*$E'pcC90jEQ-!4f9d8'pbG!"$E'pcC9*PFdCTE'8!3Qa[BfY0EhC\rP4'&dB3"33PGbDA4P3A0jEQ-!8%*)4f9d9QpX8hPZB`"M-R"cG()!3fKKEQGPC&*\rPFfpeFQ0P!&"#3fpZG(*[E%&cH@jM!&0jFh4PE94KFfX!8%*)4'9XCA4P8hPZB`"\r%DA0`Eh0P4'PKE'pR!%GPG%PZC&*PFfpeFQ0P!&*PE'9KFf95CA0[GA*MC3"33P0\rPG%C3Eh0"FhPZB`"5CA0&FR*[FJ"'D@jN4QpXC'9b!%GPFh4KE(3!6NGPG&4bBA"\r"C'4bCA0c!&"#8f9d4P"[Fe0jEQ-!8%*$EfjdFQpX8hPZB`"33PGbDA4P8hPZB`"\r'8h"2F'9Z8Q9c4QPXC3")6h"PEP*PFdCTE'8!3h9b8Q9c4QPXC3"3C@j6DATP!&G\rbDA4P8Q9cEh9bBf8!5%a[BfX!4'PcF'pcC8KKEQ4XC3"*ER0PG&*PBh3!6Q9h8(4\rb!'jeE6*NC@-!4f9d3P0%6@&M6e0&FR*[FNGPG%*64%eKBdp64A*bEh*(E(9PG'9\rcG&pdFQ&MDh4PFh4IG(*KBfY(E(9P!!!!#!!!!!J!!J!3263!&-5R!!URQ3!1HTS\r#!!05!!!#J!!"!3!$BJ!!!pJ!!3)!!hB!!!*S!!%"!!1!!!!$,!!"!*!)I!J#TT!\r!!3!)P#(r`$JK!%#!!3!)I!J$TNk!!#"m#!+QNq(rr*!!!3!)P#(r`$aJ!!%iBkT\rZ1)!!!8J!Ab'!33!8I(mEH$aJ!!%iBkKZ1)!!!8J!A`Q!33!8I!2i3%##!!`iB!)\r!5!!!#$KJ"!#!!3")1#%!3(`)!kD$iIrm6S!!)&4N"5P!JJ!-1'!!!%k!!#!iB!!\r"6S!!)(`)!UD6iIrmNm(rq*1Krr53!!%!#*3Krl"mIaYiIq2lH%[rrmPmIKYiIm-\r(G#`$!!&!JJ!J5rrr8AaM"c4Ar`9qIq3(0(`%'!""J!!)1q#SRhrMqhKra20i5!"\rHDB""!"4mI4Yi2'!!!6KMU*miJ!!"5!"H8B""!"4m!qK!I+!!*P5P(rjSS`!"J!%\r!@$JK!&"m#!1QJq(rr)2"rrL$SIrd6S!!)(`)!UD6iIrmNm(rq*!!!3!)P#(rS(a\rq'hKmRb0i1'!!!6L"!$a)!&iTJ%%!&+KK!%Tra20iIqAlH$M"!$K)!&iTJ%%!&(a\rM"c9"JJ!81'!!!,"q!!!iJ!!!N!#I!!#!!3"S1#%!B(`)!kD$iIrmJm(rq%k!!#"\rm#!+QNq(rr*2"rrL6SIrdN!!"!!L8)Iq`I(dEH(bH)hJli!!!1'#KV8[rrX&8B`B\rr3B)!*$aJCQmiBfaN1)%!1%J!AB'!33!8I'-(08##!!Jli!!"9q-'2d##!"4rSqY\riIm6cH%[rrbP)!!!m1'#!!$b!Bh3iK(*X1+!!!(qQkhKrar0i5!"GKB""!"4mB`F\re3B)!&$L!!!#`R3!!1+!!!*!![J!!J!%!@$JK!&"m#!1QJq(rr)2"rrL$SIrd6S!\r!)(`)!UDrBIrXN!!"!!L8)Ii`I(XEH(bF)hKm[5YiI0icH$KJ!!#3!'%"4$L"!$L\r3!)%"5V1K!8k6`3&S1+!!!E#K!94)!!"mJ-%"@(`'f%"!JJ"JJ1%"A(`(i%"!JJ"\r8Ik2VH(r%mhJiS3!i1-!!!8J!A2@!33!8I(mEH$aJC'iiBh*`1)!!!8J!A2@!33!\r8+!-!!%##!"4rirYi5!"EmB""!"4)!!!-Iq2lH%J!!#bT!3&813J!!E%"!956`3&\rS1'%"1%J!A0'!33!8I'-(08'#rhJiB2rrJ!%"f$JK!G"m#!1QZf(rl%k!!#"m#!+\rQNq(rr*!!!3!)P#(rX$KK!$`iJ3!i5rrq36aJBf3iBf9f2)"kG$L%Bh#SS3!mJ-%\r!1%[rrZ9mIaYiIq-(0#`$rrp"JJ!-Iq2lH%J!!)JiB3!m1)%!1%[rrBdmB'0N1'0\rPGMb!EA3iK'0`U+%!2)$"!$K,rrkPI(mEH(rN"c3X"2rr3B)!$(rMqhK)!!")1'%\r!2$L"!$K,rrh"2'"MC$KMCABmJ'ed1)4MF+LK!$b!`3!i5rrqCAar'hKrj3Fd,!A\rrrd'#!!arirYi5!!!#$KJrrq!!3"B1#%!8(`)!kD$iIrm6S!!)(`)!UD6iIrmNm(\rrq*!!!3!)P#(r`*!!B3"BJ')"p#J$!!""JJ!-1'!!!%J!!-a,rrlYI(mEH$aJC'i\riBh*`1)!!!8J!@fQ!33!8N!"L!IL!JJ(i+!3!!%##!"")!&SaJ%%!&%J!!*5!BJ(\ri5!"EFB""!"4rj3Fd,!Arrd'#!""rirYi5!"D1B""!"5!BJ(i5!"ECB""!"5!BJ(\ri5!"DDB""!"5!`J(iJ-B!!*!!`J(dJ')"p$L!!q%iS!!"J-%!@%J!@df!33!8I(i\rEH(r("c9"JJ!NJ')"q%J!@df!33!8J')"q%J!@eQ!33!813!!!*%#!I4r`r0iJ!%\r!5$JK!%"m#!1QJq(rr)2"rrK1J!!JI!J#TT!!!3!)P#(r`*!!B3"BN!#"!&b3!+%\r!B*!!`3"NJ')"p#J$!!"!JJ!-1'$rj%J!!#b!BJ(d2)!!!6L%rq%iS!!$J-%!@)$\rK!&b"!3"JJ5%!C%J!@Uf!33!8J!%!5$JK!%"m#!1Q6S!!)(`)!UD6iIrmNm(rq*!\r!!3!)P#(r`*!!B3"B1q)4r$[#%I5!B3"B1))3mB#L!Aa)!!-CB!!!!#`$!!""JJ!\r-1'!!!%J!!$b!BJ&mN!"q!!!iJ!!!N!#H!!3iSK$aN!#r!!!i`!!!N!$I!!3ii!!\r#N!$r!!Jj!!!%N4m!$*2I!""rirYiJ!%!5$JK!%"m#!1QJq(rr)2"rrK1J!!JI!J\r#TT2Krrb3!!%!#*3Krm!iBJ,i1))#$NJ!AI'!33!8I(m(0(rMqhL!!3")1#%!3(`\r)!kD$iIrm6S!!)(`)!UD3!!%!#*3Krm#!BJ))+!-!!%'#!"5"JJ))5!"H+B""!"4\r)!!!)1'!!!)!"!%Ji)3"!I!J$TNk!!#"m#!+QNq(rr*2"rrL3!!%!#*3Krm"mIKY\riU(i!!#`$!!&"JJ!-U(i!!%J!!#4,rrqCI(mEH8'#!!arirYi5!!!%%J!@DQ!33!\r85rrrd)!"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)(`)!UD6iIrmNm(rq*1Krr53!!%\r!#*3Krl"mI4Yi1q)5%+KL!JiX!`!!3))!(%[rr[PmIKYi,"i!!%'#!!ar`r0i5!!\r!Z(rMqhJiJ!!!1+!!CNJ!-lPJ!!!!U))#$V#I!"JiS!!QX,m!'T1r!"`i`!!HQ0m\r!)$MJ!!#Br`!K13$r`*NI!#*rirYi5!"F[B""!"3iI`!35rrr#Aaq'hKrirYi1)!\r!!$LJ!'C)!$0KB!!!!+NL!Jka2`!B18!!+V&I!"U6[`!FIq2lH%J!A-@!33!8UAm\r!%#`,!!"!JJ!3J(m!)%J!(M9J!!!!,"i!!%##!!LVh`!3Im2cH)!"!&Ji)3"3I!J\r$TS2Krrb$`IriJk(rp%k!!#"m#!+QNq(rr*2"rrL3!!%!#*3Krm#3!'%!@$[L%RL\rSBJ)1,!-!!%##!"a,rrhTI(iEH#`H!!""JJ!-1'!!!%J!!'arirYi1)!!!$LJ!'C\r)!$+TB!!!!+L#!Jk`R`!B1+!!+,#r!"U!`3"BN!$I!"arirYi5!"E`B""!"3iI`!\r35rrq$Aaq'hJX(J!!3B)!$$KJ!!")!!!BS2m!2#J(!!"p!!!Q93JIrQN$!!'!!3"\r)1#%!3(`)!kD$iIrmJm(rq%k!!#"m#!+Q[f(rl*!!!3!)P#(rX*!!B3"SI*XMH*!\r!S3"`1q)5i)2#!Bb!BJ)%,!-!!%##!#`iBJ,p5rrl&@!!!!"mI3Fd,"d!!%'#!!a\rrSqYi5!!!T$L!!!'3!))#")"L!C!!1)!$`$LJ!!&)!&FeJ%%!&(am'hJiS!!"X,i\r!!)"K!'Krj2YiIiAMH(r'mhK,rr[0B!!!!)$I!!!X"UAq3))!%(r$mhK,rrdTN!"\rr!!"rJq0i5!"A(B""!"5!r`!!,!F!!%'#!!b!I`!!5!!!,)%I!35")3"`N3N!!#J\rE!!""JJ!8If2EH$LI!!4)!%mYB!!!!$KJ!!#!!3"B1#%!8(`)!kDlBIrX6S!!))#\rM!!#`T!!!6S!!)(`)!UD6iIrmNm(rq*!!!3!)P#(r`,#"!&jm[LYiS'%!ALJ$!!&\r!JJ!FIprcH(r$mhL!R`!)JCm!"%J!@SQ!33!8J!%!5$JK!%"m#!1QJq(rr)2"rrK\r1J!!JI!J#TT2Krrb6`IriNk(rp*1"rr#3!!%!#*3Krh"mI"YiN!#"!+b3!+%!X*!\r!`3#dN!$K!,L4!3#m1k)6p$[!!!#SBJ)1,!-!!%##!"a,rrZKI(iEH#`H!!""JJ!\r-Im2cH%J!!1JiB3!i1)!!!$LJ!$T)!$"KB!!!!$KJ!!a)!"VGB!!!!(ar'hJS(`!\r!3))!$$KJ!!a)!!#d1)!!&,#"!&+SSJ)1X+%!8)$"!,#3!-%!@)$K!,53!1%!A)%\rG!!!S#!!!3))!()"L!B3iJ$l!1+!!!8J!9@@!33!8N!"p!!#"23!!N5%!B+&F!!#\ra33"NNq%!CMKK!$K)!&NCJ%%!&+PK!%JX#`!!3B)!'(rMqhK)!"V4B!!!!+KK!%K\r)!!!`JB%!9*'I!!#!B3#mN!"r!!5!J3#XN!#I!!L!S3#iNq8!!+$"!'5`h!!!Im2\rcH)!"!*Ji)3#3!(`)!kD$iIrmJm(rq)1Krr5$JIr`6S!!)(`)!UD6iIrmNm(rq*!\r!!3!)P#(rF*!!B3#SN!#"!+b`S3#bN!$"!,53!1%!Z$KK!%3iJ!!!1+!!1NJ!,c9\rJ!!!!J'%!Z,"K!$L!J3#dN!#"!$SiS!!!X+%!2S2K!+Ji`!!AX-%!AUML!Jk`i3"\rFJ4m!!*%"!'#")3#XN5%!CU&"!,+a33"U1@!!!CPK!(!jJ3!iNB%!E$KK!%4)!&J\r4J%%!&$KK!&4,rrTGI(iEH(r$mhL!!3#B1#%!N!"m#!1QJq(rr)2"rrK1J!!JI!J\r#TT2Krrb6`IriNk(rp*!!!3!)P#(rF*!!B3#SN!#"!+b3!+%!X*!!`3#dI2dlH*%\r"!,`iB3!i1)!!!$LJ!$T)!#jTB!!!!)2"!+JiB!!9X'%!8UL#!Jk`J3"3J,i!!*!\r!S3"8L-)#$,$"!&JiB3!i5!"AGB""!"3iB3")5rrj`Aar'hJX(`!!3B)!$(rMqhK\r)!!"dJ'%!Y)#"!'#Ji3"NI"di!%#!!!arTHYi5!!!#+#K!'4)!#fjB!!!!+%"!'5\r")3#mN3N!!)&"!&U"B3#XN8X!!+'"!&k!B3#`XB-!!$L!!"D`J3"51'%!1%J!9[Q\r!33!81'%!5%[rq89mIaYiIq2lH)!"!*Ji)3#3!(`)!kD$iIrmJm(rq)1Krr41J!!\rJI!J#TT2Krrb3!!%!#*3Kri#3!'%!Q$KK!$`iJ!!!1+!!1NJ!,@PJ!!!!Jq%!Q$K\rJ!"L`B3"@U))#$V#"!&5![`!!N!#K!&JiB3!m5!"@IB""!"3iB3"-5rribC!!B3!\riIq2lH%J!'$9J!!!!J!%!L$JK!)"m#!1QJq(rr%k!!#"m#!+QNq(rr*!!!3!)P#(\rrN!#3!'%!L+KL!JiX!`!!3))!&%[rq!PmIaYi,"m!!%##!%`iB3!i1)!!!$LJ!#4\r)!#c4B!!!!$L!!!q`J3"5U+)#$V#K!&!iB3!i5!"9mB""!"5S`3"),!B!!%##!"#\r!i3"8J3%!L*!!k!!!J!%!H$JK!("m#!1QJq(rr%k!!#"1J!!JI!J#TT2Krrb3!!%\r!#*3Krm#!BJ)3+!-!!%'#!!`iB!!!5!!!J$KJ#3")!"EGB!!!!*!!BJ)3J))#%#J\r%!!"!JJ!N1+!!$$M#&l#3!+B!!$MJ!!`j!K4iX1J!!$KJrrp)!!"%J')#%$L!!!!\riS!N!5!!X%@!!!!!li!!!5!!!($Nr!)#"3J)3(Am!5$P+!!4p+PNZ1rm!!5`I!#"\r"J2rN1'!!!)!"!%Ji)3"!I!J$TS2Krra1J!!JI!J#TT2Krrb3!!%!#*3Krm",rrm\rp,!-!!%'#!!`iB!!!5!!!3$[J!!")!!!XJ')#%"bI!%KmBb#Z9'22rd##!"5!SJ)\r3(0m!5(aP-K4)!!!81rm!!5`I!#""J2r81'!!!)!"!%Ji)3"!I!J$TS2Krra1J!!\rJNq(rr$[J!!")!!!`J))#%"br!%JiK!!%I)3S,R`$)!"!JJ!8J-)#%"cr!%KmCMS\r85!!!&$[r!!%X(`!J3B$rd$KJ!!#$iIrm6S!!)(`)!UD6iIrmN!!"!!L8)Ir!I(m\rEH(rMqhJiJ!!!1+!!"%J!+ZPJ!!!!1'!!!*!!I`!iJ*m!0#J%!!""JJ!3J(m!0%J\r!&G9J!!!!1+!!!*!![`!d1-!!!*!!h`!`J!%!5$JK!%"m#!1QJq(rr%k!!#"m#!+\rQ[d(rk*!!!3!)P#(rX(am'hKmQL0iI,XVH$ZL&(Jl`KH`,"`!!N##!"3X'`!!3B)\r!*#`E!!*"JJ!F1'!!&T!!IJ!!1)!!&V#G!!!iB2rr5!!"!#`D!!*"JJ!N,"S!!8'\r#!"`iS!!@N!#q!!!i`!!@X0d!!$KJrrp)!!$B5rrq@Aar'hJS(`!!3))!($MJ!!b\r3!2i!!$N!!!ba(3!!1'$rrdJ!!,#cR`!)Xjm!',1I!#LcI`!UNem!,)%r!$3S#3!\r!3))!3$KJ#!")!"4GB!!!!*!!I`!d18!)!*&I!$#"I`!d+!X!!%##!"`jJ!!-NCi\r!!$KJ!!b`I3!!1'$rrdJ!!&4rirYi1)!!!$LJ!!4)!#Q4B!!!!$L!!!')[`!!8)8\rq-*Lr!!!i`!!!S2m!!&$(2(#`r`!!13!!!)Nr!!&4#5EfQ6m!!6P!!!#4A`!iJ(m\r!")!"!&Ji)3"3I!J$TVY"rqK1J!!JI!J#TT2Krrb3!!%!#*3Krm#3!)%!A)2K!&b\r)I`!!9'22rd##!"!iBJ-$5!"5(B""!"5JR`!!9)A12MLP!!&3T$a`X*m!!)!"!%J\ri)3"!I!J$TS2Krra1J!!JI!J#TVm"rq#3!!%!#*3Krk#3!'%!H*!!J3"mI,JVH(c\rj1hL4!3#-1k)8H$[#&l#!B3"i5rrpAAar'hJS(`!!3))!($KJ!"D3!(i!!$L!!"D\r`R3!!1'$rrdJ!!4L![`!X,!8!!N##!"#Jh`!)+!B!!N'#!"`ii!!@N!$q!!!j!!!\r@X4d!!$KJrrp)!!$SJ6m!1#J*!!"!JJ"S1(m!#RrNqhL![`!dJ0m!-$Mr!$L"!J'\ri5rrhD@!!!!"mHKYi,"S!!%'#!#"rirYi5rrp&6P!!"Q4AJ!!Xed!!$KJrrp)!!#\r81(m!$%[rq[9J!!!!1@!!!BQI!!&4E#EfQCm!!B"K!)`S!`!33))!%+#C!!!S"!!\r#3B)!($LJ!"D3!,i!!$M!!"D`h3!!1'$rrdJ!!%Kr2-YiJ(m!1)#F!!5J[!!#J-%\r!I(m(`hK,rrJjB!!!!(al'hJX'`!!3B)!'$MJ!"Q3!2i!!,0p!!!iB2rr5!!!#(m\r$`hL!!3"S1#%!B(`)!kDl!IrJ6S!!)(`)!UDr3IrSN!!"!!L8)IqJN!"K!(L3!)%\r!I*!!S3#!N!$K!)Kp'N0i1k)8H$[#&l#!B3"i5rrlhAar'hJS(`!!3))!($KJ!"D\r3!(i!!$L!!"D`R3!!1'$rrdJ!!0#![`!X,!8!!N##!"#Jh`!)+!B!!N'#!"`ii!!\r@N!$q!!!j!!!@X4d!!$KJrrp)!!#JJ6S!!#J*!""!J!!F18!!&T&H!!!jB!!@XAd\r!!$KJrrp)!!"m1B!!%*'D!!#$J3#)1'!!!V"m!!#!I`!i1*`!"$Lm!!+!`3"mJ1%\r!J$N"!$K,rrIPB!!!!(al'hLJR`!!9)612d'#!"LJ[`!!9+E12MM'rrp3a6a`X,m\r!!#`E!!"!JJ!-J'%!1%J!!"3ii!!CN!$q!!#cI3!!1'$rri!"!'Ji)3"JI!J$TVY\r"rqK1J!!JI!J#TVjKrmb3!!%!#*3Krj!!I(JEH(bE)hKm[#YiI0-cH(cd1hJkSK4\rB1b)8'$Y#%rJS&!!!3))!$$VJrrj)!!!S5!"*cB""!"5!P!!!()3!2)#d!!3i`%%\rDI+8cPRaM+K4qj"S8Id26H$L!!!!iS!!J5!!PZ@!!!!"r)mYi1)!!!$LJ!#")!#@\rPB!!!!$KL&$JiJ!!!1+!!)%J!*C&J!!!!IU1VH$L!!!!iS!!J5!!PI@!!!!!lS!!\r!+"X!!%##!!KqZkYi+"`!!%##!!Kq[+Yi+"-!!%##!!KqXkYi1q!!!%J!!0Jii!!\r"9qJ'rRcR3$"AkHMkI6a),RcR5$P"JJ!N18!!!9IV"[jp5PJ`9qcSqRajB#jmBe0\riI(PK,MZp!!%iJ!!"9q8'rRb%+$"AjZMkI0X`,Rb%-$P"JJ"m12rrJ#`(!#""J3"\r`Iq2lH%[rqBPmIKYi+"i!!%'#!&b*(J!!93M2rd'#!&#K2J!!95R12d##!#5"AJ!\rX,!S!!8##!$L!IJ!m5rraX@!!!!!X!`!!3B)!*$PJ!!&Al!EqI@YJ-&IMk2TmQKJ\rZI)4EH(bD'5il[3!"1rm!!A`I`!""J2mS,"d!!%##!#4)!%RGJ%%!&%[rppPJ!!!\r!5!")0B""!"4m!lK!3B$qq$Li!!GmYKj`IYB"P#J@!#"!J3!)1X!!)(pMfhKr400\riIX@cH%J!)q&J!!!!Ii2MH(mNbhKqaE0i5!!Mc@!!!!"qBjYi1))81(l&XhK)!#1\rjB!!!!(qMkhL!!3"i1#%!F(`)!kDkBIr-6S!!)(`)!UDrBIrXN!!"!!L8)Iq`I(X\rEH$ZL&(Jl`KH`,"X!J%#!!"4rBpYi5!"#m@!!!!")!!$dIf2EH%[rq%PmIaYi+"m\r!!%##!!`iB!!!5!!!f#JI!!""JJ!FL(m!!&4Mcrp"JJ!3S*m!+#J%!!*"JJ!F1+!\r!&T!![J!!1-!!&V$G!!!iB2rr5!!!S)$r!#`X"`!#3B)!9%#!!'`X"`!"3)!!#%J\r!!'#"(`!m+!J!!%'#!'b!I`!m5rr['@!!!!"mI"Yi,"`!!%'#!&3j)!!CN6i!!,1\rG!!"rirYi5rrhp6KJrrp)!!"%J9m!1#J+!!""JJ!XJ(m!1%[rp9PJ!!!!5!!!($P\rJ!"D4IJ!!1B!!&V'G!!!iB2rr5!!!%(rMqhK,rrHa1'!!!)!"!&Ji)3"3I!J$TVY\rKrqa1J!!JI!J#TT!!!3!)P#(r`)"L!L!S!`!!3))!&$KJ!XK)!!d*B!!!!*!!BJ)\rJJ))#(#J%!!"!JJ!81'!!&%J!$1eJ!!!!N!"L!Kb!!3")1#%!3(`)!kC1J!!JI!J\r#TT!!!3!)P#(r`)"L!L!S!`!!3B)!%)"L!L")!!djB!!!!$L!!!#3!))#))#L!K`\rS"3!!3B)!%)"L!Ka)!!dCB!!!!$M!!!#3!-)#()!"!%Ji)3"!I!J$TNk!!#"m#!+\rQN!!"!!L8)IZ`N!"K"'L`J34ZN!#K"(!iB3!iJ)%%F%J!2kPJ!!!!1'%!1%J!54f\r!33!8J'%%D+L""'iiS34!1-%%4$MK"$K)!%NCJ%%!&)"K"%3iJ3!i5!"*)B""!"5\r!!34B1#%%8(`)!kC1J!!JI!J#TT!!!3!)P#(lX*!!B34SX)%%ET!!S34`J'%%D+L\r""'iiS34!1-%%4$MK"$K)!%M&J%%!&)"K"%3iJ3!i5!"*TB""!"3iB3!i5!"*XB"\r"!"5!B34`1)%!1%J!2`&J!!!!J!%%@$JK"&"m#!1Q6S!!)(`)!UD6iIrmNm(rq*1\rKrr56JIr`N!!"!!L8)IqJI(`EH(bH)hKm[5YiS(i!!#`$!!0"JJ!BS*i!!#`%!!9\r"JJ!-1'!!!%J!!1b![J!#9,m'2L`I!!e"JJ!J3)!!%#`I!!0"JJ!85!!!b#`I!"Y\r"JJ"N5!!![$M!!!'`h3!!Ii2MH$L!!!%iS3")1-%!2$MK!%")!%IaJ%%!&)"K!$`\riJ!!+5!")%B""!"3iB!!)1)%!1%J!5"Q!33!8J'%!2$L!!!")!%IaJ%%!&$KJ!!&\r)!!"N11!!!V$p!!"rJq0i1)!!!MLK!%Ji`3!m11%!3%J!4j@!33!8J'%!2$L!!!T\r)!%HeJ%%!&$KJ!!JiJ3!i5!"([B""!"5!B3!m1)!!!%J!4j@!33!81'!!!8J!!!J\riB!!!J!%!D$JK!'"m#!1QJq(rr)2"rrL$SIrdJi(rm%k!!#"m#!+QN!!"!!L8)Im\r31'!!!*!!B3"%1)!!!*!!J3"+1'%!1%J!5$'!33!8I'-(08'#!!`iB2rr5!!!4$L\rJ!!#3!+%!H$M!!!#``3#)U1%!6V$K!))j!!!!N3%!IMKK!'a)!%J0J%%!&(aM"c9\r"JJ!-1'$rrdJ!!!L!B3#+J!%!q$JK!2"m#!1Q6S!!)(`)!UD6iIrmNm(rq*1Krr5\r3!!%!#*3Krk"mI4Yi1'!!!,"K!%`iB!4-1)!!!$LJrrp)!%C*J%%!&(aq'hJS(J!\r!3))!$$KJrrp)!!&F1)!!!)#p!!#BK3!!1-!!!)$p!!#Ba`"NIm2cH$L!!!5![3!\r!5rrmfAr$mhJiJ!!'J4d!!$LS!'4,rrc&J')"d$L!$p!iS!!"5!"%"B""!"4mIaY\ri1'%!5%J!4Q@!33!8Im2cH%J!4R'!33!8Im2cH$L!!!%iS3"%1-%!1$MK!$a)!%A\rGJ%%!&$KJ!!-iJ!!$5!"'AB""!"3iB3!m1)$rr$LJrra)!%CKJ%%!&$KK!$`iJ!!\r31+!!%%J!4Q@!33!8Iq2lH$L"!%a)!%CYJ%%!&+NK!%`X#3!"3B)!%+P"!%`X#J!\r#3),rh(rMqhK)!%14J%%!&+PK!%`X#`!"3))!0(r$mhJiJ!!%J,d!!%[rr'&r`r0\ri1)!!"S'G!!!iV!"N5rrm68[rrJQ!R3!!N!"N!-Kr`r0i5!"'HB""!"4rSqYi5!"\r'KB""!"4rSqYi5!"'NB""!"5SB3"-J!%!D$JK!'"m#!1QJq(rr)2"rrL$SIrd6S!\r!)(`)!UD6iIrmN!!"!!L8)Ir!N!"K!&LBJ3"I2'"dG$KMG@NiJ!4-5!""6B""!"4\rmIaYi+"m!!%##!&`iB!$-5!"%6B""!"4mIaYiIq2lH$b!G(3iK(9T1+!%6$M#!da\r)!%4&J%%!&)"r!!!iJ!!!1+!!c%J!(39J!!!!Iq2lH%[rrF8X!`!"3B)!4$KJrrp\r)!!"JL'%!AbJ$!!&"JJ!B5rrp(B#I!!#!K!$)I!3B!%'#!"arirYi5rrpM5`$!!&\r"JJ!-1'$rrdJ!!#L!B3"BJ*m!!$LJ!-a)!"aPB!!!!(rMqhK)!%*"J%%!&$KJ!!#\r!!3")1#%!3(`)!kD$iIrm6S!!)(`)!UD6iIrmNm(rq*!!!3!)P#(rS(aq'hJiB!!\r"1)%!3%J!3,'!33!8I(mEH(rM"c9"JJ!FIm2cH$L#!f"rj3Fd5!!jV@!!!!")!!!\rdU)%!6*!!J3!iIm2cH$L#!hkSS3"!U-%!3UMK!%5T!3"'L5%!5)P"!%P)!$PjB!!\r!!)!"!'Ji)3"JI!J$TS2Krrb$`Iri6S!!)(`)!UD6iIrmNm(rq*!!!3!)P#(r`$a\rJ3e-iBe451)!%6%J!2lf!33!8I(mEH#JI!!""JJ"3Iq2lH%J!2lf!33!8J(m!!%[\rrjL9J!!!!I(iEH#JH!!""JJ!8J(i!%)"M!!#!B`!!N!"L!KKrirYi5!"!UB""!"4\rrirYi5!""&B""!"5!!3")1#%!3(`)!kD$iIrmJm(rq%k!!#"m#!+Q[`(ri*!!!3!\r)P#(h`*!!B3KBN!#"#&bBS3KMI2JlH$YJ!!")!$k4J%%!&(ak'hJiJK4mJ'3!!%J\r!2X@!33!8,"J!!8#"!#4)!$lPJ%%!&(bM`jCmTF(@I+8B88'#!!`iB!!!5!!#i)$\r#!KJX"J!!3))!(%[rr[@!iJ)B,!F!!%##!!`iB!!!5!!#[$KK!`K,rrj&1b!!!&F\rS"Mp"JJ!X1'%(6)L"#'0,rrdY,!-!!%'#!$"r3p0i5!!q4B""!"3iB2rr5!!#J$N\rJ!!#C)3G-18!!!*P""l!jB!!!N@%)&%[rpmf!BJ)J1)!!!$LJ!XK)!"TCB!!!!$Q\r!!!'!BJ)JXB-!!$L!!!'!SJ)JX)8!!MM!!!'!iJ)JX-F!"&FS"Mp"JJ!-15!!!8J\r!!!Jj)!!!95N'2S&#!L#a+J!'5!!pmB""!"5"BJ)JN!"V!!JiB3"-1))$b6LK"d`\ri`3H`11%$#%J!0f&J!!!!JB%)@)"L!Kb4J`!!J)%)A)#L!Kb3!)8!"$M#!p+!iJ)\rFN!$(!!Jj!J)8J5)#(*%*!!`j33"-J@)#(*&,!"#!BJ)JJ))#(%J!!V9J!!!!I(`\rEH$KJ!!)iJ!!#1+!!!%[rlZPJ!!!!I(mEH$Q!!!+aJ3!m1'!K0,"K!$k!JJ)BN!#\r"!%"rirYiJ))#)(q&ihJi`!!!11%!2$N!!"",rr"TB!!!!$ZJ!!!iB3F)1)!!!$L\rJ!#")!"NaB!!!!$LJ!!&AjJEqI+8`-&IRk2Sj!3F)I5Ji,RdT+hKp+$NZ18!!"C&\r""b`jB!!!N@%(-$KJ!3!iJ3F)1+!!!$M!!!!ii3FX5rrb[@!!!!"mIKYi,"i!!%#\r#!#4rirYiJ))#)(q&ihJi`!!!11%!2$N!!"",rqrCB!!!!#`H!!"!JJ!31ld!!5`\rG!!0"J2pN,"i!!8##!(3jJ!!3NB%!1(rMqhL!JJ)J1+!#b$M!!!!ii3!m13%!1%[\rrm49J!!!!N!"K"bJX!`!!J))#)+#%!!BX"!!%3))!0)"L!L!iJ3Fi5!!!N@!!!!#\r!S3G%L+8!!#`&!&*"JJ!)5!!!#$YJrrq!`3G)N!$""c4rirYi5rrd6@!!!!",rrA\r4Id26H%J!1m@!33!8If2EH)!"#%Ji)3K!I!J$TVX"rq"1J!!J5!!!**!!C3!!1+8\r!"(`$)%"!J!!8L1-!!$KM!!&mj`Ge3),rl#`'!!!ia[rr3),rf%k!!#"m#!+QNq(\rrr*!!!3!)P#(r`(ar'hL3!)%!A$Kr!!`iR`,(J+%!A$M!!!9,rrqPJ!%!5$JK!%"\rm#!1QJq(rr%k!!#"m#!+Q[f(rl*!!!3!)P#(rX(ar'hKmR#0iI,iVH(cG-hKrqrY\ri5!!!6)"q!!!S!`!!3))!&$L!!!#BR`!!1rm!!8J!!"KrirYiJ*i!!(bri&")!$8\rPB!!!!(rMqhJiJ!!!5!!eM@!!!!!li`!"1pi!"#`G!!!l[Irr3),rX(alq&#!!3"\rB1#%!8(`)!kDlBIrX6S!!)(`)!UD6iIrmNm(rq*!!!3!)P#(r`(aq'hL3!)%!A$[\rJ!!8iIJ!-1,i#b(bI+&#!S3"FIqElH%[rrcNiB`!-J!%!5$JK!%"m#!1QJq(rr)2\r"rrK1J!!JI!J#TT2Krrb6`IriNk(rp*1"rr#3!!%!#*3Krl"mI"Yi1q)8I$[!!!"\r)!$GpB!!!!%J!1G'!33!8I(dEH$KJrrq3!(m!!)#F!!`X"!!"3))!0)"m!"!iJ!!\r"5!!j`B""!"4mB`FdN!"r!!#![`!!,!Arrd##!"")!$QpJ%%!&(aq'hKrSqYi5!!\rjaB""!"4r`r0iJ!%!@$JK!&"m#!1QJq(rr)2"rrL$SIrdJi(rm%k!!#"m#!+QN!!\r"!!L8)Ir!1')8I)"M!!!X!rrr3))!&$L#&(b!C!!!5!!jMB""!"4)!$FKB!!!!)!\r"!%Ji)3"!I!J$TNk!!#!iBK4iU'-!!%k!!#!iB!!!6S!!)%k!!#!iB!!!6S!!)$K\rJ!!"1J!!JI!J#TT2Krrb6`IriN!!"!!L8)Ir!I(iEH$[L&)JiB!!"5!!)l@!!!!#\r!!J)N,!!!!%##!"KrirYi5!!@P@!!!!!i!!!"N!!#!L4rirYiIm6cH%J!&X&J!!!\r!I(mEH$KJ!!&)!!LaB!!!!(rMqhL!!3")1#%!3(`)!kD$iIrmJm(rq%k!!#"m#!+\rQNq(rr*!!!3!)P#(r`(ar'hL!!J)N,!!!!%'#!#`iB!!"5!!)C@!!!!!iBK5)Iq6\rlH%J!&q&J!!!!1'!!!8J!#%eJ!!!!J!%!5$JK!%"m#!1QJq(rr%k!!#"m#!+QNq(\rrr*!!!3!)P#(r`(ar'hL3!)%!A$MJ!!#3!2m!!)!"!&`S"J!!N!!I!!5)(`!)81!\rZ0*JI!!L)(`!)81!QpTJI!!LBr`!-Q2m!$C!!r`!83B)!((bN+hKrirYi1+!!!NJ\r!!ZeJ!!!!5!!!((rMqhKmj$YiI18lH(cQ1hK)!!,4B!!!!)!I!"JiB!!!N!!I!##\r3!(m!*+!I!!48!-qq,!!!!N'#!'"!J!!3,!!!!8#!!"4)!!"3,!!!"%#!!%K)!!!\rSJ')"0)!#!6#3!(m!0)"L!5b3!"m!1)!#!5L3!(m!2*!!(`"!5!!!))!#!553!(m\r!0)"L!5#3!"m!1)!#!4b3!(m!2*!!(`"!1!!!!*!!(`"%J!%!5$JK!%"m#!1QJq(\rrr%k!!#"m#!+QNq(rr*2"rrL6SIrdN!!"!!L8)Iq`1'!!!NJ!"[9J!!!!1k)$q$[\r!!!!li!!%S"d!"&3!clp"JJ!FIk2VH%J!#HeJ!!!!S"d!"&2J2I#`(3!%1pi!!6Z\rp!%JX(J!M3B$rd$KJ!!*)!!DYB!!!!)!"!&Ji)3"3I!J$TS2Krrb$`IriJk(rp%k\r!!#"m#!+QNq(rr*2"rrL6SIrdN!!"!!L8)Iq`1m!!!$ZL!rKrhr0iS"d!"&3!clp\r"JJ!FIk2VH%J!#M9J!!!!,!-!!%'#!!Jl`2rr1rm!!6Zp!%JX(`!M3B$rd(r$mhL\r!!3"B1#%!8(`)!kD$iIrmJm(rq)1Krr41J!!JJ-3!!$L!!!Si!!!05!!!+)LM!!!\rS"3!03))!$*L$!!")!!!3+!8!#N##!!LB!`!!1'-!!5J'!!!ia[rr3),re%k!!##\r!!`!BN!!$!##!!`!FN!!$!#5!S`!8J)-!+)!$!#4mT#!iI!3!8*!!!`!NJ!-!&*!\r!!`!`6S!!)(`)!UD6iIrmNm(rq*!!!3!)P#(r`(aq'hKmRb0iJ(i!')!H!#"m!`"\r43B)!D*!!(J!NL"i!"93!erp!JJ!3J(i!'$LH!#4,rrp&J(i!!)#H!"L!hJ"%JCi\r!2$Lq!#4)!$Y"J%%!&#JI!!""JJ!-J"i!**!!(`!!,!-!!%'#!!K)!!!JJ(i!*)!\rH!"4m!"S8N!!H!"4r`r0i5rrr16KJ!!#!!3")1#%!3(`)!kD$iIrmJm(rq%k!!#"\rm#!+Q[f(rl*!!!3!)P#(rX(aq'hKmQb0iI,`VH(cI-hL)(J!)S(i!"&3!hhp8Bmq\rq3))!$#`$!!"!JJ!-1'$rrdJ!!4!X(!!!3B)!(#`F!!&"JJ!8,"`!!N'#!!`iB2r\rr5!!!m)"q!"JS!`!!3B)!')JH!!K8!1Ir3B)!$%[rqpeJ!!!!L"i!"$L!!!"6J!p\rmQ"i!")Kq!!Ji(J!38)-QpTKq!!L3!"i!'*!!(J!J1k!!!C1q!"b3!*i!*#`F!!#\r3!*i!+%'#!!`S(`!"3)!!')#H!#!i!!!!I!-$H*J%!!")!!"d+"X!!%##!$"rirY\ri5rrkk@!!!!"mHaYi+"X!!%##!!`iB2rr5!!!6)JH!!K6S#EfQ"i!#*0q!"L!IJ!\rB1!!!!*!!IJ!JNri!(*!!(J!SS"i!"&3!cliX!!!"3))!&&IJ"Ip!JJ!-1!!"rj!\r!(J!S1'!!!)!"!&Ji)3"3I!J$TVYKrqa1J!!JI!J#TT2Krrb6`IriN!!"!!L8)Ir\r!I(iEH(bI)hLJI`!%1!!!!*!!(`!NL"m!$94McliS!!!!3))!$#`$!!"!JJ!-1'$\rrrdJ!!A3X!`!#3))!$%J!%0eJ!!!!L"m!#&3!hhp!JJ"FL"m!"&3$lhj8B!Hp3B)\r!6&4J"hY"JJ!SIq2lH$L!!!!iS!!#5!!2"@!!!!!X!`!!3B)!$$KJ!!")!!%FL"m\r!#$KJ!!&3B#idIq2lH*JI!!K,rrd"B!!!!)JI!!K8!0pq+!!!!8'#!"`i!!!"Q"m\r!$6J!!!#3!"m!*$KJrrp)!!$BL"m!"&3!rliS!!!#3B)!()"r!"L!(`!JJ*m!((`\r$!&"m"!"!3))!0(rMqhJiJ!!!5rrme@!!!!!X!`!!3B)!($J!!!'B(`!01!!!!*!\r!(`!N1'$rrdJ!!)#!I`!N1!2rrj!!(`!NJ(m!)$J$!!'3!"m!)*[$!!#)(`!%9!2\rr[P4J"MiS!!!#3B)!6&4J"Mp"JJ!-,"i!#N##!$4rirYi1)!!!%[rr'9J!!!!,!-\r!!%'#!"`i!!!"Q"m!$6J!!!#3!"m!*$KJrrp)!!!31!!!!*!!(`!N9m-'2S!"!%J\ri)3"!I!J$TS2Krrb$`Iri6S!!)(`)!UD6iIrmN!!"!!L8)Ir!J!)#+$[J!!!X!!!\r"3))!$$KJ!!&)!!"X1'!!!dJ!!B&J!!!!J!)#+#`!!!"!JJ"%5!!2(@!!!!"rirY\ri5rri1@!!!!"mB!Fe3B)!%$J!!!+3!!)#+%J!!"b!JJ%m1')8J$J!!!'3!)-!!(`\rI!hL3!!)#+$KJ!!0)!!%YB!!!!(rMqhL!!3")1#%!3(`)!kD$iIrm6S!!)(`)!UD\r6iIrmNm(rq*!!!3!)P#(r`(bH)hKm[bYi5rrr35`$!!"!JJ!-1'!!!8J!!%3iBJ2\ri1'-!5%J!",9J!!!!Im2cH)#I!!",rrHYB!!!!*!!I`!!J(m!!$J!rrpm!`"!3))\r!$$KJ!!&)!!!)1'!!!)!"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)(`)!UD6iIrmNm(\rrq*!!!3!)P#(r`(bH)hKm[bYi5rrqZ5`$!!"!JJ!-1'!!!8J!!$4r`r0iJ*m!!%[\rrpbeJ!!!!N!"r!!#!I`!!1!$rrh`$!%"!JJ!-1'!!!8J!!!JiB!!!J!%!5$JK!%"\rm#!1QJq(rr)2"rrK1J!!J1'!!!%k!!#"1J!!J6S!!)(`)!UDr)IrNN!!"!!L8)Iq\rJI(XEH(bC)hKmfM0iIlNTed'#!"b)'J!0+!!!!%##!"#JHJ!%9'$2[d##!!`iB!!\r!5!!#`&4JcliX!!!#3))!$%J!$9PJ!!!!L"S!"6[J!!"8!0Ir3B)!,+!D!!48!-q\rq,!!!!d'#!"b)'J!%9!$r[LJ!!!*"JJ!-+!!!!8##!!Jli!!"L"S!#&3!hhp!JJ"\rFL"S!"&3$lhj8B!Hp3B)!6&4J"hY"JJ!SId26H$L!!!!iS!!#5!!,4@!!!!!X!`!\r!3B)!$$KJ!!")!!)SL"S!#$KJ!!&3B#idId26H*JD!!K,rrP"B!!!!)JD!!K8!0p\rq+!!!!8'#!"`iB!!"1!!!!*Kk!!em!`0iN!!D!#4)!!(N+"d!!(pqfhJlJ!!!3B)\r"2)"k!##!'J!BI!-!3%##!!`X(`!!3B)"*)#D!"L!HJ!JJ"S!((aN'&"m!`"3N!!\rD!#5!'J!N1f!!!*!!!3!iJ!%!1(`!k%"!J3!)Nk%!1)JD!!48!2qq+!!!!8##!$L\r!S3!i+!8!!%'#!#ar`r0i1)!!#NJ!#bPJ!!!!I(XEH#JE!!""JJ!31"X!!A`H!&#\r3!!%!1)#K!$JS"3!!3B)!3)"k!#"ra20i5!!+9@!!!!#!J3!iJ"S!)(rH)K4m!#)\r8N!!D!##!B3!iJ"S!*(qF)K4m!`"3N!!D!#4rT1K3J"S!*#J!!!""JJ!B+"X!!%#\r#!"#)'J!%9!$r[d##!$4r3p0i1)!!!%[rq$9J!!!!,!-!!%'#!"`iB!!"1!!!!*K\rk!!em(30iN!!D!#4)!!!8+"d!!%'#!!`X(`!!3),qr#JG!!""JJ"`,"m!!%##!'L\r$HJ!BJrS!((`HkK56fJ!BNlS!((p$dhL3!"S!)$L"!$K,rrI0B!!!!#`$!!""JJ!\r81!!!!CJD!!di!!!!N!!D!#5!!3!iId26H*0k!"L6qJ!FIj`#&%[rpf9J!!!!1!!\r!!*!!'J!NL"S!"&3!rliS!!!#3B)!$$J!!!#3!"S!*$JCrrpm(!)8I'$,PS!"!'J\ri)3"JI!J$TVXKrq41J!!JI!J#TT2Krrb6`IriNk(rp*!!!3!)P#(rX(ap'hJS(3!\r!3))!$$KJrrp)!!#%S"d!"&3!clp!JJ!-1'!!!%J!!("rSqYi5!!!K@!!!!"mIaY\riJ(d!!)'G!%")!$+9J%%!&+!G!!3iJ!!!8)!pm,!G!!53!*d!!)JG!!KmIKYi9!$\rRrd'#!"#!I3!B5rrce@!!!!!X(`!!3))!$#`H!!""JJ!-1'$rrdJ!!!JiB!!!J!%\r!@$JK!&"m#!1QJq(rr)2"rrL$SIrd6S!!)(`)!UD6iIrmNm(rq*!!!3!)P#(r`(a\rr'hJS(`!!3))!%%[rpAPJ!!!!5!!!q)JI!!dS!!!!3))!%+!I!!48!-qr3))!$$K\rJrrp)!!$BL(m!#&4JhhiS!!!$3B!!&(aJ'hJiB!!#8'!Z0*JI!!L)(`!)9!$IILJ\r!!!*!JJ!-1!!!!*!!(`!NL*m!#&5!hhiS!!!"3B)!'$KJ!!"mJ#0i8'!Z0*JI!!K\r)!!"mS"m!"&3!cliX!!!"3))!((rMqhK)!!9KB!!!!(aq'hJS(J!!5!!!#$[!!!"\rrirYi1)!!!%[rpDeJ!!!!,!-!!%'#!"`i!!!"Q"m!$6J!!!#3!"m!*$KJrrp)!!!\rJL"m!#$L!!!"3J#idQ"m!#*2I!"4mJb0iN!#I!#5!!3")1#%!3(`)!kD$iIrmJm(\rrq%k!!#!iSKHd1!!!)h`*!kDSK3!!I'!(0(`%!!"!JJ!-I+-VH%k!!#!iT3")3J$\rrj$KJ!!"1J!!JI!J#TT2Krrb6`IriN!!"!!L8)Iq!I,iVH(cI-hJiS!!!N!#K!%5\r`B3"3N!#"!&L!(J!!+"m!!*!!!3"FX+%!C%'#!$!iB3!i5!!Y,B""!"4)!!!3Iqc\rlH%J!-'@!33!8U!%!5#`!!!""JIrX5!!!%$KK!$K)!#dCJ%%!&)!"!'#3!"i!!+J\r"!%JX!2rC3))!))!H!!!S!!!!3B)!$$KJ!!")!!!J1'!!!NJ!!"JX!!!!3))!$$K\rJ!!")!!!)1'!!!B!"!)Ji)3#!I!J$TS2Krrb$`Iri6S!!)(`)!UD6iIrmNm(rq*!\r!!3!)P#(rJ(bq+hKmhc0i1+!!!*!!S3"%X'%!8*!!J3"BJ"i!!#JI!!#3!!%!A,#\rK!'4"JJ!`1'%!1%J!,)Q!33!85!!!%(rXqhK)!#q4J%%!&+J"!%JX!!!!3B(rl%J\r!!"!iB3!i5!!XGB""!"5!!3"JN!!H!!#S!3"),!!!!%##!!`iB!!!5!!!#$KJ!!'\r!!3#)1#%!J(`)!kD$iIrmJm(rq%k!!#"m#!+QNq(rr*2"rrL6SIrdNi(rm*!!!3!\r)P#(rJ(am'hKmRL0iI,dVH(cI-hJi!!!!N!!"!%3X(3!"Xi%!8%'#!$4!J!!3,"d\r!!%#!!"a)!!!N,"d!!d#!!"`i!!!#X!%!C%J!!"Ji!!!"X!%!C%J!!!`iB!!"5!!\r"H)!H!!!S(`!!N!!"!'C"JJ!`1'%!1%J!+`'!33!85!!!%(rXqhK)!#kCJ%%!&+J\r"!%JX!!!!3B(rl%J!!"!iB3!i5!!UlB""!"5!B3"QJ"i!!(`$!&&!J3%!+"m!!(`\r$!K53!!%!9%'#!$!iB3!i5!!UfB""!"4)!!!3IqclH%J!,N'!33!8U!%!5#`!!!"\r"JIrX5!!!%$KK!$K)!#V&J%%!&+J"!%JX!!!!3))!$$J!!!")!!!)1!!!!5`!!!"\r!JJ#B1!!!!*!!!3"%,"d!!E1"!&""JJ!d3)!!%#`G!!"!J!!F5!!!*#`G!!0!J!!\rF1!!!!V!"!'4)!!!B1!!!!E!"!'4)!!!-1'!!!8J!!'b!(J!!+"m!!*!!!3"Q3B)\r!-$KK!$K)!#ReJ%%!&%J!!""rl2Yi5!!YMB""!"5S!3"),!!!!%'"rqa)!!!31'%\r!1%J!+H'!33!8J!%!CT!!(J!!U!%!5#`!!!"!JJ!-1'!!!%J!!!JiB!!"J!%!L$J\rK!)"m#!1QJq(rr)2"rrL$SIrdJi(rm%k!!#"m#!+QNq(rr*2"rrL3!!%!#*3Krd"\rmIKYiIm2cH%[rr#&mIaYiXm%!8$KK!$K)!#S9J%%!&(aJ"c9!JJ!`+"m!!%'#!#J\ri(`!)N!!"!%US(`!#1'%!1,!"!%k!(`!%N!!"!'K)!#RjJ%%!&#JI!!""JJ!-1!!\r!!,!I!!"mB!Fe3))!$$KJ!!")!!!)1'!!!B!"!-Ji)3$!I!J$TS2Krrb$`Iri6S!\r!)+!$!!48!-qq+!!!!8'#!!`S!!!#3))!%)J$!!dS!!!!3B)!'$KL&l!i!!!MN!!\r$!!!iB2rr6S!!))J$!!K8"Ypq9-!'2d##!!b!B`!86S!!)&6!"Mk!S`!BJ)-!)#J\r!!!1!B`!`I!8J8(aM!K40J!!J1!ErrRaJ'&"1J!!JI!J#TT!!!3!)P#(r`%[rrhQ\r!!3")1#%!3(`)!kC1J!!JI!J#TT2Krrb6`IriNk(rp*!!!3!)P#(rX(ap'hKm[LY\riN!#"!'bJ(3!%1q)AX&3!cliS!!!"3))!%)JG!!dS!!!!3B)!&$J!!#13!"m!!$K\rJrrp)!!'%L"d!#&3!hhiS!!!"3))!2(qMkhJiJ!!!5rr[i@!!!!!X!`!!3B)!*$J\r!!!'B(3!01!!!!*!!(3!N1!!!)j!!(`!!1'$rrdJ!!6`X(J!"3))!)$[!!!"rSqY\ri5rrqZB!"!'`S!`!!I!!D&*!!!3"X,"i!!N'#!*!!L"d!"&3!lhiS!!!$3B)!J)J\rG!!K8!0pq+!!!!N'#!!`S!!!$3))!D)#"!'b!(3!8I!3!3%#!!"#!(3!`I!3!3%#\r!!"L)(3!)1'!!!&"J,M5B(3!)5!!!5)"p!"Km!#"3I!-#&*!!(3!JJ)%!E)!G!"3\riB!!#I!3!8*!!(3!NL"d!#&"J,M5B(3!)5!!!&)JG!!JiB!!!8'!Z0*JG!!L)(3!\r)9!$IId##!'5"R3!d+!`!!%'#!%5!I3!!J0d!4(r&mhJiJ3"X5!!UAB""!"3X!`!\r!3B)!*$J!!!'B(3!01!!!!*!!(3!N1!!!)j!!(`!!1'$rrdJ!!"`iB!!!Q(d!$)!\r"!'b3!"d!&*!!I3!N1'!!!)!"!&Ji)3"3I!J$TS2Krrb$`IriJk(rp%k!!#"m#!+\rQN!!"!!L8)Ir!5rrq"B!"!%Ji)3"!I!J$TNk!!#"m#!+QNq(rr*!!!3!)P#(r`(a\rr'hKmJb0iIq6lH%J!*`@!33!8Iq2lH)!"!%Ji)3"!I!J$TS2Krra1J!!JI!J#TT2\rKrrb3!!%!#*3Krm"mIaYiIq2lH%J!!(PJ!!!!Iq2lH)!"!%Ji)3"!I!J$TS2Krra\r1J!!J1'2rrcLP!!&)!!!8M!-!!A`!)%"!JJ!)6S!!)$5Prrp!J[rX1'!!!%k!!#"\rmBbS81+8!!8J!!"5-!rrrI!!J3%##!!K1J!!J0+Arrd##rq`iB!!!6S!!)#J&!#"\r8KJBq112rrd'!!*!!I!F!d&3!"lp"JJ!8I+!S8*c(!!%d!2rr3),rq#J'!!""JJ!\rF9-2!$P6!J"j8a%!ZI'!$H(b!!hKmaJ0i9+$CIcMRrre"JJ!XP-F!"*6(!!58a`!\r%P-F!"*6(!!58a`!%P-F!"*6(!!3d!2rr3),rh&5Jphp"JJ!3P-F!"$3!rrp!J[r\ri11F!!e5P"liS"3!!6B)!)*c(!!%dTIrr3),rq%k!!##!!J&%1')8K*!!!`!!6S!\r!)$M!!!#3!--!"$J$!!53!!-!$*!!!`!)2)!!!B#L!9#3!!-!!)!#!8b3!+-!%*!\r!!`!81)5!!*!!J`!BN!$$!"b3!--!)*!!``!N6S!!)(`)!UD6iIrmNm(rq*1Krr5\r6JIr`N!!"!!L8)Iq`I(`EH#J%!!"rRq0i3B)!%$J!rr4m"!"!3)%!$$KJ!!")!!%\rX1'3!#i!F!"K8I3!iI"d!3%'!!&b"R!!3+!`!!%'#!&#!(!!F,!!!!%##!%3lh3!\r3Im2cH(q%ihK)!#H0J%%!&(r%mhKrKH0i5!!##Aaq'hJS(J!!3))!$$KJ!!")!!$\r-J"i!!&3G!$T)!!#N+"d!%%#!!!JlS!!3Iq2lH(qNkhK)!!+&I(iEH#JH!!""JJ!\r8Iq2lH(r%mhK)!!)p5!!!A)!F!"!S!!!!3B)!3)"m!"Km(4K!3B%!$$[$!"")!!!\r)1pd!%)'F!""r`r0iIi6MH%J!*[@!33!8Im6cH(q&ihK)!!&aI(iEH#JH!!"!JJ!\r-1'!!!%J!!$4rirYiIm6cH(qPkhK)!!)pI(dEH)!H!!!iIJ!%B!!!!C!!(J!!I"l\rS,Q!!!!*m(ZNZJ!%!@$JK!&"m#!1QJq(rr)2"rrL$SIrdJi(rm%k!!#"m#!+QNq(\rrr*2"rrL3!!%!#*3Krm"mIaYi+!3!!(rqqhK"JJ$31+6rr)!&!!"r`r0i9!!!2*!\r!"3!!J!8!!(bN+hK8"`!kI-8k&)!'!!"8!!IkN!!'!!#3!1Err%J!!R9mC4YiJ"m\r!&)"P!!!S!!!!9'F!1Rc&1K4"JJ"`9'!([8##!'L!"Irm,!!!!%#!!&b!"J!!,!!\r!!%#!!&!iCIrdJ)-!!#J%!!""JJ!3J!-!"*!!"!!%5!!!$)!$!!53!"m!))#$!!3\rS"!!!3B)!$)!$!!#3!!3!!)'I!"4rj2Yi5!!PTB""!"4)!!!3Im2cH(bN+hK)!!#\r"J!%!5$JK!%"m#!1QJq(rr)2"rrK1J!!J+!-!!%##!!`iB!!!6S!!))$&!#"mCaY\ri+!B!!(cS1hJj*2r`3B)!#*%'!!!i!!!!N!!)!!#!"3!J1)$rr*!!#!!%N38!)*5\r(!!L9*`!%1!Rrr(cR!K54*`!!P)F!"$KM!!a1J!!J1!-!"*!!"!!%J!-!$*!!"!!\r)J+-!$*!!K3!%N!#$!!a1J!!JJ+-!!(`%+%"!JJ!-J!8!#*!!!`!!J!3!")"N!!L\r3!!-!")!%!!L!C!!%N!!$!!K1J!!JI'BEH)#Q!!"mSbYiJ!8!!&3!!$Tm!#"!3B!\r!%(bM+hL3!+B!!%k!!##!T3!)I!8B3%##rp`iB!!!6S!!)(`)!UDr)IrNN!!"!!L\r8)IqJI(mEH(bC)hL$f3!!1!8!"eI$!$TrH4S8JlX!!&3D!$JX(3!!IjSB8%'!!#K\rAS!Ir3))!)(rMqhKrC0Yi5rrr59HJ!$TrR!)8IhX#&%J!!"!S(!!33)!!#%J!!&K\rA`!HqId-$H&I!"rq3!(N!!(bCdK4!JJ!)Nd6rr&I!"rp"JJ!-1!!!!NJ!!!Ji!!!\r!Ii!$H*!!"!!!Nj[rr)!E!!"rirYi9!!(qT!!'`!!5rrq[Ap$dhL!!3"S1#%!B(`\r)!kDl)IrN6S!!)(`)!UDrBIrXN!!"!!L8)Iq`I(XEH(bF)hL!(!!!9"i!1RrmmK5\r!(`!!,!!!!&3G!$T"J!!X9!!(rd##!#4rBpYiIq6lH%[rrRf!(!!!IplU&&3!"lj\rr`!0iN!!F!!#!(!!!Jlcrr&3!"le!JJ!-,"d!!%#!!"!i([rmIp`",NJ!!$4rrH"\r3If2EH(rNqhK,rrieJ"m!!(qpmK48!!HqIk!$H*!!(`!!1"hrr(rmqhKr[`%ZIi2\rMH)!"!&Ji)3"3I!J$TVYKrqa1J!!JI!J#TT!!!3!)P#(r`%J!(`@!33!8J!%!5$J\rK!%"m#!1Q6S!!)(`)!UD3!!%!#*3Krm")!"ljJ%%!&)!"!%Ji)3"!I!J$TNk!!#!\ri!!!"Q!(rm$J!!!#B!IraQ!(rmTJ"rr1B!IrdN!!"rrL3!!(rr$M$!!'*"J!!1')\r0d(d)"h3X#!!P3))!-*N"rr@!JIr`J!(rp$KQ!!'3!)8!!*!!"3!%J)(rq)!"rrb\r3!)8!#*!!"3!-6S!!)$J)rq!S!!!315!!!8'"!'3iiJqJ9!!31RcR!#jmk31Q6S!\r%)$J!!!#B!Ir`5!!!5*NKrr&)!!"!L!(rm5J!!!&"JJ!d1!!!!TJ"rr&)!!!SQ5(\rrmdJ!!##)!Ir`+!!!!%'#!"3i!!!#Q!(rm%J!!!Jj)!!!,!N!!%'#!"#0"J!"I3J\r(G%[rrh`X#!!U3))!B)$N!!!ij`!%N!$N!!#!"rrm,!!!!*!!!Iri3)!!'$J!!!#\rB!Ir`J!(rq(`!!0#3!!(rq)d'!!&p#!Gd5!!!0%J!!##!!Iri(!!!#RcS!K3i"rr\r3N!!"rrL0"J!"I3J(G&8!"Mjm!`#Z9!!'pd##rpL!!Iri,!!"r8#"!$3i!!$rQ!(\rrpB#"rr#!!Ird1'B!!C!!K3!!N!!&!!5!JIriJ!(rr*!!K3!)N!!&!!a1J!!J,!J\r!,N##!(`i!!!"Q!(rmSd'!!&p#!Gd,!J!+N##!&5!C!!!1'-!"*!!C!!!J!2rr#`\r!!!#3!!(rr%#!!!`i!!!!Q!(rmSd'!!&p#!Gd5!!!0%J!!##!!Irm(!!!#Rb)!K3\ri"2r3N!!"rrb0"J!"I3J(G&8!"Mjm!`#Z9!!'pd##rpJX#!"S15!!!8'#!#"!J!!\r3,!J!6%'#!#K)!!!`,!J!E%'#!"")!!!NQ5(rp%J!!#!i!!!#Q!(rp%J!!"3i!!!\r%Q!(rp%J!!!Jj)!!!,!N!!%'#!!b0"J!"I3J(G$J)rlXS!!!cQ3(rp8'"!5!iBJl\r39!!31RaM!#jmD31Q6S!%))J"rr3S!!!%3))!$$J!!!1B!IrdL!(rmLJ!!!"!JJ!\r31!!!!C!!!Irm5!!!k)J"rr!S!!!#3))!h$J!!!'B!Ir`5!!!d)!"rr`X!!!!3))\r!$$J!!!'3!!(rr)J"rr3S!!!"3B)!$#J!!!*!JJ!31!!!rjJ"rr9)!!#FL!(rmLJ\r!!!"!JJ#3!$J!!!D3!!(rr%J!!)3i!!!#Q!(rp$J!!!'B!Irc1!!!H*J"rr8i!!!\r)N!!"rra)!!"JL!(rmLJ!!!"!JJ!3L!(rp#J!!!""JJ")1!!!rjJ"rr9)!!!mL!(\rrp#J!!!""JJ!`1!!!rjJ"rr9)!!!NL!(rp#J!!!4!JJ!B1!!!!jJ"rr4)!!!-1!!\r!rjJ"rr@!JIr`J!(rp$KQ!!'3!)8!!*!!"3!%J)(rq)!"rrb3!)8!#*!!"3!-6S!\r!)*!!S3!JN!$"!#53!1%!+*%"!#`X!`!!11!!!$LNrrpmDKYiI1BlH*MP!!"!JJ!\r`J3%!,#`)!!"!JJ!NL3%!)bJ)!!""JJ!3L3%!*5J)!'p"JJ!-I+-VH%k!!##*!3!\rP15MrU#J*!#""J3"F13)2j&8T%$Tp#%JZI3N$TNk!"#!X!`!!1!!!#N#!!$ap5J$\r311!!!8J!!$!i!!!!Q!%!)6J!!!K)!!!J1!!!!*J"!#%i!!!+5!!!%$J!!!#B!3!\rK1!!!%(d+!jCp#!(@I3K38(e+!jBX#!!+3)!!$$N)!$")!!!JL'%!*6N)rrBS!`"\ri3))!$$N)!'&)!!!)13J!35J+!!#G"Irr1-B!!8##rlJS!!!)3))!+)KK!#-S!`!\r!3B)!()KP!!!X!`!`3B)!%$KJ!$#FCIrr1-B!!BKK!#!S!`!#3))!6)"K!#JX"`!\r!N!"K!#a!JJ!3L'%!)5J$!!""JJ!3J'%!,$KMrrq3!'%!,#J!!""!JJ!FL'%!)bJ\r$!!""JJ!3J'%!,$KMrrk3!'%!,)%"!#amC5"3I'JD&#`$!Ie!J3!-1'!!!%k!!#!\riJ!!`5!!!$*b&rrmiaJ!"J'%!,(`''!""J2r`+!!!%%##!##)!3!M+!!!!%'#!"5\r)!3!PR!ArrcJ!!$#F"Irr,!F!!%'#!"!i!!!YR!ArrdJ!!#b)!3!K+!!!!8##!"!\ri!!!VR!ArrdJ!!"3S!!!#3))!$$J!!##F"IrrI+-VH%k!!#"m#!+Q[Z(rh*!!!3!\r)P#(rS*!!`3#%N!$K!)L4!3#-I,JVH*%K!*!!1b!!!(mJrR"mKFTiI'!#H$Yirrp\rmS!0jI*iMH(ar'hKr1XYiQcX!!%##!$#!!3#3!#`!!!"!JJ!NL!%!KbJ!!!""JJ!\r3L!%!L5J!!'p"JJ!-If2EH%J!!Nb)S3#*1!ArU#J!!#""J3"i1+)3D&3!%$TmT3!\rZI+N$TNk!"#!lS!!!E'@!!'qMJ!"m(5!3I'-T%(aP+4"mB`$41i!!#N'#!%!MhJ!\r!Irm"N!!l)!!"5!!!-$ZJ!!#ES3#&1i!!#%J!!#!lS!!!Qk%!K6Z!!!T)!!!31k!\r!!*ZK!)8lJ!!3Iq2lH(r%mhKrTHYiIiEMH%J!&(PmPb0iIq2lH(r%mhKrTHYiIiE\rMH%J!%h8X&`!+I*iMH(ar'hK!J!!-1[F!-%J!!##)!3#*1[IrpLJ!!(K!JJ!-1[F\r!B8J!!!Jkp`""1)!!!(r$)RKri#*iI'!$HCllrrml@J!"3),rL$J!!!KrJ`*iIk!\rLH(aJ!hP!JJ!SL!%!KbJ!!!""JJ!FL"X!!#`!!$""JJ!31!!!-*`Errml@J!"L!%\r!K#J!!!*!JJ"FJ!%!M#`C!!#3!!%!N!"!JJ!3L!%!K5J!!!""JJ!3J'%!N!!i!rr\rrN!!"!*!!1'!!%$J!!!"rJaTiIk!#H(aJ!hP!JJ!FL!%!KbJ!!!""JJ!3J'%!N!!\ri!rrqN!!"!*!!J'%!N!"m'm"3I!-#&#`!!Ie!J3!-1'!!!%J!!*3iB!!`5!!!$*a\rlrrml@J!"J!%!N!"m'J!!3B$rm$KJ!"!i!!!!Ii-DH(qJ!RKmB!0j3))!))J"!)F\rS!!!!3B)!&)J"!)QF'rrr1!!!-*`ErrmX'3!!3B)!%$J!!#fF'rrr5!!!,)J"!)8\rS!!!"3))!%$J!!#ZF'rrr5!!!&#J!!!*!JJ!-1!!!)*`ErrprBpYiJ!%!D$JK!'"\rm#!1QZZ(rh%k!!#!X"!!!3)!!*$J!!!#B!`!!X!-!!MJ!!!'B!`!%1!!!-*J$!!9\r1J!!JL--!"(`%-!"-J!!JI+-L&$MP!!D-Trrr1+Ard(bJ"h3X!!!&3))!3(bM-K3\riT3!&1+Arrh`&1%"!J3!3L!8!!#`!!$""J[rXI!8i3%##!"#)"rrr9!B(rNJ!!&3\ri`!!"5!!!6(`!!#C8"KIq5!!!3)`(rrpmS$)81+Ard(bJ"h3X!!!*I!!!*P3'&rp\r!JJ!-I+!(G8##!!`iK2rr5!!!%$J&!$#B"`!!5!!!$#`%!!"!J[r!,!B!!%'#!#5\rSJ`!#1!!!!6L%!!'`J`!#Q!-!"$J!!$'B!`!&6S!!)#`%!!""J[m!Q)-!"%k!!#"\rm#!+Qfq(rq*2Krqb6`IrSN!!"!!L8)Iq!N!$"!+6ri!L3!*!!i3#SN3%!V(bq+hL\r4)3#`J!%!X#`!!Ie!J3!-1'!!!%J!"36m)2L3!$J!!!#B!3!i1!!!),!"!$SiB3!\ri1-%!2%J!&E'!33!8L!%!3$[K!%&rr`)85!!!()KK!%!i!rrrQ!%!3+KK!$ii!`!\r"X!%!2SJ"!%!S!!!"3)%!%)`IrrmX!!!`3B,re)J"!%%X!!"*3B)!-%#!!"!X!!!\r`3B)!&%J!!(`X!!"13B)!@%J!!(!i!!!!Q!%!2,!"!$j)!!"Jb!)#12`I!%"!J!!\rF1rlrqcL#%1arirYi5!!,q@!!!!")!!!B1rlrr(rMqhJiJJ)X5!!,i@!!!!"rirY\ri5!!%+$[qrrarirYi1))#-%J!#m9J!!!!Iq2lH%J!"!b)B3"!U!%!2MKMrrpm!"S\r8X!%!2M[qrrmi!!!!Q"m!!)J"!+NX!!"P3B)!p%#!!#JX!!"'3B)$d%#!!"!X!!"\r&3)!!h%J!!m!X!!")3)!$Z%J!!"3X!!"R3B)!$%#!!kK)!!))L!%!3)#"!,"m!#!\r!3)%!$$KK!$a,rrdjU)%!2L`%rra"J!!3J'%!X(`%'!""J!"3L!%!TbJ!!!""JJ!\r8J'%!X$J$rrq3!!%!X%J!!"#)B3"!1!2rrj!!!3#`L!%!U5J!!'G!JJ!31!!!CCJ\r"!+P)!!"-1!!!4CJ"!+P)!!"!L!%!TbJ!!!""JJ!81!3!!A`!'!!%!X%J!!A#\r)!3"!1'3!!A`$!&'3!!%!X%#!!9`i!!!!N!!"!,")!!&3J'%!X)J"!%!iJ`!"I!!\rJ!%#"!!`iB3!m5rrmIDLK!$iii!!V,!8!!%#!!!amT3$311!!,6M!!!!iJ!!+5!!\r!)(aP)pCmBb(@I'-S8(bP)pBi!`!`R"rrrcM'!!%X"3!!3),ri#`'!!*"J2rBR2r\rrriJ"!+QF(rrrJ)%!X(`Im&"m"!)8,!!"r8#"!!`iB!!!5!!#A)KK!%!i"!!"I!-\r!!%#!!#!i"!!#I+-!8$J!!$")!!!)R"rrrc5Prrp!J[riL+%!3$L"!%&mK#S85!!\r!$)`%rrqF(rrr0+Arrd##rr5!!3#`,!!!!%##!"#)!3#R+!!!!%'#!!`i!!!ZR"r\rrriJ"!%'F(rrrL!%!2(`!"h9"JJ!31!!!,C`Irrp)!!(-L!%!T5J!!!&!JJ!31!!\r!+j`Irrp)!!'d+!!!!N##!D`i!!!JR"rrrdJ!!D#S!3!qL'%!3(`!!0!iirrrI1!\rk&8#!!!Jii!!!J'%!X(`('!"!J3!dL!%!3(b$1&!iB3!mI)3!8%[rqa'S!3!qL'%\r!3(`!!0!iirrrI1!k&8#!!!Jii!!!U!%!2M5J!!&!J!!)1+!!!(`&1K3X!!(p3)%\r!$$KJ!!")!!%SL!%!3$L"!%&mK!)81-!!!$KJ!$")!!!-R(rrrcM'!!'!!3#`I!F\r!8(`'!!""J2rX1-!!!%J!!"#-"2rr1-B!!C`Irrpm"MJ!3)!!%)J"!%"m"J!!3B$\rrj$J!!$")!!!-R"rrrcM'!!&m"MJ!3B$rp)!"!,!X!!!!3))!%)J"!+FS!!!!3B)\r!$$J!!#kF(rrr,!8!!%'#!%3i`!!!1'!!-%J!!!bFIrrr1-B!!BJ"!%"m!#K3I!B\r!!%'!rqa)!!!3M!6rrcM'!!'F(rrrI!BS!%'!rr")!!!-1!!!-*`Irrq)!3!mI!!\r(G8'#!"!i!!!YR"rrrdJ!!#b)!3#P+!!!!8##!"!i!!!VR"rrrdJ!!"3S!!!#3))\r!$$J!!##F(rrrIq2lH)!"!)Ji)3#!bq(rq(`)!kD$iIrXJm(rk%k!!#"m#!+Q[U(\rre*!!!3!)P#(pJ(ae'hL3!+%#S(bE)hJlS!!!1q%#0dJ!"QarBpYi1)!!*8J!"m&\rJ!!!!I(`EH#JF!!"!JJ"%If2EH%J!"bPJ!!!!I(iEHAqpmK4"JJC%If2EH(r%mhK\rqTUYi1+!!!8[rh19J!!!!+!-!!%##"L3iB2rr5!!')(rEi&&r[I)83B)!,(pMfhK\rra20iIUDVH$LJ!!&,rpbaB!!!!#J$!!"!JJ!-1'$rrdJ!"HarQq0iIf2EH$L"!U!\riS3)i5rr[kBJ"!MemHaYi,!!!D8'#!+4!J!"B,!!!@%'#!@4!J!!S,!!!48'#!L4\r!J!!3,!!!*8'#!j!!5!!$S#`!!%G"JJ)-5!!$P#`!!'4"JJ"S3)!!%#`!!'0!J!0\r-5!!$I#`!!'K!J!0d5!!"j#`!!(9"JJ%33)!!+#`!!'p"JJ%%3)!!%#`!!'j!J!+\ri5!!$6#`!!(0"JJ)85!!$3#`!!2p"JJ-i3)!$0#`!!(K"JJ$85!!$+)J"!M`S!!!\r#3))!')"K!U!iB`!%N!"K!U#$3rrm5!!!0#J!!!0!JJ!FJ'%#S$KM!!L3!'%#S)-\r$rrb$)rri5!!!&)"K!U!iB`!%N!"K!U#$3rrmL!%#2#J!!!&!JJ!)IeS(0)J"!M`\rS!!!$3))!0)$"!ML!i3)mJ3%#3)%K!N4r)mYiI`6$H$LK!MK,rr5aI(FEH#JA!!"\r"JJ+3!%J!!#b!S3)iJ-%#2)$K!N#"!3*%Id26H$L"!MK,rr*CI(FEH#JA!!""JJ*\rNIpIi8%J!!U5)!3)m+!!!!N##!"L!B3+J1'-!"*!!B3+JJd2rr%J!!$3S!!!$3))\r!()"K!U!iB`!)N!"K!U#$!rrmJb2rq%J!!"5!B3+J1'-!"*!!B3+JJd2rr)J"!M`\rS!!!"3))!#&GD"$k)!3)m+!!!!d##!$5!`3)iJ1%#2)%"!N#")3*%Ib2,H(m%`hJ\riS3)i5rrcjAah'hJS&`!!3B)"a%J!!#b!S3)iJ-%#2)$K!N#"!3*%Id26H$L"!MK\r,rr'0I(FEH#JA!!""JJ'BIpIi8%J!!GL)!3)m+!!!"%##!"L!B3+J1'-!#*!!B3+\rJb#2rq%J!!"5!B3+J1'-!#*!!B3+Jb#2rq)$"!ML!i3)mJ3%#3)%K!N3iS3)i5rr\rh5Aah'hJS&`!!3B)"2(rAq&")!!&mJ'%#S$KM!!53!'%#S),Mrr`S&`!!3))!#$V\rL!M5)!3)l+!!!!%'#!#b)!3)kLpF!!#J!!!!kp`!"3B)"3)!"!N4m(J!!3)%"0(`\rH!hK)!!%XL!%#1LJ!!!""JJ!XJm%#4(lMZhKraI0i1)!!!%[rjK&J!!!!+!-!!%'\r#!3"reaK35!!!q(lMZhK)!!0jB!!!!(aq'hK)!!$NJ'%#S)J"!M`iB`!%N!"K!U!\rX!!!#JZ2rr%'#!$4!J!!8,!!!!%'#!"K!J!!F5!!#A#`!!!4!J!*85!!!(*1h!!"\r)!!*)XlF!!%J!!N#6Y`!!5!!#1*1h!!4rS2j`N!!A!!")!!)SJ'%#S$VK!$JiB`!\r%N!"K!U#!!rrm1m!!!CJA!!")!!"J1Z%!1$J!!#@B&`!!1m!!!8J!!%arJq0i5!!\r#c@!!!!"mIKYjIlhb&%'#!#arJq0iIm6cH(kQUhJiS!!"5rrBL@!!!!!S!`!!3))\r!$$KJrrp)!!(%Ik2VH%J!!Eb)!3)iIpccH#J!!!""JJ$i+!!!!N##!!`k`!!`5!!\r!#$V!!##)&`!!I!!(G#`!!#Y"JJ!-,!!!,8##!-"q`!Gd,!!!-%##!,5!G3!N+!-\r!!$J$rrq3!"8!*%'#!##!G3!JL*F!!$J$!!'3!"8!)*L$!!"8J`Bq5!!!')Kh!!"\rqT+YiI'-(G%[re'&J!!!!,!2rrd##!!`iB2rr5!!")$Vh!!%lh[rr5!!!9)"e!#3\rS!`!!1!2rrj!!&3!N3B)!()#9!#"@``Bq1!3!!C!!&3!JQX3!!%J!!"4q``GdIU5\rVH%[re!PJ!!!!,!2rrd##!!`iB2rr5!!!b$ZF!!'!!3*!I"`!!%'!rkJX(J!!3B)\r!,(lMZhKra20iIUDVH$LJ!!&,rpG0B!!!!#J$!!"!JJ!-1'$rrdJ!!)L)!3)i+!!\r!!%##!'Jk`!!J5!!!9)"e!#3S!`!!1!2rrj!!&3!N3B)!()#9!#"@``Bq1!3!!C!\r!&3!JQX3!!%J!!"3iB!!JIU5VH%[rdfPJ!!!!,!2rrd##!!`iB2rr5!!!+$ZF!!'\r!!3*!I"`!!%'!rkKr[H)8L"X!!(`!"h9!J[Q3!(qMkhL!!3+)1#%#J(`)!kDkSIr\r86S!!)(`)!UD6iIrmNm(rq*1Krr53!!%!#*3Krh"mI4YiI*iMH(br+hKrT1Yi1'%\r!1$LJrrmi`!!"5!!"L@!!!!"ra20iIqAlH$KK!$K,rrN&,!-!!%'!!!`i!!!!I"d\rCVS!"!*Ji)3#3!(`)!kD$iIrmJm(rq)1Krr41J!!JI!J#TT!!!3!)P#(r`*!!S3"\rJN!$"!'53!1%!D*%"!'b4)3"`N8%!G*!!J3"FJ)%!A$LK!'",rrpCJ!%!5$JK!%"\rm#!1Q6S!!)$L!rrmiBrrrM!-!!6L%!!%S!!!!3),rp(b$)hK1J!!J1+6rrcM$rrq\r-K3!"9)!'2jb'!!&!J[rd6S!!)$M%rrmiirrr1+8!!8J!!#b-KJ!"9)!'2jb(!!&\r!JJ!F1!!!!%J!!!LF"`!"0+Arrd##rrK1J!!J0+Arrd##rp41J!!J1'2rre5%"Mj\r)!!!3I!!J3%##!!K1J!!JM!-!!93!"Mp!J[rX+!3!!%f#!#!iB!!!6S!!)$LMrrp\r8K!Bq1'!!!%J!!""m!#"!3))!#(bM+hL-"3!"9!!'2d##rq`S!`!!3B)!#%k!!#!\rS"!!!3B)!$$KJ!!"1J!!JI+-VH%k!!#"m#!+QNq(rr*2"rrL3!!%!#*3Krm"mIKY\riI)FMH(bJ+hKmhc0iJ))#3(r$mhKmj6YiI!B$H%[rc(PJ!!!!L"i!#(r$mhK6i#i\rdQ"i!#%[rcX9J!!!!1'!!!)!"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)$KJ!!*1J!!\rJ1'!!!%k!!#!iB!!!6S!!)(`)!UD6iIrmNm(rq*1Krr53!!%!#*3Kr["mI4Yi,"d\r!!%'!!"3X(3!#3B%!$$KJ!!")!!#3!$[J!!#ci3"8Xk%!8*2K!%SiB3!i5!!*bB"\r"!"4mIKYiIm!(08##!%#S!3"11'%!H,!"!)kcS3#3!%J!"`@!33!8I(iEH(r!"c9\r!JJ!FU!%!6T2K!)U`!3#11'%!H%J!#CQ!33!8Im!(08'#!"!iBKH`Im!(0*!!!`!\r!Im!(08##!!`iB!!!5!!!#$KJrrq!!3%B1#%"%(`)!kD$iIrmJm(rq)1Krr41J!!\rJ18)KM$PJ!!!i!!!JI!N$TS!+!!JS!!!!3))!+*!!DJ!)N!#+!!b3!+S!%*!!bJ!\r8N!$U!!#4#J!%I@0EH*%U!"K1J!!J1@X!!6P+!"a#!2r)1'$rrdk!!#!X!`!!6B!\r!)#`$!#"-J!!J('-!($L#)B`i!!!!I'3D&*!!!`!)N!!$!!b3!!-!%*!!!`!8N!!\r$!!#3!!-!"*!!!`!B6S!!)(`)!UD6iIrmN!!"!!L8)Ir!1q)P$%J!!##!"3!!1)$\rrrj!!(`!!J'8!#)'&!!4)!!LpJ%%!&)#r!!!S"3!!3),rh)!"!%Ji)3"!I!J$TS2\rKrra1J!!JI%-6H%k!!#"m#!+QN!!"!!L8)Ir!5rrrlAaT'hL!BJ&`J))"E$LL!!!\ri`L83J1)"B)%#!9a,rrlPB!!!!)##!I#3!'3!!%[rSiPJ!!!!1'!!!)!"!%Ji)3"\r!I!J$TNk!!#"m#!+QN!!"!!L8)Ir!5rrr3@!!!!#!BJ(`J'-!!%[rr[&J!!!!J!%\r!5$JK!%"m#!1Q6S!!)#`$!!"mB!!dI)N!0%##!!Ji#3!J,!8!!(bT!$4mbJ!d3))\r!#$NU!#"m!%J!)8!!3%'"!,!j+3!")5N!3(`!5K4p+9"3I5N$TL`*!#!ikIrJ3B!\r!%(aS2$!ii!!!5!!!'(b)6$!Jk3!JI'Fi-(d)1hKmCd``,!!!)$%Jrq""J!!3I)0\r)-$L!!!")!!!BI'-!-#%J!#"mL8``I'0,H(b%!$!j32rr-1F!!(b%)44mBaN8I3K\r"&(cR144m"N!3I58j%8'!!""m#!0iI5G,H$!+!!&#!2rBI)3K&(aM'441J!!J1)!\r!!$KJ!!"1J!!J,!-!!(aJ!$4mL3!d3))!#$J*!#!X"3!!I+N!0(c+!$4!JJ!)15S\r!)(`!5!!K3!"!3B%!X$NT!!%K+3"!I!"+&(dT8&"p+31Q,!N!)$MTrq""J!!3I'J\rm-$MJ!!")!!!BI)K--#$T!#"mCcJ`I3JlH(aR6$!X!!!J-5$ri%'!!""mJdJ`1)!\r!!%J!!"KmB`!`)5!!)(b*6$"mBdYiI)3!-$P!rrm`j`!!I)3K&(aM'44p#%%8I1F\rj&(`'3""p*6N43B!!%(`)!hKp*dYi-!S!!8)!rpKp"%0iI1-lH%k!!#"1J!!JJB)\r!k*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!1#3!%%!&)!-!!#!6!!%I!N$TNk!"##\r"JJ$%N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!,*!!33!8J!`!!)"-!!4m#31Q6S!\r%))'#!*!!N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!5*!!33!8J!`!!)"-!!4m#31\rQ6S!%))'#!(53!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ$dN!""!"5!$!!!J%`!"(`\r*!kC1J!3JJB)!d*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!-b3!%%!&)!-!!#!6!!\r%I!N$TNk!"##"JJ!3N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!"*!!33!8J!`!!)"\r-!!4m#31Q6S!%))'#!-L3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ$NN!""!"5!$!!\r!J%`!"(`*!kC1J!3JJB)!Z*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!$53!%%!&)!\r-!!#!6!!%I!N$TNk!"##"JJ"!N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!$*!!33!\r8J!`!!)"-!!4m#31Q6S!%))'#!#53!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!8N!"\r"!"5!$!!!J%`!"(`*!kC1J!3JJB)!q*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!)#\r3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ#XN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)\r!B*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!,b3!%%!&)!-!!#!6!!%I!N$TNk!"##\r"JJ%!N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!9*!!33!8J!`!!)"-!!4m#31Q6S!\r%))'#!-#3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ$8N!""!"5!$!!!J%`!"(`*!kC\r1J!3JJB)!H*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!$#3!%%!&)!-!!#!6!!%I!N\r$TNk!"##"JJ!)N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!'*!!33!8J!`!!)"-!!4\rm#31Q6S!%))'#!*L3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ$FN!""!"5!$!!!J%`\r!"(`*!kC1J!3JJB)!L*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!,#3!%%!&)!-!!#\r!6!!%I!N$TNk!"##"JJ#8N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)""*!!33!8J!`\r!!)"-!!4m#31Q6S!%))'#!$L3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ"SN!""!"5\r!$!!!J%`!"(`*!kC1J!3JJB)!C*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!+#3!%%\r!&)!-!!#!6!!%I!N$TNk!"##"JJ"-N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!E*!\r!33!8J!`!!)"-!!4m#31Q6S!%))'#!!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ"\r%N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!M*!!33!8J!`!!)"-!!4m#31Q6S!%))'\r#!)53!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ$XN!""!"5!$!!!J%`!"(`*!kC1J!3\rJJB)!r*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!!#3!%%!&)!-!!#!6!!%I!N$TNk\r!"##"JJ!FN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!A*!!33!8J!`!!)"-!!4m#31\rQ6S!%))'#!$b3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ#FN!""!"5!$!!!J%`!"(`\r*!kC1J!3JJB)!+*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!,53!%%!&)!-!!#!6!!\r%I!N$TNk!"##"JJ#NN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!m*!!33!8J!`!!)"\r-!!4m#31Q6S!%))'#!(b3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!JN!""!"5!$!!\r!J%`!"(`*!kC1J!3JJB)!U*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!(#3!%%!&)!\r-!!#!6!!%I!N$TNk!"##"JJ"BN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!f*!!33!\r8J!`!!)"-!!4m#31Q6S!%))!-!!#3!%%!&(`*!kD!6!!%6S!%)!!!!"b!!!"N#!#\r3"TL!!!#N'!#3"3%mJ!!!G"!!N!8"X)!!!-!B!*!&!R#!!!$S+!#3"30BJ!!!k!J\r!N!8%3)!!!3`3!*!&"8b!!!"S!*!'"E5!!!#8%!#3"3C)J!!!2!J!N!8'K)!!!$`\r!N!B'`)!!!'33!*!&"b5!!!%8'!#3"3JiJ!!!`"!!N!8)q)!!!33S!*!&#JL!!!"\rB%!#3"3TJJ!!"C#!!N!8,a)!!!-33!*!&$)L!!!%F'!#3"3fNJ!!!I!J!N!81))!\r!!)`)!*!&$V#!!!#d#!#3"3pNJ!!!G!J!N!83*)!!!'`)!*!&%*!!J!!"C$!!N!8\r4p)!!!&J)!*!&%Nb!!!'!3!#3"42-J!!"1$!!N!89")!!!P4S!*!&&eL!!!%i+!#\r3"4L3!)!!!&3!N!BBj)!!!&`!N!BC3)!!!(!!N!BCX)!!!(!!N!BD))!!!9!J!*!\r&'h#!!!#)!*!''rL!!!(!'!#3"4fiJ!!"!!J!N!8HZ)!!!*33!*!&(db!!!#B%!#\r3"4rNJ!!$@%!!N!8MF)!!!%!)!*!&)l#!!!#8+!#3"54%J!!!9"!!N!8NQ)!!!,!\rJ!*!&*8L!!!"%!*!'@q#!!!"8#!#3"9`mJ!!!@!#3"Pb8J!!!0!#3$B)+)K2dJJ)\rA&(JAX"4m&)J#i!,S![!#X!,!!XJ#Z!2i!SJ8J!+3!"5%!Y!#f!h3*3aR+'6F*4!\r%)QFS"L)4r))#(a(d!I`3m3*)%Z!#!!*3![d5H!,i%K!8@"3i&"J6q!-$!PJ$dJ2\r*!hi$B!0-!Q!AY"$X%'J2j!l3$k!KM!*%(L%r&b0*EQB")djK6JdL(F!))JS)KJ)\r8#I`4p"SJ(q3P5#5B*B`PS#H`,VJZ3#fi0k!eP$6N0""#"%(J@QKDB#*D@!3J-`3\rZ59"3"@K[Fh4c*h0[BfYPG&pPGQ9ZG&pSB@jNE'9b1L"cEf0VCA3JEQpd)'PZ)(9\rcC3%MU[i(#b,Ap3%K!3%K"!)L!QJ))$%69'9cG&4bB@0V)&9cCA)J5@jQEd9bFQp\rb)#9N)%GPG(4TEQFJ8hPc)%9ZGQPbEfjc!5"+4@jf9Q9b)#9N)'eKBfK8HA"P)#9\rN)(0jFeCPFL!PC#"`FQpM)#9N)%C395!PC#"$Efa[FP&%)#9N)'YLC#!PC#"KG&C\rPFR-J*@3"+#9c1L9c1L9c!590B@028`%MU[i($#%P!5%"!5%%!L)#J!`K#a8L&,!\r#)3%$)K5`&L)#U!)L!U!#)J+B##%6&5)9X!)K!3-L&E!@)J+S!L)#S!)L!TJ))4%\r9)KD`!L%"!b)@X"BL!UJ#)J+J!L)#Q!#5"##"I`'3#3+3"3'3%J3)N!m`N!S)N!H\rJN!D!N"3)N!CJN!C!N"3)N!3"J*!(3*!C#*!(3!L3"S#!#*!13%!)N!Z!N!4!#*!\r)3)!)N!4!3!L3"B#3#`L!N!3)N!S$)N8JJJ+""8A343a&d%A34G"&d%A34G"&d%A\r34G"&d%A34G"&d%A34G"&d%6)4G"&d%A34G"&d%A34G"&d%A34G"&I%6)45"&)%8\r-4G"%b%A34G"&d%A34EK%b%9B4G"&d%@J4G"%b%A34G"%b%,)3`"$!%,J3`"$!%-\r!3`"$!%-!3`"#`%-!3V4$!%-!3ZK'Y%E!4X"'`%E!4X"'`%E!4X"'`%E!4X"'I%E\r!4X"'`%E!4Ra'`%E!4X"'`%E!4T4'`%E!4X"'`%E!4U4'`%E!4V4*)%NX55a*,%N\rX55a*,%NX55a*,%NX55a)c%NX55a*,%NX5-a*,%NX55a*,%NX53"*,%NX55a*,%N\rX54"*,%NX*NNJ,8PZCJ'j&J!!!3!!!!(p!!!!r3!!!&S!N2-4GQ9bFfP[ER-ZE@P\rd,Q9NG3#3"%J!3B!!!!!&-#id,M%l-#id,M%X)%0[F(PbD@GSG#!a16Nh)%eKFh0\rKBfKeFf9dG(-J5@jcG'PdGA4P)'pQ)&4PBfKZEfa[ChN!!!#B!*!,!3#3%`*Y0MK\rV!*!6!3#3"PES!*!*2"&0594IT94PFh48FQ&MDdaTBR"hF'-!N"-"!!"@m!!!F8d\r!N!Nm%8e*9&qP9'9cG&4bB@0V6'PL!!!"!!!!!Id!!!$p!!!!@JG,jj!!64i!!!!\rF!&S!!N069&)!!!!DGQ9bF`!!!#CMCR*R!!!!-J4-rrm!N!N"rrm!!!!9!*!'rrm\r!!!"K"e'ZQ+%S:\r
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (C) 1997 by the Massachusetts Institute of Technology
- * All rights reserved.
- *
- * For copying and distribution information, please see the file
- * COPYRIGHT.
- */
-
-short MacOSErr;
-
-#include <CodeFragments.h>
-#include <Processes.h>
-/* sarac 02/19/98, added Sound.h for SysBeep() */
-#include <Sound.h>
-
-#include "TestTrackLib.h"
-
-#define TBALERTID 135
-#define TB30ALERTID 136
-
-struct VersionResourceRecord {
- Byte majorRev; /* Major revision in BCD*/
- Byte minorRev; /* Minor vevision in BCD*/
- Byte releaseStage;
- Byte nonReleaseRev; /* Non-final release # */
- short countryCode; /* Region code */
- Str255 shortVersNumStr; /* Short version number */
- Str255 longVersNumStr; /* Long version number */
-};
-
-typedef struct VersionResourceRecord VersionResourceRecord, *VersionResourcePtr, **VersionResourceHandle;
-
-OSErr ShlibTestTrack(CFragInitBlockPtr ibp);
-
-OSErr ShlibTestTrack(CFragInitBlockPtr ibp)
-{
- OSErr err = noErr;
- short fileRefNum, saveRes, processResFile;
- ProcessSerialNumber thePSN;
- ProcessInfoRec thePIR;
- FSSpec currAppSpec;
- VersionResourceHandle versResource;
- char versionString[256];
- char processSignature[5];
- short len, i;
-
- if ( (Ptr) test_track != (Ptr) kUnresolvedCFragSymbolAddress ) {
- /* Start our hack by saving the current resource ref*/
-
- saveRes = CurResFile();
-
-/* if (ibp->fragLocator.where == kDataForkCFragLocator)
- {
- fileRefNum = FSpOpenResFile(ibp->fragLocator.u.onDisk.fileSpec, fsRdPerm);
-
- if ( fileRefNum == -1 )
- err = ResError();
- }*/
-
- /* We assume that the current process is the one calling us. Good bet */
- err = GetCurrentProcess( &thePSN );
-
- if ( err == noErr )
- {
- /* fill in required fields for the ProcessInfoRec */
- thePIR.processInfoLength = sizeof(ProcessInfoRec);
- thePIR.processName = nil;
- thePIR.processAppSpec = &currAppSpec;
-
- GetProcessInformation( &thePSN, &thePIR );
-
- /* copy the processSignature into a string */
- BlockMoveData (&(thePIR.processSignature),&processSignature,sizeof(OSType));
- processSignature[4] = '\0';
-
-/* processResFile = FSpOpenResFile(&currAppSpec, fsRdPerm);
- err = ResError();*/
-
- if (err == noErr)
- {
- versResource = (VersionResourceHandle)GetResource('vers',1);
-
- if (versResource != nil)
- {
- /* Make a local C-string copy of the short version number string (a Pascall string) */
- HLock((Handle)versResource);
- len = ((**versResource).shortVersNumStr)[0];
- for (i = 1; i <= len; i++)
- versionString[i-1] = ((**versResource).shortVersNumStr)[i];
- versionString[len] = '\0';
- HUnlock((Handle)versResource);
-
- ReleaseResource((Handle)versResource);
- }
- }
-
- if ( thePIR.processType == 'APPL' )
- {
- if (test_track(processSignature, versionString, true, true, 0) == -1) {
- SysBeep(10);
- SysBeep(10);
-
- ExitToShell();
- }
- }
- }
- /*if ( fileRefNum != -1 )
- CloseResFile( fileRefNum );*/
-
- UseResFile( saveRes );
-
- }
-
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 1997 by the Massachusetts Institute of Technology
- * All rights reserved.
- *
- * For copying and distribution information, please see the file
- * COPYRIGHT.
- */
-
-#ifndef __SHLIB_TESTTRACK__
-#define __SHLIB_TESTTRACK__
-
-#include <CodeFragments.h>
-
-/* Special version of TestTrack for shared libraries -- uses calling application's
- version information */
-
-OSErr ShlibTestTrack(CFragInitBlockPtr ibp);
-
-#endif /* __SHLIB_TESTTRACK__ */
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (C) 1992 by the Massachusetts Institute of Technology
- * All rights reserved.
- *
- * For copying and distribution information, please see the file
- * COPYRIGHT.
- */
-/*
- * Function prototypes for testtrack routines - shared library version
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if GENERATINGCFM
-
-#define InitializeMacAthenaLib()
-#define TerminateMacAthenaLib()
-
- #if defined(__CFM68K__)
- #pragma import on
-
- extern int test_track(char *appl_name, char *appl_vers, Boolean edit_flag,
- Boolean do_logging, int check_probability);
- extern short GetBSDMacOSError( void );
-
- #pragma import reset
- #else
-
- int test_track(char *appl_name, char *appl_vers, Boolean edit_flag,
- Boolean do_logging, int check_probability);
- short GetBSDMacOSError( void );
-
- #endif /* endif __CFM68K__ */
-
-#else /* else GENERATINGCFM */
-
- typedef int (*test_trackProcPtr) (char *appl_name, char *appl_vers, Boolean edit_flag,
- Boolean do_logging, int check_probability);
- typedef short (*GetBSDMacOSErrorProcPtr) (void);
-
- extern test_trackProcPtr gtest_trackGlue;
- extern GetBSDMacOSErrorProcPtr gGetBSDMacOSErrorGlue;
-
- #define test_track(appl_name, appl_vers, edit_flag, do_logging, check_probability)\
- ((gtest_trackGlue)(appl_name, appl_vers, edit_flag, do_logging, check_probability))
- #define GetBSDMacOSError()\
- ((gGetBSDMacOSErrorGlue)())
-
- OSErr InializeMacAthenaLib (void);
- OSErr TerminateMacAthenaLib (void);
-
-#endif /* endif GENERATINGCFM */
-
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/*
- * Copyright (C) 1992 by the Massachusetts Institute of Technology
- * All rights reserved.
- *
- * For copying and distribution information, please see the file
- * COPYRIGHT.
- */
-/*
- * Function prototypes for testtrack routines
- */
-
-
-OSErr tt_open_MacTCP(short *drvrRefNum); /* Pass NULL if you feel like it*/
-
-
-/* function prototypes from tt.c */
-void tt_acknowledge(char *control, ...);
-void tt_fatal_error(char *control, ...);
-void tt_ensure(OSErr errcode, char *message);
-int tt_edit_user_info(struct tt_user_info **user);
-void tt_install_callback (int (*callback)(struct v_pkt *));
-int test_track(char *appl_name, char *appl_vers, Boolean edit_flag,
- Boolean do_logging, int check_probability);
-
-
-/* function prototypes from vlib.c */
-void v_parse_pkt (struct v_pkt *pkt, struct v_info *info);
-int v_read_pkt (int sock, struct v_pkt *pkt, struct v_info *info,
- struct sockaddr *sa, int *sockaddr_len);
-int v_assemble_pkt (struct v_pkt *pkt, struct v_info *info);
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:&%0$B@0SC8GXEf*KE(0-D@)Z0MK,!(0SE')rN!3!N!3"#J!!!CBl&%T[H5&`C@C\rQE6BiD`!!!!'b#cB`!*!0!`!#!*!EP!!"!J#3"!8!N!G)!!!!5!!!!!m!!!#8!J%\r#!*!%$J#3$fB!!!#N"!%#!%eKD@i!*8%e9fpbE'3!6'pKC'9b!*!&+L)r2!%M"UR\r`!L,rr443rj!%!*!%rj!%!*!%rj!%!*!2!3!!!%3!!!"%!!!!8!!!!!%!!!!"!!%\r!N!TR3fjdFQa#E'pMD`!!"!#3"3%!#eP3!3#3"J3!!Ble!!!"!!!!!@3!!!"N!!!\r!-J#31'!!!!""F("X!*"!B!!!!%e06%)!N#"-D@)J5@e`Eh*d)&"33`#3&Ne36%B\r!N#0J!*!,!3#3%`&Y0MKV!*!6!3#3%8!968P8Ak9$3f&MD'9(E'pLB@ac6'PL!!!\r"!!!!!@3!!!"N!!!!-J9@1G!cb!!!!"`!-J!!BfCbC`!!!!S!!2rr!*!)q0d:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:&%0$B@0SC8GXEf*KE(0-D@)Z8&"$!(0SE')rN!3!N!A`!!!"PU")5Qpj)A"PCQC\r`Gh"M!!!!!E*6cT3!N!d$!!)!N!6rN!3!N"2`!!3%!2q3"!#3"`J!N![`!J3%!2q\r3"!#3$fB!!!#!"!3%!*!&rj!%!*!%rj!%!*!%rj!%!*!2!3!!!%3!!!"%!!!!8!!\r!!!%!!!!"!!%!N!TR3fjdFQa#E'pMD`!!"!#3"3%!#eP3!3#3#!%!N!T+,`!!!3!\r!!!&N!!!!C!!!!$)!N%`3!!!!,`)!!!!#!!!6!!F"!!%!N"!(!3!"!*!3!3%!N!S\r(!3!"!3!"!3!!!!%!!!d!!3#3"4&KER0TAh"bC@CTH#jYB@-ZD!#3%!%"!!!!!3!\r!!!%!N!3"!*!&"3'3"`#3"J%!!!P0CA*R!!!!B!#3#`%!N"-"F(G`B`#3%`%!N"&\r!&8e*9&qP3d0KBfKP4fa[BQ&XFdaTBJ!!!3!!!!&N!!!!C!!!!$)&9MR30#B!!!!\rF!$)!!'0QFQF!!!!+!!$rr`#3"!9EF&$%G`:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:$80$B@0SC8aTBLif1%X!FfKXBN0"*%J"!!!!(ei!!!'5RAj+EhNKF'9QCQdf1'X\r!!!!"XJXf03#3$3-!!J#3$KM+!!!BbJ!!'-S!!!#8!!%#!*!%"3#3"J*i!!!#H!!\r!!D-!!"PJ!J%#!*!%$J#3$J4D!!!E"!3"!J"0B@PZ!#9"09G[FQaN!%a[B@4PFJ#\r3"#T451FB1#4[!"JS,`!F*Lm!)#K[!#3JEIpi*P!J#fBb5(J!%'(r!!!-1#5!*P)\rJ#fB%F!CJ2N+V!!3J8N+3!#"53UJ!##"53UJ!$#"YrhJJNQ!#*)Y`!EL!E`4`#@!\r@5S0R"L"$F!%JJ#!-C`BJEIrm+*!!F!"-ha`B6R3!%#T451F!-#4[!!`J#QFB*P)\rJ#fF5,`YKr`!!&L![%Q(r!!!+Z'!%F!TJ"%+5F!"-h``!6R3!"#T451FH1#C[!#!\rQ,`!N,#m!+#K[!#`U,`!`+#m!0#!,CJC`#Q!!!0C+K'B'F!aJ!!$-5(J#*Q(r!!!\r,G#4!)!TQ"R!'B!!!YNU$Ca)J3h$r8S"+''Ek$)!!!!$rC3C`!@!!!*SJ5L*$)!J\r3f@Em)!aR%L"-F2p5J%SBC[S-J!!!!2pP"(!-B(4"kJ%%)N`J#"$CC[`P43)-3QS\r#"#9'!3!9I!!#!K"`C#9!!K)[#Q(r!!!,1L9!!JK+UJ))CJ4`"Q!k5UX!#'B33US\r#)N+U!KiQLLG+!!4J&L"V!!3K5J)H*@X!"!)L3US#(LG+!!45U`!)8UX!$#"%))T\r`!%cI((K1G!!B+P&19[ri51FH2#SZ!!JSEJ!-+#i!%#CZ!"Kf!%U&CJC`#Q!!!*S\rJ#fB'F!aJ!!#3!#!-CN`JEIq),""`!Eb!CKj`!5m!5(J!UbmYrr3[,Iri)QhrM#"\rC6T!!+Qlrp'!LF!5mJ'BFF!%[!%Ki!+X[,Ird,bhrq#*Yri`J@8k3!#TZrr3J454\r3B#)[#Lm-)QhrJ#"C6T!!+Qlrp%U!CJUiUJ%!CJ4f!@!%*'S#(L!+C`4+!fI@5J0\rR"LD+F!"J"%+6F!T-haai6Pj1G!!8+P&19[ri51F32#KZ!!JNEJ!-)!aQ"(!+B(`\rJ#QB%F!aJG%U5CN`JEIq)*K"`!ED!CKj`!5m!5(J!c5mYrr3[,Ir`)QhrM#"C6T!\r!+Qlrp'!LF!5fJ'BFF!%[!%Ki!-d[,Ird,bhrm#*Yri`J@8k3!#TZrr3Q8J`V!!%\r#%'F%F!jJ&Lm,,`aKr`!!%&3[#f(r!!!)5%+5F!"-ha`)6Pj1G!!)+P&19[ri51F\rB2#CZ!!JSEJ!-)!YQ"R!+B!!!hL!-CJC`$'!!!04+P'C-)'hrL#B3F!'fJ'BHF!%\r[!%Ki!1X[,Ird,bhrm#*Yri`J@8k3!#TZrr4J)R!%YS"Q((!",`")H!$V,bhrp#m\rYrr!LEIq-)&P1N!!UE[rd*&4`C,#U!K*R%#m+BIm!!"155J"Q"(!)B'K+UJ)LCK!\rQUJ)H*LS#(QF')%0#U!)L5US#(QB5*fS#)J!%*LS#)QF')%0#U!)H+#S#)QF@*LS\r#(QF3)%-K4!)L)'S#)L&U!Ki#(K9m!!%#%#m-,`XLEIrX)&P1N!!UE[rd*J"5U`!\r-)!0-ha`B6Pj1G!!)+P%LE`!%)'m!##!*CJ4`#Q!1)!KR###T!!a`!'!#F!a1G!!\r)+P&)ja!`*Qm!%#4[!"3J#fB%F!TJ5#!+CJ4`#Q"!*LS#%R"NYS"R&R"QYS"Q$#m\r+BIm!!"+q5J"Q"(!)B#![,`!F,bm!(#m+BIm!!!dJ*J"+JfB%8UX!#&+V!!`J!dc\rI$!K1G!!3+P&)ja!`*Qm!%#4[!"3J#fF%)!TQ"(!+B$BQ+J)5F'5fJ'F@F'DfJ'B\r-,`TKr`!!%Pa+!'B%F!KJ&Lm[!"`[,`!F,`TKr`!!$E*5U`!-F!"-h``)6R3!%#T\r46PErq%MR'$`QEJ!)*'i!$#JZ!"!SEJ!8)!YR"#!+CJC`#Q!!!*JJ$'C-)'hrL#B\r3F!'fJ'BHF!%[!%Ki!@X[,Ird,bhrj#*Yri`J@8k3!#TZrr4J)R!%YS"Q((!",`"\r)H!&V,bhrp#mYrq3LEIq-)&P1N!!UE[rd*LS#%R"NYS"R&R"QYS"Q$#m+BIm!!"'\rQ5J"Q"(!)B#DiUJ%!C`4`#Q!F5(J!rbm-5'S""#*Yrh`J@8k3!#TZrr45U`!-F!"\r-ha`B6Pj1G!!3+P&)j`!i*'m!&#C[!"JJ#QB%F!TJ3("QX+S#%QB3,`TKr`!!%8K\r+!'B%F!KJ+#!,Cb*)H!$rBIm!!!88*S!S8b!-CJ4`"Q!1)%a$kJ%%)!J3f@EmF!"\r-ha`!6R3!$#T451F!-#4[!"!QE`!8)!TQ"(!+B#C`CV#U!K*Q%#m+BIm!!"$U5J"\rQ"(!)B!iJ#fB%F!CJ"LDU!3"`!%cI$!"1G!!-+P&)j`!`*'m!%#C[!"3J#QB%F!T\rJ0("QX+S#%QB3,`TKr`!!%+C+!'B%F!KJ(#!,CaC)H!$rBIm!!!4b*S!J8b*+)!J\r3f@EmF!"-h``!6R3!$#T451FB1#J[!"JSE`!F*'m!)#!-C`JJ#QF%5S4Q"(!+B%K\r+NQBD5(J!#'(r!!!%,#5!*K*Q"(!'B$!J4#*$)T!!)&)Q%'B3,a*Kr`!!"%a#NN+\r8F!0J&#m-,`0Kr`!!$GSQ8L"6*UJ#(R!!60mF'%jd!!`U88MR($K46bB[!#3QE`!\rS+'m!,#4[!$!J#fF))!TR"%U$CJC`#Q!!!6`J$'B'F!CJ!!%bF'D`U`)5CK)[#f(\rr!!!2a%S!CJC`#'!!!4K+NQBN5(J!#'(r!!!$ML5!*K*Q"R!'B!!!rL"$3UJ!"'!\r')%05U!!%1LX#"$!&5-!Q%L"$+#J!",L!E")J"1@))'X###"`#!"`Bl#3!'I8-!9\r)`,L!E4)[%Q(r!!!$I%+83T*`!f!!!,!J"1@))'X###S`#!!J45B3F!'fJ'CS5(J\r!#'(r!!!$&#L!5T4Q"R!'B!!!K%Ki(AjKr`!!![iJ9#&!!!3J9#BS!!4Q"(!'B'B\rJ8L!S!!6PL#"V!JJJF!J!)'J!"#*$)$`!!"eqFL#`J@8%SLjJ$NU!C`SL#4,B8i"\rQqL*"B#K`!VD!CK`[D!!%!!4`!Lk!,``[,`!),bm!#'(r!!!(KQ!'3T4`%'!))&*\r5U!!%F!"36dcI($K1G!!3+P&19[ri51FB2#KZ!!JNEJ!-H!!J$'B'F!TJ!!#F)!T\rQ"R!'B!!!NL!X!!K5J1@),`!LEIqX)&P1N!!UE[rd*)"+NQB%F!CJF#C8B'K)H!)\r#)QhrV#"C6T!!+Qlrp#"5)B!i!#K55V3i!'B%F!CJ5L"d1!!L5b!)%0PQr#"5)(!\ri!%(S!2p$k`%%)!J3f@Em)&)JF$J!)@X"!!(q*QX#(P+%@)-J#fDQ)!6PL#"53V!\r)!(!!B!4f!'$U60mF'%jH6R3!##T4,`SNE`!-)!TQ"(!'B!S[#Q(r!!!"i(!!*&p\r1G!!)+P%[#L4[!!`J#QB%F!CJ#Lm+BIm!!!(!F!!NAdjd!!JU85m+*'m!$#!+CJ4\r`#Q!8,a*Kr`!!$MJ[%Q(r!!!"Q%+5F!!NAdjd!!JU88j@rrK)jaJd*'i!$#!+CJ4\r`#Q!iH!"J-#mc1!!LEIqF)&P1N!!UE[rd8S4BJbC55V-i!'EN,a)LEIqF)&P1N!!\rUE[rd3T*`!'!%GJ"Ji%cI$"K1ANjd!!JU88j@rqa)ja!N*'i!$#BZ!"!J#QB'F!a\rJ!!$15'lrm#*YrkJJ@8k3!#TZrqK`C,#U!K*R'%KZrqp)DJ)@5'lrm#*Yrk3J@8k\r3!#TZrqJJ!e1!C`a6J'F58i"R0Q!!!)C`C#9!!K*J!!#!*LS#%R"NYS"Q&("P*8!\r#%L9Zrr!#&L9Zrr3#'Q"JF'DfJ'CDF!KJ@#BU!K*`C,D!CK4`CL9!!K)PE[r`!KB\rPE[rd!KTJ1("QYS"Q#NSZrqpQ"(!)B#T`CED!CL*+,[r[Ca4`CL9!!K)PE[r`!KB\rPE[rd!KTJ#(!)B!C`$'!#F!"-h`3)6Pj1G!!-+P&19[ri51F3*#BZ!!J[!b*Yrk`\rJ@8k3!#TZrr3N3#!+Ca![!bm+)QhrQ#"C6T!!+Qlrp#!+60m%#%jH6R3!"#T46PE\rrq%MR'#3NEJ!),`SLEIqJ)&P1N!!UE[rd*J!J#QC-)'hrL#J3F!'iJ'BHF!%[!%K\ri!#F[,IrB,bhrh#*Yri`J@8k3!#TZrr4J)R!%Z)"Q((!",`")H!!R,bhrf#mYrp`\rLEIq-)&P1N!!UE[rd5S0Z6#"YriJS%(!"Z)"Q(R!",`")H!!S,bhrf#mYrp3LEIq\r-)&P1N!!UE[rdB#*`",L!CKa`!5m!5(J!+#mYrpJ[,Ir8)QhrM#"C6T!!+Qlrp#m\r$3UF[#L*Yri3J@8k3!#TZrr3[!d+R,`SLEIq%)&P1N!!UE[rd,`-[#L*Yrj3J@8k\r3!#TZrr3[#L*Yrj`J@8k3!#TZrr4-h`3B6Pj1G!!%+P&19[ri51F3*#BZ!!J[!b*\rYrj!!)&P1N!!UE[rd*%!J#QF3,`-[#L*YrjJJ@8k3!#TZrr3J#NcI"!K1ANjd!!3\rU88j@rrK)ja!N*'i!##!+CN`JEIq)*K"`!ED!CKj`!5m!5(J!8#mYrpJ[,Ir3)Qh\rrM#"C6T!!+Qlrp'!LF!5fJ'BFF!%[!%Ki!&![,IrB,bhrd#*Yri`J@8k3!#TZrr4\r#DJ)%0A`!#J)'5(J!+'(rN!4@*8!###!U!JK-h`3)6Pj1G!!%+P&19[ri51F30#4\rZ!!JJ#QC-)'hrL#B3F!'fJ'BHF!%[!%Ki!&i[,IrB,bhrc#*Yri`J@8k3!#TZrr4\rJ)R!%YS"Q((!",`")H!"H,bhrf#mYrm`LEIq-)&P1N!!UE[rd*+i!$#9Z!"!!"%U\rZ!"4Q#%+U!!K`!'!q,bi!%'(rrrrqa#9!!!JQDJ!))!YQ"(!'B#3L5b"Z!"3J,J!\r3FL#`J@8%SLjJ$NU!C`SL#4,B8i"QqL*"F!"-h``)6Pj1G!!3+P&19[ri51FH2#K\rZ!!JNEJ!-H!!J#QC-)'hrL#S3F!'kJ'BHF!%[!%Ki!(3[,IrB,bhrb#*Yri`J@8k\r3!#TZrr4J)R!%ZS"Q((!",`")H!"d,bhrf#mYrmJLEIq-)&P1N!!UE[rd*N`J$'B\r)3T*J!!'`8S4+QfEk)!45J1@),`"KrrrrrJ)NJ#S!5S9Q6#"YriJX%(!"[)"Q(R!\r",`")H!"m,bhrf#mYrm3LEIq-)&P1N!!UE[rdB#*`",b!CKa`!5m!5(J!I#mYrpJ\r[,Ir%)QhrM#"C6T!!+Qlrp%U&C`!"3LC-B!!"+NKi!!aKrrrrrCJJ8L#!)&*+N!"\rQ6#"YriJX%(!"[)"Q(R!",`")H!#$,bhrf#mYrm!LEIq-)&P1N!!UE[rdB#*`",b\r!CKa`!5m!5(J!JbmYrpJ[,Ir!)QhrM#"C6T!!+Qlrp#"5,""R!!$8)NBJ9(!-FL#\r`J@8%SLjJ$NU!C`SL#4,B8i"QqL*")&)J8#mS!!4Krrrrr3iJ8L"3)8!!##"5)&"\r+U!!)CN`JEIq),""`!Eb!CKj`!5m!5(J!LbmYrpJ[,Iqm)QhrM#"C6T!!+Qlrp'!\rLF!5mJ'BFF!%[!%Ki!)X[,IrB,bhr[#*Yri`J@8k3!#TZrr3J8L"3,#J!#'Fq*K3\rJ3b!S!!3L4L"$)'J!#()JX)&P"+)ZB!j+J'F+)JN5f&1!C[SL39L+@)Y+NfB!rY3\rJ"1@))%9#X!J!*)9-haai6Pj1G!!)+P&19[ri51F!2#KZ!"!QEJ!-)!aQ"R!'B!!\r"%%Ki!!KKrrrrr$JSJ%U8CJC`"Q!!!2T)H!"-BIrrrr`L*%!J#QB'F!CJ!!$N5(J\r%iQ(rrrrm$#5!5T*Q"R!'B!!!cNKi"1*KrrrrqrBP3!!%5US!"'B'F!CJ!!#d5(J\r%hbm6,a)LEIpm)&P1N!!UE[rd5(J%hbmV!!3[+J!%)QhrI#"C6T!!+Qlrp#mV!"!\r[+`!-,bX!#%KU!!KKrrrrr'BPD`!8!"3PD`!B!"JPD`!F!"`PD`!J!#!PD`!N!#3\rPD`!S!#K)DJ!X,bX!,'(rrrrmmLmV!$J[+`!d,bX!-%KU!$"Krrrrr"i[+`"%,bX\r!3#mV!$a)DJ!mBIrrrr`)3US!5#"8F!)JJ#"8)8S!"(!!60mF!%jH6R3!$#T451F\r!-#4[!"3J#QB%F!CJ@NKi!!KKrrrrq`iNJ#C5)!YQ"(!'B%4`!5D!5(JGIQ(rrrr\rkp#C!)!YQ"(!'B#`L5b"[!"!J2!!!(Ajb),#"C35L,Q!15S"R#L)*%YK6J'Ek)N%\rJ8L&,!!4`!%cI$!"1G!!-+P&)j`!`@8mNE`!33TFJ#QB'F!TJ!!$8F!'`V`!8C`j\r`!V#[!"4R"R!3B!!![P*U!J3`+J)%X'S#"QCL-#S#"Y"!08!#"M!U!JC)`1@),`"\rKrrrrqQ!Q3#!,CJC`"Q!!!)S`+J)'5-"-I!J!N!3#jBJL5b"U!JKb),#"C35L,Q!\r15S"R#L)*%YK6J'Ek)N%[+J))BIrrrrN5*8X##(!"X+m!&'B55&F[,`!F,bm!('(\rrrrrqh'!HF!+`V`!8CK*)9bm[!"`[,`!FBIrrrrf1B!4`%'!8-#S#"%M!8i$PL#"\rU!JJKP`J!F!"B6dcI$!"1G!!-+P&)ja`i*'m!(#!+CJC`#Q!!!*af!'!!!*)[,`!\rN,bm!*#"U!JJJF%J!,bJ!"#mS!!"Kr`!!!6a+!'G8)!2PL#"U!JJSF!J!,`aKr`!\r!"3![$'(rrrriB#J$B%JQDJ)))!45J1@)*l-)!&J!8S4BK6!U!J4)`&1!*J#iJ'h\rH)!2PL#"U!JK#X!J!8fS#"'!38S0BK$!U!J4)`,D!E3$rI(!!B!SU!q@0B-Ci!'$\rQ60mF1%jd!!`U88j@rr4)jaJd*Qi!##4Z!!a#V[rd)!TQ6#"YriJQ%(!"YS"Q(R!\r",`")H!&),bhrf#mYrlJLEIq-)&P1N!!UE[r`B#*`",D!CKa`!5m!5(J"5#mYrpJ\r[,Iqi)QhrM#"C6T!!+Qlrm#!+CJ4`$'"!H!"J1#"U!JJYF$J!rr4)E[rd,`XLEIr\rJ)&P1N!!UE[r`8S4BJc!U!J4)`,L!EGB[+J))BIrrrrGFF!"J"(B!B14-h``B6Pj\r1G!!)+P&19[ri51F!0#4Z!!`J#QF)*Qi!&#!,CJC`!'!!!,`J,J!)X+i!%'F'F!"\rJ!!#XF!'`VJ!)CPT)D`!"5'S!!5*Yri!J@8k3!#TZrr4+J'Bq5'X%idKU"1-LEIq\r!)&P1N!!UE[rd5S"Q*NKV%iP)DK1*)QhrJ#"C6T!!+Qlrp%U!CJiJ+KKmX+XBI'B\r%F!&J6(!!B%K`!V#Z!!KQ2Lm6,a)LEIq!)&P1N!!UE[rd5S"Q*LmV!!3[+J!%)Qh\rrJ#"C6T!!+Qlrp%U!CJiJ+J!BX+X!''B%F!&J"R!!B!*`!%cI$!"1ANjd!"!U88M\rR($JQE`!F+'m!)#!-CJC`"Q!!!@j)H!)QBIrrrrB'+)!N9#!+CJC`"Q!!!9BJ5L*\r,)!J3f@Em*@X"!!%!3HS""%2V!33J#"$CC[`eD`)%!J3eD`)'!JB9I!!"!K!`+J)\r'5-$PL#m!BIrrrr@i*8!##%UU!JKQ"R!'B!!""RJ!B!!!r#"V!JJSF$J!+K4`!EU\r!CJ!!K%Ki!!KKrrrrpBBJDJ)))B!i!#"U!JJSF$J!)!aQ"R!'B!!!bR!"+)")H"e\rqBIrrrr9H)'S###"`1!!K3!!%)'S###"`1!!SD!!%)!aQ"R!'B!!!QL*-)'X###"\r`1!!JD!!%)$`!!"eqFL#`J@8%SLjJ$NU!C`SL#4,B8i"QqL*"B%T`!VU!CKJJDJ)\r)5(!i!#mX!!3[,!!!BIrrrrRLB#a`BlU!CLC)H!!)BIrrrr6J)'S###'!1!!JDJ)\r)+(!i!#!-CJ4`"Q!NF'-SJ&+%@)-`+J)%5-#iJ'd!ra4#UJ)L3US#(R!!B!4f!'$\rN60mF1%jd!!JU88MR!$JSE`!3*%`J$'B1B"S[+`!)BIrrrr5q@)SQ8L!,CZi[$'(\rrrrrdVNcI(!"1G!!%+P&19[ri51F3*#4Z!!JJ#QCH)'hrL#B3F!'fJ'BHF!%[!%K\ri!F)[,IrB,bhrY#*Yri`J@8k3!#TZrr4J0(!%YS"Q,R!",`")H!(#,bhrf#mYrl3\rLEIq-)&P1N!!UE[rdB"![#Lm+)Qhrk#"C6T!!+Qlrp%U5CZa`!%cI"!K1ANjd!!3\rU88j@rqa)ja!N*'i!##!+CN`JEIq)*K"`!ED!CKj`!5m!5(J"dLmYrpJ[,Ir3)Qh\rrM#"C6T!!+Qlrk'!LF!5fJ'BFF!%[!%Ki!G)[,IrB,bhrd#*Yri`J@8k3!#TZrqK\r)E[rZ)QhrU#"C6T!!+Qlrk$B!-!0)`'F%F!"J0("NX+S#%QFN5'lrpdKU!KC)E[r\rZ)QhrT#"C6T!!+Qlrk$B!-!0)`'F)F!"J#%)ZrrF3,[rh60m%#%jH6R3!"#T46PE\rrq%MR%$`QEJ!))!YQ6#"YriJQ%(!"YS"Q(R!",`")H!(R,bhrf#mYrl!LEIq-)&P\r1N!!UE[rdB#*`",D!CKa`!5m!5(J"jbmYrpJ[,Iq`)QhrM#"C6T!!+Qlrp(!#X*0\rQCL4V!!3[%Q(rrrrbrLmU!!4Krrrrm[4+UJ!3C`S[+J!3BIrrrr,N5US!1'F+,bS\r!1'(rrrrbe%UU!%4R#LmU!%4KrrrrmX3SDJ"))!aR##m-BIrrrrhJ+'S!,#!-C`J\r[$'(rrrrpd#mV!!4KrrrrmTT`!%cI(!K1ANjd!!4PF`3Z68P8)%N[8b"0B@0%CAB\r&,J3-)5KZB@eP)#%p)$!T!5N)3d0KBfKP,Q-")$d2)5JUD'&ZC'aP)#%p)$!T%5%\rSF(*TEQ0TF'&X)#%p)$!T$5%SFf&QC9!J)6dJ-#N-3d0KBfKP9A4TE#jM!5d-)5K\rcDATP)$iJ-%`T!5X+)5KZBb!K25!`+3%j#b%SEf*U)#%p)$!T$#%SC'9cG#!K25!\r`+3%r$h*PG'4PFh3J26dJ6P9-6!iU+Q4PFh3J26dJ6P9-6!%h&LJU+Q4PFh3T,6j\rNBA4K)$dp)%j96%`"+`TZBb!p25"198a-!6-5)5KMER4bE%*XEf0V)#%p)$!T!5i\r0)5KMFQ9NFb!K25!`+3!l)IU#!K-!jJ$D!-)!XJ#L!*3!L!"m!'i!B!"5!GJ!3!*\r!!NJ!-!!Q!"J!&!!J)Mmm!5-'UI!#)[rp$L)+)S)#*`'3!!R+!C!!#D!"N!!*J!'\r3!!PJ!C!!#*i"N!!(-!'3!!Dq!C!!"Q`"N!!'+!'3!!A+!C!!"3)"N!!%UJ'3!!4\r%!C!!"#!"N!!$(J'3!!*q!C!!!EB"N!!!XJ'3!!"m!C!!"#)"N!!)C2q3"!#3"2q\r3"!#3"2q3"!#3"`3!!!!1!!!!!3!!!0`!!!$S!!!#p!!!!!3!!!!9!*!2!3#3#b)\r!N!X$!!!!!3#3"d8!!!!"!!!!!3!!!!)!!!!%!*!(FJ#3#`J!!!!'!*!%!3!!&J)\r!!#m#!!!h!J!!2J%!!&F#!!"N!J!!I`)!!)N#!!#@!J!!S3)!!+`#!!#h!J!!``)\r!!08!!3#3"3B!N!3"3B$[5Je#%i!h4K40594IT80$B@0SC8GXEf*KE(0-D@)!Cd0\rZG(*X3Qa[BfX!68P8Ak90594$6'PL!(0dFQjMF(N!Fh4bBfe`!'ePEA0PG!"0594\rIT84PBR9RCfPZCdaTBJ"R4'9LG@G6D@GZB@`!3@aPFR46D@GZB@a"G!"*ER4PFQC\rKBf9-D@)!6Q9h8(4b8hPc!&9ZD'pXC%ePE@pbH3")EfaN6@9YEh*j!%4TFh"[Ff9\r3G()!4f9d8(4b8fPkC3"6B@eP8(*[Bf9cF`"(CA4$GA*bC@jd8(*[Bf9cF`"1CAG\r3G()!Bf0ICf9dAf0bC@4IGQ9bFfP[EJ"MBepQFQ9PAdj$AfPZCQm!Bf0ICf9dAf0\rSB@jRC9pdD@eP!'0MAf4PFh4bEhN!Bf0IBfa[Ff8!Bf0IBh*PBA4P!'0MAfCbC@9\rIBh*PC(-!Bf0ICf9dAfjKE@8!Bf0ICR*PC9p`FQPZBfP`B@`!Bf0IFQ9YEhCPAf0\rbC@3!Bf0IEh"PEJ"MBepRCA4I6N0ID@jQE`"MBepcCA&ICQ9dBfKI6N0c!'0MAh0\rPG&p`FQPZBfP`B@`!Bf0IFfKeG'4[Gfi!Bf0IFf9aAfCPG'0SAf0bC@4c!'0MAfG\rPG&p`FQPZBfP`B@`!Bf0ID@jTG'PKE'PkC3"MBepcG'pbC3"MBepXEf0VAh*PFA9\rPFh3!Bf0ICR*PC9pZB@eP!*!*"!!!!!`!!3!)!!3!!!!'!!J!"J!)!!J!!!!+!!3\r!#J!!!!X!%!!,!!`!$`!!!")!"!!5!!!!%`!)!"-!%qq*!!mc9`!569F!#TVI!!J\rQc`!*6#%!$Fk[!!XfqJ!4q!B!$ZC6!!F66!!1ZFB!%)+a!"#-#J!,2Ad!%JKH!"$\r-#`!0b18!##F0!!mB(J!-CeS#!!$F!!!#%!!"!J!!m!!!!G!!!3)!!3!!!!)i!!%\r#!!%6!!!#3!!"!J!"(J!!!NJ!!3)!!5F!!!*B!!%#!!%a!!!"f!!"!J!"2`!!!JJ\r!!3)!!8X!!!(S!!%#!!&G!!!#+!!"!J!"E!!!!P!!!3)!!A3!!!(`!!%#!!'$!!!\r#!!!"!J!"P!!!!L!!!3)!!D8!!!*J!!%#!!'a!!!"q!!"!J!"a!!!!KJ!!3)!!G8\r!!!*S!!%#!!(M!!!#-!!"!J!"l!!!!FJ!!3)!!I`!!!(J!!'qG3!!!3!!!!&J!!!\r!B!!!!$)[Fh*M,feKBbpdC@aZCA30Eh9d)'CPC5"TFb"SCA*PBRNJCh*KER4PC#`\rJF(*[GQPNC@3JG'KKG#"dD'8JB@*[GQ8JBfp`HA*TCfKd$5!U)'j[G'PMC5"KF("\rPBA)JD@iJB@aX)'0[F'PPFb"KEQ3JG'KKG#"LEh4S)(4SBA3JBfp`HA*TCfKd)'j\r[G'PMC5"KEQ30)#SJG'KTFb"`CA*YDA0cD@pZ)'j[G'PMC5"KF("PBA)JD@iJFh9\r`F'pbG'PZCb"NEf0eE@9ZG'&dD@pZ,#"KEQ3JG'KKG!dJ+L"dD'8JEQ&YC5"[CL"\r0,NNZ9#i!!!"F!*!,!3#3%`&Y0MKV!*!6!3#3%6`168P8Ak9$3f&MD'9-D@)!N!8\r"!!!!!@!!!!"J!!!!-J9@1G!cb!!!!"`!-J!!BfCbC`!!!!S!!2rr!*!)H,J:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:%d0$B@0SC8aTBLif1%XZC'9LG@F!FfKXBN0"*%J"!!!!*fB!!!'@B"K+EhNKF'9\rQCQdf1'X!!!!"XJXf-3#3$3-!!J#3$L!B!!!J'!!!)"J!!!#8!!%#!*!%"3#3"J,\r`!!!#m!!!!G%!!##X!J%#!*!%$J#3$J6Q!!!LJ!3"!J"0B@PZ!#9"09G[FQaN!%a\r[B@4PFJ#3"#T46PErq%MR!$JNEJ!)+'i!%#CZ!"3JEIpJ5T!!CM*)H!!3BIm!!!p\r`*)"+NQB%F!CJ4#"53UJ!"#"53T!!)&*#U!!))&*#U!!-)'hrB##5B!BJEIpJ**!\r!F!'`VJ!-E!4`#@!8)!aR"(!"+)!J#fF')'hrr#D3!(!!60mF!%jH6R3!%)eMBep\rTEQPdD@&XDATP!!!U88j@rrJ[#L4Z!!JJ#QF@5T*R%Lm5BIm!!"[),a*Kr`!!$9K\rJ"(!+B!4#NR!!*&p1ANjd!!5,Bf0IFfKeG'4[Gfi!!#T46PErq%MR'$JQEJ!)*Li\r!$#KZ!"3S,J!FPFSJ#fB'F!TJ!!$D5S4Q"R!-B!!!d%Ki!LCKr`!!$SSN3#!+CJC\r`"Q!!!,T+JfF5)%0`re+!5KKQqJb!!!!!rf8'F!&J!!#H)%SL3b!)%0PQr#!-Ca)\rJ6($r8S"+''Ek$)!!!!$rC34`$'"i3HS""#*-)!J3f@Em*@i!'!)-3QS#"#9Z!"!\r"!"9m!!)#%("N*8!#%Lm+BIm!!!jD*8!##%UU!JKQ"(!'B$T+U`!)CK"#UJ)L3US\r#(LD+*dS!"'!@)'X!"#&+!KiPD`!%!L*#UJ)H*dS!"&+V!!K5U`!-)%3JLR!!60m\rF'%jH6R3!')PMBepMFQ9KG'8!!#T46PErq%MR($`U,J!)*Qi!$#JZ!"!SEJ!BPFT\rf!%U&CJC`#Q!!!0)J$'B'F!aJ!!$))!YQ!!#%)'hrM(!"X*!!CKj`!#m!5(J!Ubm\rYrr3[,Iri)QhrN!!J@8k3!#TZrr4J@L"Yria`!V#3!'B5,bhrq#*YrhJJ@8k3!#T\rZrr4J2L"Yria`!l#3!'B1)QhrC#"C6T!!+Qlrp'!Q)'hrM(!%X*!!CKa`!5m!5(J\r!UbmYrr3[,Iri)QhrN!!J@8k3!#TZrr3J4543B#)[#Lm,)QhrQ#"C6T!!+Qlrp%U\r!CJUiUJ%!CJ4f!@!%*'S#(L!+C`4+!fI@5J0R"LL+F!"J"%+8F!T-ha`i6Pj1G!!\r8Kf0MAfp`C@i!!#T46PErq%MR!$`SEJ!)*'i!$*I,)!aQ"R!+B!!!ZL!+CJC`$'!\r!!,"+NQB!!)3JEIq-F!'`N!"Q(R!!,`")H!$0,bhrp#mYrr!LEIq3!#"C6T!!+Ql\rrp'"D)'hrM(!#X*!!CK)[,Ir`)QhrH#"C6T!!+Qlrp'!q)'hrM(!$X*!!CJiLEIp\rN)&P1N!!UE[rdB#BJEIq-F!5`N!"Q((!",`")H!$0,bhrp#mYrr!LEIq3!#"C6T!\r!+Qlrp#"5$#J!!3)3C`4`$Q!B*P)[#bm-BIm!!"5i,`YKr`!!#NC#NR!!60mF!%j\rH6R3!#)KMBepME'pcC3!!!#T46PErq%MR%$`SEJ!)*Qi!$*A+)!aQ"R!+B!!"(L!\r,CJC`$'!!!44+NfB!!)3JEIq-F!'`N!"Q(R!!,`")H!$V,bhrp#mYrr!LEIq3!#"\rC6T!!+Qlrp'"D)'hrM(!#X*!!CK)[,Ir`)QhrH#"C6T!!+Qlrp'!q)'hrM(!$X*!\r!CJiLEIpN)&P1N!!UE[rdB#BJEIq-F!5`N!"Q((!",`")H!$V,bhrp#mYrr!LEIq\r3!#"C6T!!+Qlrp#46F'5`UJ)5Ca![#Q(r!!!BPNS!CJ4`#'"`5US#)QB5++S#(NU\rU!KjR##"U!Kj#U!)L5US#(QB8+@S#)J!%5US#)QF))'S#)N+S!Kj+UJ)LCaT+UJ)\rHCa3JDJ)H)@S#)J)L)'S#)L&U!Ki#(K9m!!%#%#m,,``LEIrX)&P1N!!UE[rd*J"\r5V!!-)!0-ha`)6Pj1G!!)LQ0MAf4PFh4bEhN!!!!U88j@rrK+VJ!)CJ4`#Q!B5Ui\r!$'F3)'i!##*Z!!`LU!!-F!"J!R!-6Pj1G!!)NQ0MAfGPG&pMD'&ZCf9IG'PYC3!\r!!#T46PErq%MR%$!QEJ!)*'i!$(B!)!YQ"(!+B%JJ#QB%F!TJ3("NX+S#%QFBF'D\r`UJ)5CJ`[#Q(r!!!AKNS!CJ4`#'!J,bi!&#mZ!"![#Q(r!!!3e#B!5S0Q"&+V!!K\r5U`!-)!0-h``)6Pj1G!!3L'0MAh0dEh*P!!!!+P&19[rd51F!-#CZ!!JNEJ!-3Ul\rrp#!,C`3J#QB%F!TJ0R"NX+S#%QFBF'D`UJ)5CJ`[#Q(r!!!A$NS!CJ4`#'!@,bi\r!&#mZ!"![#Q(r!!!4GP+V!!a`!%cI$!"1ANjd!"#1Bf0IFQ9YEhCPAf0bC@3!!!!\rU88j@rrK)j`!m+'i!##CZ!!`NEJ!8)!aR"#!,CJC`#Q!!!03J#QB!!)3JEIq-F!'\r`N!"Q(R!!,`")H!&V,bhrp#mYrq3LEIq3!#"C6T!!+Qlrp'"D)'hrM(!#X*!!CK)\r[,IrN)QhrH#"C6T!!+Qlrp'!q)'hrM(!$X*!!CJiLEIpN)&P1N!!UE[rdB#BJEIq\r-F!5`N!"Q((!",`")H!&V,bhrp#mYrq3LEIq3!#"C6T!!+Qlrp("NX+X#%QFBF'D\r`U`)5CJ`[#f(r!!!@%%S!CJ4`#'!U)#X"!,#Z!""R"(!+B"a)H!$r,`T)D`%%)Qh\rrP#"C6T!!+Qlrp&+X!!a`!%cI(!"1ANjd!"#3!'0MAh0PG&p`FQPZBfP`B@`!!!!\rU88j@rrK)j`!`*Qi!$#4Z!"!J#fB%F!TJ2R"QX+X#%QB3,`YKr`!!&CC+!'B%F!K\rJ*L!+Cb")H!$rBIm!!!B+*)"+NQB%F!CJ$L"53qX""#!)%0PQr(!!60m-!%jH6R3\r!$*!!Bf0ICf9dAh"bD@jMDA"KE!!!!#T46PErq#m+*'i!$#!+CJ4`#Q!XF'D`UJ)\r5CK![#Q(r!!!9*NS!CJ4`#'!85Ui!%'B%F!CJ#L"Z!"!JUJ%!F!!NAdjH6R3!$*0\rMBepRCA4IBh*PC&pfCA*cD@pZ!!!U88j@rrK)j`!`*'i!$#CZ!"!J#QB%F!TJ0("\rQX+S#%QB3,`TKr`!!&-*+!'B%F!KJ(#!,CaC)H!$rBIm!!!8f*S!J8b*+)!J3f@E\rmF!"-h``!6Pj1G!!-Lf0MAfGPG&pZB@eP!!!U88j@rrK)j`!i+'i!##CZ!!`NEJ!\r3)!YR##!+C`3J$'B%F!TJ5NU5CKK)H!!)BIm!!!6F*)"+NQB%F!CJ-L"5)*3J8NU\r3!'B3,a*Kr`!!"3T#NN+6F!0J'#m,)&)[%'(r!!!49L"5)&!L8L+S!Kj`!%cI(!"\r1ANjd!!b3!'0MAh0PF9pQCA4MD&p13h-!!!!U88j@rr")ja!i*Qi!$#KZ!"!NEJ!\r8)!YR#L!+C`C+VJ!)CJC`#Q!!!9!J$'B'F!CJ!!&'F'D`U`)5CK)[#f(r!!!6Y%S\r!CJC`#'!!!5a+NQBN5(J!#'(r!!!%*L5!5T*Q"R!'B!!"%L"53UJ!"'!')&*5U!!\r%-#X#"%M!)&+`U!!%Ea3J8L*V!JJJ+!!%)R%-!("MX*&Rf$!V!J4)`#"5X+J!"'i\r5,a*Kr`!!""j#P%+5F!0J!!$#)&)LD`)))#J!"#*a$!!Q%A!"YS"QDNKi!!KKr`!\r!!kSSJ%U8CJC`"Q!!!*C)H"eqBIm!!!18)&3K3!!%)&4+U!!%CJ4`"Q"i)&)LD`)\r))#J!"#*a$!!JD3!%)P3LD3!%)$`!!"eqFL#`J@8%SLjJ$NU!C`SL#4,B8i"QqL*\r"B$K`!VD!CL`J8L*V!JJJ+!!%)R%-!#eT!!6rp(!#,8$rm#m-,blrp#mZrr"Kr`!\r!#LCJ"N+8F""J##"58UJ!"(!!60mF#%jH6R3!%**MBepcCA&ICQ9dBfKIBh*PC(-\r!!!!U88j@rrK)ja!m+'i!##CZ!!af!*A+)!aQ"R!+B!!!NL!,CJC`"Q!!!)JJ,!!\r)8S$PL#m!)QhrL#"C6T!!+Qlrp#D!5T0Q"(!'B'BN9'"@5(J#!L*YriJJ@8k3!#T\rZrr3J8b'!2!!J8dU`2!"Q"(!'B%!J8b"`2!!L5L!)%0PQr#"6)(!m!%(S!2p$kJ%\r%)!J3f@Em)&-JF$`!)@S"!!(q*'S#(P+$)!TQTL"63V!m!(!!60mF#%jH6R3!#)j\rMBepRCA4I6N0ID@jQE`!!!#T46PErq%UZ!!aQ"(!'B!`[,J!-BIm!!!*1F!"1ANj\rd!!L4Bf0ICR*PC9p`FQPZBfP`B@`!!#T46PErq%UZ!!aQ"(!'B!`[,J!-BIm!!!)\rBF!"1ANjd!!L-Bf0ICR*PC9pZB@eP!!!!+P&19[ri,`SNEJ!-)!TQ"(!+B"3[%Q(\rr!!!5$Lm5BIm!!!(F3T*`!#4I6Pj1G!!)M@0MAfCbC@9IBh*PC(-!!#T46PErq%M\rR%#3NEJ!-)!TQ"(!+B$4f!'!8)&)[-$`!)QhrG#"C6T!!+Qlrp&+$)&*+X$`!CZ3\r[%L*Yrh3J@8k3!#TZrr4#NTA+F!"-h`3)6Pj1G!!)Mf0MAfCbC@9I6N0ID@jQE`!\r!+P&19[rX51F!*#4Z!!`J#QB'F!aJ!!$D5'lrm#*Yri3J@8k3!#TZrqJp32rXF'5\r`UJ)5Caa)E[r[5'S#&NKZrr!LEIq!)&P1N!!UE[rS28$rl#!Z!""6J'F-8i"R%P1\r!CcCJ!!#)F'3P3!)5B!!!JR"NX+S#%QB8F'8P3!)5*@lrm!)@*@lrp!)DB'4`CV#\rU!K*QA(!)B&T`C,#U!K*Q&("Q*8!#%L9Zrr!#&L9Zrr3#'Q!mF'D`UJ)5CJT+,[r\r[CJ4`#'!XF'@`UJ)5CL*+,[r[Ca4`CL9!!K)PE[r`!KBPE[rd!KTJ#(!)B!C`$'!\r#F!!NAdjH6R3!$)pMBepXEf0VAh*PFA9PFh3!!#T46PErq%MR!#3[,J!))QhrL#"\rC6T!!+Qlrp#4!)!TR%LmZ!!J[#L*Yrh!J@8k3!#TZrr3J#L4I6Pj1G!!%LNjPGe0\rKCQ93G()!!!!U88j@rrK)ja!N*'i!##m+)QhrI#"C6T!!+Qlrp#B!)!TQ!!#%)'h\rrM(!"X*!!CKj`!#m!5(J!*bmYrpJ[,IrF)QhrN!!J@8k3!#TZrr4J@L"Yria`!V#\r3!'B5,bhrh#*YrhJJ@8k3!#TZrr4J2L"Yria`!l#3!'B1)QhrC#"C6T!!+Qlrp'!\rQ)'hrM(!%X*!!CKa`!5m!5(J!*bmYrpJ[,IrF)QhrN!!J@8k3!#TZrr4+Jfi!!)3\rJEIq-F!'`N!"Q(R!!,`")H!!S,bhrf#mYrp3LEIq3!#"C6T!!+Qlrp'"D)'hrM(!\r#X*!!CK)[,Ir8)QhrH#"C6T!!+Qlrp'!q)'hrM(!$X*!!CJiLEIpN)&P1N!!UE[r\rdB#BJEIq-F!5`N!"Q((!",`")H!!S,bhrf#mYrp3LEIq3!#"C6T!!+Qlrp#m$3UF\r[#L*Yrj`J@8k3!#TZrr3[!d+R,`SLEIqF)&P1N!!UE[rd,`-[#L*Yrf`J@8k3!#T\rZrr3[#L*Yrh3J@8k3!#TZrr4-h`3)6Pj1G!!%MN4TFh"[Ff96B@CP8(4b!!!!+P&\r19[ri51F!*#mZ!!JLEIpS)&P1N!!UE[rd*%!J#QF5,bi!##m+)QhrF#"C6T!!+Ql\rrp#!+*&p1ANjd!!506Q9h8f&QC9"dFP0jF`!!+P&19[ri51F!*#4Z!!JJ#QB!!)3\rJEIq-F!'`N!"Q(R!!,`")H!"3,bhrf#mYrp!LEIq3!#"C6T!!+Qlrp'"D)'hrM(!\r#X*!!CK)[,Ir3)QhrH#"C6T!!+Qlrp'!q)'hrM(!$X*!!CJiLEIpN)&P1N!!UE[r\rdB#BJEIq-F!5`N!"Q((!",`")H!"3,bhrf#mYrp!LEIq3!#"C6T!!+Qlrp%*U!J3\reI!!+!JC)H!!SBIq3""!P3!)))#S###4I6Pj1G!!%M@jPGd0bC@4#G@CQCA)!!#T\r46PErq%MR!#3NEJ!))!TQ!!#%)'hrM(!"X*!!CKj`!#m!5(J!ALmYrpJ[,Ir-)Qh\rrN!!J@8k3!#TZrr4J@L"Yria`!V#3!'B5,bhrc#*YrhJJ@8k3!#TZrr4J2L"Yria\r`!l#3!'B1)QhrC#"C6T!!+Qlrp'!Q)'hrM(!%X*!!CKa`!5m!5(J!ALmYrpJ[,Ir\r-)QhrN!!J@8k3!#TZrr3NVJ!-*@i!%!!%5Ui!&'B)3US!#(!!B$i[,J!3BIrrrri\ri*8!!#%UU!!KQ"(!'B#BLDJ!))'i!&#!Z!""b),#"C35L,Q!15S"R#L)*%YK6J'E\rk)N&`!#4I6Pj1G!!3Lf0[F(P%BA4K6f*U!!!U88j@rrK)jaJm+'i!##4Z!!ai!*I\r,GJ!J#QB!!)3JEIq-F!'`N!"Q(R!!,`")H!"d,bhrf#mYrmJLEIq3!#"C6T!!+Ql\rrp'"D)'hrM(!#X*!!CK)[,Ir))QhrH#"C6T!!+Qlrp'!q)'hrM(!$X*!!CJiLEIp\rN)&P1N!!UE[rdB#BJEIq-F!5`N!"Q((!",`")H!"d,bhrf#mYrmJLEIq3!#"C6T!\r!+Qlrp#C-)!YQ#%+5B!!#@P+%5TYQqL!%8S$PL#m!BIrrrrdZ*)!Q!%U$CJ!!K#"\rYria`!E#3!'BHF!![!%Ki!(`[,IrB,bhra#*Yrj!!)&P1N!!UE[rdB&SJEIq-F!+\r`N!"Q%LmYrm3LEIpi)&P1N!!UE[rdB$iJEIq-F!1`N!"Q$L*Yrf3J@8k3!#TZrr4\rJ*L"Yria`",#3!'BFF!%[!%Ki!(`[,IrB,bhra#*Yrj!!)&P1N!!UE[rd5S0R!!'\rd*NaJ!!'J5(J!$'(rrrrmM#"5))!J8NU3!'B!!)3JEIq-F!'`N!"Q(R!!,`")H!#\r$,bhrf#mYrm!LEIq3!#"C6T!!+Qlrp'"D)'hrM(!#X*!!CK)[,Ir!)QhrH#"C6T!\r!+Qlrp'!q)'hrM(!$X*!!CJiLEIpN)&P1N!!UE[rdB#BJEIq-F!5`N!"Q((!",`"\r)H!#$,bhrf#mYrm!LEIq3!#"C6T!!+Qlrp#"55T!!C`!"$L*5)P%J9(!-FL#`J@8\r%SLjJ$NU!C`SL#4,B8i"QqL*")&)J8#mS!!4KrrrrqmJJ8L"3)8!!##"5)&"+U!!\r)CJ!!K#"Yria`!E#3!'BHF!![!%Ki!)X[,IrB,bhr[#*Yrj!!)&P1N!!UE[rdB&S\rJEIq-F!+`N!"Q%LmYrl`LEIpi)&P1N!!UE[rdB$iJEIq-F!1`N!"Q$L*Yrf3J@8k\r3!#TZrr4J*L"Yria`",#3!'BFF!%[!%Ki!)X[,IrB,bhr[#*Yrj!!)&P1N!!UE[r\rd)&)J8%US!!KR2L"8)#J!"#*5)P%LD3!))&3JD!!)FL#`J@8%SLjJ$NU!C`SL#4,\rB8i"QqL*"@)TBLdU6CJ$qAL"$3V"-!#5$60mF'%jH6R3!#)eMEh"j4'&dB8&bFQ&\rj!!!U88j@rrK)j`!m+'i!%*A+PmXQEJ!-)!aQ"R!'B!!"%%Ki!!KKrrrrqUBSJ%U\r8CJC`"Q!!!2T)H!"-BIrrrrU3!#4!)!TQ"R!'B!!!j%Ki"1*KrrrrqRSNJ%U5CJC\r`"Q!!!-j)H!6LBIrrrrTN*8!!"%UU!!4Q"R!'B!!!Y%Ki"0m[%bm5)QhrP#"C6T!\r!+Qlrp%Ki"0m[+`!%,bS!"#*Yrj3J@8k3!#TZrr3[+`!3,bX!$#mV!!K)DJ!)BIr\rrrrXS*@X!&!!8*@X!'!!B*@X!(!!F*@X!)!!J*@X!*!!N*@X!+!!S5'S!,#mV!#a\rKrrrrqrJ[+`!i,bX!0#mV!$")DJ!`BIrrrrVJ,bX!4#mV!%![+`!m5'S!2'(rrrr\rkbN+U!%JJ9(!#))!J9#&+!!4`!%cI(!"1ANjd!!b+Bfp`H9Be3h*PC!!!!#T46PE\rrq%MR!$!QEJ!3PFSJ#fB%F!CJ@NKi!!KKrrrrq@JQJ%U6CJ4`"Q"')&0`!5#!5(J\rGIQ(rrrrj6L4!)!TQ"(!'B#`L5L"Z!!`J2!!!(Ajb),#"C35L,Q!15S"R#L)*%YK\r6J'Ek)N%J8b&+!!4`!%cI$!"1ANjd!!b+Bfp`H9Bd3h*PC!!!!#T46PErp%MR!$!\rNEJ!)PmY#V[rd)!TQ"R!+B!!!i(!"X+i!$'F1F!+`VJ!-C`C`%'!!!-T5DJ)%-#S\r#","U!JCQDM!U!JE33$9!!JB`+J)'5-$PL#m!BIrrrrLN*N!J#fB'F!CJ!!#@-#S\r#"NM!)J$JLH#*i)RZLG+!iS(PL5!")NXJDJ))FL#`J@8%SLjJ$NU!C`SL#4,B8i"\rQqL*",bS##'(rrrrfc#9,!JK`!E#Z!!aQ&%KZrr3[,J!3,bi!$'(rrrrqYQ!JF!+\r`VJ!-CK4)E[rd,bi!%#mZ!!aKrrrrr94J"(!3B"3`+J)%5-"6J#"U!JJKV[rd$!"\r`!%cI$!"1ANjd!!b3!'0bC@4#G@CQCA**ER0PFR3!!!!U88j@rrK)jaJ`*'i!#*I\r,)!TQ"R!+B!!!L(J!B(B[,J!3,bi!$#"U!JJJF%`!,bJ!"#mS!!"Kr`!!!B4+!'G\r5)'S###C`6!![#f(r!!!'0#m,BIrrrrB#*J4J&#!$8S!JDJ)))QS###1`$!!m!&+\r$-#S#"%M!8i#fJ'hJ-#S#"%M!8i!JDJ))3V!-!&0U!J4J$&+%-#S#"%M!Z)"YJ(!\r!60m-'%jH6R3!$*!!Bh*PC%*eCQCPFP*PE@pfC3!!!#T46PErp%MR%$3QEJ!)*'i\r!$%+Zrr3J#QB!!)3JEIq-F!'`N!"Q(R!!,`")H!&),bhrf#mYrlJLEIq3!#"C6T!\r!+Qlrm'"D)'hrM(!#X*!!CK)[,Iqi)QhrH#"C6T!!+Qlrm'!q)'hrM(!$X*!!CJi\rLEIpN)&P1N!!UE[r`B#BJEIq-F!5`N!"Q((!",`")H!&),bhrf#mYrlJLEIq3!#"\rC6T!!+Qlrm#!+CJ4`$'!iGJ"J(L"U!JJYF$`!rr4)E[rd,`XLEIrJ)&P1N!!UE[r\r`8S-`+J)%5-#fJ'hB,bS##'(rrrrd`(!!60m-#%jH6R3!#*&NDA0`Eh0P3h*PC%*\reCQCPFJ!!+P&19[ri51F!0%UZ!!aR"NUZ!"4Q"R!!B!!!c#!Z!!L`VJ!3C`C`!'!\r!!,a`!E#Z!!KQBL4Z!!`QEJ!85'X!!8KU!!%LEIqB)&P1N!!UE[rd5S"Q2NKV"10\r)DJ6M)QhrQ#"C6T!!+Qlrp%U!CLC)Da1*5'S6L5*YrjJJ@8k3!#TZrr4+J'B1)#S\rBI,#V'(aQ"(!"B&4`!'"3F!+`VJ!)CNBNEJ!-*Qi!&#m6,a)LEIqB)&P1N!!UE[r\rd5S"Q*LmV!!3[+J!%)QhrQ#"C6T!!+Qlrp%U!CJiJ+J!BX+X!''B%F!&J"R!!B!*\r`!%cI$!"1ANjd!"#(Bh*PC'0YF!!!+P&19[ri51F31#CZ!!JSEJ!-PFSJ$'B'F!C\rJ!!'3!%Ki!LCKrrrrmc3SJ%U8CJC`"Q!!!ASN9#"+)NXJ#"$CC[`PD`%!!3""kJ%\r%3qX""#!)%0PQr$9V!J3#"$9V!JB#"K9m!!%#%$!U!JC)`1@),`"KrrrrmZBP3!)\r)5US##'B'F!CJ!!%SGJ"J!!%-)'X###"`2!"`!E#3!'B!!**)H!!)BIrrrr+f)'S\r###'!2!!JDJ))5V!m!'B'F!CJ!!$`)'S###"`2!"`!5#!5(JGIQ(rrrrbL#"U!JJ\rJF$`!)8!!"#"U!JJJF$`!5UJ!"'B'F!CJ!!#k)QS###*a2!!LD3!%)'X###"`2!!\rJD!!%)$`!!"eqFL#`J@8%SLjJ$NU!C`SL#4,B8i"QqL*"B'JJD`)))(!m!(!#X*!\r!CL!JDJ))5(!m!#"V!JJJF$`!,bJ!"#mS!!"Krrrrq4"J1L"V!JJJF$`!F'1`N!"\rQ,%Ki!!KKrrrrmHSJDJ)))B!m!#"U!JK+X$`!CJ4`"Q!N)'S###"`2!"`Bb#!8S-\r`+J)%5-#fJ'd!rZa#UJ)L3US#(R!!60mF#%jH6R3!#)9NGA"13`!!+P&19[ri,`S\rNEJ!))!TR(Q!1)&)[+!!)BIrrrr(+@)T+NQEZ,bi!#'(rrrraZL4I6Pj1G!!%N!"\rNDA0`Eh0P4'&dB8&bFQ&j!!!!+P&19[ri51F!*#4Z!!JJ#QB!!*BJEIq-F!'`N!"\rQ(R!!,`")H!(#,bhrf#mYrl3LEIq3!#"C6T!!+Qlrp'"X)'hrM(!#X*!!CK)[,Iq\rd)QhrH#"C6T!!+Qlrp'"3)'hrM(!$X*!!CJiLEIpN)&P1N!!UE[rdB$JJEIq-F!5\r`N!"Q,R!",`")H!(#,bhrf#mYrl3LEIq3!#"C6T!!+Qlrp'!3,`S[#L*YrqJJ@8k\r3!#TZrr4+NQEXF!!NAdjH6R3!")TQFQ9P6N0-DA0d!!!!+P&19[rX51F3*#4Z!!J\rJ#QB!!)3JEIq-F!'`N!"Q(R!!,`")H!(5,bhrf#mYrp!LEIq3!#"C6T!!+Qlrk'"\rD)'hrM(!#X*!!CK)[,Ir3)QhrH#"C6T!!+Qlrk'!q)'hrM(!$X*!!CJiLEIpN)&P\r1N!!UE[rSB#BJEIq-F!5`N!"Q((!",`")H!(5,bhrf#mYrp!LEIq3!#"C6T!!+Ql\rrk%KZrqiLEIq%)&P1N!!UE[rS0J!`!dM!C`4`!'!dF'5`UJ)5Cb4)E[rh5'S#&NK\rZrqiLEIq!)&P1N!!UE[rS0J!`!dM!C`K`!'!)3Llrpa!ZrrG-h`3)6Pj1G!!%LQP\rc6'pMDdpeFR-!!!!U88j@rrK)j`!d*Qi!##!,CJ!!K#"Yria`!E#3!'BHF!![!%K\ri!HF[,IrB,bhrX#*Yrj!!)&P1N!!UE[rdB&SJEIq-F!+`N!"Q%LmYrl!LEIpi)&P\r1N!!UE[rdB$iJEIq-F!1`N!"Q$L*Yrf3J@8k3!#TZrr4J*L"Yria`",#3!'BFF!%\r[!%Ki!HF[,IrB,bhrX#*Yrj!!)&P1N!!UE[rdF!+`NfCQ*'X!"#m5BIrrrqmd,bS\r!"'(rrrr[+NUU!""R#LmU!""KrrrrlaT+UJ!iC`S[+J!iBIrrrqm+5US!4'F+,bS\r!4'(rrrrZqNUU!%KR#LmU!%KKrrrrr3K+UJ!XC`S[+J!XBIrrrrci,bX!"'(rrrr\rZd(!!60m-!%jH6R3!"*CMBepQFQ9PAf0bC@4ID@jdCA*ZB@ac!!!!+P&19[ri,`0\rf!#mZ!!KKr`!!!&if!$!$5-"R"$!$B!JJEIpJ3T!!-!-Q(djH6R3!"***EQPdD@&\rXDATP3f&MD'9-D@)!!!!U88j@rrKKr`!!!%j1ANjeN94PFQeTEQ&dC80KBfKP6'P\rL!!"1G5T46PErq#m0)!d[!#mYrk`LEIqN)&P1N!!UE[rd+d$rA'(rN!6FF!"1ANj\rd!!3U88j@rrJ[$5mYre`LEIqJ)&P1N!!UE[rd6Pj1G3JZ68P8)%N[8b"0B@0%CAB\r&,JJ-)5KZB@eP)#%p)$!T!5N)3d0KBfKP,Q-")$d2)5JUD'&ZC'aP)#%p)$!T%5%\rSF(*TEQ0TF'&X)#%p)$!T$5%SFf&QC9!J)6dJ-#N-3d0KBfKP9A4TE#jM!5d-)5K\rcDATP)$iJ-%`T!5X+)5KZBb!K25!`+3%j#b%SEf*U)#%p)$!T$#%SC'9cG#!K25!\r`+3%r$h*PG'4PFh3J26dJ6P9-6!iU+Q4PFh3J26dJ6P9-6!%h&LJU+Q4PFh3T,6j\rNBA4K)$dp)%j96%`"+`TZBb!p25"198a-!6-5)5KMER4bE%*XEf0V)#%p)$!T!5i\r0)5KMFQ9NFb!K25!`+3"1)J(SJJ)9!UJ!rJ$U!0i!aJ#f!+B!Q!#-!)!!FJ"N!&B\r#%!"%!RJ#J!!d!#S!(!!B!#!L2c`")`DTm!)Lrrd5)J'`JJ)X(kJ"X"pL!E!-XJ'\r`$%`"X!`-!E!,fJ'`#k3"X!VB!E!*3!'`#,)"X!K-!E!(lJ'`"hJ"X!CN!E!&m!'\r`"AB"X!8b!E!$i!'`![3"X!(S!E!!e!'`!*!!!E!%)J'`JJ)%!9JJ'!%B!#!B)ar\r1!3%K#!-M(r`"!5%)!b)J'!`!!!$rN!3!N!F"!!!"q!!!!!%!!!(`!!!!"3!!!")\r!!!!"!!!""!!!!43!!!1!!!!!"!!!!"8!N!m"!*!,)J#3#`S!!!!"!*!(RJ!!!!%\r!!!!"!!!!!J!!!!X!N!I4!*!,!`!!!!d!N!Ik!*!,!J!!!"!!N!3"!!!@!J!!,`)\r!!$J#!!"#!J!!6`)!!&S#!!"P!J!!EJ)!!(N#!!#&!J!!P`%!!,B#!!$$!J!!j!)\r!!1`#!!$c!J!"%`)!!5N!!3#3"3F!N!3"JB$c5K&#&B!h4KG#!!!!68P8Ak9$3f&\rMD'9(E'pLB@ac6'PL!'G$ER4bE%*XEf0V!%PZG'9bCQ&MC8aTBJ"6HA0#FQ9KD`"\r1CAG3G(*6HA-!9@jSEfaN6@9YEh*j!%K[E'40C@e[FRN!4'PcF'pcC9"dFJ"%C@*\reCe0dFJ"(CA43G(*6DATP!&0KE@93FQpMCA0c!%GPG%0eFR*PER43FQpMCA0c!%j\rPGe"dFJ"0594IT84PBR9RCfPZCdaTBLjNC@*eC`"R4'9LG@G6D@GZB@`!3@aPFR4\r6D@GZB@a"G!"0594IT8e*9%0-D@)ZC'9LG@F!Fh4bEQ0`H3"cG(*MEA!!E@9YFf9\rd!%e*9&qP68P88R9ZG'PYC8aTBLjNC@*eC`"IAh9ZFQ9RDA0dCA*ICR*KCfePER3\r!AepbC@GTFh4PFPpQFQ&RE@9ZG!"MBepRCA4IBh*PC&pfCA*cD@pZ!'0MAfCbC@9\rI6N0ID@jQE`"MBepRCA4IBfKKEQGPAh4TE@8!Bf0IC'9cG(*[H3"MBepME'pcC3"\rMBepMFQ9KG'8!Bf0ICR*PC9pMFQ9NF`"MBepRCA4IEQ&YC3"MBepQFQ9PAh"bD@j\rMDA"KE!"MBepbC@e[GQ9IBh*PC!"MBep[F'9Z!'0MAfGPG&p13epTEQC[!'0MAh0\rPF9pQCA4MD&p13h-!Bf0IFf9dAh"bD@jMDA"KE!"MBepcD(9dC'phEJ"MBepcCA&\rICQ9dBfKIBh*PC(-!Bf0ICf9dAh"bD@jMDA"KE!"MBepTEQPdD@&XDATP!'0MAh0\rdEh*P!'0MAfa[BfYIFQ9aG@9cG!"MBepQFQ9PAfjKE@8!N!J%!!!!$!!"!!J!"!!\r!!!B!#!!'!!J!#!!!!!S!"!!+!!!!#`!3!!X!$!!2!!!!%J!%!")!!!!6!!J!%`!\r6liN!$c0A!"*09`!+QYm!##E2!!P-)3!0cUm!#cEk!"(i"J!1jP-!"a0-!!kjaJ!\r3JV%!%)`+!!XpI3!5#&i!%-`,!!h)j3!)*`d!$aJH!!aR@J)!!6d!!!*)!!%#!!&\r4!!!##!!"!J!"B3!!!R!!!3)!!A3!!!*i!!%#!!&r!!!#J!!"!J!"L!!!!T!!!!%\r#!!'5!!!#%!!"!J!"S!!!!N!!!3)!!D`!!!)J!!%#!!'q!!!#B!!"!J!"c3!!!SJ\r!!3)!!G8!!!)S!!%#!!(N!!!#1!!"!J!"p3!!!PJ!!3)!!JB!!!+B!!%#!!)5!!!\r#-!!"!J!#*3!!!P!!!3)!!MB!!!+J!!%#!!*%!!!#D!!"!J!#63!!!J!!!3)!!Pd\r!!!)B!!%Bd`!!!3!!!!&N!!!!C!!!!$)!N20J!*!,!3#3%`&Y0MKV!*!6!3#3%8!\r868P8Ak9$3f&MD'9-D@)ZC'9LG@F!!!!"!!!!!@3!!!"N!!!!-J9@1G!cb!!!!"`\r!-J!!BfCbC`!!!!S!!2rr!*!)5'8:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:$80$B@0SC8aTBLj38%-!FfKXBN0"*%J"!!!!-#J!!!'5'R*+EhNKF'9QCR"hF'-\r!!!!"XP21U`#3$3-!!J#3"2q3"!#3"LPX!!!TE!!!+@`!!!93!!3%!2q3"!#3"J*\rK!!!#A3!!!@J!!#l!!J%%!2q3"!#3$J6'!!!!J!3%"!#3"Iq3"!#3"`%!!!&J!!!\r!!3!!!9J!!!!&!!!!%`!!!!%!!!%)!!!"'!!!!f!!!!!%!!!!&3#3$`J!N!X0!*!\r,!3!!!!J!N!FM!*!,"J!!!!N!N!F`!*!,!J!!!!m!N!G$!!!!!3!!!!%!!!!#!!!\r!%3#3"!)!!&8#!!"I!J!!E!)!!(F#!!##!J!!M3)!!*N#!!#V!3!!XJ)!!,i#!!$\r&!J!!c!)!!03#!!$E!J!!iJ)!!1N#!!$r!3!"%`)!!5!!!3#3"3J!N!4+%N!"3J&\r!!8)33J#!!dB@5@jdCA*QB@0P6'PL!%e*9&qP3d0KBfKP4fa[BQ&XFdaTBJ"0594\rIT8e*9%0-D@)!68P8Ak905945G@jdD@eP6'PL!%e*9&qP4'9LG@GRD@jR6'PL!%j\rPGe"dFP0jF`"9EQK[E'40C@e[FRN!5'pXC%ePE@pbH3"%DA0`Eh0P8(4b!%GPG&"\rdFP0THQ8!8f&YC9"bEf0PFh-!4f9d3h9bFQ9ZG&"bEf0PFh-!6Q9h8(4b!'G$ER4\rbE%*XEf0V!(0dFQ0YF!"YC@eMF(N!Fh4bEQ0`H3"cG(*MF(N!Fh4bE'9Z!'ePEA0\rPG!"IAh9ZFQ9RDA0dCA*ICR*KCfePER3!AepbC@GTFh4PFPpQFQ&RE@9ZG!"R4'9\rLG@G6D@GZB@`!3@aPFR46D@GZB@a"G!"MBepRCA4IBh*PC&pfCA*cD@pZBf0IC'9\rcG(*[H@0MAfGPG&pMD'&ZCf9IG'PYC@0MAfCbC@9I6N0ID@jQEf0MAf0bC@&dC@0\rMAf0XEh0PBf0ICf9dAfjKE@9MBepQFQ9PAf0bC@4cBf0IFQ9YEhCPAf0bC@4MBep\rQFQ9PAh"bD@jMDA"KE'0MAfp`C@jMBepcD(9dC'phEQ0MAh0PG&p`FQPZBfP`B@a\rMBepcCA&ICQ9dBfKI6N0cBf0ICf9dAdj$AfPZCQpMBepTEQPdD@&XDATPBf0ICf9\rdAh"bD@jMDA"KE'0MAh0PF9pQCA4MD&pMFQ9NFf0MAh0dEh*PBf0ICR*PC9pZB@e\rPBf0IE'pMDepbCA&eCA0d!*!("!!!!!`!!3!)!!3!!!!'!!J!"J!)!!J!!!!+!!3\r!#J!!!!X!%!!,!!`!$`!!!")!"!!5!!!!%`!)!"-!%qq*!!UDh`!569F!$c0A!!P\r-)3!)*Xm!#cEk!!h1V`!1jP-!%IJ'!!F66!!,2Ad!%)`+!"##X3!1ZFB!$FMP!"$\r-#`!5#&i!##F0!!aR@J!2'"i#!!%Z!!!!q!!"!J!"33!!!5J!!3)!!8X!!!%J!!%\r#!!&G!!!!Z!!"!J!"E!!!!8!!!3)!!A8!!!%`!!%#!!&p!!!!m!!"!J!"L!!!!-!\r!!3)!!C8!!!%3!!%#!!'M!!!!d!!"!J!"Y!!!!6J!!3)!!EX!!!&)!!%#!!('!!!\r"#!!"!J!"eJ!!!1J!!3)!!HB!!!$B!!%#!!(d!!!"8!!"!J!#!3!!!3!!!3)!!K%\r!!!$J!!%#!!)M!!!"'!!"!J!#+`!!!-J!!3)!!MF!!!#`!!%!N!Tm#!+QN!!"!!L\r8)Ir!1#%!3)!"!!Km#!1Q6S!!)(`)!UDrBIrXN!!"!!L8)Iq`I(XEH(bF)hKm[5Y\riI0icH)2L!##!(`!!+!!!!%##!&3iB!!35!!9*@!!!!#3!(X!!)"l!!!S!`!!3))\r!$$KJ!!C)!!"S1!!!!*!!!`!%J(X!!*!!!`!!J(X!!*!!!`!)J(X!!*!!!`!-J"X\r!!*!!(`!!5!!!#*!!'`!!,"`!!8#"!!`iB!!*5!!!+#JG!!""JJ!-1!!!!C!!(3!\r!+"i!!%'#!!b!!J#SN!!H!!!iB!!!J!%!@$JK!&"m#!1QZf(rl%k!!#!!N!BJ3B!\r&!*!&c!!1,Q0MAfPZDA4TB@aTHQ9m#!+QNq(rr*!!!3!)P#(r`(ar'hJS(`!!3B)\r!+)"r!!!S!`!!3B)!(%J!)T9J!!!!J(m!!%J!%ZeJ!!!!5!!!$$KJ!!T)!!!-1'!\r!!*!!I`!!J!%!5$JK!%"m#!1QJq(rr%k!!#!!N!BJ3B!"!*!&C!!-,Q0MAh0SGA4\rNEhGZ!!"m#!+Q[b(rj*!!!3!)P#(rS(aj'hKmQL0iI,XVH(cF-hKmrcYiI4e$H#J\rC!!"!JJ!-1'!!#NJ!!6JS(3!!3))!$$KJ!!a)!!%S1'!#+%J!%jeJ!!!!I(iEH#J\rH!!"!JJ!-1'!!"NJ!!3JS'J!!3B)!'(p$dhK)!#FpJ%%!&#J$!2p"J!!-1'!!!8J\r!!14r`r0iId66H%J!*Sf!33!8+"`!!%'#!"KrJq0i5!!R#B""!"3S!`$r3B!!$$K\rJ!!a)!!#`1(i""(q%ihK)!#CCJ%%!&*2q!J`li!!!Xri#"*0q!3!i!!!#Q"i#%$J\r!!'53!"i#&(r$mhK)!"0PB!!!!*!!IJ))J"i###J!!!"!JJ!-1'!!"NJ!!&b!'3!\r),!!!!%##!"L6rJ)NNri#)*2C!!#6f3!%5!!!()"j!!56``)JJ"N!"*!!(J)NNri\r#)*2C!!5!H3!)1!-!!C!!'3!)J(N!$$J$!!'3!"N!$*2G!!!iB!!!J!%!D$JK!'"\rm#!1QZb(rj%k!!#!!N!BJ3B!(!*!%!B!!#LjMBepMFQ9KG'9m#!+Q[d(rk*!!!3!\r)P#(rX(ak'hKmQb0iI,`VH(cp1hJiJJ'%1')"Gi#L!%3li!!!IrllH#JD!!"!JJ!\r-1'!!#NJ!!,`S(3!!3))!$$KJ!!a)!!#X+"X!!%##!$b!"3!!,!!!!8##!"JiS!#\rV1-!!!8J!**f!33!85!!!(#`!!!4!JJ!81+!!UcM!!!&)!#5"J%%!&)2k!!")!!!\rdIf2EH(rNqhK)!#9CJ%%!&#`$!!"!JJ!BJ"m"!(`F!!"!JJ!-1m!!!8J!!!L$r`)\rJ+"m!!%'#!!ar`!Ge3B,ra(r!"h9"JJ!3Nrd!!$KJ!!")!!!31!!!!*!!(3!!1'!\r!#S!"!&Ji)3"3I!J$TVY"rqK1J!!J!*!')%'!"J#3"!%3!!JZBf0IEh"PEJ!!I!J\r#TVqKrr53!!%!#*3Krl"mI4YiI*iMH$KL!BdiJJ'%J+)!4#JG!!"!JJ!-1'!!#NJ\r!!*JS(J!!3))!$$KJ!!a)!!#)J"i!!#J!!!"!JJ!mJ!8!!#`!!!&!JJ!B1+!!c6M\r!!!&)!#0pJ%%!&%J!!"`X!!!%3))!&$LJ!-di`!!"5!!MBB""!"5!IJ!!L!-#%#`\r!!!&"JJ!-1'!!$NJ!!#amIaYiIk2VH(rNqhK)!"S*B!!!!(rMqhK)!!mGB!!!!$K\rJ!!#3!(i!!)!"!&Ji)3"3I!J$TVZKrr41J!!J!*!')%'!!`#3"G`!#5jMBepME'p\rcC3"m#!+Q[k(rp*!!!3!)P#(rX(aq'hKmRb0i1')"M6L#!B5!SJ"%+"i!!%##!!`\riB!!+5!!"(#JI!!"!JJ!-1'!!$%J!!3b!(`!!+!!!!%##!$b!"3!!,!!!!8##!"J\riS!$V1-!!!8J!)S@!33!85!!!(#`!!!4!JJ!81+!!kcM!!!&)!#*TJ%%!&)1r!!#\r!(3)8,!!!C%'#!#"rSqYi5!!HP@!!!!"mB!Ge3))!$$KJ!!K)!!#FJ"d#*#J!!!"\r!JJ!JJ"d#)*!!(J!!J(d#)#J$!!""JJ!-1!!!!*!!!`)NJ"d#)#J!!!"!JJ!JJ"d\r#**!!(J!%J(d#*#J$!!""JJ!-1!!!!*!!!`)JJ"d#*#J!!!""JJ!JJ(d#)#J$!!"\r"JJ!8N!!$!L5!(3)JJ(d#**!!!`)J1!!!!CJG!K"r`r0iIq6lH%[rrFf!RJ!-1!3\r!!C!!(J!-J!%!@$JK!&"m#!1QZk(rp%k!!#!!N!BJ3B!$!*!%!@!!#bjMBepNCA0\rdFQpj!!!!+!-!!%##!!`iB!!+6S!!)#J%!!""JJ!8J!-!$*!!"!!!1'!!!%k!!#!\riB!!-6S!!)!#3"L"!!*!(-!!6,Q0MAfGPG&pMD'&ZCf9IG'PYC3!!!(`)!UDr`Ir\riN!!"!!L8)Ir!I(iEH(bI)hL3!+%!B*!!`3"N+"i!!%##!!`iB!!+5!!!H#JI!!"\r!JJ!-1'!!#NJ!!'L!(`)8,!!!C%'#!#JX!!"Q3))!'(rMqhK)!"d"B!!!!(aJ"h9\r!JJ!-1'!!#%J!!$KrirYiJ)%!B)#K!'4)!"6eB!!!!#`$!!"!JJ!3J*i!#$J%!!'\r3!"i!#)#H!!`i"!!"N!!H!!b!!3")1#%!3(`)!kDl`Iri6S!!)!#3"L""J!)!N!@\ri!!NZBf0IFh4[FQ8!I!J#TVr"rrL3!!%!#*3Krm"mIKYiI*mMH*!!S3"JN!$"!'3\rS(J!!3B)!$#JI!!"!JJ!-1'!!#NJ!!&L!(`)8,!!!C%'#!#JX!!"Q3))!'(rMqhK\r)!"`eB!!!!(aJ"h9!JJ!-1'!!#%J!!#KrirYiJ)%!B)#K!'4)!"9jB!!!!)"q!!`\ri!`!"N!!H!!`iB!!!J!%!5$JK!%"m#!1QZm(rq%k!!#!!N!BJ3B!#!*!&S!!2,Q0\rMAh*PE@pfC9pMFQ9N!!!!I!J#TVq"rr#3!!%!#*3Krl"mI"YiI*dMH(bq+hKmhc0\ri1')"R6L#!B5!SJ"%+"`!!%'#!!`S(3!!3))!$$KJ!!T)!!#X+"m!!%##!$b!"3!\r!,!!!!8##!"JiS!&V1-!!!8J!(aQ!33!85!!!(#`!!!4!JJ!81+!"DcM!!!&)!"l\rpJ%%!&)!G!K3X!!"N3B)!+#`!!'C!JJ!BIk2VH%J!'b9J!!!!I'!(G8##!!`iB!!\r)5!!!2)!G!3"m!2!!3B)!$$KJ!!T)!!!S1(d""(rNqhJiS!$r5!!IIB""!"5!I!!\r-1!-!!C!!(!!-1'!!!)!"!&Ji)3"3I!J$TVZ"rr"1J!!J!*!')%'!"!#3"!%!!"%\rZBf0IFf9dAh"bD@jMDA"KE!"m#!+Q[m(rq*!!!3!)P#(r`(bH)hKm[bYi+"i!!%#\r#!!`iB!!+5!!!D)!H!K3X!!"Q3))!)(r$mhK)!"TPB!!!!(aJ"h9!JJ!-1'!!#%J\r!!%!S(`!!3B)!0$KJ!2p)!!PpB!!!!*!!I`!!J(m!!#J$!!"!JJ!-1'!!"NJ!!"3\riRJ%%5!!H6B""!"3iB!!!J!%!5$JK!%"m#!1QZm(rq%k!!#!!N!BJ3B!#!*!&S!!\r4,Q0MAfGPG&p`FQPZBfP`B@`!I!J#TVr"rrL3!!%!#*3Krm"mRL0iI,mVH#JH!!"\r!JJ!-1'!!#NJ!!%L!(J)8,!!!CN##!#"r`r0i5!!CS@!!!!"mB!Ge3))!$$KJ!!K\r)!!!J+"m!!%##!!`iB!!'5!!!%)!H!3#3!"m!!$KJ!!#!!3")1#%!3(`)!kDl`Ir\ri6S!!)!#3"L""J!)!N!@!!"3ZBf0ICf9dAf0bC@4IGQ9bFfP[EJ!!I!J#TVr"rrL\r3!!%!#*3Krm"mRL0iI,mVH#JH!!"!JJ!-1'!!#NJ!!&L!(J)8,!!!CN##!#"r`r0\ri5!!Bq@!!!!"mB!Ge3))!$$KJ!!K)!!!`+"m!!%'#!#3iB!$r5!!)%@!!!!#3!(m\r!!)"r!!"ra20i5!!FmB""!"3iB!!!J!%!5$JK!%"m#!1QZm(rq%k!!#!!N!BJ3B!\r#!*!&N!!!$#jMBepRCA4IEQ&YC3!!I!J#TVqKrr53!!%!#*3Krl"mI4YiI*iMH(b\rr+hJS(J!!3B)!&#JI!!""JJ!-+"d!!%##!!`iB!!+5!!!M)!I!!!S!!!!3))!-$K\rJ!!K)!!GaB!!!!*!!I`!!J(m!!#J$!!"!JJ!-1'!!"NJ!!&b!(3!!N!!$!!#!I`!\r!J!-!!#J!!!"!JJ!J5!!(U@!!!!!i!!!!N!!I!!#3!"i!!$KJ!!0)!!!SI!-$H(r\r%mhK)!"5eB!!!!)#I!!#!C!!!J!-#)*!!"!!!1'!!!)!"!&Ji)3"3I!J$TVZKrr4\r1J!!J!*!')%'!!`#3"GJ!%5jMBepcCA&ICQ9dBfKI6N0c!(`)!UDrSIrdN!!"!!L\r8)Iq`I*dMH(bq+hKmhc0i+"d!!%'#!"3S(`!!3B)!$#J$!!"!JJ!-1'!!#NJ!!FJ\rS(J!!3))!$$KJ!!C)!!'iJ"d#&#`!!'C!JJ!JIk2VH%J!&bPJ!!!!I'!(G8##!!`\riB!!)5!!"N!#!(`!!+!!!!%##!%3iB!!)5!!'2@!!!!#3!(m!!)"r!!!S!`!!3))\r!$$KJ!!C)!!&J1!!!!*!!!`!%5!!!&)#I!!#!C!!%1!-!!C!!"!!%J(m!!)#$!!5\rS(3)%I!3!!%#!!"b!I3))9)!31RaM!#k!!`!!,!!!Bd'#rmL!I`!!J)-!"+JG!J4\rm"!!!3B!!)%J!"M&J!!!!1!!!!*!!(J!!N!!I!!!iB!!$5!!!k)"p!JK8J"!kI'-\r!,S!$!!!X!!!"3))!I$KJ!!K)!!@*B!!!!*!!IJ!!J"i!!#J!!!"!JJ!-1'!!"NJ\r!!+`iB"f!5!!&C@!!!!#!RJ!!N!"N!!5!IJ!!J'-!"#J$!!"!JJ!-1'!!"NJ!!)#\r![3))J*m!!)!%!!48!"!kI)8!,S#%!!3iS"f!5!!D4B""!"4)!!"%,!!!!N##!#b\r!!`!%N!!"!$`i!!!#N!!"!$L!B3!iJ)%!2(r&mhK)!!YYB!!!!%J!!"3i!!!!N!!\rH!!!iB!!35!!!')#I!!#!C!!%1!-!!C!!"!!%1'!!!)!"!&Ji)3"3I!J$TVZKrr4\r1J!!J!*!')%'!!`#3"!)8!"-ZBf0IFf9aAfCPG'0SAf0bC@4c!!!!I!J#TVpKrqb\r3!!%!#*3Krl"mI"YiI*XMH$ZJ!!"r[qYi+"`!!%##!!`iB!!+5!!!d#JE!!"!JJ!\r-1'!!"NJ!!-#!I!!)1!-!!93$%$T)!"N9J%%!&*!!H`!!J"X!!#J!!!"!JJ!-1'!\r!"NJ!!*5$R!!!5!!!G$KJ!J4)!"MTJ%%!&)#E!!"rr[YiI'6a,S"l!!"mBr!Z+!-\r!!%##!!`iB!!'5!!!A(q%ihK)!"M4J%%!&)"l!!"mBr!Z1'-!rcLF!34)!"LjJ%%\r!&)!F!3#!H`!!I'2`,T!!!`)!Jj`#)$Zp!!%lr`!%+"`!!%##ri`iB!!!J*X!!&H\rJ%$TmC!%ZJ!%!@$JK!&"m#!1QZf(rl%k!!#!!N!BJ3B!&!*!%!4!!$bjMBepRCA4\rI6N0ID@jQE`!!!(`)!UD3!!%!#*3Krm!S"!!!3))!$$KJ!!C)!!!8I)-MH%J!!k&\rJ!!!!1'!!!)!"!%Ji)3"!I!J$TNk!!#!!N!BJ3B!!N!Bm!")ZBf0ICR*PC9p`FQP\rZBfP`B@am#!+QN!!"!!L8)Ir!+!3!!%##!!`iB!!'5!!!&(b$)hK)!!0"B!!!!$K\rJ!!#!!3")1#%!3(`)!kC1J!!J!*!')%'!!*!'2!!0,Q0MAfCbC@9IEQ&YC3"m#!+\rQNq(rr*!!!3!)P#(r`(bI)hJS(`!!3))!$$KJ!!T)!!!NJ(m!!%J!&"eJ!!!!J(m\r!!%J!!Y&J!!!!1'!!!*!!I`!!J!%!5$JK!%"m#!1QJq(rr%k!!#!!N!BJ3B!"!*!\r&@!!1,Q0MAfCbC@9IBh*PC(0m#!+Q[m(rq*!!!3!)P#(r`(bH)hJS(J!!3))!$$K\rJ!!T)!!"%1!!!!(`I!hK)!!!BJ(i!!(aMq#j)!"C*J%%!&$[r!!5!IJ!!I!2i,LJ\r!!!"!J[rJ5!!@,B""!"3iB!!!N!"q!!#!!3")1#%!3(`)!kDl`Iri6S!!)!#3"L"\r"J!)!N!9i!"!ZBf0ICR*PC9p13epTEQC[!!"m#!+Q[m(rq*!!!3!)P#(rX(bI)hK\rm[LYi+"m!!%##!!`iB!!-5!!"*$KK!$K)!"@*J%%!&)!I!K3X!!"N3B)!'$KK!$J\riR`)B1+%!3%J!&B'!33!8,"i!!N'#!#a!J!!3,"i!!8#!!"4)!!$8,"i!"%#!!-a\r)!!")1!!!C*!!(`)85!!!a)!I!K3X!!"N3))!)$J!!'@3!"m#&)"K!$L!!3!mN!"\rr!KL3!"m#(%J!!*`X!!"Q3))!P$KJ!!K)!!#3!)!I!K3X!!"N3))!)$J!!'D3!"m\r#&)"K!$L!!3!mN!"r!KL3!"m#(%J!!'3X!!"Q3))!')J"!%!S!!!!3))!$$KJ!!K\r)!!"-J"m#&#`!!'9!JJ!mL!%!3#J!!!""JJ!J1!!!CT!!(`)8J'%!1)!"!$b3!(m\r#'*!!(`)F5!!!&$KJ!!K)!!!31'!!$%J!!!JiB!!!J!%!@$JK!&"m#!1QZm(rq%k\r!!#!!N!BJ3B!#!*!%!9`!%#jMBepXEf0VAh*PFA9PFh3!!(`)!UDr`IriN!!"!!L\r8)Ir!I(iEH%J!&-Q!33!8I(mEH#JI!!""JJ!8Iq2lH(r%mhK)!"6GJ%%!&(rMqhL\r!!3")1#%!3(`)!kDl`Iri6S!!)!#3"L""J!)!N!93!!XZ6Q9h8f&QC9"dFJ!!!(`\r)!UDr3IrSN!!"!!L8)Iq`I(SEH$Z#!FSlSJ'p1m)"Vi2L!%4)!"3"J%%!&(al'hJ\rS'J!!3))!6)!I!!!X!!!"3))!)(r$mhKrT1Yi1+!!*cM!!!&)!"1jJ%%!&%J!!#3\rX!!!%3))!((r$mhKrT1Yi1+!!*cM!!!&)!"19J%%!&#`E!!""J3"-J"m!!#`!!!&\r!JJ!JIi2MH(qNkhJiS!!S1-!!!8J!%fQ!33!85!!!*#`!!!4!JJ!FIi2MH(qNkhJ\riS!!S1-!!!8J!%d@!33!8Id26H$L!!!"rCGYi5!!6BB""!"4r3p0i1)!!!(pPfhK\r)!"00J%%!&(p$dhKrC0Yi5!!69B""!"4r3p0i5!!5kB""!"5!!3"B1#%!8(`)!kD\rl3IrS6S!!)!#3"L""J!B!N!3"+!!2,N4TFh"[Ff96B@CP8(4b!!!!I!J#TVr"rrL\r3!!%!#*3Krm"mIKYi5!!6EB""!"4mIaYi+"m!!%'#!"4rirYiIm6cH%J!%b'!33!\r8Iq2lH)!"!%Ji)3"!I!J$TV["rrK1J!!J!*!')%'!!J#3"9!!$Lj1CAG6B@CP8(4\rb8hPcI!J#TT2Krrb3!!%!#*3Krm"mIaYi1')"ecL#!Ef!SJ"%+"m!!%##!$b!"3!\r!,!!!!8##!"JiS!"31-!!!8J!%K@!33!85!!!(#`!!!4!JJ!81+!!8$M!!!&)!"(\rjJ%%!&$J!!!#`(`)%1!!!#V!I!JBiB!!S5rrr(C!!I`))J(m##)!"!%Ji)3"!I!J\r$TS2Krra1J!!J!*!')%'!!3#3"C3!$LjZCAG$FQ9N3R9QCQ9bI!J#TT2Krrb3!!%\r!#*3Krm"mIaYiN!#"!&b3!+%!B*!!`3"N1')"iML#!Ef!SJ"%+"m!!%##!$b!"3!\r!,!!!!8##!"JiS!"H1-!!!8J!%9@!33!85!!!(#`!!!4!JJ!81+!!AMM!!!&)!"%\rjJ%%!&)!"!&b3!"m!!)!"!'#3!"m!")!"!'3S!!!!3))!%$KJ!!#3!(m!#%J!!$L\r!B3"J5rrq4C!!I`!)J(m!##J$!!"!JJ!-1'!!"NJ!!"L!J3"NJ+%!B%J!%BQ!33!\r81'!!!)!"!%Ji)3"!I!J$TS2Krra1J!!J!*!')%'!!3#3"G`!$#jMEh"j4'&dB8p\rLDJ!!I!J#TVl"rpL3!!%!#*3Krk"mGaYiI*JMH$Z#!KSlSJ),1X)"qcKL!Hil`J'\rpJq)!4$YJ!!!S'!!!3))!4)!I!!!X!!!"3))!((r%mhJiS!"d1-!!!8J!%%f!33!\r85!!!)#`!!!4!JJ!BIm6cH$LJ!(3i`!!"5!!3,B""!"4qqVYi+"S!!%##!"Ji!!!\r!N!!B!!")!!(F5!!!#$Yl!!'!'J!!1eS!"#J!!!"!J[r`1"X!!93$%$T,rrdYN!"\ri!!"mH4Yi+"N!!%##!%b!(`!!,!!!!8##!#"q`l0iIm6cH$LJ!(`i`!!"5!!2[B"\r"!"4)!!!N,!!!"%##!"aq`l0iIm6cH$LJ!(`i`!!"5!!2QB""!"3S'3!!3B)"@(l\rkZhK)!!%d1'!!$%[rr,f!Q!!!N!"N!!#!H!!!J!-!!#J!!!"!JJ"-J"m!!#`!!!&\r!JJ!JIk2VH(r%mhJiS!#$1-!!!8J!$d@!33!85!!!*#`!!!4!JJ!FIk2VH(r%mhJ\riS!#$1-!!!8J!$b'!33!8J(J!!)"M!!!S!`!!3B)!f)#A!!!iS!!-5!!2UB""!"5\r!H!!!J'-!!)"M!!4,rr`YJ*J!!)#%!!#3!'3!#)"i!!#!B`!!J!-!##J!!!"!JJ"\r-J"m!!#`!!!&!JJ!JIi2MH(r%mhJiS!#,1-!!!8J!$Uf!33!85!!!*#`!!!4!JJ!\rFIi2MH(r%mhJiS!#,1-!!!8J!$SQ!33!8J(J!!)"M!!#!B`!)+!-!!%'#!$b!Y`!\r!J)8!#)#P!!4)!!m*J%%!&$XB!!3l@J!%J"S!!#J!!!"!J[l)1'!!!&GJ%$TmH3%\rZNcJ!!)!"!'Ji)3"JI!J$TVV"rpK1J!!J!*!')%'!#J#3"!+!!!iZBfp`H84KG'&\r"FR*KHA`)!UDrSIrdN!!"!!L8)Iq`N!"K!'L3!)%!E(bp+hL$`3"X+"d!!%##!!`\riB!!'5!!"2$KJ!!K,rrX0N!"p!!#!(3!!+!!!!%##!!`iB!!'5!!"($KJ!%a,rrV\rYI(mEH#JI!!"!JJ!-1'!!"NJ!!3!iB!6L5rrkdC!!I`!!J"m!!#J!!!"!JJ!-1'!\r!"NJ!!1!iB!6L5rrkXC!!I`!%J"m!"#J!!!"!JJ!-1'!!"NJ!!-#!I`!!J*i!!$L\rJ"0p)!!iKJ%%!&)"r!!5!RJ!%1+!%hdJ!$Jf!33!81(m!#)#H!!L![J!-J0i!%%[\rrqi'!(J!8N!!I!"5!(J!BN!!I!"L!(J!FN!!I!"b!(J!JN!!I!##!(J!NN!!I!#5\r!(J!SN!!I!#L!IJ!X1*m!,%[rr%%iI`!`J*i!-)#q!$5!hJ!i5rrl-6Kr!$b!RJ!\rmJ,i!3)$H!%4,rrXG1'!!!*!!I`")1!!!!S#G!!#3!!3!!)#G!!#6j!!%J!%!@$J\rK!&"m#!1QZk(rp%k!!#!!N!BJ3B!$!*!%!A`!#bjMEh"j9M9$FQ9N!!!!I!J#TVr\r"rrL3!!%!#*3Krm#3!'%!@*!!J3"FI,iVH#JH!!"!JJ!-1'!!"NJ!!'JiB!!)5rr\rjGC!!IJ!!J(i!!#J$!!"!JJ!-1'!!"NJ!!%Ji!!!"N!!$!!!iB"f!5rrj6Aar'hJ\rS(`!!3))!$$KJ!!C)!!!NIq2lH)#"!&`iS"f!5!!-NB""!"5!IJ!!Nq-!"$KJ!!#\r!!3")1#%!3(`)!kDl`Iri6S!!)!#3"L""J!)!N!@N!!XZBfp`H9Bd3h*PC!!!!(`\r)!UDr`IriN!!"!!L8)Iq`I(iEH*!!J3"XN!#K!(!li!!!Nq%!1#JH!!"!JJ!-1'!\r!#NJ!!1L!!3"X,!!!!8'#!"3X!!!#3B)!$$KJ!"")!!$-U(i#"$J$!!'`(J)%U(i\r#"+JH!JCm!`!!3))!@&3!#$b`(J)'U"i#"P3$%$T,rrKPI(mEH#JI!!"!JJ!-1'!\r!"NJ!!)KrirYiJ*i##+JH!JCm!!j`I!!"P&3&%$T)!!ZGJ%%!&)"q!JK,rrEGNri\r##)"K!'`X!`!"3))!&)#"!(!iS3!i5rrqD8J!!#3X!`!#3))!&)#"!(!iS3!i5rr\rmY8J!!!`iB!!35!!!))#K!$L!RJ))U(i#"$J$rrp8!"!kI+3",MKJ!!#!!3"B1#%\r!8(`)!kDl`Iri6S!!)!#3"L""J!)!N!3",!!4,Q0bC@4#G@CQCA**ER0PFR3!I!J\r#TVqKrr53!!%!#*3Krl"mIaYiN!#"!'b3!+%!F$[!!!!S(`!!3))!$$KJ!!T)!!$\r!IphcH%J!!+L!I`))I)2`,S"N!!#!K!!%J+%!E)$"!(")!!(4B!!!!(aJ"h9"JJ"\riJ(m##(r$m#jr`r0i5!!('@!!!!"r`r0i5rrecAqPkhK8Sa!k5!!!))#I!JJi"3!\r"9!!31R`%!#jm""NZ1+8!!6KM!!5SR`)%1!6rrh`&!!""J2rB1)!!!)"r!JK8!"!\rkI)-",UKr!J3i!rrrX"m#"%J!!"Jl[3!"1pi!"+JI!J4m(3!!3B$r9$KJ!!#!!3"\rB1#%!8(`)!kDlSIrd6S!!)!#3"L""J!-!N!3"!!!4,Q0bC@4#G@CQCA*5C@e[GQ8\r!I!J#TVq"rr#3!!%!#*3Krl"mI"YiI*dMH$KL!M%iJJ'pJ+)!4$J!!!#3!!%!1#J\rG!!"!JJ!mJ!8!!#`!!!&!JJ!B1+!"5$M!!!&)!!MPJ%%!&%J!!"`X!!!%3))!&$L\rJ!8Ji`!!"5!!)bB""!"3S(3!!3))!$$KJ!!a)!!"-1m!!!(rImhK)!!!SJ(d##(`\r$q#k3!!%!1(q$ihJiJ3!i5rraJ@!!!!!lhJ!"1rm!"+JG!J4m(J!!3B$re)"p!JK\r,rr4P1'!!!)!"!&Ji)3"3I!J$TVZ"rr"1J!!J!*!')%'!"!#3"GJ!%LjNDA0`Eh0\rP3h*PC%*eCQCPFR`)!UDr`IriN!!"!!L8)Ir!N!"K!&L3!)%!A*!!S3"JN!$"!'5\r$`3"F+"i!!%'#!"#$i3"N+"m!!%##!!`iB!!!5!!!k)"K!&L!!3"JI!-!!%'#!!`\riB!!!5!!!d#`$!!&!JJ"X1(i!!6LI!!&)!!LjJ%%!&#`$!!"!JJ"-1(i%icLI"10\r)!!LKJ%%!&#`$!!"!JJ!d1(i6L6LI%iP)!!L*J%%!&#`$!!"!JJ!FJ(iBI)!I'(a\rm!`!!3))!$$KJ!!&)!!"S1'!!!%J!!'!X!`!#3))!9)"q!!#!R`!!5!!)5B""!"3\rX!`!!3))!0)"q!!5!R`!%5!!)-B""!"3X!`!!3))!()"q!"L!(`!BI!-!!%##!!`\riB!!"5!!!%$KJ!!")!!!)1'!!!)!"!%Ji)3"!I!J$TV["rrK1J!!J!*!')%'!!J#\r3"!%i!!JZBh*PC'0YF!!!I!J#TVq"rr#3!!%!#*3Krl"mI4YiI*`MH#JF!!"!JJ!\r-1'!!"NJ!!C`iB!)S5rrb0C!!I!!!J"`!!#J!!!"!JJ!-1'!!"NJ!!Aam(`0iIq2\rlH(qNkhK)!!F"J%%!&)!G!3#3!"m"!$Kr!33iR3%%5!!'kB""!"5S(3)%X"m#"+J\rG!JD`(`)'1!!!!CJI!K#S(`)'9!-31N[rmFf3!(m##)!I!JJS!!!!3))!$$KJ!!C\r)!!%81m!!!(rFmhK)!!$`J(d##(b$i#k!C!!!,!-!!8##!)!iB!!)5rraMB#I!JK\rmC1%ZJ(m##(aMi#iS!`!!3))!$$KJ!!C)!!$-1!!!!C!!!`!!1'!GJ%[rm9f!R`)\r)I)6J,T!!C!!%J(m##(aMi#k!B`!%+!-!!%##!!`iB!!'5!!!P)#G!JKmK1!ZJ)3\r!"$LJ(B")!!C&J%%!&%J!!&JX!`!#3))!')#%!!5!(`))I+$L&%[rphe)!!!m,!-\r!Bd##!$3iB!!)5rr`lB#I!JKmC1%ZJ(m##(aMi#iS!`!!3))!$$KJ!!C)!!!X1!!\r!Bj!!!`!!1pi!!6ZF!!5S(`)%I"i!!%'!r``iB!!!N!"r!L53!(m#))!"!&Ji)3"\r3I!J$TVZ"rr"1J!!J!*!')%'!"!#3"!(8!!BZC(9`6N0m#!+Q[m(rq*!!!3!)P#(\rr`(aq'hKrhr0i+"m!!%'#!#a)!!!8J(m!!)"M!!K,rr#j1rm!")!I!!!S!!!!3),\rrk(r$mhK,rr#KJ!%!5$JK!%"m#!1QZm(rq%k!!#!!N!BJ3B!#!*!&A!!4,Q4TFh"\r[Ff9%BA4K3A*bBAN!I!J#TT2Krrb3!!%!#*3Krm"mIaYi1')#2$L#!Ef!SJ"%+"m\r!!%##!&#!"3!!,!!!!8##!"JiS!(#1-!!!8J!"$@!33!85!!!-#`!!!4!JJ!S1+!\r"`MM!!!&)!!3CJ%%!&%J!!"4rirYiIq6lH%[ri4eJ!!!!J"m!!#J!!!"!J[rS1'!\r!!)!"!%Ji)3"!I!J$TS2Krra1J!!J!*!')%'!!3#3"CJ!#bjQFQ9P6N0-DA0d!!!\r!I!J#TT2Krrb3!!%!#*3Krl"mIaYi1')"ecL#!Ef!SJ"%+"m!!%##!$b!"3!!,!!\r!!8##!"JiS!(51-!!!8J!!hf!33!85!!!(#`!!!4!JJ!81+!"dMM!!!&)!!0KJ%%\r!&$KK!$K)!!-0J%%!&(aJ"c9"JJ!-1'!!!%J!!%#!(`)8,!!!C%'#!#JiB3!i1*m\r#'$LK!%")!!,eJ%%!&(aJ"c9"JJ!81'!!!%J!!"!i!!!!Q!%!3)KK!%#!!3"B1#%\r!8(`)!kD$iIrm6S!!)!#3"L""J!%!N!A-!!XZDA0-Ef0V6h9bF`!!!(`)!UDr`Ir\riN!!"!!L8)Ir!I(iEH$KL!NmiJJ'pJ+)!4#JH!!"!JJ!mJ!8!!#`!!!&!JJ!B1+!\r"jcM!!!&)!!+4J%%!&%J!!"`X!!!%3))!&$LJ!HFi`!!"5!!#GB""!"5!(J!!,!!\r!!N##!'L$rJ!%J(m!!%[rlNf!I`!%5rrZ4B"r!"!S!`!!3B)!#%[rlM@!I`!i+!-\r!!%'#!!K,rqiPJ(m!4#J$!!""JJ!)5rrZ&B"r!%JS!`!!3B)!#%[rr5'!I`!X+!-\r!!%'#!!K,rrd4J(i!"%[rlHdiB!!!J!%!5$JK!%"m#!1QZm(rq%k!!#!!N!BJ3B!\r#!*!&m!!A,Q0MAfCbC@9IBh*PC&pTER4PFQjKE(-!!!"m#!+QN!!"!!L8)Ir!5!!\r!U@!!!!"mB!Fe3B)!#%J!!"!i!!!!J))!)*!!"!!!J!%!5$JK!%"m#!1Q6S!!)!#\r3"L""J!#3"M`!%bj*EQPdD@&XDATP3f&MD'9-D@)!!!"m#!+QN!!"!!L8)Ir!5!!\r!R@!!!!#!!3")1#%!3(`)!kC1J!!J!*!')%'!!*!'*!!5,P4PFQeTEQ&dC80KBfK\rP6'PLI%-6H%k!!#"m#!+QN!!"!!L8)Ir!5rrrlAaT'hL!BJ"JJ))!A$LL!!!i`J*\rGJ1)!8)%#!%a)!!"CJ%%!&)##!+53!'3!!%[rf)eJ!!!!1'!!!)!"!%Ji)3"!I!J\r$TNk!!#"m#!+QN!!"!!L8)Ir!J')!T)"M!!")!!!aJ%%!&)!"!%Ji)3"!I!J$TNk\r!!##"JJ"!N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!2*!!33!8J!`!!)"-!!4m#31\rQ6S!%))'#!"L3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!8N!""!"5!$!!!J%`!"(`\r*!kC1J!3JJB)!$*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!%L3!%%!&)!-!!#!6!!\r%I!N$TNk!"##"JJ!3N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!1*!!33!8J!`!!)"\r-!!4m#31Q6S!%))'#!!53!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!FN!""!"5!$!!\r!J%`!"(`*!kC1J!3JJB)!-*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!!L3!%%!&)!\r-!!#!6!!%I!N$TNk!"##"JJ!SN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!!*!!33!\r8J!`!!)"-!!4m#31Q6S!%))'#!#b3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!NN!"\r"!"5!$!!!J%`!"(`*!kC1J!3JJB)!0*!!33!8J!`!!)"-!!4m#31Q6S!%)!!!*cL\r!!!"B!*!'*j!!J!!!,!#3#8iL+@`#)LP8!L)#ABB#!5PX)J'GJJ)4!Bd"K!&h!Nm\r#2!)a!KS##`(l!Hi"iJ(A!FS"[3'[!+`"D!3L%ML'!K84R"%N%-J3D!md$2J,r!Y\r-#U3*i!Lm"rJ(*!E-"8`%9!-S!B`"#!!F*ZJL*S3%,Ne*9#"*,e-J6@&M4'9f!5#\r"CJ`K+'jKE@8J)6dJ-#N)3d0KBfKP,Q-2)5JUD'&ZC'aP)#%p)$!T%5%SF(*TEQ0\rTF'&X)#%p)$!T$5%SFf&QC9!J)6dJ-#N-3d0KBfKP9A4TE#jM$#%SFfPkC5!q)$"\r-+3SK+'jM)#%p)$!T#b%SEf*U)#%p)$!T$#%SC'9cG#!K25!`+3pbCA4NCA0d)$d\rp)%j96%`1+LTNCA0d)$dp)%j96%`@+#SUC'9cG#NY2Q4KG'%J26dJ6P9-6!TZBb!\rp25"198a-%L%SBfjdFQa#E'pMDb!K25!`+3dK+'0bC@4c)#%p)$!TFGB!!!%!!!!\r"B!!!!'!!!!!b!,V"!*!%2S!!CL!!ZZ%!N!3qK3#X)!$p1`#3"B!!E!!!Z[d!N!@\r!!(J!!,X2!*!%2S$rr`!!Zam!N!3qMIrr!!#l3`#3"$k-rrm!!,Yr!*!%2SArr`!\r!qmF!N!3qJ2rr!!#lZ`#3"$k0rrm!!,[[!*!%2Scrr`!![#-!N!3qKIrr!!$lN`#\r3"$k!!))J!,aA!*!%2S!!M3!![&m!N!8"rrm!!2Xr!*!%2SArr`!!r*d!N!Err`!\r!r@N$VL"F!d0@8`T8BA0V)%jKE@9c$%0A3eC6)&"KEQ9XF`i!!!"F!*!,!3#3%`&\r`Gh"M!*!6!3#3%6`168P8Ak9$3f&MD'9-D@)!N!8"!!!!!@!!!!"J!!!!-J9@1G!\rd*J!!!"`!-J!!BfCbC`!!!!S!!2rr!*!%"9Bi[&YF:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:%d0$B@0SC8aTBLj38%-ZC'9LG@F!FfKXBMq3"!#3"$LS!!!"PV5C5Qpj)A"PCQC\r`Gh"M!!!!!E*6cTi!N!d$!!)!N!6rN!3!N!Ba`!!!-F!!!$(!!!!&J!!%"!$rN!3\r!N!B#D3!!!Q8!!!&S!!!h3!)%"!$rN!3!N!i%mJ!!!)!%"!3!N!ArN!3!N!F"!!!\r"D!!!!!%!!!&J!!!!"3!!!"8!!!!"!!!"%!!!!5!!!!1-!!!!"!!!!"8!N!m+!*!\r,$3#3#`%!!!!+!*!()`!!!!%!!!!"!!!!!J!!!!X!N!Fl!*!,!J!!!!d!N!G8!*!\r,"J!!!!m!N!3#!!"R!J!!F!)!!(S#!!#(!J!!NJ)!!*d#!!#Q!J!!X3)!!,d#!!$\r2!3!!eJ%!!1)#!!$[!J!!r3)!!4-#!!%R!J!",J)!!68#!!%p!J!"4!)!!8X!!3#\r3"3J!N!4+&%!"3J&!!8)33J#!!dB@5@jdCA*QB@0P6'PL!%e*9&qP3d0KBfKP4fa\r[BQ&XFdaTBJ"0594IT84PBR9RCfPZCdaTBLjNC@*eC`"0594IT8e*9&*eER4TE@9\r-D@)ZC'9LG@F!68P8Ak90594$6'PL,Q4PBR9R!&0jFd*bC@&V!%jPGe"dFP0jF`"\r9EQK[E'40C@e[FRN!5'pXC%ePE@pbH3"%DA0`Eh0P8(4b!%4PBR9R8h4b!%GPG&"\rdFP0THQ8!8f&YC9"bEf0PFh-!4f9d3h9bFQ9ZG&"bEf0PFh-!6Q9h8(4b!'G$ER4\rbE%*XEf0V!'G%C@*eCe0TCfjKE!""E'9bG&0TCfjKE%&d!&pIG@jbC@GTFh4PFPp\rQFQ&RE@9ZG!"IAh*PCfPcG'9bAfCbB@GYC@jd!(0dFQ0YF!"YC@eMF(N!Fh4bEQ0\r`H3"cG(*MF(N!Fh4bE'9Z!'ePEA0PG!"MBepRCA4IBh*PC&pfCA*cD@pZBf0IC'9\rcG(*[H@0MAfGPG&pMD'&ZCf9IG'PYC@0MAfCbC@9I6N0ID@jQEf0MAf0bC@&dC@0\rMAf0XEh0PBf0ICf9dAfjKE@9MBepQFQ9PAf0bC@4cBf0IFQ9YEhCPAf0bC@4MBep\rQFQ9PAh"bD@jMDA"KE'0MAfp`C@jMBepcD(9dC'phEQ0MAh0PG&p`FQPZBfP`B@a\rMBepcCA&ICQ9dBfKI6N0cBf0ICf9dAdj$AfPZCQpMBepTEQPdD@&XDATPBf0ICf9\rdAh"bD@jMDA"KE'0MAh0PF9pQCA4MD&pMFQ9NFf0MAh0dEh*PBf0ICR*PC9pZB@e\rPBf0IE'pMDepbCA&eCA0d!*!("!!!!!`!!3!)!!3!!!!'!!J!"J!)!!J!!!!+!!3\r!#J!!!!X!%!!,!!`!$`!!!")!"!!5!!!!%`!)!"-!%qq*!!UDh`!569F!$c0A!!P\r-)3!)*Xm!#cEk!!h1V`!1jP-!%IJ'!!F66!!,2Ad!%)`+!"##X3!1ZFB!$FMP!"$\r-#`!5#&i!##F0!!aR@J!2'"i#!!&5!!!"!!!"!J!"C3!!!6!!!3)!!@m!!!%S!!%\r#!!'"!!!!`!!"!J!"N!!!!!&)!!%#!!'C!!!"1!!"!J!"S3!!!2J!!3)!!D`!!!$\r)!!%#!!'j!!!"'!!"!J!"a`!!!0J!!3)!!GJ!!!&!!!%#!!(I!!!"8!!"!J!"kJ!\r!!4!!!3)!!IS!!!$`!!%#!!)+!!!!i!!"!J!#'!!!!9J!!3)!!L8!!!%)!!%#!!)\re!!!!k!!"!J!#4`!!!5!!!3)!!Nm!!!$3!!%#!!*E!!!!Z!!"!*!1I!J#TT!!!3!\r)P#(r`$JK!%#!!3!)I!J$TNk!!#"m#!+QNq(rr*2"rrL6SIrdNi(rm*!!!3!)P#(\rrX(ar'hL3!)%!E(bm+hKmh60iJm)!+)"q!!!S!`!!3))!B$KJ!"")!"PeB!!!!*!\r!I`!!J*m!!#J%!!"!JJ!-1'!!"NJ!!(`iS!!!J0m!!*!!TJ!%J2m!!*!!T`!!13!\r!!)%r!!#4#3!)18!!!)&r!!#45`!-JCm!!*'H!!")!!!-J(i!!*!!I`!!J)%!E#`\r%!!&!J3!-1'!!#8J!!#JS(!!!3B)!$$LJ!!'3!,`!!#JG!!""JJ!-J-)!X*!!h3!\r!1'!!!)!"!&Ji)3"3I!J$TS2Krrb$`IriJk(rp)1"rr"1J!!J!*!')%'!"!#3"IJ\r!$LjMBepTEQPdD@&XDATPI!J#TT2Krrb3!!%!#*3Krm"mIaYi+"m!!%'#!#b!I`!\r!+!-!!%'#!##!I`!!5!!U)@!!!!#!I`!!5!!@T@!!!!")!!!-1'!!#NJ!!"!iJ!!\r!N!#I!!!iB!!!J!%!5$JK!%"m#!1QJq(rr%k!!#!!N!BJ3B!"!*!&E!!-,Q0MAh0\rSGA4NEhGZ!!"m#!+Q[f(rl*!!!3!)P#(rX(aq'hKmR#0iN!#K!("mh60iN!$K!(K\rp'd0i1q!!!#JH!!"!JJ!-1'!!#NJ!!8JS'`!!3))!$$KJ!!a)!!%i1'!#+%J!&m&\rJ!!!!I(mEH#JI!!"!JJ!-1'!!"NJ!!4JS(!!!3B)!'(q$ihK)!#pCJ%%!&#J$!2p\r"J!!-1'!!!8J!!24rirYiIi6MH%J!,UQ!33!8+"d!!%'#!"KrSqYi5!![*B""!"3\rS!`$r3B!!$$KJ!!a)!!$!1(m""(qNkhK)!#jeJ%%!&)"K!(L3!(m#$$L!!!#`R`)\r%J+%!F*!![`%!1-!!!TMI!K!ii!"NN!$r!K4rirYi5!!AM@!!!!#3!(m##)%I!JJ\rS#!!!3))!$$KJ!!C)!!"NJ6i!##`*!!"!JJ!F18!!!*&I!L54A`)JNri!!*2q!!4\r)!!!JJAi!"*2V!L#"RJ!%NCm#*$KJ!!#3!(m#)*2q!!5!RJ!)1)3!!C!!RJ!)J,i\r!$$LP!!'3!,i!$*2l!!!iB!!!J!%!@$JK!&"m#!1QZf(rl%k!!#!!N!BJ3B!&!*!\r%!C3!#LjMBepMFQ9KG'9m#!+Q[Z(rh*!!!3!)P#(rS(ah'hKmQL0iI,NVH(ci1hJ\rlSJ'-1m)"Ii2L!#`lJ!!!1f!!!#JA!!"!JJ!-1'!!#NJ!!3`S'!!!3))!$$KJ!!a\r)!!$m+"S!!%##!)5!I`!!,!-!!8##!#"r`r0iIk6VH$LJ!+Xi`!!!5!!XFB""!"4\r)!!"FJ*m!!#`%!!*!JJ!8Im2cH%J!,'f!33!85!!!3)#r!!!X"3!$3))!%%J!,'f\r!33!85!!!+)$I!!!X"J!%3))!((r$mhKrT1Yi1+!!UcM!!!&)!#`9J%%!&)1A!!"\r)!!!dId26H(q%ihK)!#dGJ%%!&#`$!!"!JJ!BJ2`"!(`C1!"!JJ!-1f!!!8J!!!L\r$R!)J+"`!!%'#!""rD!Gd,!J!!%'#rm"rD3Gd,!N!!%'#!"#6Q!!!1'!!!%J!!"!\rj3!!!N9J!!$KJ!!U!!3"S1#%!B(`)!kDkiIrF6S!!)!#3"L""J!N!N!3"B!!),Q0\rMAfp`C@i!!(`)!UDr3IrSN!!"!!L8)Iq`I(SEH(bF)hJl`J'91k)"M)2L!#`lB!!\r!+"S!!%##!!`iB!!+5!!!k#JF!!"!JJ!-1'!!$%J!!0L!I!!!+!-!!%##!)5!R`!\r!,!3!!8##!#"r`r0iIk6VH$LJ!-di`!!!5!!UrB""!"4)!!"FJ,m!!#`&!!*!JJ!\r8Im2cH%J!+[Q!33!85!!!3)$I!!!X"J!$3))!%%J!+[Q!33!85!!!+)$r!!!X"`!\r%3))!((r$mhKrT1Yi1+!!c6M!!!&)!#UKJ%%!&)%F!!#*#!)3I3J(G#`)!!&"JJ!\r-1'!!$NJ!!$#$I!!!Id26H(pNfhK)!"r0B!!!!(pMfhK)!")GB!!!!$NJ!!#42!!\r!1'!!!)!"!&Ji)3"3I!J$TVY"rqK1J!!J!*!')%'!"J#3"!%`!!NZBf0IBfa[Ff8\r!I!J#TVmKrq53!!%!#*3Krk"mHKYiI*XMH$[#!C8lSJ'-Jq)!,$Z!!!!S'J!!3))\r!$$KJ!!T)!!'!+"X!!%##!!`iB!!-5!!"F)"l!!!S!`!!3))!K)#I!!!X"!!"3))\r!)(r$mhKrT1Yi1+!!kcM!!!")!#QaJ%%!&%J!!&b![`!!,!8!!N##!"4r`r0i5!!\rTVB""!"4)!!"!J0m!!#`'!!0!JJ!35!!TVB""!"4)!!!SJ2m!!#`(!!4!JJ!FIm2\rcH(qNkhJiS!$V1-!!!8J!+9@!33!8JjX!!)%F!K3X#!"N3B)!*(q$ihK)!#9jB!!\r!!(aM"h3X!`!!3))!$$KJ!!K)!!#dJ6`#*#J*!!"!JJ!NJ9`#)*&D!!#"I!)J+!X\r!!%'#!"!jJ!!!J(`#)*'$!L5!R!)J+!3!!%##!#5![!)NN!#k!!5!h!)N+!B!!%'\r#!"!ii!!!J4`#**!!k!)JJ6`#*#J*!!""JJ!SJ9`#)#J+!!""JJ!FJA`#*)'F!L#\r4E!)NJ(`#))#F!L53!'3#)$LJ!!'B[!)3Id26H(pNfhK,rrdCI(NEH)$D!!`iaJ!\r"N!$D!!ar)mYiJ!%!D$JK!'"m#!1QZb(rj%k!!#!!N!BJ3B!(!*!%!FJ!#bjMBep\rNCA0dFQpj!!!!+!-!!%##!!`iB!!+5!!!)#J%!!""JJ!8J+-!$*!!T!!!1'!!!%J\r!!!JiB!!-6S!!)!#3"L"!!*!(-!!6,Q0MAfGPG&pMD'&ZCf9IG'PYC3!!!(`)!UD\r6iIrmNm(rq*1Krr53!!%!#*3Krl"mI4YiI*mMH*!!S3"`N!$"!(3l`!!!+"d!!%#\r#!!`iB!!+5!!!L#JI!!"!JJ!-1'!!#NJ!!(L!I`)8,!-!C%'#!$#!R`)8,!3!CN#\r#!"arirYi5!!MZ@!!!!"mB`Gd,!-!!%##!!`iB!!)5!!!3(rMqhL!J3"`J+%!G%J\r!'HeJ!!!!I(iEH#`H!!"!JJ!3J,d!#$LP!!'3!,d!#)$G!!`iaJ!"N!$G!!ar`r0\riJ!%!@$JK!&"m#!1QJq(rr)2"rrL$SIrd6S!!)!#3"L""J!-!N!AF!!NZBf0IFh4\r[FQ8!I!J#TT2Krrb6`IriN!!"!!L8)Iq`I(iEH(bI)hL3!+%!F*!!`3"d1'!!!*!\r!B3!i+"i!!%'#!!`S(`!!3))!$$KJ!!T)!!"JJ*m#&#`%!'4"JJ!`J,m#&#`&!'C\r!JJ!FIq2lH%J!)XPJ!!!!I'-(G#`$!!"!JJ!-1'!!#%J!!#KrirYiJ)%!F)#K!(4\r)!"TaB!!!!)$H!!`iaJ!"N!$H!!`iB!!!J!%!@$JK!&"m#!1QJq(rr)2"rrK1J!!\rJ!*!')%'!!J#3"EJ!$bjMBepbC@e[GQ9IBh*PC!!!!(`)!UDr3IrSN!!"!!L8)Iq\r`I(SEH(bE)hL3!+%!F(cF-hJl`J'P1k)"M)2L!#`S'J!!3B)!$#JE!!"!JJ!-1'!\r!#NJ!!3!S(!!!3))!K)"r!!!X!`!"3))!)(r$mhKrT1Yi1+!"DcM!!!")!#@PJ%%\r!&%J!!&b!R`!!,!3!!N##!"4r`r0i5!!PSB""!"4)!!"!J,m!!#`&!!0!JJ!35!!\rPSB""!"4)!!!SJ0m!!#`'!!4!JJ!FIm2cH(qNkhJiS!&V1-!!!8J!*8Q!33!8J2X\r#&#`(!'4"JJ!`J4X#&#`)!'C!JJ!FIf2EH%J!)@9J!!!!I'-(G#`$!!"!JJ!-1'!\r!#%J!!%#"1`%!J8%!F(`*8!""JJ!-1'!!#NJ!!#JiH`%%Ii6MH$LJ!2p)!#AYJ%%\r!&)&k!!`jD`!"NAS!$$KJ!!#!!3"B1#%!8(`)!kDl3IrS6S!!)!#3"L""J!B!N!3\r"9!!4,Q0MAh0PG&p`FQPZBfP`B@`!I!J#TT2Krrb6`IriN!!"!!L8)Ir!I*iMH(b\rr+hJS(J!!3))!$$KJ!!T)!!"`J(i#&#`$!'C!JJ!NIm2cH%J!)*PJ!!!!I'-(G#`\r$!!"!JJ!-1'!!#%J!!%3S(`!!3B)!1$KJ!2p)!!YYB!!!!*!!I`!!J*m!!#J%!!"\r!JJ!-1'!!"NJ!!"L!I`!!1*i""%J!*,'!33!81'!!!)!"!%Ji)3"!I!J$TS2Krrb\r$`Iri6S!!)!#3"L""J!)!N!@`!"%ZBf0ICf9dAh"bD@jMDA"KE!"m#!+QNq(rr*2\r"rrL3!!%!#*3Krm"mRb0iI,iVH#JI!!"!JJ!-1'!!#NJ!!%b!I`)8,!-!CN##!#4\rrirYi5!!Ia@!!!!"mB`Gd,!-!!%##!!`iB!!)5!!!)#JH!!"!JJ!-1'!!"NJ!!"#\r!R`%!N!#H!!!iB!!!J!%!5$JK!%"m#!1QJq(rr)2"rrK1J!!J!*!')%'!!J#3"B`\r!&#jMBepRCA4IBh*PC&pfCA*cD@pZ!!"m#!+QNq(rr*2"rrL3!!%!#*3Krm"mRb0\riI,iVH#JI!!"!JJ!-1'!!#NJ!!&b!I`)8,!-!CN##!#4rirYi5!!I%@!!!!"mB`G\rd,!-!!%##!!`iB!!)5!!!-#JH!!""JJ!N1'!!rdJ!#H9J!!!!N!"q!!#!IJ!!Iq6\rlH%J!)cf!33!81'!!!)!"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)!#3"L""J!)!N!@\rF!!`ZBf0ICf9dAfjKE@8!!(`)!UD6iIrmNm(rq*1Krr53!!%!#*3Krl"mI4YiI*i\rMH(br+hJS(J!!3B)!&#JI!!""JJ!-+"d!!%##!!`iB!!+5!!!S)"r!!!S!`!!3))\r!0$KJ!!K)!!NjB!!!!*!!I`!!J*m!!#J%!!"!JJ!-1'!!"NJ!!(#![3!!J0m!!*!\r!TJ!!J2m!!)$R!!!S"`!!3))!+)"r!!")!!PeB!!!!$N!!!#4(`!!15!!!*%q!!!\riB!!$5!!!-)&I!!#!DJ!!Im6cH%J!'E&J!!!!JAm!!)&V!!#"D`)JJCm!!*&X!!!\riB!!!J!%!@$JK!&"m#!1QJq(rr)2"rrL$SIrd6S!!)!#3"L""J!-!N!Am!"%ZBf0\rIFf9aAfCPG'0SAdj$F`"m#!+QNq(rr*2"rrL6SIrdNi(rm*!!!3!)P#(rX*!!B3"\rSI*iMH(bp+hKmhc0i+"i!!%'#!"JS(`!!3B)!%)"K!'JS!`!!3))!$$KJ!!T)!!)\r%+"d!!%##!!`iB!!'5!!"p)#H!K3X"!"Q3))!*(r$mhK)!"d"B!!!!(aM"h3X!`!\r!3))!$$KJ!!K)!!()J,m!!#J&!!"!JJ")1'!!#%J!"p&J!!!!N!"r!!#!h`!!+!B\r!!%##!!`iB!!'5!!"Q$MJ!!#"(`!!N!$S!!4)!!!8J6m!!)&*!!3j5J!"N8N!")&\rr!!#"D`!%UCi#"(`,B!"!J!!NJ(i##)#I!!#!K!!%9)331RaM)#k!B`!!,!-!Bd'\r#rm#![`!!J+8!"+MH!J4m"6!!3B!!+)"r!!")!!I"B!!!!$MJ!!#3!2d!!$N!!!#\r4(`!!1'!!!dJ!!3b"2J))J9m!!)&+!!495K!kI5P3,S1*!!!X(!!"3))!K$KJ!!K\r)!!F"B!!!!*!!I3!!JAd!!#J,!!"!JJ!-1'!!"NJ!!-JiB"f!5!!'h@!!!!#"R3!\r!N!"X!!5!I3!!J'-!"#J$!!"!JJ!-1'!!"NJ!!*b!R3!!J'3!")#q!JL!h`!!J-B\r!"&6'%$TmT6!ZJ)8!"$LJ(B")!#!YJ%%!&%J!!&JX(!!#3))!3)$q!JL"(`!!J3J\r!"&8)%$Tmjd!ZJ1F!"*!!i3!m15!!!T%K!$L!B3!iJ)%!2(qPkhK)!!mKB!!!!%J\r!!"3j3!!!N9d!!$KJ!"")!!!BJAm!!)',!!3jM!!"NBX!"$KJ!!#!!3"B1#%!8(`\r)!kD$iIrmJm(rq)1Krr5$JIr`6S!!)!#3"L""J!3!N!3#F!!6,Q0MAh0PF9pQCA4\rMD&pMFQ9NF`!!!(`)!UD6iIrmNm(rq*1Krr56JIr`N!!"!!L8)Iq`I(`EH(bG)hJ\rli!!!1m!!!#JF!!"!JJ!-1'!!#NJ!!1JS(3!!3))!$$KJ!!C)!!$BJ*`!#$L%!!&\r8Ja!k5!!HdB""!"53!(d!!)#p!!!S"3!!3))!$$KJ!!C)!!#XJp`!!%J!!)JiB!)\r%5!!HTB""!"5!h3!!9qF31RaQ15k"(3!!9qN31Rd)5#iS#!!!3))!$$KJ!!C)!!"\r`J9d!!&IV%$TmDPJZIm6cH%J!(Rf!33!8JCd!!&IN%$TpM#!Z1'`!rcLH!34)!"j\rKJ%%!&)#q!3#!h3!!9qF31Rc'1#k3!+B#!)2H!L!lr`!"+"i!!%##rhJj!!!!J6d\r!!&IU%$Tp#9%Z1'!!!)!"!&Ji)3"3I!J$TS2Krrb$`IriJk(rp)1"rr"1J!!J!*!\r')%'!"!#3"!&!!!mZBf0ICf9dAdj$AfPZCQm!!!"m#!+QNq(rr*!!!3!)P#(r`(b\rI)hJS(`!!3))!$$KJ!!C)!!!8Iq2lH%J!"-9J!!!!1'!!!)!"!%Ji)3"!I!J$TS2\rKrra1J!!J!*!')%'!!3#3"8J!%LjMBepQFQ9PAh"bD@jMDA"KE(`)!UD6iIrmN!!\r"!!L8)Ir!I*mMH#JI!!"!JJ!-1'!!"NJ!!"4rirYi5!!%@@!!!!!iB!!!J!%!5$J\rK!%"m#!1QJq(rr%k!!#!!N!BJ3B!"!*!&5!!0,Q0MAfCbC@9IEQ&YC3"m#!+QNq(\rrr*!!!3!)P#(r`(bI)hJS(`!!3))!$$KJ!!T)!!!SJ(m!!%J!'EeJ!!!!J(m!!%J\r!!q9J!!!!1'!!!*!!I`!!1'!!!)!"!%Ji)3"!I!J$TS2Krra1J!!J!*!')%'!!3#\r3"9`!$LjMBepQFQ9PAf0bC@4cI!J#TT2Krrb6`IriN!!"!!L8)Ir!I*iMH#JH!!"\r!JJ!-1'!!#NJ!!&3li!!!5!!!()#H!!"Aj4!kI'3S,NJ!'j'!33!81rm!!B$H!!"\rAja!kI-Bi,LJ'!!"!J[rBJ(i!!%J!'ff!33!813!!!*%H!!!l`!!!1'!!!)!"!%J\ri)3"!I!J$TS2Krrb$`Iri6S!!)!#3"L""J!)!N!@3!!!3,Q0MAfCbC@9I6N0ID@j\rQE`!!I!J#TT2Krrb6`IriN!!"!!L8)Iq`I*mMH*!!S3"`+"m!!%##!!`iB!!-5!!\r"1$KK!$K)!"UjJ%%!&(aq'hL!I`)8,!-!C%'#!"`iB3!i1*m#'$LK!%")!"UYJ%%\r!&(aq'hL!J3"`,!3!!N'#!#a!J!!3,!3!!8#!!"4)!!$F,!3!"%#!!04)!!"-1+!\r!C*!![`)85!!!c)$I!K3X"J"N3))!)$MJ!'@3!2m#&)%"!$L")3!mN4m#'*%r!Ka\r)!!#NJ9m#&#`+!'C!JJ#B1'!!#%J!!*5"I`)8,!X!C%##!#!jJ!"QNCm#&)"K!$L\r!J3!mN!"r!KL3!*m#(%J!!'L![`)8,!8!CN##!"L)`3"!+!B!!%##!!`iB!!)5!!\r!6)$r!K3X"`"P3))!2)N"!%!S#!!!3B)!)$NJ!'D42`)8J8%!1)&K!$b4A`)BNAm\r#(%J!!"3iB!!)5!!!%$KJ!!a)!!!)1'!!!)!"!&Ji)3"3I!J$TS2Krrb$`Iri6S!\r!)!#3"L""J!)!N!3"H!!3,Q0MAfa[BfYIFQ9aG@9cG!!!I!J#TT2Krrb3!!%!#*3\rKrm#3!'%!@$[J!!#!B3"B5!!BI@!!!!"mIaYiIq-(0#`$!!""JJ!-Iq2lH%J!!"3\riJ!!!J+)!+*!!K3!!Iq2lH)!"!%Ji)3"!I!J$TS2Krra1J!!J!*!')%'!!3#3"@!\r!%bj*EQPdD@&XDATP3f&MD'9-D@)!!!"m#!+QN!!"!!L8)Ir!5!!BA@!!!!#!!3"\r)1#%!3(`)!kC1J!!J!*!')%'!!*!'*!!5,P4PFQeTEQ&dC80KBfKP6'PLI!J#TT2\rKrrb6`IriN!!"!!L8)Ir!I(iEH(r$mhK)!"NjJ%%!&(ar'hJS(`!!3B)!&(rMqhK\rra20i5!!C6B""!"4rirYiJ!%!5$JK!%"m#!1QJq(rr)2"rrK1J!!J!*!')%'!!J#\r3"9`!#bj1CAG6B@CP8(4b!!!!I!J#TVp"rqL3!!%!#*3Krl"mHaYi1i)"dM[#!F8\rlSJ'hJq)!,(pMfhK)!"KTJ%%!&(ak'hJS'`!!3))!K)"r!!!X!`!"3))!)(qMkhK\rra20i1+!!*cM!!!")!"IaJ%%!&%J!!&b!R`!!,!3!!N##!"4rSqYi5!!AlB""!"4\r)!!"!J,m!!#`&!!0!JJ!35!!AlB""!"4)!!!SJ0m!!#`'!!4!JJ!FIk2VH(r%mhJ\riS!!R1-!!!8J!&j@!33!8,"S!!%'"!)5!r`!!,!F!!8##!#"rJq0iIm6cH$LJ!#J\ri`!!!5!!ADB""!"4)!!"FJ4m!!#`)!!*!JJ!8Ii2MH%J!&f@!33!85!!!3)%r!!!\rX#3!$3))!%%J!&f@!33!85!!!+)&I!!!X#J!%3))!((q$ihKra20i1+!!+$M!!!&\r)!"F0J%%!&(pMfhJiJ!!!IdA6H%J!&eQ!33!8If2EH$L!!!"r4G0i5!!A4B""!"4\rrBpYiId66H%J!&df!33!8If2EH%J!&V'!33!8J!%!@$JK!&"m#!1QZd(rk%k!!#!\r!N!BJ3B!'!*!%!C`!$bj%DA0`Eh0P8f&QC9"dFJ!!!(`)!UD6iIrmNm(rq*!!!3!\r)P#(r`(aq'hKr`r0i5!!AAB""!"4mIaYi+"m!!%'#!"4rirYiIm6cH%J!&a'!33!\r8Iq2lH)!"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)!#3"L""J!)!N!9F!!iZ6Q9h8f&\rQC9"dFP0jFh`)!UD6iIrmNm(rq*1Krr56JIr`N!!"!!L8)Iq`I(`EH$[#!GmlSJ(\r&Jq)!,#JF!!"!JJ#%J(m!!#`$!!&!JJ!JIm2cH(qNkhJiS!"31-!!!%J!&Ef!33!\r85!!!A)#I!!!X"!!#3))!&(r$mhK)!"@jJ%%!&%J!!%#![`!!,!8!!d##!"")!"@\rjJ%%!&%J!!#L!h`!!,!B!"%##!"ar`r0iIk6VH$LJ!&!i`!!"5!!9BB""!"3ii!!\r!X2`#"$N!!!Ua(!)'1'!!+%[rrVf3!(`##)"m!JL!!3"B1#%!8(`)!kD$iIrmJm(\rrq)1Krr5$JIr`6S!!)!#3"L""J!3!N!Ad!!iZEQ9h3h*PC%*eCQCPFR`)!UD6iIr\rmNm(rq*1Krr56JIr`N!!"!!L8)Iq`I(`EH*!!J3"XN!#K!(#3!-%!G$[#!HSlSJ(\r&Jq)!,#JF!!"!JJ#%J(m!!#`$!!&!JJ!JIm2cH(qNkhJiS!"H1-!!!%J!&*f!33!\r85!!!A)#I!!!X"!!#3))!&(r$mhK)!"5CJ%%!&%J!!%#![`!!,!8!!d##!"")!"5\rCJ%%!&%J!!#L!h`!!,!B!"%##!"ar`r0iIk6VH$LJ!&ii`!!"5!!83B""!"5!i3"\rXN!$m!!#"!3"`N4`!")%K!(3S#3!!3))!&$P!!!#4A!!)1'!!!%J!!$b!B3"`5rr\rpJC!!I!!)JA`!##J,!!"!JJ!-1'!!"NJ!!"b!I!!)J)%!G)#K!(")!"5jJ%%!&$K\rJ!!#!!3"B1#%!8(`)!kD$iIrmJm(rq)1Krr5$JIr`6S!!)!#3"L""J!3!N!3"4!!\r-,Q0[F(P%BA4K6f*U!!"m#!+Q[U(re*!!!3!)P#(rN!"mGaYiI*XMH$Z#!L)lSJ)\r61b)#!cY#!IBl`J(&Jq)!,$UJ!!!l!!!!1X!!!#JE!!"!JJ#%J(m!!#`$!!&!JJ!\rJId26H(r%mhJiS!"d1-!!!%J!%c@!33!85!!!A)#I!!!X"!!#3))!&(p$dhK)!"-\raJ%%!&%J!!%#![`!!,!8!!d##!"")!"-aJ%%!&%J!!#L!h`!!,!B!"%##!"ar3p0\riIm6cH$LJ!(3i`!!"5!!5fB""!"4qq,Yi+"J!!%##!"3ii!!!N!$l!!")!!+B1V8\r!!B%B!!!l'!!%+!J!!%##rr!j03!"95-31N[rr"@3!(X!!(af'hJS&J!!3))!K)&\rI!!!X#J!"3))!)(mMbhKra20i1+!!I$M!!!")!"*YJ%%!&%J!!&b"I`!!,!X!!N#\r#!"4r)mYi5!!5DB""!"4)!!"!JCm!!#`-!!0!JJ!35!!5DB""!"4)!!!SJ(m!!#`\r$!!4!JJ!FIb2,H(r%mhJiS!"m1-!!!8J!%K'!33!8+"B!!%'#!H"qq,Yi5!!"[$K\rJ!!a,rrYYJ*X!!*!!C!!!J,X!!)#P!!!S"3!!3))!K)$I!!!X"J!"3))!)(qMkhK\rra20i1+!!JcM!!!")!"'pJ%%!&%J!!&b!r`!!,!F!!N##!"4rSqYi5!!4ZB""!"4\r)!!"!J4m!!#`)!!0!JJ!35!!4ZB""!"4)!!!SJ6m!!#`*!!4!JJ!FIk2VH(r%mhJ\riS!#$1-!!!8J!%@'!33!8J9X!!)&+!!!S#J!!3B)"+)&l!!#!D`!!J*F!!$LJ!!a\r)!")4J%%!&)'E!!#"M!!!J'`!"%[rqTf!Q`!!J)3!!*!!C!!)J,X!!)#P!!#!T3!\r)+!8!!%##!)5!h`!!,!B!!8##!#"rJq0iIm6cH$LJ!)Xi`!!!5!!3jB""!"4)!!"\rFJ2m!!#`(!!*!JJ!8Ii2MH%J!%1'!33!85!!!3)%I!!!X#!!$3))!%%J!%1'!33!\r85!!!+)%r!!!X#3!%3))!((q$ihKra20i1+!!LcM!!!&)!"#*J%%!&)&E!!#"5J!\r!J8S!##J+!!""JJ"-JAX!!)&V!!#!D`!)JCF!!)#-!!L!e`!!J+B!"%J!%5Q!33!\r81hX!"$XB!!5!q!!!+!F!!%##rN!j!!!!9UN31Rd@55k5f`!!J!%!H$JK!("m#!1\rQZU(re%k!!#!!N!BJ3B!,!*!%!i3!$LjMEh"j4'&dB8&bFQ&jI!J#TT2Krrb6`Ir\riNk(rp*!!!3!)P#(rX*!!B3"SN!#"!'am[5Yi1q!!!$[!!!#$`3"X+"d!!%##!!`\riB!!'5!!"3$KJ!!K,rrNPN!"p!!#!I3!!+!-!!%##!!`iB!!'5!!")$KJ!%a,rrN\r&I(mEH#JI!!"!JJ!-1'!!"NJ!!33iB!6L5rrikC!!I`!!J*m!!#J%!!"!JJ!-1'!\r!"NJ!!13iB!6L5rribC!!I`!%J,m!"#J&!!"!JJ!-1'!!"NJ!!-5!I`!!J*i!!$L\rJ"0p)!"!aJ%%!&)"r!!5!RJ!%1+!%hdJ!%"f!33!81(m!#)#H!!L![J!-J0i!%%[\rrqJ@!hJ!8N!$I!"5!rJ!BN!$r!"L"(J!FN4m!()%q!##42`!JJ9i!**&I!#5"IJ!\rSNAm!+)"q!#`iR`!X5rrl,6Kr!$#!RJ!`J,i!0)$H!$K,rrQe1(m!2)#H!$b![J"\r!J0i!4%[rqD%jJ!!!NCm!5$KJ!!+!R3!!N!"N!!#![3!!Nq8!"$KJ!!#!!3"B1#%\r!8(`)!kD$iIrmJm(rq)1Krr41J!!J!*!')%'!!`#3"!'B!!XZBfp`H9Be3h*PC!!\r!!(`)!UD6iIrmNm(rq*!!!3!)P#(r`*!!B3"BN!#"!&am[LYi1q!!!#JH!!"!JJ!\r-1'!!"NJ!!'`iB!!)5rrhHC!!IJ!!J(i!!#J$!!"!JJ!-1'!!"NJ!!%`iJ!!"J,i\r!!*!!K3!!1'!GJ%[rpdemIaYi+"m!!%##!!`iB!!'5!!!*(rMqhL!J3"F1+!GJ%J\r!$SQ!33!8J0i!!*2Q!!3iB!!!J!%!5$JK!%"m#!1QJq(rr)2"rrK1J!!J!*!')%'\r!!J#3"E3!#bjMEh"j9M4$FQ9N!!!!I!J#TT2Krrb6`IriN!!"!!L8)Iq`I(mEH*!\r!J3"XN!#K!(!l`!!!1'!!!*!!B3!i+"m!!%##!!`iB!!+5!!"!)#"!'`X"!!"3B)\r!')#K!'`X"3!#3B)!$$KJ!"")!!$JU0m#"$M'!!'`h`)%U2m#"(cR"c5T(`)'I!G\r!!%##!&bT2`)'95N)2,%r!JDTA`)'98-31N[rpNemIKYi+"i!!%##!!`iB!!'5!!\r!P(r$mhL!R`))UAm#"ReV$R"pD`'89@831NJ!$Af!33!8J(m##%[rp&'6h`))JB%\r!E#`-!!&!JJ!BJ'%!E)#"!(!iS3!i5rrq38J!!#b!B3"X,!-!!N##!"L!B3"XJ)%\r!F$LK!$K,rraT5!!!$$KJ!"")!!!JJ)%!1)#r!JLSh`)%1-Erre6'%$TmK6%Z1'!\r!!)!"!&Ji)3"3I!J$TS2Krrb$`Iri6S!!)!#3"L""J!)!N!3"8!!4,Q0bC@4#G@C\rQCA**ER0PFR3!I!J#TT2Krrb6`IriNk(rp*1"rr#3!!%!#*3Krl"mIKYiN!#"!'b\r3!+%!F$Z!!!!S(J!!3))!$$KJ!!T)!!$31k!!!%J!!,L!IJ))9k331RaM)#k!J`!\r%J'-!!)#K!'b!`3"`5!!#,@!!!!"mB`Gd,!-!!%'#!)5![J))9kB31Rq&-#jrJq0\ri5!!)m@!!!!"rJq0i5rrc'AqrkhK)!!!NJ2i##$NI!!&9#"!kI1G!,S%q!JKAkK!\rkI1P4,M[r!!'TIJ)%1@[rrh`I@!""J2r81B!!!)"q!JLSRJ)%1)6rre5%%$TpJb%\rZU,i#"$LPrrq`[J)%5!!!&$Zp!!'ShJ)%I"d`!%'!rd3iB!!!J!%!@$JK!&"m#!1\rQJq(rr)2"rrL$SIrdJi(rm%k!!#!!N!BJ3B!%!*!%!5J!%5jMFQ9N3R9QCQ9b8Q9\rYEhCP!(`)!UDr3IrSN!!"!!L8)IqJI(SEH(bF)hJl`J)j1k)"aB2L!#`iB!!!N!"\rK!$JS(!!!3))!K)#I!!!X"!!"3))!)(r$mhKrT1Yi1+!"5$M!!!")!!T9J%%!&%J\r!!&b![`!!,!8!!N##!"4r`r0i5!!+8B""!"4)!!"!J0m!!#`'!!0!JJ!35!!+8B"\r"!"4)!!!SJ2m!!#`(!!4!JJ!FIm2cH(qNkhJiS!&)1-!!!8J!#IQ!33!8+"`!!%#\r#!!`iB!!-5!!!5$YJ!!")!!!SJ4`##>%$Tp#%JZN3%!1(p$dhJiJ3!i5rrYB@!\r!!!!lH`!"U9`#"(`E8!""J2r8J(`##%[rm9diB!!!J!%!D$JK!'"m#!1QZd(rk%k\r!!#!!N!BJ3B!'!*!%!4`!%LjNDA0`Eh0P3h*PC%*eCQCPFR`)!UD6iIrmNm(rq*1\rKrr56JIr`N!!"!!L8)Iq`N!"K!'L3!)%!E*!!S3"`N!$"!(5!B3"X+!-!!%'#!"#\r!J3"d+!3!!%##!!`iB!!!5!!"!)#K!'L!`3"`I!8`!%'#!!`iB!!!5!!!k)$K!'J\rX"`!"3))!G)2K!'b$`3"d1(m!!6LH!!&)!!S&J%%!&#`$!!"!JJ"-1(m%icLH"10\r)!!RYJ%%!&#`$!!"!JJ!d1(m6L6LH%iP)!!R9J%%!&#`$!!"!JJ!FJ4mBI)%q'(a\rm#%J!3))!$$KJ!!&)!!"d1'!!!%J!!'b"33"S,!S!!N##!&b$S3"XJi%!G)"p!!#\r!R!!!5!!*LB""!"3X!`!!3))!0)"p!!5!R!!%5!!*FB""!"3X!`!!3))!()&p!"L\r"R!!BI!YJ!%##!!`iB!!"5!!!%$KJ!!")!!!)1'!!!)!"!&Ji)3"3I!J$TS2Krrb\r$`IriJk(rp)1"rr"1J!!J!*!')%'!"!#3"!&S!!JZBh*PC'0YF!!!I!J#TT2Krrb\r6`IriNk(rp*1"rr#3!!%!#*3Krl"mI4YiI*`MH$[!!!!S(!!!3))!$$KJ!!C)!!)\r81'!#+%[rlZ'3!(`!!)"m!!!S!`!!3))!$$KJ!!C)!!(dJp`!!(r$mhKrT1Yi5!!\r)*B""!"5!R3%!N!#H!3!iIJ%%1*d""%J!#!f!33!8U,d#",#q!J5Sh3)'X0i#"MM\rJ!!'BrJ)3U4i#"P8$%$T,rqjjN!"q!JL"2J))+!N!!%##!!`iB!!'5!!"M$[J!!"\r)!!&SJ9d##&IV%$Tp5PJZJ8S!!#`+!!&!JJ#`1'!!#%[rlMQ"RJ))9q331RaX)5k\r![J))9qB31RbP-#iS"3!!3))!$$KJ!!C)!!%m11!!!B%H!JKAk4!kI3K),T!!k!!\r!1'!GJ%[rlI@"AJ))9qX31Re+@#k3!'S!")'H!JKAia!kIB`B,S'-!!3S$!!!3))\r!$$KJ!!C)!!$`J*i##&IP%$TmK#JZJ'3!")$G!JKAja!kI-Bi,S#'!!3iS"f!5!!\r(1B""!"4)!!#JJ4d##&IT%$Tp#%JZJ3J!!#`)!!*!JJ!XJ9d##&IV%$Tp5PJZJ'S\r!!)#+!!5"RJ))9qB31RbX-K4,rrBY5!!!B)$p!JKAk"!kI1G!,S$R!!!X"`"M3))\r!5$KJ!!K,rqdeJ6i##&IU%$TmD9%ZJAi##&IX%$TpDf!Z+!X!!%##!!`iB!!'5!!\r!1$KJ!'1!RJ))9q831Rb%+#k3!'3!!$[r!!'ShJ)%I"m`!%'!rT3ii!!!N!$q!L5\r3!2i#)$KJ!!#!!3"B1#%!8(`)!kD$iIrmJm(rq)1Krr5$JIr`6S!!)!#3"L""J!3\r!N!3#D!!',Q4eF%j$I!J#TT2Krrb6`IriN!!"!!L8)Ir!I(iEH(rImhJS(`!!3B)\r!,%J!!"5!R`!!J'3!#%[rl1Nlr`!%J,m!!#J&!!"!J[rSIm2cH%[rl0'!!3")1#%\r!3(`)!kD$iIrmJm(rq%k!!#!!N!BJ3B!#!*!&C!!4,Q4TFh"[Ff9%BA4K3A*bBAN\r!I!J#TT2Krrb6`IriNk(rp*1"rr#3!!%!#*3Krl"mI"Yi1m)#4$ZL!F@$iJ!X+"`\r!!%##!*L!I`!!,!-!!8##!#"r`r0iIk6VH$LJ!F)i`!!!5!!%LB""!"4)!!"`J*m\r!!#`%!!*!JJ!8Im2cH%J!")@!33!85!!!9)#r!!!X"3!$3))!%%J!")@!33!85!!\r!2)$I!!!X"J!%3))!-(r$mhKrT1Yi1+!"`MM!!!&)!!3YJ%%!&%J!!"4rJq0iIi6\rMH%[rfIPJ!!!!J2`!!#J(!!"!J[rS1'!!!)!"!&Ji)3"3I!J$TS2Krrb$`IriJk(\rrp)1"rr"1J!!J!*!')%'!"!#3"IJ!#bjQFQ9P6N0-DA0d!!!!I!J#TVpKrqb3!!%\r!#*3Krk"mI"Yi1m)"hcZL!F@$iJ!X+"`!!%##!)5!I`!!,!-!!8##!#"r`r0iIk6\rVH$LJ!G)i`!!!5!!$IB""!"4)!!"FJ*m!!#`%!!*!JJ!8Im2cH%J!!hQ!33!85!!\r!3)#r!!!X"3!$3))!%%J!!hQ!33!85!!!+)$I!!!X"J!%3))!((r$mhKrT1Yi1+!\r"dMM!!!&)!!-KJ%%!&$KK!$K)!!,0J%%!&(al'hKrC`Fd,!F!!%'#!!`iB!!!5!!\r!5)%F!K3X#!"N3B)!-$KK!$JiR!)B1+%!3%J!!Uf!33!8I(XEH(pT"c3X#3!!3B)\r!&$KJ!!")!!!318!!!*P"!%#)B3"!J!%!D$JK!'"m#!1QZf(rl%k!!#!!N!BJ3B!\r&!*!%!53!#bjTFda[BfY2GA*c!!!!I!J#TVpKrqb3!!%!#*3Krl"mHaYi1m)#9cZ\rL!F@$iJ!X+"X!!%##!)5!I`!!,!-!!8##!#"r`r0iIk6VH$LJ!HFi`!!!5!!#1B"\r"!"4)!!"FJ*m!!#`%!!*!JJ!8Im2cH%J!!M@!33!85!!!3)#r!!!X"3!$3))!%%J\r!!M@!33!85!!!+)$I!!!X"J!%3))!((r$mhKrT1Yi1+!"jcM!!!&)!!(GJ%%!&)$\rl!!!X"`!#3))!I)1E!!5!I!!!5rrTHB"m!!4,rqPaJ4`!%#J)!!""JJ!-J(`!%%[\rrk9f"2!!i+!N!!%'#!!b!I!!i5rrT5B&F!%3S#J!!3B)!$)"m!%4,rqNeJA`!5#J\r,!!""JJ!-J(`!5%[rr!Q"R!!X+!`!!%'#!!b!I!!X5rrlpB"l!!4,rqN&1'!!!)!\r"!&Ji)3"3I!J$TVYKrqa1J!!J!*!')%'!"3#3"!&-!"FZBf0ICR*PC9pMFQ9NAfP\rZG'9bEQ&XF`!!!(a$%hK1J!!JI!J#TT!!!3!)P#(r`%[rrqemD4YiJ')!D)##!'3\riSJ!!1-)#CB$L!&L"!J"85!!!@B""!"5!JJ#XN!"N!!",rp"TB!!!!$KJ!!#!!3"\r)1#%!3(`)!kC1J!!JI!J#TT!!!3!)P#(r`)"L!+b!B`!!5!!!-B""!"5!!3")1#%\r!3(`)!kC1J!!JJB)!1*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!$53!%%!&)!-!!#\r!6!!%I!N$TNk!"##"JJ!JN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!(*!!33!8J!`\r!!)"-!!4m#31Q6S!%))'#!"#3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!`N!""!"5\r!$!!!J%`!"(`*!kC1J!3JJB)!&*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!!#3!%%\r!&)!-!!#!6!!%I!N$TNk!"##"JJ!BN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!8*!\r!33!8J!`!!)"-!!4m#31Q6S!%))'#!!L3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!\rNN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!5*!!33!8J!`!!)"-!!4m#31Q6S!%))'\r#!!b3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ"!N!""!"5!$!!!J%`!"(`*!kC1J!3\rJJB)!"*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!%53!%%!&)!-!!#!6!!%I!N$TNk\r!"##"JJ!mN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!6*!!33!8J!`!!)"-!!4m#31\rQ6S!%)!!!,eb!!!"B!*!',l5!!!!X!*!&9L)a`!)L-DJ#)J*PKJ)"-F!L!D@#!K%\r"P3'-!Am#9`*%!MN#)J)6!J-"pJ(U!Gm"dJ(&!EF!Y!&`"#)9+)B#&44d%rJ6N!!\r6*"(!$bJ1#!e-$*J,a!T-#A!)H!JJ"MJ%l!0`!F!"0!!F&d`L&X3%,Ne*9#"*,e-\rJ6@&M4'9f!5#"CJ`K+'jKE@8J)6dJ-#N)3d0KBfKP,Q-2)5JUD'&ZC'aP)#%p)$!\rT%5%SF(*TEQ0TF'&X)#%p)$!T$5%SFf&QC9!J)6dJ-#N-3d0KBfKP9A4TE#jM$#%\rSFfPkC5!q)$"-+3SK+'jM)#%p)$!T#b%SEf*U)#%p)$!T$#%SC'9cG#!K25!`+3p\rbCA4NCA0d)$dp)%j96%`1+LTNCA0d)$dp)%j96%`@+#SUC'9cG#NY2Q4KG'%J26d\rJ6P9-6!TZBb!p25"198a-%L%SBfjdFQa#E'pMDb!K25!`+3dK+'0bC@4c)#%p)$!\rT1k3!!!%!!!!"C!!!!'3!!!!bC@*eCcSf1%XJ3fpNC8GPEJ"0593J8R9ZG'PYC9"\r33b"%6%`ZC'9LG@Fk0MK,)%4TFf&cFf9YBQaPFJ"0593J8R9ZG'PYC9"33b"%6%`\rZC'9LG@Fk0MK,)%GXEf*KE#"2F(4TE@PkCA)!68P8)&*eER4TE@938%-J4%a-,Q4\rPBR9R1MBi5b"-D@jVCA)!68P8)&*eER4TE@938%-J4%a-,Q4PBR9R1MBi5b"3FQp\rUC@0d!%e*9#"5G@jdD@eP8&"$)%4-6#jNC@*eCcT$,d-V+b"$Efe`D@aPFJ"0593\rJ8R9ZG'PYC9"33b"%6%`ZC'9L!!!!B!#3#`%!N"-"F(G`B`#3%`%!N"&!&%e*9&q\rP3d0KBfKP6'PL,Q4PBR9R!!!!!3!!!!&N!!!!C!!!!$)&9MR30#B!!!!F!$)!!'0\rQFQF!!!!+!!$rr`#3"!9EF&b1RJ:\r
\ No newline at end of file
+++ /dev/null
-/*************************************************************
- *
- * Header file for Credential Cache API for MacOS
- *
- * -as defined by the document found at http://www.umich.edu/~sgr/v4Cache/
- * -definitions borrowed from a windows implementation found at
- * /afs/umich.edu/user/s/g/sgr/Public/TsoCacheDll shell/
- *
- * Revision 1: Frank Dabek, 6/4/98
- * added missing calls from revision four of the API
- * deleted some WIN specific Information
- * added some misssing definitions
- * renamed to CCache.h
- **************************************************************/
-#ifndef _CCache_h_
-#define _CCache_h_
-
-#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
-# pragma import on
-#endif
-
-#include "Processes.h"
-/*
-** The Official Error Codes
-*/
-#define CC_NOERROR 0
-#define CC_BADNAME 1
-#define CC_NOTFOUND 2
-#define CC_END 3
-#define CC_IO 4
-#define CC_WRITE 5
-#define CC_NOMEM 6
-#define CC_FORMAT 7
-#define CC_LOCKED 8
-#define CC_BAD_API_VERSION 9
-#define CC_NO_EXIST 10
-#define CC_NOT_SUPP 11
-#define CC_BAD_PARM 12
-#define CC_ERR_CACHE_ATTACH 13
-#define CC_ERR_CACHE_RELEASE 14
-#define CC_ERR_CACHE_FULL 15
-#define CC_ERR_CRED_VERSION 16
-
-#define CRED_TYPE_IN_UNION
-
-typedef int cc_int32;
-typedef cc_int32 cc_time_t;
-typedef cc_int32 cc_nc_flags;
-//typedef short cc_cred_vers;
-
-enum StringToKey_Type { STK_AFS = 0, STK_DES = 1};
-
-enum { MAX_V4_CRED_LEN = 1250,
- KRB_PRINCIPAL_SZ = 1250,
- KRB_INSTANCE_SZ = 1250,
- KRB_REALM_SZ = 1250,
- KRB_SERVICE_SZ = 1250,
- ADDR_SZ = 16 };
-
-// V4 Credentials
-typedef struct _V4Credentials {
- unsigned char kversion;
- char principal[KRB_PRINCIPAL_SZ];
- char principal_instance[KRB_INSTANCE_SZ];
- char service[KRB_SERVICE_SZ];
- char service_instance[KRB_INSTANCE_SZ];
- char realm[KRB_REALM_SZ];
- unsigned char session_key[8];
- cc_int32 kvno;
- enum StringToKey_Type str_to_key;
- long issue_date;
- cc_int32 lifetime;
- char address[ADDR_SZ]; // IP Address of local host
- cc_int32 ticket_sz;
- unsigned char ticket[MAX_V4_CRED_LEN];
- unsigned long oops;
-} V4Cred_type;
-
-// version indentfiers
-// extend to authentication schemes beyond Kerberos?
-enum cc_cred_vers {
- CC_CRED_VUNKNOWN = 0, // For validation
- CC_CRED_V4 = 1,
- CC_CRED_V5 = 2,
- CC_CRED_VMAX = 3, // For validation
- CC_INVALID_RECORD = 99
-};
-
-#define NC_MAX_NAME_LENGTH 255
-typedef struct _infoNC {
- char name[NC_MAX_NAME_LENGTH];
- char principal[NC_MAX_NAME_LENGTH];
- enum cc_cred_vers vers;
-} infoNC;
-
-
-typedef struct _cc_data {
- cc_int32 type; // should be one of above
- cc_int32 length;
- unsigned char* data;
-} cc_data;
-
-typedef struct _cc_creds {
- char* client;
- char* server;
- cc_data keyblock;
- cc_time_t authtime;
- cc_time_t starttime;
- cc_time_t endtime;
- cc_time_t renew_till;
- int is_skey;
- cc_int32 ticket_flags;
- cc_data **addresses;
- cc_data ticket;
- cc_data second_ticket; //????
- cc_data **authdata;
-} cc_creds;
-
-//union of v4, v5 pointers
-typedef union cred_ptr_union_type {
- V4Cred_type* pV4Cred;
- cc_creds* pV5Cred;
-} cred_ptr_union;
-
-//version 4 and version 5 union data type
-typedef struct cred_union_type {
-#ifdef CRED_TYPE_IN_UNION
- enum cc_cred_vers cred_type;
-#endif
- cred_ptr_union cred;
-} cred_union;
-
-#define kInitialCredBufferSize 10
-#define kLocalCopyNCType 1
-#define kMasterRecordNCType 2
-#define kUnlocked 100
-#define kReadLock 101
-#define kWriteLock 102
-typedef struct _ccache_p {
- char name[NC_MAX_NAME_LENGTH + 1];
- enum cc_cred_vers vers;
- char principal[NC_MAX_NAME_LENGTH + 1];
- short numCreds;
- short maxCreds;
- cred_union** creds; //self-growing array of pointers
- int cc_flags;
- char typeFlag; //master or local copy
- long lock;
- ProcessSerialNumber lockOwner;
- struct _ccache_p *next;
- struct _ccache_p *prev;
-} ccache_p;
-
-
-typedef struct _ccache_it {
- ccache_p *prevNC;
- int lastCredOffset;
-} ccache_it;
-
-typedef struct _apiCB {
- ccache_p* listHead;
- ccache_p* listTail;
- int numNCs;
- cc_time_t changeCount;
-} apiCB;
-
-
-// --- Globals -------------
-extern apiCB *gCntrlBlock;
-
-
-/*
-** The official (externally visible) API
-*/
-
-#define CC_API_VER_1 1
-
-// -- Main cache routines ------
-
-/* Initialize the Credentials Cache, return a control structure in cc_ctx,
- This should be the entry point of the shared library, or called from
- the entry point */
-int
-cc_initialize(apiCB ** cc_ctx, // < SL's primary control structure.
- // returned here, passed everywhere else
- int api_version, // > ver supported by caller (use CC_API_VER_1)
- int* api_supported, // < if ~NULL, returned max ver supported by DLL
- char** vendor); // < if ~NULL, returns read only C string, vendor name */
-
-/* Termination routine */
-int
-cc_shutdown(apiCB** cc_ctx); // <> SL's primary control structure. NULL after call.
-
-
-/* Open a name cache within the ccache designated by name and version?
- Returns a control struture pointer to the NC in *handle */
-int
-cc_open(apiCB * cc_ctx, // > SL's primary control structure
- char * name, // > name of pre-created cache
- const enum cc_cred_vers vers, // > version of credentials held in this NC
- int cc_flags, // > options
- ccache_p ** handle); // < named cache control structure
-
-/* Close and deallocate memory assoicated with the named cache pointed to by *handle */
-int
-cc_close(apiCB* cc_ctx, // > DLL's primary control structure
- ccache_p** handle); // <> named cache control structure. NULL after call.
-
-/* Create a new named cache in the cache cc_ctx.
-Specify the cache by: a name, a principal, a version
-return a pointer to the control structure for the cache via handle */
-int
-cc_create(apiCB* cc_ctx, // > DLL's primary control structure
- char* name, // > name of cache to be [destroyed if exists, then] created
- const enum cc_cred_vers vers, // > version of credentials to be held in cache
- char* principal, // > name of principal associated with named cache
- int cc_flags, // > options
- ccache_p** handle); // < named cache control structure
-
-/* Seems remarkably similiar to cc_close ???? */
-int
-cc_destroy(apiCB* cc_ctx, // > DLL's primary control structure
- ccache_p** handle); // <> named cache control structure. NULL after call.
-
-/* Get the global last changed time variable for the CCache
- Replace this with a change counter instead of an actual time?*/
-int
-cc_get_change_time(apiCB* cc_ctx, // > DLL's primary control structure
- cc_time_t* time); // < time of last change to named cache
-
-// -- Named Cache routines ---------
-
-/* store the credentials (tickets) in cred in the named cache pointed
-to by handle. Maybe the last argument should be more general? */
-int
-cc_store(apiCB* cc_ctx, // > DLL's primary control structure
- const ccache_p* ccache_pointer, // > named cache control structure
- const cred_union cred); // > credentials to store in cache named
-
-/* Remove the credentials pointed to by cred from the Named Cache pointed to
-by handle. */
-int
-cc_remove_cred(apiCB* cc_ctx, // > DLL's primary control structure
- ccache_p* ccache_pointer, // > named cache control structure
- const cred_union cred); // > credentials to remove from named cache
-
-/* set the principal of the NC *ccache_pointer to principal,
- principal should be a null terminated C string */
-int
-cc_set_principal(apiCB* cc_ctx, // > cs
- const ccache_p* ccache_pointer, // > NC
- const enum cc_cred_vers vers, // > version: to check pointer?
- const char* principal); // > new principal name
-
-/* Get the name of the principal associated with the NC handle */
-int
-cc_get_principal(apiCB* cc_ctx, // > DLL's primary control structure
- ccache_p * ccache_pointer, // > named cache control structure
- char** principal); // < name of principal associated with named cache
- // Free via cc_free_principal()
-
-/* Get version of credentials stored in the NC pointed to by ccache_pointer */
-int
-cc_get_cred_version(apiCB* cc_ctx, // > cs
- const ccache_p* ccache_pointer, // > the named cache
- enum cc_cred_vers* vers); // <> the version of credentials in the NC
-
-/* Return the name of the NC specified by ccache_p */
-int
-cc_get_name(apiCB* cc_ctx, // > control struct
- const ccache_p* ccache_pointer, // > NC
- char** name); // <> name
-
-
-// - Search routines ----
-
-/*
-Sequentially open every NC in the CCache.
-To use (?): initially set handle and itCache to NULL
-after each call set itCache to handle,
-repeated calls will return all currently held NC's
-*/
-int
-cc_seq_fetch_NCs(apiCB* cc_ctx, // > DLL's primary control structure
- ccache_p** ccache_pointer, // <> named cache control structure (close, then open next)
- ccache_it** itCache);// <> iterator used by DLL, set to NULL before first call
- // Also NULL for final call if loop ends before CC_END
-
-/* Sequentially fetch every set of credentials in the Named Cache handle
-use similiarly to cc_seq_fetch_NCs */
-int
-cc_seq_fetch_creds(apiCB* cc_ctx, // > DLL's primary control structure
- ccache_p* ccache_pointer, // > named cache control structure
- cred_union** creds, // < filled in by DLL, free via cc_free_creds()
- ccache_it** itCreds); // <> iterator used by DLL, set to NULL before first call
- // Also NULL for final call if loop ends before CC_END
-
-/* a wrapper for cc_seq_fetch_NCs.
- Returns: a null terminated list (array) of pointers to infoNC structs
- if this works, maybe we should hide that seq call...
- */
-int
-cc_get_NC_info(apiCB *cc_ctx, // > control structure
- infoNC*** ppNCi); // <> info about the NC (yes.. three asterisks...)
-
-
-// -- Memory recovery ---------
-
-/* just a wrapper for free() ??? */
-int
-cc_free_principal(apiCB* cc_ctx, // > DLL's primary control structure
- char* principal);// <> principal to be freed, returned as NULL
- // (from cc_get_principal())
-/* another wrapper? */
-int
-cc_free_name(apiCB* cc_ctx, // > DLL's primary control structure
- char* name); // <> name to be freed, returned as NULL
- // (from cc_seq_fetch_cache())
-
-/* free storage associated with cred_union** */
-int
-cc_free_creds(apiCB* cc_ctx, // > DLL's primary control structure
- cred_union** creds); // <> creds (from cc_seq_fetch_creds()) to be freed
- // Returned as NULL.
-
-/* Free that nasty array we created above */
-int
-cc_free_NC_info(apiCB *cc_ctx, // > control structure
- infoNC*** ppNCi); // <> pointer to free
-
-
-// -- Locking ----------
-
-#define CC_LOCK_UNLOCK 1
-#define CC_LOCK_READER 2
-#define CC_LOCK_WRITER 3
-#define CC_LOCK_NOBLOCK 16
-
-/* Place a lock on the Named Cache handle, lock types are above
-NB: API indicates that this call is not implemented*/
-int
-cc_lock_request(apiCB* cc_ctx, // > DLL's primary control structure
- ccache_p* ccache_pointer, // > named cache control structure
- int lock_type); // > one (or combination) of above defined lock types
-
-#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
-# pragma import reset
-#endif
-
-#endif /* Krb_CCacheAPI_h_ */
+++ /dev/null
-#include "CCache.h"
-
-#define kCredsMatch 1
-#define kCredsDiffer 0
-
-// ----- Prototypes for Private Functions ------------------
-cred_union ** newCredBuffer(ccache_p *nc);
-int credBufferInsert(ccache_p* nc, cred_union creds);
-int credBufferRemove(ccache_p* nc, const cred_union cred_to_remove);
-
-char credcmp (cred_union a, cred_union b);
-
-char isLockOurs(const ccache_p *nc);
-
-int copyDataObj(cc_data *obj, cc_data src);
-int copyV5Cred(cred_union src, cred_union **dest);
-int copyV4Cred(cred_union src, cred_union **dest);
-int dupNC(ccache_p* src, ccache_p** dest);
-void copyDataArray(cc_data **src, cc_data ***dest);
-
-void disposeDataArray(cc_data **base);
-int cc_free_cred_internals(cred_union *creds);
-int freeNCList(apiCB *cntrlBlock);
-int disposeCredBuffer(apiCB *cc_ctx, ccache_p *nc);
-
-Ptr NewSafePtr(long size);
-Ptr NewSafePtrSys(long size);
-void DisposeSafePtr(Ptr safeP);
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:#Q4PFfaTBLif1%X!FfKXBMq3"!#3")8`!!!"MQI+5Qpj)A"PCQCY0MKV!!!!!E*\r@K3m!N!d$!!)!N!j8UJ!!9+S!!&5U!!!!P!!"!J#3"!8!N!BZB!!!,Q!!!#VF!!"\r93!)"!J#3"!i!N!i&&!!!J"`%!3)!6@&TEJ!P369AEh*XC!"-Ef&NCA)!N!41G5T\r46PErq#m0)!d[!#mYre`LEIp))&P1N!!UE[rd+d$r$'(rN!6FF!"1ANjd!!3U88j\r@rrJ[$5mYr``LEIp%)&P1N!!UE[rd6Pj1G5T46PErq%MR%!4f!#mZ!!JLEIpB)&P\r1N!!UE[rd0J!`!dM!C`3`!f!#-!-Q(djH6R3!"*0IAfPZDA4TB@aTHQ9IC'9cE'P\rL!!!U88j@rrJ[$5*Yre3J@8k3!#TZrr41ANjeNPpIG'9bE@PZBA4PAf4PFfaTBJ!\r!!#T46PEri%MR(c`X,J!)*Li!$#iZ!"!SEJ!B*'i!&%UZ!"aR!!8@*Nak!"SEFKM\rMVA!!%"Yb%11SLS"`!"!EiBL+J(!!%"Z+J(J!'"Yb'11XF!!3'h)3ikL)J(!!%"[\rKL)L!F!!3'iL!*NBS3f!!"-*`#,k!EAT`!"!E!S!!!!$rFKMMU,'&F!!3'`+!!!!\r!rh)3ikLaKA!!%"X#J!!!!2rKL,'&F!!3'`+!!!!!rl'&F!!3'`+!!!!!rh)BikL\raK(!!%"X#J!!!!2pb%11SXB4`!"!E!S!!!!$riBLaK(!!%"X#J!!!!2qaK&'(B!!\r!NYI()!F-J!!!!!GL!!##-$X#"Nll!!)!H!"S!&J!5J!q!#i!(J!3F!!3)`+!!!!\r!rq')XB4`!"!M!S!!!!$rFK$MU,'%F!!3)`+!!!!!rh)BikLaK(!!%#-#J!!!!2q\raKA!!%#-#J!!!!2rKL,'&F!!3)`+!!!!!rh)3ikLaKA!!%#-#J!!!!2pb'11SXB9\rq!#!%!S#UN!6LL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8\r!!!$r)'hrr#S`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`\rL-"`!jBQ#K5S%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$\rBK#)$G"MNU3+"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3\r!!!$r)'hrr#J`6!$RM)L"I!"J!!'B*J4b&H1V)J4d#q5TJS-Q'V1$F$mL!h3Bj+R\r#J#"YrrK`2b3$,8$ri(!3i+V%V[rJjBSLEIridm)J+3%!J,!F!()r*!2JLX5"jBS\rJEIridF+!U!)!FMr#Jq@*)'hrq0("J+J$!,'&*J4b#H1V)J4d&q5TJS-Q'V1$F$m\rL!h33j+R#J1@*)'hrq0("F$mL!h3Bj+R#J1@*)Qhrq02")#N%!)#S"3"b2b3$i)V\r%JH@+)'hrq0(#J+J'!()r`S2PL5"YrrM4`B#S"`#aK5B&FKAMUb)&G![NUB+$*KU\rcJh!r)J0d'15T`S!JEIriF$mN!be!rq"`%1#Ua+lri1@+)Qhrq02#)#N"!)#`(!"\rb2b3$i)V%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK#B&FJRMUb)&G"I\rNUB+$*KUcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!T"!#\r!U!8!FMmN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB45KR!)[)"\rY!2jN)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+!+!%U"()3iUd\r#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+&+J6JM3+&!!!\r!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!!!2mJEIrd+$"\r-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"Yrr3S-%`!jBb\r)J5)$!S%!!!$r)'hrp)L`(!"&k[q!)!9b'1+S!S!!!!$r'-!J"A)3iUJ#J!!!!2m\rB`#!&i)J#J!!!!2mB`#!&!S!!!!$r'-!J"()BiUJ#J!!!!2mB`#!%FK$LU!+!!!!\r!raM!)!6JL!+!!!!!raM!)!3#J!!!!2mB`%U(EJ$l2'!!"6j+Kfi'F!"J!!8f*Na\r`!"!EFKMMU#e!rr4`!"!EFK$MU)'Zrr4`!"!EiBL"V[rdF!!3'i'Zrr4`!"!EFKM\rMU#e!rr"`!"!EFK$MU)'Zrr"`!"!EiBL"V[r`F!!3'i'Zrr!Q4LK$HJ!D'h)Bike\r`!"!EFK$MU)U!F!!3'q')LS"`!"!ELS"i!"JEFKMMV(!!%"Yb%11SL)"`!"!EiBL\r)J(!!%"Z)J#e&rq`Y42rS)!3#J+U3"1+)*J8#JkU3")D!)!3#J&@3"#)&!S&9N!6\r5JB+!+!%U"()3iUd#K3!!!2mJEIrm+M"F!0U&)J4d'15T!S%!!!$r)'hrr)U`(!!\rL"1#*!S%!!!$r)'hrr#)`(!$PLB+&+J3#K3!!!2mJEIrm+M"F!1H0LS%S!h)3iU`\r#K!!!!2mJEIrm+$"-!0L%)J0d'15T!S%!!!$r)'hrr)L`(!!L!q#*!S%!!!$r)'h\rrr#)`(!$PLB+%+!-#K!!!!2mJEIrm+$"-!1H-L)&&kJ#!I!"J!!()*J4b#H1V)J4\rd&q5TJS-Q)V1$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*YrrM6`#!T"`#!U!B!FMm\rN!be!rq"`%1#Ua)(PLL"YrrM4`L!S"3#!V[rJFMmN!be"rq4b'1+Ua+lrj1@+)'h\rrq0(#J+J%!,'&*J4b&H1V)J4d#q5TJS-Q)V1$F$mL!h3Bj+R#J#"YrrK`2b3$i)V\r%J1@+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)!G$mY32rN)!-Y3IrJFK$\rLU-##jBJJEIridF!J+!%!J+lrj)#Zrq#aK5B&FJRMUb)&G"INUB+$*L+cJh!r)J2\rJLF+!jBNJEIridF&`2m#$jBJLEIridm!J+3F!J+J'!()r*!-Y32rNF"$JUX5"jBS\rJEIridF)J+!8!J+lrj()r*!-Y3IrJFKMLUX5Zrq$PLL"YrrM4`S#S"!#aK#B&FKA\rMUb)&G![NUB+$*L+cJh!r)J0d'15T`S!JEIriF$mN!q#+a)$PLL*YrrM6`R!r`)2\rPL#)`(!!JEIridF!J+!-!J+N#!(3r,8$rj#!$,8(ri()3iUM!JZ@))'hrq0(!)#J\r"!)#Zrq5!V[rJXB45KR!)[)"Y!2id)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)\r%!S%2N!6TLB+!+!%U"()3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'h\rrp#)`(!$YLB+&+J6JM3+&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!\rS!h)3iU`#K!!!!2mJEIrd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2\rJM!+%!!!!rb"Yrr3S-%`!jBb)J5)$!S%!!!$r)'hrp)L`(!!J,[rdXB8J,[r`XB4\r`#,k!EhC4Kb!&FKMLU!+!!!!!raM!)!9b%1+S!S!!!!$r'-!J"H#)!S!!!!$r'-!\rJ"3+!!!!!raM!)!4b'1+S!S!!!!$r'-!J"()3iUJ#J!!!!2mB`#!%i)J#J!!!!2m\rB`#!%!S!!!!$r'-!YE[rXrr3YE[rSrr"J!2ZffFFJ"`b!!!!!#')!!)!`1`)'6[X\r!!J"f!'J!@J"1!%3!0J!S!"`!%L!%!S!!!!$r'3!J"1#)!S!!!!$r'3!J"()3iUJ\r#J!!!!2mC!#!%FKMLU!+!!!!!raN!)!8#J!!!!2mC!#!&i)J#J!!!!2mC!#!&FK$\rLU!+!!!!!raN!)!9b'1+S!S!!!!$r'3"`!%cI(2K1ANjd!"L2C'9cAf0LBepPEQ0\rbHA"d!!!U88j@rr4)jamm+'i!&#CZ!"Kk!"SEFKMMVA!!%"Yb%11SLS"`!"!EiBL\r+J(!!%"Z+J(J!'"Yb'11XF!!3'h)3ikL)J(!!%"[KL)L!F!!3'iL!*Qi!##iZ!""\rJ!!4JF!LqJ'ekF!!3'`+!!!!!rh)BikLaKA!!%"X#J!!!!2pb%11SXB9`!"!E!S!\r!!!$riBLaKA!!%"X#J!!!!2qaKA!!%"X#J!!!!2pb'11SXB4`!"!E!S!!!!$rFK$\rMU,'%F!!3'`+!!!!!rq')XB4`!"!E!S!!!!$rXB44Kf!!!*,Aab!($)!!!!!(BJ!\r!JM!l!JC1q`!#!(J!D!"B!%S!2J!Z!"i!%(!!%#-#J!!!!2rKL,'%F!!3)`+!!!!\r!rh)3ikLaK(!!%#-#J!!!!2pb'11SXB4`!"!M!S!!!!$rXB9`!"!M!S!!!!$riBL\raKA!!%#-#J!!!!2pb%11SXB9`!"!M!S!!!!$rFKMMU,'&IJ!N6#!%!S#UN!6LL#B\r&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$r)'hrr#S`A!$\rDK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`!jBQ#K5S%!S8\r!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)$G"MNU3+"!!!\r!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$r)'hrr#J`6!$\rRM)L"I!"J!!'B*J4b&H1V)J4d#q5TJS-Q'V1$F$mL!h3Bj+R#J#"YrrK`2b3$,8$\rrp(!3i+V%V[rdjBSLEIridm)J+3%!J,!F!()r*!2JLX5"jBSJEIridF+!U!)!FMr\r#Jq@*)'hrq0("J+J$!,'&*J4b#H1V)J4d&q5TJS-Q'V1$F$mL!h33j+R#J1@*)'h\rrq0("F$mL!h3Bj+R#J1@*)Qhrq02")#N%!)#S"3"b2b3$i)V%JH@+)'hrq0(#J+J\r'!()r`S2PL5"YrrM4`B#S"`#aK5B&FKAMUb)&G![NUB+$*KUcJh!r)J0d'15T`S!\rJEIriF$mN!be!rr4`%1#Ua+lrp1@+)Qhrq02#)#N"!)#`(!"b2b3$i)V%JH@+)'h\rrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK#B&FJRMUb)&G"INUB+$*KUcJh!r)J0\rd%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!T"!#!U!8!FMmN!q#+a)(\rPLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB45KR!)[)"Y!2jN)!8#J2#3"1L\r)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+!+!%U"()3iUd#K3!!!2mJEIrd+M"\rF!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+&+J6JM3+&!!!!rb"Yrr3U-&`!jBf\r+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!!!2mJEIrd+$"-!1Q-)J0d'15T!S%\r!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"Yrr3S-%`!jBb)J5)$!S%!!!$r)'h\rrp)L`(!"&k[q!5SGZ!2ZH*Qi!$#!&FKMLU!+!!!!!raE!)!9b%1+S!S!!!!$r&X!\rJ"H#)!S!!!!$r&X!J"3+!!!!!raE!)!4b'1+S!S!!!!$r&X!J"()3iUJ#J!!!!2m\r@`#!%i)J#J!!!!2m@`#!%!S!!!!$r&X!J"%cI(2K1ANjd!"50C'9cAf0LBepMDh0\reE3!!+P&19[r`51FH-#CZ!"!NEJ!)HJ!D'R)Bike`!"!DFK$MU)U!F!!3'Z')LS"\r`!"!DLS"i!"JDFKMMV(!!%"Tb%11SL)"`!"!DiBL)J(!!%"U)J#!%!S#UN!6LL#B\r&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$r)'hrr#S`A!$\rDK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`!jBQ#K5S%!S8\r!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)$G"MNU3+"!!!\r!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$r)'hrr#J`6!$\rRM)L"5Ui!&'F!!D`N5h`!B!!"Q#B%FKAMUb)%G![NUB+$*KUcJh!r)J0d'15T`S!\rJEIriF$mN!be!rr"`%1#Ua+lrm1@+)Qhrq02#)#N"!)#`(!"b2b3$i)V%JH@+)'h\rrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK5B%FJRMUb)%G"INUB+$*KUcJh!r)J0\rd%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!T"!#!U!8!FMmN!q#+a)(\rPLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB8Q"A)9ikXL"A3,j+Q#JbBDXi0\r`2b)$G"MNUF+!)'hrq(!r*!-Y32r`F"$JUX5Zrr$PLL*YrrM6`L!T!3#!X"`!FMm\rN!q#+a)(PLL"YrrM4`S#S!J"b2m+$jBNJEIridF'!U!-!XB3Q"A)*ikXL"A3Aj+Q\r#JbBDXi0`2b)$G"$NUF+!jBNJEIridF&`2b)$G"MNUF+!jBNLEIridm%J+33!J+J\r&!()r*!2JLX5"jBSJEIridF+!U!B!FMr#Jq@*)'hrq0("J+J(!,'%8SC`#,b!E3$\rqC'!!!G`N5dAU!)"m!'!!!FJQ"()*ikXL"(3Aj+Q#JbBLXi0`2b)$i)R#J1@*)'h\rrq0("F$r!Jq@))Qhrq02!)#N(!)#S"J"b2b3$,8$rm(!3i+V%JH@+)'hrq0(#)#J\r&!)#Zrr"b2b3$,8(rp()BiUV%V[rdjBSJEIridF+!U!3!XB8Q"()9ikXL"(3,j+Q\r#JbBLXi0`2b)$G"MNUF+!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJL-"`!)'h\rrq0(!)#J$!)#T!J"d2be!rr3J!be"rr"b%1+S`),PL#"YrrM4`#!S!3#!V[rdJ+l\rrm,'&*J9b#H1V)J9d&q5TJS-Q)V1$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*YrrM\r6`#!T"`#!U!B!FMmN!be!rr4`%1#Ua)(PLL"YrrM4`L!S"3#!V[rdFMmN!be"rr"\rb'1+Ua+lrm1@+)'hrq0(#J+J%!,'%*J9b&H1V)J9d#q5TJS-Q)V1$F$mL!h3Bj+R\r#J#"YrrK`2b3$i)V%J1@+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)!G$m\rY32rd)!-Y3Ir`FK$LU-##jBJJEIridF!J+!%!J+lrp)#Zrr#aK&+'F!LmJ'd!rM3\rJ"3+!m*!%k)JQ"!+$m*!%KS!J"3+!$j!%)J3#J3q3"1Q*JS!S!5S%FK$LV3+&!!!\r!rb"Yrr3U-&`!kBdL"(3Bj+N#J3!!!2mJEIrd)M!F!1f*JS8U"1#0!S8!!!$r)'h\rrp#S`A!$PMBU")J3#J3!!!2mJEIrdLV!F!#J$FK$LV!+%!!!!rb"Yrr3S-%`!kB`\rL!h3Bj+N#J3!!!2mJEIrd)M!F!1f*JS3S!q#-!S3!!!$r)'hrp#J`6!$PM)L")J-\r#J3!!!2mJEIrdL,!F!#4Z!!`J"A)BiUJ#J!!!!2m8`#!&FK$LU!+!!!!!ra6!)!A\rJL!+!!!!!ra6!)!8#J!!!!2m8`#!%FKMLU!+!!!!!ra6!)!4b%1+S!S!!!!$r&-!\rJ"1#)!S!!!!$r&-!J"!+!!!!!ra6!F!"-h`ai6Pj1G!!3Mf4PFepPBf*IC@jMFRP\r`G!!!+P&19[rF,`-JEJ!)GJ"J!!$+!M!!rMJ!F!&b!h32,8$rh(!!%$!i!1L!`))\r8-$J!!S)!!!!2XB,NJX5"F!0b$be"rq"b!")`1!$SJF+Zrq!Y3[rN&$!i!!+#!!!\r!$l1#a)!J,[rNXB,LJX5Zrpa`!A)$,8$rk(!!%$!i!1L!!S!!!!!2,8(rl")`1!!\r#J3!!!!qaJH5"`Ulrl(!$,8,rm(3!&$!i!1L#!S)!!!!2,8$rp"!`1!!#J!!!!!q\reJ-#Zrr5cJ-#ZrqJL,[r`Xi!+J!!!!!'"-$J!8S0`#,D!C3$r-LBI6Pj1G!!%P'4\rPFepQDAKeF&pVCAPIF'&bDA4j!!!!+P&19[rB,`-JEJ!)GJ"J!!$dF!&b!h32,8$\rrf"!`1!!#J!!!!2lSJ-##G!mY3IrF%M!i!!+"!!!!rX+#XB(NJF+Zrpa`!h32,8,\rri"3`1!!#JJ!!!2lSJX5Zrq!Y32rN%$!i!!+!!!!!rJ+!!!!!$l@!`+lrj,1!iS$\r!V[rBFJ&d!be"rqJ5-$J!!S%!!!$qk)%#J3!!!!mY3[rX&$!i!!+#!!!!rJ+#!!!\r!$l1#j),%V[rXFJ-Y32r`%$!i!!+!!!!!rZL!!S!!!!!2,8(rp")`1!!#J3!!!2i\r#J3!!!!qaJF+Zrr5eJF+ZrqJJ,[r`XB%3-$J!G!(!JV#"CJ4`!'!-8S0`#,D!C3$\rr#(!"*Kp1ANjd!!58C'9cAf0SC@0VAfYPH9p`BA*TG(N!!!!U88j@rq")jamm,#i\r!##BZ!!`SEJ!B*'i!&%UZ!"aR!!8@*Nak!"SEFKMMVA!!%"Yb%11SLS"`!"!EiBL\r+J(!!%"Z+J(J!'"Yb'11XF!!3'h)3ikL)J(!!%"[KL)L!F!!3'iL!*NBS3f!!"-"\r`#,#Z!""X@Ri!(KYb'11[F!!3'h)3ikL1J(!!%"[KL)k!F!!3'ik!F!!3'h)BikJ\rY32rdF!!3'h)3ikL"V[rdF!!3'q')JDlrp(!!%"Z"V[rd[i8J,[rdXB44VJ!3B!!\r!TYIZ!"!J,J!3$)!!!!!)BJ!!N!!`1`)'6[X!!J#'!(B!CJ"B!%`!2!!X!"i!%R!\r!%#-#J!!!!2qaK(!!%#-#J!!!!2rKL,'%F!!3)`+!!!!!rh)3ikLaK(!!%#-#J!!\r!!2pb'11SXB4`!"!M!S!!!!$rXB9`!"!M!S!!!!$riBLaKA!!%#-#J!!!!2pb%11\rSXB9`!"!M!S!!!!$rFKMMU,'&3Ui!%#!%!S#UN!6LL#B&!S1UN!5'J#!%!S"9N!3\rL"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$r)'hrr#S`A!$DK5)%G"MNU3+"!!!!rb"\rYrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`!jBQ#K5S%!S8!!!$r)'hrr#S`A!$RMBU\r"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)$G"MNU3+"!!!!rb"Yrrb)X"`!)J2JL3+\r"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$r)'hrr#J`6!$RM)L"I!"J!!'B*J4b&H1\rV)J4d#q5TJS-Q'V1$F$mL!h3Bj+R#J#"YrrK`2b3$,8$ri(!3i+V%V[rJjBSLEIr\ridm)J+3%!J,!F!()r*!2JLX5"jBSJEIridF+!U!)!FMr#Jq@*)'hrq0("J+J$!,'\r&*J4b#H1V)J4d&q5TJS-Q'V1$F$mL!h33j+R#J1@*)'hrq0("F$mL!h3Bj+R#J1@\r*)Qhrq02")#N%!)#S"3"b2b3$i)V%JH@+)'hrq0(#J+J'!()r`S2PL5"YrrM4`B#\rS"`#aK5B&FKAMUb)&G![NUB+$*KUcJh!r)J0d'15T`S!JEIriF$mN!be!rq"`%1#\rUa+lri1@+)Qhrq02#)#N"!)#`(!"b2b3$i)V%JH@+)'hrq0(#J+J#!()r`S2PL5"\rYrrM4`B#S!`#aK#B&FJRMUb)&G"INUB+$*KUcJh!r)J0d%15T`S$PL5"YrrM4`A!\rr)J0d'15T`S$PL5*YrrM6`5!T"!#!U!8!FMmN!q#+a)(PLL"YrrM4`S#S"J"b2m+\r$jBNJEIridF'!U!F!XB45KR!)[)"Y!2jN)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q\r3"#)%!S%2N!6TLB+!+!%U"()3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$\rr)'hrp#)`(!$YLB+&+J6JM3+&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U\r`(!!S!h)3iU`#K!!!!2mJEIrd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+\r%+!2JM!+%!!!!rb"Yrr3S-%`!jBb)J5)$!S%!!!$r)'hrp)L`(!"&k[q!)!9b'1+\rS!S!!!!$r'-!J"A)3iUJ#J!!!!2mB`#!&i)J#J!!!!2mB`#!&!S!!!!$r'-!J"()\rBiUJ#J!!!!2mB`#!%FK$LU!+!!!!!raM!)!6JL!+!!!!!raM!)!3#J!!!!2mB`,q\r&)#lrp,'%5Ui!%'i!qcaJ!!8q5Ui!%'i'F!"J!!8d*Naq!"iEFKMMVh!!%"Yb%11\rSMS"`!"!EiBL1J(!!%"Z1J(!!%"Yb'11S,8$rm(!!%"Yb%11SJDlrm(!!%"[KL)'\rZrr"`!"!EJDlrm#C'+%0k!"SEFKMMVA!!%"Yb%11SLS"`!"!EiBL+J(!!%"Z+J(J\r!'"Yb'11XF!!3'h)3ikL)J(!!%"[KL)L!F!!3'iL!,8Arl#e%rqJJ"!+!UT!%iSJ\rQ"3+$UT!%KS!J"!+!9C!%)J8#J9@3"0+"JS!S!5S%FK$LV3+&!!!!rb"Yrr`U-&`\r!fS8L"(3Bj+N#J3!!!2mJEIrmLV!F!#)%i)N#J3!!!2mJEIrm)M!F!1@*JS8U"!+\r&!!!!rb"Yrr`U-&`!jif+J5J$FK$LV!+%!!!!rb"Yrr`S-%`!f)3L!h3Bj+N#J3!\r!!2mJEIrmL,!F!#)$i)N#J3!!!2mJEIrm)M!F!1@*JS3S!`+%!!!!rb"Yrr`S-%`\r!jib)J8AU!)"m!'!!!FJQ"()*ikXL"(3Aj+Q#JbBLXi0`2b)$i)R#J1@*)'hrq0(\r"F$r!Jq@))Qhrq02!)#N(!)#S"J"b2b3$,8$ri(!3i+V%JH@+)'hrq0(#)#J&!)#\rZrq"b2b3$,8(rj()BiUV%V[rNjBSJEIridF+!U!3!XB8Q"()9ikXL"(3,j+Q#JbB\rLXi0`2b)$G"MNUF+!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJL-"`!)'hrq0(\r!)#J$!)#T!J"d2be!rq3J!be"rq"b%1+S`),PL#"YrrM4`#!S!3#!V[rNJ+lri,'\r&*J9b#H1V)J9d&q5TJS-Q)V1$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*YrrM6`#!\rT"`#!U!B!FMmN!be!rq4`%1#Ua)(PLL"YrrM4`L!S"3#!V[rNFMmN!be"rq"b'1+\rUa+lri1@+)'hrq0(#J+J%!,'%*J9b&H1V)J9d#q5TJS-Q)V1$F$mL!h3Bj+R#J#"\rYrrK`2b3$i)V%J1@+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)!G$mY32r\rN)!-Y3IrJFK$LU-##jBJJEIridF!J+!%!J+lrj)#Zrq#aK&+'F!LmJ'd!rM3J"3+\r!m*!%k)JQ"!+$m*!%KS!J"3+!$j!%)J3#J3q3"1Q*JS!S!5S%FK$LV3+&!!!!rb"\rYrr3U-&`!kBdL"(3Bj+N#J3!!!2mJEIrd)M!F!1f*JS8U"1#0!S8!!!$r)'hrp#S\r`A!$PMBU")J3#J3!!!2mJEIrdLV!F!#J$FK$LV!+%!!!!rb"Yrr3S-%`!kB`L!h3\rBj+N#J3!!!2mJEIrd)M!F!1f*JS3S!q#-!S3!!!$r)'hrp#J`6!$PM)L")J-#J3!\r!!2mJEIrdL,!F!,q&)#lrm,'%F!L`VJ!3E(a4VJ!3)!9b'1+S!S!!!!$r'-!J"A)\r3iUJ#J!!!!2mB`#!&i)J#J!!!!2mB`#!&!S!!!!$r'-!J"()BiUJ#J!!!!2mB`#!\r%FK$LU!+!!!!!raM!)!6JL!+!!!!!raM!)!3#J!!!!2mB`#iZrqblKb!ZrqLjJ#e\r!rr"J!2ZbfHi!%#!Z!"!-J!!!!!KL!!#!-$X#"Nll!!)!GJ"S!&S!6J"%!$B!+!!\rF!")J"!+!!!!!raN!)!6JL!+!!!!!raN!)!4b%1+S!S!!!!$r'3!J"()BiUJ#J!!\r!!2mC!#!&!S!!!!$r'3!J"H#)!S!!!!$r'3!J"A)3iUJ#J!!!!2mC!#!&FKMLU!+\r!!!!!raN!F!"-haci6Pj1G!!BN!"NCA0IF'0LBepPEQ0bHA"d!!!!+P&19[rS51F\rI%#*Z!!Kk!"SCFKMMVA!!%"Pb%11SLS"`!"!CiBL+J(!!%"Q+J(!(*J9d&H5VaS!\rJEIrN*M!m!0D$F!FN"5e!rqK`(H#Ua+lrk#"Yrq5'X#`!F!FN"5e$rqaf$HDUa)!\rJEIrN*$!X!1@+K+lrl(!(*JAULmD!)'hrj#B`2!$RLiD#F!mS"A34j+c)J#"Yrq!\rS-%`!f)4`$b3&,8$rl(!Ci+V%V[rX)'hri)L`,!"`$b3&,86rk(J*k+V%J#"Yrq!\rN-#`!jBU%V[rSF!mS"H+-b)!JEIrJ+$"-!1H-L)*k!"SCFKMMVA!!%"Pb%11SLS"\r`!"!CiBL+J(!!%"Q+J(!2)J9d&15T`S!JEIrF)M!F!0+"F!mN"5e!rqa`(1#Ua+l\rrl#"Yrpb#X#`!F!mN"5e"rqKb$1+Ua)!JEIrF*$!X!1@+K+lrk(!2)JASLF+!)'h\rrh#)`(!$RLB+#KS&`"b)&G"(NUF+!)'hrf#)`(!$5JA!(*!8Y32rXF"RJUX5Zrq`\rJEIrBJV!X!(!(*!8Y3IrSFJRLUX5!)'hrf#3`,!$PLS5ZrqK`"b)&iSR#J#"YrpJ\rL-"`!jiQ#JSL")Qi!$#im!!"qr(!3*N"J!!'#F!(!KfFU)!0b'Z+S)J2PL3+"$rr\rrr)+!*J%J"()DiUJL"1@*!S%2rrrmJS!S!@!S)!0b'q+S)J25J3+"$rrrrS+!*J%\rJ"()EiUJL"0+"!S%2rrrqJS!S!H+(HMmL!h3@j+R#K5"Yrp4k-#3$,8Arl(S3kUV\r%V[rXHJmYF"`!rqJL!be#rr"d$q5T`S@#V[r`jBNJEIr8dF%U+!%!LUlrk()m*!-\rY4IrdHJRUUX5"HJ-L!qL*`S@#JZ@*)'hre0("+LJ#!)UZrr4b1#3$k)V%JA)(`S1\r#JZ@*)'hre0("LUJ$!(`r)J4d&Z5T`SBJEIr3I$!N"#e'rr4m$qbUa+lrp(`2,A!\rF!2r`)J3Y3[rXG!lNUF+'JUlrl1@*)'hrd0(",#J"!)bZrr"b2b3%lSV%JH@+)'h\rrd0(#M+J#!()m*!6LLX5"FJ2#K)+#jBNJEIr3dF'-U!-!)!B#J2m!!2mL"3+"!2r\rr!)+!)X%J"J+!!2rr!#)&!S(r!!$rJS!L`91,Y[`!!'i!rRT`!%cI#2K1ANjd!!L\r1E@&VC9pVCAPIFf0SC@3!!!!U88j@rrK)j`!N*'i!##mZ!!`[#L*Yrm`J@8k3!#T\rZrr3[#L*YrqJJ@8k3!#TZrr4+J'B%F2pJ'#m+)QhrJ#"C6T!!+Qlrp%U!C`4`rQ!\r#F!!NAdjH6R3!#)eNCA0IDf9jAh0MD'9N!!!U88j@rrK)j`!N*'i!##m+)QhrX#"\rC6T!!+Qlrp#m+)Qhrl#"C6T!!+Qlrp#m+)QhrJ#"C6T!!+Qlrp%U!CY*`!#4I6Pj\r1G!!%NQ4PFepZCAGIFQ&ZC'pYAfYPH3!!!#T46PEri#m0)Qhr6#"C6T!!+Qlrh#e\r!rqJLEIp-)&P1N!!UE[rF,8$rl#mZ!!JLEIqi)&P1N!!UE[rF5'lrk#*Yrl3J@8k\r3!#TZrpa)E[r`)Qhra#"C6T!!+Qlrh%KZrr!LEIqi)&P1N!!UE[rF5'lri#*YrcJ\rJ@8k3!#TZrpa)E[rN)Qhr1#"C6T!!+Qlrh#mYrcJLEIqd)&P1N!!UE[rF5'lrm#*\rYrm3J@8k3!#TZrpa)E[r`)QhrZ#"C6T!!+Qlrh%jH6R3!")!JC'9cAfPZDA4IFQ&\rZC'pYAfjeE@*PFPpRC@jPFQ&dEh)!!#T46PErq%MR%!3[,Ir!,bi!##*YrmJJ@8k\r3!#TZrr4f!'!+)'hr[%)`1!"5Jh!)YS"Ym#BI6Pj1G!!%R@4PFepcCA4IFQ&ZC'p\rYAfGPEQ9bBA4[FPpcC@9N!!!U88j@rrJLEIqm)'i!#(!)FL#`J@8%SLjJ$NU!C`S\rL#4,B8i"QqL*"6Pj1G!!%Pf4PFepcCA4IFf9aG@9ZBf9IER9YBQ9b!!!U88j@rrK\r)ja!%5(J!!5mYrm![,J!),bhr[#*Yrr!J@8k3!#TZrr4f!'!Q)'hr[(!!%$!i!&+\r!!S!!!!$r)'hr["'!1!!JEIqm5M!i!'B)8S0`#,D!EG3Q(djH6R3!"*PNCA0ICf9\rZCA*KG'9IFQ&ZC'pYAf*XEf0V!!!U88j@rrK)jami+'i!$#4Z!"J[#Q(r!!!!p#`\r!5'S!"'(r!!!!k#i!)!aQ"R!",8!!&(!"*N"JE#JZ!"!NEJ!)B&4`!EL!EaB[#Q(\rr!!!!K()!-J$5KLB"9)T9K'!)GJ!@'YD'H!!U"b!&6!8!!#)$6!-3!0+!6(`3!(r\rrrrmX!#!&"S!%r(-Y6!-!!%am!!&rrrrr,J&+K'DS)!aR"#M'+-G5Lh!%Ym"Z"VI\rZ!"4[L#!'60mFq%jH6R3!&)jNCA0IFA9KC&pMDh0eE3!!!#T46PErp#"Z!!JGD!!\r"rrBJEJ!)(9$rpc!ZrrC1ANjd!!59G(G[Af*jG'9cAhCKH&pdEepZCA4c!!!U88j\r@rr3JEJ!)(@J!!rrd(@J!![re(@J!!Irf(9$rpb!Zrr41ANjd!!5@CQpeFPpLHA4\rPFepfBAKIG'pIEQ9dF`!!!#T46PErm%MR(M`SEJ!)*%`Q6%KZrr!LEImi)&P1N!!\rUE[rX)Qhr6#"C6T!!+Qlrl#)Zrr#aJ5"Yrk`J%&+3!,1!,`!LEImS)&P1N!!UE[r\rX)Qhr-#"C6T!!+Qlrl#e!rr3L5d(Zrr4`"()JX)&P"+)ZB!j+J'F+)JN5f&1!C[S\rL39L,)Qhr-#"C6T!!+Qlrl#e!rr3L5d(Zrr4`"()JX)&P"+)ZB!j+J'F+)JN5f&1\r!C[SL3A`!B$4i!(B!&K*k!'!+iSY`!F#$XB45KA!'ZS"[m%U%CJS3%J!!!!%8J'!\r)%")#!!$q&)"5LP+'F!HmJ'r'F!"-haai6Pj1G!!%MQ4PFepbB@jNEfeIDf9j!!!\r!+P&19Zri51F3"#mZ!"![,J!-5(J3!%KZlrJLEIqF)&P1N!!UEZrd*J"+JfB8,bi\r!#%KZlrJLEIqB)&P1N!!UEZrd5(J3!%+R5'l[q#*Yrd!J@8k3!#TZlr3J!bBI6Pj\r1G!!-N@4PFepbC@&NAh"KFh0hEh*N!!!U88j@lrK)ja`m*Qi!##JZ!!`SEJ!3+Li\r!&(B!$)3!!"!!E`!"+R$rB!!"I#m-)Qhr'#"C6T!!+Ql[p#"Yra")D!"')Qhr)#"\rC6T!!+Ql[p#mYra!["#m,)Qhr&#"C6T!!+Ql[p%U!@%pQ&#mYra!LEImF)&P1N!!\rUEZrdB!!!e%Ki!!S[#b*Yrb3J@8k3!#TZlr3N3%U!C`*#%NU&C`!!XLm-,bhrU#*\rYraJJ@8k3!#TZlr3JEIm35'J!4L*Yrb!J@8k3!#TZlr3[,Im35(J3!%KZlrJLEIm\r8)&P1N!!UEZrd5S"36fB5,bhr%#*Yra`J@8k3!#TZlr4JA%Ki!!T)EZri)Qhr*#"\rC6T!!+Ql[p#4!5S"R!N)55'l[q#m,)Qhr,#"C6T!!+Ql[p%U!CbJ[,IqN)Qhr'#"\rC6T!!+Ql[p#"Yra")D!"')Qhr)#"C6T!!+Ql[p&K2B!*f!8U$C`$qfNU$CK)["%+\rR,`XLEIp!)&P1N!!UEZrd,bhrS#*YraJJ@8k3!#TZlr4+K9K2CaC)H"!!3UG)EZr\ri)Qhr3#"C6T!!+Ql[p#!%8i"#-`J!)!0A`%3!5F"-ha`i6Pj1G!!3NQ4PFepbC@&\rNAh"hAh0dFQPZC`!!!#T46PEr0%MR(c`QEJ!)+'i!$#e,rc4k!8AZrlJJ5h$r8S"\r+''Ek,J")H!"!3UG)E[qi)Qhr3#"C6T!!+Qlr-(`"B$S@'dR$H!"J'NU&C`SJ!h)\r"`)'a'Q!))!0b!F#"X5,LLe+%F!DiJ'rJF!I!KQB+)!9A`%3!5F!U!&+'[)GM`NA\rZrlJQ6(`!B"jf!(J!B!iJ"&+!%KT*`H'TKS&5K(!'Z)"[l"E$8SC`"lb!Bp`[$#*\rYrq`J@8k3!#TZrc")E[mi,``LEIr))&P1N!!UE[m`,`a)E[mi,`F[$#mZrc4Krrr\rrh%T)H!#!3UG)E[mi)Qhr3#"C6T!!+Qlr-#m-)Qhrl#"C6T!!+Qlr-(!!60mFq%j\rH6R3!#*&NCA0IFh4bD@jRAh4[AfYPH3!!+P&19[ri51F30#4Z!!`QEJ!)GJ![,Iq\r8,`SLEImm)&P1N!!UE[rd8%pJ0R!!%"X[!#mYrj!!,`SLEImm)&P1N!!UE[rdF!L\rfJ%r[!!aX&#mYri`[#L*Yrc`J@8k3!#TZrr436b!$8S0b#,#"EF![,Iq),`SLEIm\rm)&P1N!!UE[rd8%p-h``)6Pj1G!!)P@4PFepMBQa[BfYIF(*TER4ICQPXC3!!+P&\r19[ri51F30#CZ!!JNEIq%GJ"J)NKi!!J[#b"+8)T)8#*Yrc3J@8k3!#TZrr4+J'B\r%F!&J#P+$F"#fJ'ABF!"-h``)6Pj1G!!%Mf4PFepTFephC@&VAfYPH3!!+P&19[r\rF51FI2#`Z!!`Q,J!J*'i!&#CZ!"JSEJ!F5Ui!*'F!$)`Z!b"(8SGk!"S3FKMMV5"\r(8SG`!"!3FK$MU)U!)%G5Kh!!%"$KL)U!)%G5Kh!!%"#+J#"(8SGi!"J3FKMMV#"\r(8SG`!"!3FK$MU)L!)%G5Kh!!%"$KL)L!)%G5Kh!!%"#)J#iZ!!JY4[rdB!!-%R!\r)X+i!%'i!!*iJ4e+(F!!3%!+!!!!!rh)BikLaK5"(8SG`!"!3!S!!!!$rFK$MU,'\r&)%G5Kh!!%"!#J!!!!2rKL,'&)%G5Kh!!%"!#J!!!!2qaK5"(8SG`!"!3!S!!!!$\rrFKMMU,'%)%G5Kh!!%"!#J!!!!2pb%11SXB3J4e+(F!!3%!+!!!!!rq')XB3J4e+\r(F!!3%!+!!!!!rl'%8Di!%'!!!,6HVJ!3)#i!%!b!!!!!"f)!!*i`1`)'6[X!!J#\r8!)!!E!"D!%S!0J!L!""6Kb"(F!!3%!+!!!!!rq')XB46Kb"(F!!3%!+!!!!!rh)\r3ikLaK&1()%G`!"!3!S!!!!$rFKMMU,'%8iFJ4h!!%"!#J!!!!2qaK91()%G`!"!\r3!S!!!!$riBLaK91()%G`!"!3!S!!!!$rFK$MU,'&8iFJ4h!!%"!#J!!!!2pb'11\rSXB9#VJ!3)!3#J+U3"1+)*J8#JkU3")D!)!3#J&@3"#)&!S&9N!65JB+!+!%U"()\r3iUd#K3!!!2mJEIrm+M"F!0U&)J4d'15T!S%!!!$r)'hrr)U`(!!L"1#*!S%!!!$\rr)'hrr#)`(!$PLB+&+J3#K3!!!2mJEIrm+M"F!1H0LS%S!h)3iU`#K!!!!2mJEIr\rm+$"-!0L%)J0d'15T!S%!!!$r)'hrr)L`(!!L!q#*!S%!!!$r)'hrr#)`(!$PLB+\r%+!-#K!!!!2mJEIrm+$"-!1H-L)&m!'!!!CJQ"()9ikXL"(3,j+Q#JbBDXi0`2b)\r$G"MNUF+!)'hrq(!r*!-Y32rFF"$JUX5ZrpcPLL*YrrM6`L!T!3#!X"`!FMmN!q#\r+a)(PLL"YrrM4`S#S!J"b2m+$jBNJEIridF'!U!-!XB8Q"()*ikXL"(3Aj+Q#JbB\rDXi0`2b)$G"$NUF+!jBNJEIridF&`2b)$G"MNUF+!jBNLEIridm%J+33!J+J&!()\rr*!2JLX5"jBSJEIridF+!U!B!FMr#Jq@*)'hrq0("J+J(!,'&*J9b&H1V)J9d#q5\rTJS-Q'V1$F$mL!h3Bj+R#J#"YrrK`2b3$,8$rh(!3i+V%V[rFjBSLEIridm)J+3%\r!J,!F!()r*!2JLX5"jBSJEIridF+!U!)!FMr#Jq@*)'hrq0("J+J$!,'%*J9b#H1\rV)J9d&q5TJS-Q'V1$F$mL!h33j+R#J1@*)'hrq0("F$mL!h3Bj+R#J1@*)Qhrq02\r")#N%!)#S"3"b2b3$i)V%JH@+)'hrq0(#J+J'!()r`S2PL5"YrrM4`B#S"`#aK&+\r'F!LmJ'd!rQ3J"3+!m*!%k)JQ"!+$m*!%KS!J"3+!$j!%)J3#J3q3"1Q*JS!S!5S\r%FK$LV3+&!!!!rb"Yrr3U-&`!kBdL"(3Bj+N#J3!!!2mJEIrd)M!F!1f*JS8U"1#\r0!S8!!!$r)'hrp#S`A!$PMBU")J3#J3!!!2mJEIrdLV!F!#J$FK$LV!+%!!!!rb"\rYrr3S-%`!kB`L!h3Bj+N#J3!!!2mJEIrd)M!F!1f*JS3S!q#-!S3!!!$r)'hrp#J\r`6!$PM)L")J-#J3!!!2mJEIrdL,!F!%AUri!J"!+!UT!%iSJQ"3+$UT!%KS!J"!+\r!9C!%)J8#J9@3"0+"JS!S!5S%FK$LV3+&!!!!rb"Yrr`U-&`!fS8L"(3Bj+N#J3!\r!!2mJEIrmLV!F!#)%i)N#J3!!!2mJEIrm)M!F!1@*JS8U"!+&!!!!rb"Yrr`U-&`\r!jif+J5J$FK$LV!+%!!!!rb"Yrr`S-%`!f)3L!h3Bj+N#J3!!!2mJEIrmL,!F!#)\r$i)N#J3!!!2mJEIrm)M!F!1@*JS3S!`+%!!!!rb"Yrr`S-%`!jib)J8IV!)"m!'!\r!!FJQ"()*ikXL"(3Aj+Q#JbBMXi0`2b)$i)R#J1@*)'hrq0("F$r!Jq@))Qhrq02\r!)#N(!)#S"J"b2b3$,8$rh(!3i+V%JH@+)'hrq0(#)#J&!)#Zrpab2b3$,8(ri()\rBiUV%V[rJjBSJEIridF+!U!3!XB8Q"()9ikXL"(3,j+Q#JbBMXi0`2b)$G"MNUF+\r!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJL-"`!)'hrq0(!)#J$!)#T!J"d2be\r!rq!J!be"rpab%1+S`),PL#"YrrM4`#!S!3#!V[rJJ+lrh,'&*J9b#H1V)J9d&q5\rTJS-Q)l1$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*YrrM6`#!T"`#!U!B!FMmN!be\r!rq"`%1#Ua)(PLL"YrrM4`L!S"3#!V[rJFMmN!be"rpab'1+Ua+lrh1@+)'hrq0(\r#J+J%!,'%*J9b&H1V)J9d#q5TJS-Q)l1$F$mL!h3Bj+R#J#"YrrK`2b3$i)V%J1@\r+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)!G$mY32rJ)!-Y3IrFFK$LU-#\r#jBJJEIridF!J+!%!J+lri)#ZrpbaK&+'F!LmJ'd!rM3J"3+!m*!%k)JQ"!+$m*!\r%KS!J"3+!$j!%)J3#J3q3"1Q*JS!S!5S%FK$LV3+&!!!!rb"Yrr3U-&`!kBdL"(3\rBj+N#J3!!!2mJEIrd)M!F!1f*JS8U"1#0!S8!!!$r)'hrp#S`A!$PMBU")J3#J3!\r!!2mJEIrdLV!F!#J$FK$LV!+%!!!!rb"Yrr3S-%`!kB`L!h3Bj+N#J3!!!2mJEIr\rd)M!F!1f*JS3S!q#-!S3!!!$r)'hrp#J`6!$PM)L")J-#J3!!!2mJEIrdL,!F!#!\r%!S#UN!6LL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$\rr)'hrr#S`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`\r!jBQ#K5S%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)\r$G"MNU3+"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$\rr)'hrr#J`6!$RM)L"I!"J!!'B*J4b&H1V)J4d#q5TJS-Q(,1$F$mL!h3Bj+R#J#"\rYrrK`2b3$,8$ri(!3i+V%V[rJjBSLEIridm)J+3%!J,!F!()r*!2JLX5"jBSJEIr\ridF+!U!)!FMr#Jq@*)'hrq0("J+J$!,'&*J4b#H1V)J4d&q5TJS-Q(,1$F$mL!h3\r3j+R#J1@*)'hrq0("F$mL!h3Bj+R#J1@*)Qhrq02")#N%!)#S"3"b2b3$i)V%JH@\r+)'hrq0(#J+J'!()r`S2PL5"YrrM4`B#S"`#aK5B&FKAMUb)&G![NUB+$*KbcJh!\rr)J0d'15T`S!JEIriF$mN!be!rq"`%1#Ua+lri1@+)Qhrq02#)#N"!)#`(!"b2b3\r$i)V%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK#B&FJRMUb)&G"INUB+\r$*KbcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!T"!#!U!8\r!FMmN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB45KR!)[)"Y!2j\rN)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+!+!%U"()3iUd#K3!\r!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+&+J6JM3+&!!!!rb"\rYrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!!!2mJEIrd+$"-!1Q\r-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"Yrr3S-%`!jBb)J5)\r$!S%!!!$r)'hrp)L`(!"*l2q!)!9b'1+S!S!!!!$r)'lrp&+Zrr33J#!&FK$LU!+\r!!!!!rb"Zrr45V[rd%)!J"H#)!S!!!!$r)'lrp&+Zrr33J#!&!S!!!!$r)'lrp&+\rZrr33J#!%FKMLU!+!!!!!rb"Zrr45V[rd%)!J"()3iUJ#J!!!!2mJE[rd8Ulrp"#\r!)!6JL!+!!!!!rb"Zrr45V[rd%)!J"!+!!!!!rb"Zrr45V[rd%)"+VJ!3EJ$ckQ!\r!$0C+VJ!3E`!-cLi$)%G5Kh!!%""b'11S,8$rm#"(8SG`!"!3FK$MU)'Zrr!J4e+\r(F!!3%1')JDlrm#"(8SG`!"!3JDlrm#"(8SG`!"!3FKMMU#e!rq`J4e+(F!!3%()\r3ikL"V[rX)%G5Kh!!%"$KL)'Zrq`J4e+(F!!3%)'Zrq`Z,J!),8Erp#"(8SGk!"S\r3FKMMV5"(8SG`!"!3FK$MU)U!)%G5Kh!!%"$KL)U!)%G5Kh!!%"#+J#"(8SGi!"J\r3FKMMV#"(8SG`!"!3FK$MU)L!)%G5Kh!!%"$KL)L!)%G5Kh!!%"#)J#e&rqJY42r\rN)!3#J+U3"1+)*J8#JkU3")D!)!3#J&@3"#)&!S&9N!65JB+!+!%U"()3iUd#K3!\r!!2mJEIrm+M"F!0U&)J4d'15T!S%!!!$r)'hrr)U`(!!L"1#*!S%!!!$r)'hrr#)\r`(!$PLB+&+J3#K3!!!2mJEIrm+M"F!1H0LS%S!h)3iU`#K!!!!2mJEIrm+$"-!0L\r%)J0d'15T!S%!!!$r)'hrr)L`(!!L!q#*!S%!!!$r)'hrr#)`(!$PLB+%+!-#K!!\r!!2mJEIrm+$"-!1H-L)&*l!#!I!"J!!()*J4b#H1V)J4d&q5TJS-Q*,1$F$mL!q#\r*`S$PL5"YrrM4`A!r`)2PL#*YrrM6`#!T"`#!U!B!FMmN!be!rq"`%1#Ua)(PLL"\rYrrM4`L!S"3#!V[rJFMmN!be"rpab'1+Ua+lrh1@+)'hrq0(#J+J%!,'&*J4b&H1\rV)J4d#q5TJS-Q*,1$F$mL!h3Bj+R#J#"YrrK`2b3$i)V%J1@+)Qhrq02#F$r!Jq@\r))M!F!#"YrrM4`#!S!`#!U3)!G$mY32rJ)!-Y3IrFFK$LU-##jBJJEIridF!J+!%\r!J+lri)#ZrpbaK5B&FJRMUb)&G"INUB+$*L5cJh!r)J2JLF+!jBNJEIridF&`2m#\r$jBJLEIridm!J+3F!J+J'!()r*!-Y32rJF"$JUX5"jBSJEIridF)J+!8!J+lri()\rr*!-Y3IrFFKMLUX5ZrpcPLL"YrrM4`S#S"!#aK#B&FKAMUb)&G![NUB+$*L5cJh!\rr)J0d'15T`S!JEIriF$mN!q#+a)$PLL*YrrM6`R!r`)2PL#)`(!!JEIridF!J+!-\r!J+N#!(3r,8$ri#!$,8(rh()3iUM!JZ@))'hrq0(!)#J"!)#Zrq#!V[rFXB45KR!\r)[)"Y!2id)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+!+!%U"()\r3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+&+J6JM3+\r&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!!!2mJEIr\rd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"Yrr3S-%`\r!jBb)J5)$!S%!!!$r)'hrp)L`(!!J"!+!UT!%iSJQ"3+$UT!%KS!J"!+!9C!%)J8\r#J9@3"0+"JS!S!5S%FK$LV3+&!!!!rb"Yrr`U-&`!fS8L"(3Bj+N#J3!!!2mJEIr\rmLV!F!#)%i)N#J3!!!2mJEIrm)M!F!1@*JS8U"!+&!!!!rb"Yrr`U-&`!jif+J5J\r$FK$LV!+%!!!!rb"Yrr`S-%`!f)3L!h3Bj+N#J3!!!2mJEIrmL,!F!#)$i)N#J3!\r!!2mJEIrm)M!F!1@*JS3S!`+%!!!!rb"Yrr`S-%`!jib)JA`!B!!"Q#B%FKAMUb)\r%G![NUB+$*KZcJh!r)J0d'15T`S!JEIriF$mN!be!rq"`%1#Ua+lri1@+)Qhrq02\r#)#N"!)#`(!"b2b3$i)V%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK5B\r%FJRMUb)%G"INUB+$*KZcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*\rYrrM6`5!T"!#!U!8!FMmN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F\r!XB8Q"A)9ikXL"A3,j+Q#JbBEXi0`2b)$G"MNUF+!)'hrq(!r*!-Y32rJF"$JUX5\rZrq$PLL*YrrM6`L!T!3#!X"`!FMmN!q#+a)(PLL"YrrM4`S#S!J"b2m+$jBNJEIr\ridF'!U!-!XB3Q"A)*ikXL"A3Aj+Q#JbBEXi0`2b)$G"$NUF+!jBNJEIridF&`2b)\r$G"MNUF+!jBNLEIridm%J+33!J+J&!()r*!2JLX5"jBSJEIridF+!U!B!FMr#Jq@\r*)'hrq0("J+J(!,'%8SC`#,b!E3$qC#!&!S$`N!6SL#B%!S2`N!5'J#!&!S!2N!3\rL"!+"$j!%kBQ#J#J"+J4b%1+Y!S8!!!$r)'hrp#S`A!$TM5)%G"MNU3+"!!!!rb"\rYrr3L-"`!lBQ#K5S%i)d#K3!!!2mJEIrd+M"F!1@0LS%L"!+"!!!!rb"Yrr5+X"`\r!+!0b%1+X!S3!!!$r)'hrp#J`6!$TM#)$G"MNU3+"!!!!rb"Yrr3L-"`!lBQ#K#J\r$i)`#K!!!!2mJEIrd+$"-!1@-L)%L!`+"!!!!rb"Yrr5)X"`!4q[rJ#!%!S#UN!6\rLL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$r)'hrr#S\r`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`!jBQ#K5S\r%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)$G"MNU3+\r"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$r)'hrr#J\r`6!$RM)L"4HS!J(`!B!!"b#B%FJRMUb)%G"INUB+$*L+cJh!r)J2JLF+!jBNJEIr\ridF&`2m#$jBJLEIridm!J+3F!J+J'!()r*!-Y32rJF"$JUX5"jBSJEIridF)J+!8\r!J+lri()r*!-Y3IrFFKMLUX5ZrpcPLL"YrrM4`S#S"!#aK5B%FKAMUb)%G![NUB+\r$*L+cJh!r)J0d'15T`S!JEIriF$mN!q#+a)$PLL*YrrM6`R!r`)2PL#)`(!!JEIr\ridF!J+!-!J+N#!(3r,8$ri#!$,8(rh()3iUM!JZ@))'hrq0(!)#J"!)#Zrq#!V[r\rFXB8Q"A)*ikXL"A3Aj+Q#JbBLXi0`2b)$i)R#J1@*)'hrq0("F$r!Jq@))Qhrq02\r!)#N(!)#S"J"b2b3$,8$ri(!3i+V%JH@+)'hrq0(#)#J&!)#Zrq"b2b3$,8(rh()\rBiUV%V[rFjBSJEIridF+!U!3!XB3Q"A)9ikXL"A3,j+Q#JbBLXi0`2b)$G"MNUF+\r!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJL-"`!)'hrq0(!)#J$!)#T!J"d2be\r!rq!J!be"rpab%1+S`),PL#"YrrM4`#!S!3#!V[rJJ+lrh,'%8SC`#,b!E3$q0#!\r&!S$`N!6SL#B%!S2`N!5'J#!&!S!2N!3L"!+"$j!%kBQ#J#J"+J4b%1+Y!S8!!!$\rr)'hrp#S`A!$TM5)%G"MNU3+"!!!!rb"Yrr3L-"`!lBQ#K5S%i)d#K3!!!2mJEIr\rd+M"F!1@0LS%L"!+"!!!!rb"Yrr5+X"`!+!0b%1+X!S3!!!$r)'hrp#J`6!$TM#)\r$G"MNU3+"!!!!rb"Yrr3L-"`!lBQ#K#J$i)`#K!!!!2mJEIrd+$"-!1@-L)%L!`+\r"!!!!rb"Yrr5)X"`!)#lrm,'&)#lrl,'%F!L`VJ!3E!!!ZP'Z!"!J"A)BiUJ#J!!\r!!2mJE[rd8Ulrp"#!)!9b%1+S!S!!!!$r)'lrp&+Zrr33J#!&i)J#J!!!!2mJE[r\rd8Ulrp"#!)!8#J!!!!2mJE[rd8Ulrp"#!)!4b'1+S!S!!!!$r)'lrp&+Zrr33J#!\r%FK$LU!+!!!!!rb"Zrr45V[rd%)!J"1#)!S!!!!$r)'lrp&+Zrr33J#!%!S!!!!$\rr)'lrp&+Zrr33J#eZrqMrm#eZrq6rl'!!p)JJ,J!3dDlrp#!Z!"!-J!!!!!KL!!$\r!-$X#"Nll!!)!YJ#J!)S!GJ"N!%i!1!!N!")J"!+!!!!!re1Zrr3JE[rd%)!J"1#\r)!S!!!!$r8klrp#"Zrr33J#!%FK$LU!+!!!!!re1Zrr3JE[rd%)!J"()BiUJ#J!!\r!!2p6V[rd)'lrp"#!)!8#J!!!!2p6V[rd)'lrp"#!)!AJL!+!!!!!re1Zrr3JE[r\rd%)!J"A)3iUJ#J!!!!2p6V[rd)'lrp"#!)!9b'1+S!S!!!!$r8klrp#"Zrr33J%c\rI(2K1ANjd!##3!'4PFemcBf*MAf9ZBh*jF(3!!!!U88j@rpK)jam`*Qi!$#4Z!!K\rf!"BDF!!3'Z')KS"`!"!DFK$MU)D!F!!3'R)BikL'J(J!'"T`!"!DiBL)J(!!%"T\rb%11SL)"`!"!DFKMMU)L!,!6SMVH'!SB2N!5pJb!'kBLaK#`$FK,MVVH'!SE-c!!\r!)!1pJ#)'G",NUE'"*J%X"()5ikkjKJ+'c-`!!#!%[B!L"R35j+QaJ5J",!6LMVH\r'!SC9N!5pJb!'d)#aK#`$i)kjKJ+'!2m!rlf%)!EKL,'$,!6LMVH'!SC9N!5pJb!\r'd)#aK#!%!S!!!2m!)J3#J3!!!2pd%1@TJS!J"!+!!2m!!(33j+L!J5)$!S(`!!!\r!k)Q#J#J"!S-2rrrrIJ"J!!(#)'hrI%U`I!"R(L!$FKVMU#)$j)Q#J#B")!4b'Z1\rS)J6NLB+!+!&J(#!$FK[MU#)$iSQ#J#B")!4b'q1S)J6LLB+!+!%#J`rrrrm#K!r\rrrrp`2m#$)'hrH()m*!2ZLX5"FJ-YF!`!rpJJ!qb)`)'!JZ@))'hrH0(!)#J"!)#\rZrpKb-#3$,8(rh()1iUV%V[rFFJmY3[rJ*!-Y32rNF!hJUX5"K+lri1@+)'hrH0(\r#)#J#!)#Zrq4b"L3$,8(rk()9iUV%V[rSFJ%Y3[rX*!-Y32r`F"6JUX5"K+lrl(!\ri)J-Y3[rdG"ENUF+!JUlrp1@*)'hrH0(")#J$!)#Zrr!N3(`m)J6JLF+'I!-N"1k\r+a)D%JH@+)'hrH0(#I$r-K1@1)QhrH02',#N%!)bS"3"b2b3%,8Erp(`2l+V%JH@\r+)'hrH0(#,#J'!)bZrr4b-#3%,8(rm()@iUV%V[r`FJmY3[rX*!3Y4[rSI"AXUX5\r"K+lrl1@+)'hrH0(#,#J(!)bZrqJJ#J+!!!$rrbS'G"$PVBU!)!APL#)&G"lNUG+\r!*X%J"J+!rrm!!#S+G"$NVBU!)!AYL#)&G"VNUG+!*X&5Kh!3[S"Y!2ikF!"-h`c\ri6Pj1G!!)Lf4PFepcCA4IDf9j!!!U88j@rrJ[$5mYrh![,J!-,bi!##*Yrf3J@8k\r3!#TZrr3J,Ip`6Pj1G!!)L@4PFepMFRP`G!!!+P&19[pF51FI2#KZ!!JS,J!-*'i\r!%%IZrqiJ4%S3CJ4`3@!')%33%%R!&)"*`#B!)'hrE(S!'M!i!1@0)%4++!!"CJ4\r`3@!))%33+!!"5F!93!!"5F!Q!#"Yrfam!"``1!$YMRi!B"BB(%S%Cb*`!"!%d)"\r"l[rQ%B"i!&+(F!LqJ'ANB!T"l[rQ3M"i!&+(F!LqJ'A`5'lrANKZrqBLEIpd)&P\r1N!!UE[pB,`B["8KZrej)E[rHBIm!!!$Q*LlrhL!$!S!!!!$r&X!J!q#)!S!!!!$\rr&X!J!h)3iUJ#J!!!!2m@`#!$FKMLU!+!!!!!raE!*LlriL!$!S!!!!$r&X!J!q#\r)!S!!!!$r&X!J!h)3iUJ#J!!!!2m@`#!$FKMLU!+!!!!!raE!I!!@2!#!3LlrpRi\r#B%*i!(S!B#EB"(!!%!0"l[rZFJ!5-'J!`S"R"!!%!!(L#dS$CJC5KKBm!)"5KA!\r'ZS"Pe(!!%!3JEIpS&E!!!(J!8SG`$Ek!CEK#+J!0)!T-haci6Pj1G!!-LQ4PFep\rQBh*jF(3!!!!U88j@rma)j`mB)QhrB(S!I!!SEJ!-,@i!%2r8,@i!&2r33Ulrc'!\r!"%#Abf!!"#JJ"R33j+JN"V'#+!,)V[r8a+lrd#i%FK$MVb!')M5m!,1!XB5rK#i\r#FK$MVb!,8S!L"L!d$!#aJE1#[i)J"1#!,8$rp#i%!SF!!!$m!Ui!!!$mrr3J!R)\rFikJL!ZL*dS!N!A!3i+`J-AJ!XB8J5G(Zrr3J+!)!XB8J"1#),8$rm#i%!SF!!!$\rm!Ui!!!$mrr!J5G(()#J%!,'&)%R4l[r`)#J'!,'&)!,JJ#e!rr3Z!J+(!!!!r!+\rZ!!!!r2rdF"$JUL"*dFFJ+!%!XB8J5G(Zrr3J+!-!XB8J!Z#!,8$rm#i#!SF!!!$\rm!Ui!!!$mrr!J5G(()#J&!,'&)%R4l[r`)#J(!,'&)!9d%15S*!@aJLJ#b+lre-5\rZrp!Z"()3ikmJ#e5!)J8J0!`!XB'cK,q%,J*b%11[)!Y@J#)&)$3-!,'"Xi+rJL!\r%i)!Y32rX,J3#K`!!!2`#VJ!!!2crl#!#FKcMU#)#k)R5J#3"F"$JV#!aH!#aKL"\r*dHlrl#!S!J#aKL!%i)JY32rS,J3#K`!!!2`#VJ!!!2crk#"*dFFJ+!3!XBBJ5G(\rZrqJJ+!B!XBBJ!Z#!,8$rl#i#!SF!!!$m!Ui!!!$mrqa`%1#U)%R4ab!S!3#aKL"\r*dHlrl#!S!`#aKL!#i)!Y32rS,J)#K`!!!2`#VJ!!!2crk#"*dFFJ+!8!XBBJ5G(\rZrqJJ+!F!XBBJ"R33j+JN"V'#+!,)V[r8a+lrd#i%FK$MVb!,@)!L"L!d$!#aJE1\r%[i3Z!R)3ikmJ#eU!)JBJ0!`!XB'cJVq#)!6JJ#e!rq3Z"!+(!!!!r!+Z!!!!r2r\rN)!*b(11S)J,SLG+!*!&`%1#X)$&i!,'&)%R4l[rN)#J#!,'&)!6JL#e!rq!Z"!+\r(!!!!r!+Z!!!!r2rJ)%R4ab!S"!#aK5"*dHlri#!S"J#aK5!#i)!Y32rN,J)#K`!\r!!2`#VJ!!!2crj(!3i+SJ5G(()#J"!,'&)%R4l[rN)#J$!,'&)!,JJ#e!rq!Z!J+\r(!!!!r!+Z!!!!r2rJ)%R4ab!S"3#aK5"*dHlri#!S"`#aK5!&G"$NU#3&XB)S!XL\rZrp6%V[r3,J4b%11[)!YFJ#)&)$3-!,'"Xi5rK#i#FK$MVb!,AS!L"5!d$!#aJE1\r#[i)J"1#!,8$rh#i%!SF!!!$m!Ui!!!$mrp`J!R)FikJL!ZL*dS!N!A!3i+`J-AJ\r!XBBJ5G(Zrp`J+!)!XBBJ"1#),8$rf#i%!SF!!!$m!Ui!!!$mrpJJ5G(()#J%!,'\r')%R4l[rB)#J'!,'')!,JJ#e!rp`Z!J+(!!!!r!+Z!!!!r2rFF"$JUL"*dFFJ+!%\r!XBBJ5G(Zrp`J+!-!XBBJ!Z#!,8$rf#i#!SF!!!$m!Ui!!!$mrpJJ5G(()#J&!,'\r')%R4l[rB)#J(!,''8)Y`),I!E3$le#3&+JBX!P+Zrma`'E#ZrmaZ!2Zk)!9b(H1\rS)JAQLG+!+J%J"R)GikJL"ZD*dS!X!53&iSUpJJ+#9C!%YBBJ!Y#!XB8N"Z#+Zi)\r#JJ$r!2qeK5!#iBLaKL3&j)UpJJ+#-j!%YBBJ!Z@)XB8N"R)3iUUlJJ+#!!$rrl@\r&)!*b%11SXBBN"HL+[B)#JJq3",@')!,TL,'&)'i!###')'i!##&&!!4-haM`6Pj\r1G!!3LfCMFRP`G&pLEf4j!!!U88j@rrK)ja`m+Li!##4Z!!`S,J!3+'i!&#CZ!"J\rQ,J!F5S0R4Lm$,`3[#Lm&)Qhrm#"C6T!!+Qlrp#!$9m"%!%R!,`![$#m+,`SLEIr\r`)&P1N!!UE[rd,`-[#bm+,`SLEIr`)&P1N!!UE[rdB%3[!bm,,`S["5*Yrr!J@8k\r3!#TZrr3J!eI!4!"*`#m!,``[#Lm+)Qhrm#"C6T!!+Qlrp#m$,`3[#Lm+)Qhrm#"\rC6T!!+Qlrp%cI($K1ANjd!"L3!'4PFemcC@0LAf9ZBh*jF(3!!!"PC!dK%)%$"J!\r3!!!3%"!!!"!!%"!3!"!3%!3K%!3K%!)L%"!%)4#"!`X3!"!!%*!&!!!"%!!"!"!\r"%"!"!!!4%!!4!"!4%"!4"L%"!L%"!b)"!3%K!3-K!3%K!3%L!3%#*!'3"!-K!3)\rL!3%")3%")3%"*!'3"!)L!3%"*!'3"53"N!3%)3%%)3%#)J%""#%"!5%"!5%"!L)\r"!3%M!3%"##%%J3-0!3!!!3!%!!3!!!3%!33!!33%!!!J!!!N!3!J!3!N!!3J!!3\rN!33J*!%%*!%$)3%#)`3"!3)L!3%")J3"!5%%!5%"!58%"!%""!%P!3%%"!%#)L!\r"!L-N!3%")b!"!3%L*!%")`3J!3%U"#3"!33J!3%%*)%$$`)!!!)!"!-!!!-!"!)\r%!!)%"!-%!!-%"!)!)!)!*!-!)!-!*!)%)!)%*!-%)#8$"#3"!J)L!3)")`3"!`)\rL!3-"*!3"!J3"*`%#"!3"!`3"*J%$"!3"!J%M)!%#!5-N!3-")b!"!`%a*!%#"#!\r"!J3N!3-%)!%$"#3%)3)&)3J")3)")3J#)3J#)J))!b))#!%M!JJ)"#)"!J)K!3)\rM#!%#!5))!3%K#!%M!3))!5%"!5F)#!%##!J"!L%"J3-(!J!"!!!*!J!*!!J"!JJ\r"!!J*!JJ*!L-"!3)")J%"!L-*!3)")JN"!5F)!3%##!%"!5J)#3%##!N"%!-K%J-\rK%!%K#!%K%J%K#!%L%!J#)K))!L-3#!J")a))#!%K%!)L!4)#)J%3!5-)!4)"*!J\r"%!J")`%5#!%U!4!)#!%5#!J"%!%K!B%$"a)!!4!!#4)!#4!)!4))!4!)#4))#5%\r3!5-"!4)")`%"%!%M#3%5!6)*!4!)!3%5#!%"%!J*!4))#3%&)33%)5##!J3%)"!\r!&!!3)#)8))%$##!!!#!%!#!!)#!%)#!3!#!8!#!3)#!8)!-K#)%$"J3!#!!J#!3\rJ#"!!#"3!#"!J##38)!JJ!L-))!3")JJJ!5JJ##!%)!JJ%!%M##!8!5N))"!J##!\r8)!L"!`FJ!!!N!!!J)!!N)!!`!!!d!!!`)!!L0##"!`JJ)!!J*!!JN!3N)#!`!#!\rd!#!`)#!d)!%K)!%K#)%$"L3!##!J##3J#$!!#$3!#$!J##8d)!JJ)!%M##!N!5X\r))#!J##!N)!JJ-!%M##!d!5N))$!J##!d)!J()K!)J3-r!!!)!"!!!J!!!K!)!J!\r)!K!!!!)!!"))!!))!")!!J)!!K))!J))!K)%!!!%!"!-!!!-!"!%!J!%!K!-!J!\r-!K!%!!)%!")-!!)-!")%!J)%!K)-!J)-!K)!%!!!%"!)%!!)%"!!%J!!%K!)%J!\r)%K!!%!)!%"))%!))%")!%J)!%K))%J))%K)%%!!%%"!-%!!-%"!%%J!%%K!-%J!\r-%K!%%!)%%")-%!)-%")%%J)%%K)-%J)-%K)!!!!#!b%#!L)#!J3K!3%K!J%K!3)\rL!J%")`)#!33L#!)#)3J")3)")`J#!J%K#!)M!3J#!5)"#!%R!J%)!J)"#!%K)!)\rL!L!$)5)#)J)L!b)J!3%M!L!"!L)L!3%M!L)"!L%J!5-)!L!")3J")5)")`J#)J%\rK#!%R)!%)!L!"#!%R)J%)!L)"#!)K!S%$"`)!!J!#N!8!!!-#!!-!!J-#!J-#)`)\r)!J%L!JJ"*`)##!)#!JJ#)`-)!J%L!`J"*`)$#!)#!`J")L!#J3-(!L!#!#)#!L)\r#!#!$!L!$!#)$!L)$!5FJ!JJ#)!))!5FL!JJ#)J))!5FJ!`J#)!-)!5FL!`J#)J-\r)"L%3"#%J!L)3)!%K%!-L%"!#)4!")5!"*"!3)!J$)3J")4!")3J#)L!)!533)!J\r3!L-)%"!")JJ3!58J#"!3))%$"`!!"!!3"!!!*!!3*"!!""!3""!!*#33%#3)!L)\r%#!%M%!3)!L)N#!%N%#3)%!%R"!J3%!3)%!%P*!J3%#5"!`F!"!!!&!!!"#!!&#!\r3"!!3&!!3"#!N%"3J#!%K"!%K#!%K&!%K#!%M"#!)!588)!J3"!%M#"!8!5J)%!3\rJ#"!8))%$"`!%"!!8"!!%*!!8*"!%""!8""!%*#33)!5-%"!J")a3%#!%M"#3\r)!6)8*!J3"!3)%"3%#"!%*!J3%)4!%)3%#)K!""5)#%!)K!J%K!3%M!K!"!5%\r#!L%J!5%3!5%J!L)")!%M%!%J!b-J!K!")L!#!5F")!)3!5!#!5%%J3-(!"!%!!!\r&!"!&!!!%!K!%!J!&!K!&)3)")J3J!5-3"#!#)J8J!5-3"5!#*`3J!K!%)!)"+!8\rJ!K!&)!)J!b%`!b)J!3)L-!%#)5!#)J)`!L-#)!%")`)`!3%L!L!")5!")6!")5!\r")b!")!%M-!%J!5%J!5-J!M!",#!#)!%J!M!")!)J")%$"`!`"!!J"3!`"3!J"!)\r`"!)J"3)`"53#)!3J!5-`"#!")b!&)!%M-!8J!6!J"#!#-!3J!L!&)!)`"5!#"#%\r%"L)""))#$!%"!!8!!3%&!3!3""!!%334!4!&%!%4"5%4!5%)J3-2!!3)!!!)!33\r)!3%)!!8)!!%)!38)!3!)%!3)%!!)%33)%3%)%!8)%!%)%38))4%#)3J")35"!`i\r)!!!)!33)!3%)!!8)!!%)!38)!3!)%!3)%!!)%33)%3%)%!8)%!%)%38L#"%")JJ\r)!5-%#!J#+JJ)!33)#!%"#!J")`8)#!%S!3J)!38)#!%"*`J)%!3)#"!"0`J)%33\r)#"%"#!J3"3J)%!%)#"%&#!J4"b%3JJ)0!!%!%4!!%"!3!4!4!3!"%!%"!4%4!"%\r3%3%L%4'"!bm3!!!3!"!3!!%3!"%3%!!3N!8"%"!4%!%!%!%3%!%"%!%4%"%!%"%\r3%"%"%"%4!3!!!3!3!3!"!3!4!4!!!4!3!4!"!4!4!3%!!3%3!C!&%3%4!!%4%!%\r4!3%4%4%!!"%!%"%!!4%!%4%3!"%3%"%3!4%3%4%"!"%"%"%"!4%"%4%4!"%4%"%\r4!534%4%3J3-2!!!3!"!3!!%3!"%3%!!3N!8"%"!4%!%!%!%3%!%"%!%4%"%!%"%\r3%"%"%#34%4!3!L)3%!%M%"!3!5-"%"!"*"%3%"!",a#3"`%3%"!4%"!"!5m3%!%\r3%"!"!4!3!4%3%"%",K!3%4!3%"%"%"!4%4!"!L)3!3%M%"!"!5-"%!%"*"%3!4!\r",a!"%"!3!4!"%!%3%4!"!3%[%!%"%"!"!3%3!3%4%!%4!5i3!4%3%!%4!4!"%4%\r3%3)L%"%")a!3%3%M!4!4!534%"%3!5m3%4!3%"%3!4!4%"%3%3%",a!4!4!3%3%\r"%"%"%4!4%3%Y%"%4%"!4%3%3%4%4!B%$$`!!!3!3!3!"!3!4!4!!!4!3!4!"!4!\r4!3%!!3%3!C!&%3%4!!%4%!%4!3%N%4%"%!)L!4!")a!"%!%M!3%3!534!4!3!5m\r"%"!3!4!3!3%3%"%"%!%",`%3!4!"%!%"!4!"%3%3%3%Z!4!4%!%3%3%"%"%4!3%\r#)J%"!5-3!3%")`'3"#34!3%3!5m"!4!3!3%3!3%"%"%"N!3[!3%"%!'3"a%"!4%\r",J%"%4!"!4%"!3%4%3%4!L)"%3%M%!%4!5-"!4%"*"%"%4!",`%4%"!"%4!"!4%\r3%3%4!3%[!4%"%!%4!3%"%3%4!4%4!5d"%4%3!4%4!3%4N!5"!`m!!"%!%"%!!4%\r!%4%3!"%3%"%3!4%3%4%"!"%"%"%"!4%"%4%4!"%4%"%4!4%N%4%4%!)L%4!")a!\r4%!%M!4%3!534%4!3!5m4%"!3%4!3!4%3%"%4%!%",a%3!4!4%!%"%4!"%4%3%3%\rZ%4!4%"%3%3%4%"%4%3%#)K%"!5-3%3%")`%4!3%N%4%"%!%[%3%3%"%"%!%4!4!\r4%3%"!5m4!3%3%3%"!4%"!4%4!4%",K%"%4!4!4%"%3%4N!3#)K%4!5-3%4%")`%\r4%3%N%4%4%!%[%4%3%"%4%!%4%4!4%4%"!5m4%3%3%4%"!4%4!4'3"!%X%4%4%"%\r4%3%4N!3%)3)%)3)#)J)#"#%#!5%#!5%#!L)#!J%M!J)#"#)#!J)K!J%K!J%M!J)\r#!5%#!L-#!J)")J)#!5J#N!F"!b%$!b)"!J)L!`)#)3%")3)")3-")3)")`%#!J%\rM!`)#!5%"!L)#!`)M!J%#!5-#!`)")J)"!5-#!J-"+J)#!3)#!J-#!J)")3%#)J)\r"!b%$!L)#!`-L!3)")`)"!J)L!`)")`)$!J)K!3%M!J)"!5%#!5%$!5-#!J-")3)\r"*`%#!J)"!J)"+3-#!J)$!J)"!3)L!`%#)J%$!L)$!`)M!3%#!5-$!3)")`%$!J%\rM!`-#!5)"!3%M!J-"!5-#!3-")`)$!`%a!J%"!J)$!3)#!3-#!J-$!J)#)3'"!`F\r#!!%!!J%#!J%!!!-#!!-!!J-#!J-#)`%#!J%L!3)"*`)"!J)#!3)#)`-#!J%L!`)\r"+!)$!J)#!`)"!5%"J3-(!`!"!3)"!`)"!3!$!`!$!3)$!`)$)3%")`%#!`%V!3)\r"!J%#!`)"!J%")`-#!`%U!`)"!J-#!`)$!J%L!3'"!`F#!3%!!`%#!`%!!3-#!3-\r!!`-#!`-"*`%"!J)"!3)"*`-"!J)$!3)"*`%$!J)"!`)"+J-$!J)$!`)"!3'"!`F\r$!3%"!`%$!`%"!3-$!3-"!j!&)#!"!3%#!`%"!J%$!3)$!`%#!3%$!J-"!`)"!`-\r#!`-$!J-L!3)#)3%")3)")`%#!J%K!3)M!J%#!5)#!3%R!J)"!J)#!3-L!`)#)3-\r")3)")`-#!J%K!`)M!J-#!5)#!`%S!J)$!J)#!`%#)J%$!L-"!3)")`%$!J%L!3%\r")`)"!`%V!J%"!J)"!`)#!3%#)J-$!L-$!3)")`-$!J%L!`%")`)$!`%U!J-"!J)\r$!`)#!`%K!3%M!3)"!5%"!5%$!5-"!J-")3%"*`%#!3)"!J%"*`-#!3)$!J%")3%\r")`-#!3%K!`%K!`%M!`)$!5%$!5F"!J-#!3)$!5N$!J-#!`)$!3%")`%$!3%M!3%\r$!5-"!`-"-`%"!3)"!`%#!3%$!J%$!`)"N!3M!`-"!5-$!3-")`-$!`%a!`%"!J-\r$!3)$!3-#!`-$!J-#)`%"!J%L!3%"*`)"!3)#!3%#)`-"!J%L!`%"*`)$!3)#!`%\r#)`%$!J%L!3-"*`)"!`)#!3-#)`-$!J%L!`-"+!)$!`)#!`-"!5-"!3-"+`%"!3)\r"!3-#!C!%)`-"!`%V!`%"!J-"!`)$!3%")`%$!`%V!3-"!J%$!`)"!`%")`-$!`%\rU!`-"!J-$!`)$!`%R!3%"!J'3"#F$!3%#!`%"!5F"!`%#!3-"!5F$!`%#!`-"!5F\r"!3-#!3%$!5F$!3-#!`%$!5F"!`-#!3-$!5"(!`-$!J-$!`'3"!-"N!3$!3%$!`'\r3"!-"!`%$!3%$!`%$!`-"N!3$!`%"!`%$!3-$!`%$!3%$!`-"!`-"!j!(!5%3!L)\r#%!%L!3)")J3""L%%!5%#!5)%!3%Q%!3"!K!%!53#%!3"!5%3"L%#!L%"!b)"!J-\rL!K!")3%#)`3"!J%K"!)M%!3"!5%3!5)"!J%K"!%K!J)M!3)3!L-#%!3#)4!")`%\r#%!3K"!-Q"!%#%!3"!5)3"!3L!3)%)K!%!5%#"#)3"!)K%!)K!J%M"!%#!53%!3)\r3!5-"!K!")3%$)3%")4!")J%#!b%#!5%%!L%3!L-#%!3$)J3"!5B3"!%#%!3$)`3\r"!J)R!3)3"!%#%!-L%!3)*3%#%!3""583"!%#%!3K"!%K!J)L!3)")33$)33#)4!\r")3%")S##"b'!!L1!JJ+"!aL!J!)!JJ)!!!)!J!!!!J#!JJ#!JJ)!!J#!!J+!J!+\r!!*!%!J!#!S!#!)!#!!##!!##!)#!!)#!!)!#!J#!!S!!!S!!!J#!!J8L!J+"!ad\r!JJ+!!!!!J!#!JJ)!!!+!J!#!JJ#!!!#!!!!!!J#!J!)!J!!!JJ#!!!)!!J!!!!+\r!!J)!JJ+!JJ)!J!+!J!#!!J+!!!)!!J)!JJ+!JJ!!!J+!!J#!!J!&)S!#!L'#"L1\r!J!)#*3%%"!%""5)%!3%L"!3")3%'*!%""!3")3%#)3%")J3%!L)%"!)K"!%K!3)\rN"!%""!%K!3%M"!3""#-""!3'*!3%!3%$)3%#)J%"!5)%!3)L"!%")33"*!%""!3\r")J%%!5)"!3)K!3)K"!%L!33$*33%!3%%!L%"!5%%!b-%!3%")33%)3%")33#)J%\r%!5%"!L-%!3%")33")3%()3%#)3%"*J3%!3%%"!%K!3%K"!)K"!)K!38L"!%")J3\r%!5)""!%K!3)K"!-N"!%""!-K"!%M!3%%!5)"!3%K"!)M"!3"!L%%!5)""!)N!33\r%!3-M!3%%!b-%"!%")33")J%""#1!!33")i!""!)K)3)KJ!%K"!8LJ#!$)J%%J3-\r,!#!%J!!%!!%!J#!%J#%!J#%%!!!%J#!!!!%!!#!%!#!%"5%J!L1!)35"!aq!)35\r!!3#!)33!)!#!!!!!)3!!!35!!3!!)3!!!!5!!!3!)3#!!!#!!3!!)!!!!33!)3#\r!)!5!!3#!)!!!)33!!35!)!5!!!#!!3!!)33!)35!!!5!)3!!)35!!33&)L!%!L%\rK"#%%!5+!!3)LJ#!#)B!")33')L!%!L)""!%LJ#!#*)#!3"!")B!")a"!J!%L%%!\r$)8!"*8!33)"!!50!J%!#)B!")4!')N!3!L*!%!%PJ%!33)!#)8!&)8!")d#!3!)\rKJ!8K%!)K3!)MJ%!3"#&!!5&!!L'!!5%3!b333)"!!5*!J!8L%%!")8!")8!#)4!\r#+%!33)"!%%#!!L&!!5&!!50!J%!$)N!3!5@!3""!J!)K3!NL3"!$)K"!!5&!!50\r!J%!")N#!!b1!3"!")B!")a"!J!%L%%!$*N#!3""!J!)L3)!&)4!")S"!!L'!!5%\r3!L9!%%#!3!%L3)!")4!$)K"!!5&!!L1!3"!%)8!")8!%)4!#*%!33"!#)`J3)!3\rK)!%Q%#!J#"!J"58)%#!J#!%K)!)K%!%K)!)M)#!)!5%J!L%3!L%)!5%J!5))%!%\rK)!%K%!8L)!J&)5!")JJ3!5)J#!)K)!)L)#!")4!")L!)!b-)%#!")`J3)!%K#!8\rQ)#!)%#!J!b)J#!%L)#!")a!J)!%K%!-K%!%K)!3M#"!J!5%)!5)J)!%N%#!J#!%\rK)!3M)!J3!L%)!5%J!L%3!5%J!5%3"5-J#"!#*3J3)#!)!5)J)!%L%#!$*L!J#"!\rJ)!8L%#!")3J$)3J#)5!")K!J!b-J)!J#)5!#)5!")JJ3!5)J#!3M%#!J!5%3"#%\rJ!5))%!%M)!J)!5)))!)K#!)K!J)P#!)))!J$)3J")JJJ!b)J#!3K!J%M)!J#!L3\r)!JJJ!5)##!%M#!))!L-###!#)3J%)b!)!J)K#!)L)!J")3J$)JJJ!5)##!)K!J%\rM)!J#!53J#!))!b)))!JL#!)")L!)!L)J#!%K#!)M!JJJ!5%#!b-###!")3)#)`J\r##!-K#!3M)!J#!5%J!L%)!L3###!)!5%)"#)J#!)M)!J#!L))!J%L)!J%)3)#)3J\r")JJJ"#3)!JJJ!5%#!5)J#!)M)!J#!L%)!5%)!5%)!5)))!3N#!)))!%L!JJ#)J)\r)!b)))!)L##!")3)")L!)!b-)!JJ"*8!)3""!!5&!!b&!!L-)3"!")3J&)a"!#!%\rL%%!")d!33!)S%%!)3""!#%!")8!$)8!")8!#)3J&)a"!#!%K%!%L#%!#)3J")K"\r!!5*!%!3K3!8K3!)P#%!33!J$)3J")K"!!L%3"5))3!-P3""!#%!")N!)"#*!%!8\rP#%!33!J")4!")3J#)8!"*%!33!J#)d!)3!-K3!%L3!J#)8!")8!%*4"!#%!3!5-\r)3"!$)4!#)8!")8!&*8!33!K!!L%)!L&!!L%3!5%)!5)33!%M3""!!L%3!5%)!5%\r3!5))3!8K3!%K3!-M3""!!b*!#!%P%%!)3"!")JK!!53"!C!!#!)q#PCPFQPQH@P\rZCb`JF'aPBA0P)(*P,@9ZG'9b)#9c!MJ+"`G0DA0YBA4MD#!Y)(4bH5"KCf&TEJS\r#)3S"*!(RN!!)!L3"ri$-!LBJ-(JJHb!#)L9i!L)X)!)L)(d#))%!!C!)rT!)(j!\r%$T!%i*!%mC!%!Ii"rJ(q!Ilq!Ii"rJ(q!4rJ(q!1m3lai"rJ(r%1m3i"i!(J!I%\r"mH!"i!(a!I%"(riIrJlq$[lq(riIrJlq$J%I!4m"$J%1(`%I!3i"$J(JrZ$qmIl\rar[lJrZ$qmIla#b%"JJ)&!!%!!3!"!!%!!38K!B)#"3!"!!%!!3!"!!%#)#l5dp6\r9eYIBfGVEh0hHhq$KiZ2NjHERk1RUkqcYlZr`mI,cp2AfprMjq[[mrIlr!5#"&3%\r#!`3&"JF)#3S,"3B(#!N+#``0$Jm3%4)6&"8@&aJC'KXF(4iI)#%L)b3P)#%L)b3\rP*LFS+5SV,#dZ,c!a-M-d06Bh1$Nk1c`p2Mp!38*$4#i[-$%b-c3e0MFi18d4\r&4NG)58T,6%e16e"48P0899CA@&PDB@*MC'9QCfKTDQYXE@j[F(&bFh4eGRGiHAS\r"ri#N#5)3)!-K)!)K%!%K!3-K!3%M%#!"!L)J!3%K%!)K#!-M#"!J!5%)!5%J!5)\r)%!%L!3J#*J%)%#!"#!%N)!%)%!-K)!-L-#!#)L!J!L%`!5%"!5%J!5%"!5-`)!%\r")b!J!3%K-!)L##!#)`J`)!%M##!J!5))-!%M!3JJ!5X"#$!J!3JJ)!%)-!%K#)%\r$"`!!#"!J#!!J#"!!#3!!#4!J#3!J#5%3!5))#!)Q#!J3)!J)!53J#!J3!5)*#!)\rQ#3J3)!N)!53J#3J3!5%)J3-()!!)-#!))#!)-!!*)!!*-#!*)#!*)6!")`J))!%\rV#!J`)!J))#!)#$!")`N))!%V#3J`)!N))#!*#$!%)3)&)5!")3)")5!#)5!#)J)\rJ!b)J)!%M!L!J"#)%!J)K"!)M)!3#!5)J"!%K)!%M"!)J!5%%!5FJ)!3#)#!%!L%\r%J3-(!J!%!!!N!J!N!#!%!L!%!#!N!L!N!L-%"!)")J3%!L-N"!)")L3%!5FJ"!3\r#)!3%!5JJ*!3#)#3%%!-K%J-K%!%K)!%K%J%K)!%L%#!#)K)J!L-3)#!")a)J)!%\rK%!)L"")#)J33!5-J"")"*#!%%#!")`35)!%U""!J)!35)#!%%!%K")%$"a)!""!\r!*")!*"!J"")J""!J*")J*#%3!5-%"")")`3%%!%M*!35!6)N""!J"!35)!3%%#!\rN"")J*!3()3%")35"!`d!!!3"!3!!!3!"!33!!33"!!!#!!!$!!3#!!3$!3!#!3!\r$!33#!33K!`)K!J-L!J%")J3#!L3%!J%"!5%#!5%"!58#!3%%!J%N!33#!3)L!J)\r#)J)$!5-%!J)"*!3#!`%")`)#!3%V!J-""!)#!33#!`J$)3J#)`%)")%$$3!)"!%\r*!!!*!!%*"!!*"!%)!!))!!-)"!))"!-*!!)*!!-*"!)*"#)$#!%K!J%K#!%P!J%\r)"!)"*3J%!J%*!5%#!5%*!58#!3N%!J%P#33#!3J")`)##!%V!J-)"!)##!3#!`N\r")`)##3%U!J-*"!)##33#!`8K%!3K!3)L%!%%)3L"!`S3!!J!!3J3!3J!%!!3%!!\r!%3!3%3!!%!J3%!J!%3JN%"%)"!-L""!#)33")3%")`33!3%K"!)M#!33!5))"!%\rR!3J%%!%)"!%K%!%M""!3!5%%!5%4!5-%%"%")33"*a!)""!3#!3"*K%)""!4#)%\r$$`)!!")!!!)"!")"!!)!#")!#!)"#")"#!)3!")3!!)4!")4!!)3#")3#!)4##8\r5%3J%!J)L"")#)`3#!3%M"")"!5)%!J%M#!35!5`)"!)"#!35!3J%!K!")`35%!%\rM"!)4!5-%%K%"-!3#%!J%%K!)"!)4#!35%3J%)4!%)3%#)K!""5)%%!)K"!%K!B%\r$'333!33J!!!`!!!J!3!`!3!J!!3`!!3J!33`!33!%!!3%!!!%3!3%3!!%!33%!3\r!%333%33J%!!`%!!J%3!`%3!J%!3`%!3J%33`%5%%!L%3!5%3!5%3!L)"%!%M%!%\r3!b-3""!")K!%!5J"%!33!4!%)!%K%!%K-!%K%!%M)!%3!5-`!4!")5!")a!%-!%\rU%!3J!4!%-!%3"!%L%"!")a!3%!)L%4!")a!4%!)R%"!%%"!3"!%U%4!%%"%3"#!\r3%!%M-"!3!5-J%4!")c!4%!%`)"!3"$!3%!3J%4!%-"%3"!3K#!BL#!J#)3J#)33\r")3J")33$)`3)#!%L"!J")3)#)JJ#!b%#!5-)#!)")3J")J)%!5-)!J3#*`)%#!J\r#"!J$)J%)J3-'!!%!!!N)!!N!"!%)"!%!"!N))J3*!5%#!5-"#!)")3%")3)")`N\r)!J%K#3%R!J3"#!)%!3%S!J3*#!)%#3+"!`F!!!S!!!)!#!S!#!)%!!S%!!)%#!S\rN"!J#!J)L#J)#)J)#!5-)#J)"*!J#!J3")`S#"!%T!J)%#!S#"!J#J3-(!!%+!!%\r#!!N+!!N#"!%+"!%#"!N+*!3*!J)")`%+!J%M!3)#!5-*#J)"-3N#!J3"#J)%!3)\r#"!N+!J3*"L%"J3-'!!J!!!J"!3!!!3!"!3J!!3J"!b%3!L)"%!%K#!%K%!%N#!%\r3!3)L%!%"*!%3!3J"*4!"#!%3!5%J!b)J!B%$"J!S!!!S!3%J!!%J!3%S!!%S!3%\rK)!%K%!%M)!%3!5%S!5%3!58S!4!")!%R%!%J!4!"+!%P%!%S!4!#)3+"!`F!!!-\r!#!)!#!-"!!)"!!-"#!)"#!-#)J)3!L)$%!%M#!)3!53)!a!"!5-#%!%"+J-3!3J\r#%!%)!a!")L!#J3-(!#!$!#J#!#J$!5!#!5!$!5J#!5J$!5-J!K!")b!$%!%M+!)\r3!6-S!a!")!)3!5!$%!%S!K!"+!-3"#%%"#%%!L)%"!8L!J3#)3)")33")`)%"!%\rK!J)K)!%K"!%K)!)L"#!")`3%)!-M)!)%!5)J!J%R"#!#"!3J!J-L)!3#)5!")33\r")b!%"!%K)!-L)J3#)5)")33")b)%"!%K)J)M)#!%!5)J)!%R"#!J"!3J)!)M)#)\r%!5)J)J%R"#!L"!3J)J)K#!%K"!%K#!)L"!J")`3%#!-M#!)%!5))!J%R"!J#"!3\r)!J)K+!%K"!%K+!)L"#J")`3%+!-M+!)%!5)S!J%R"#J#"!3S!J)M##!%!5)))!%\rR"!JJ"!3))!)M##)%!5)))J%R"!JL"!3))J)M+#!%!5)S)!%R"#JJ"!3S)!)M+#)\r%!5)S)J%U"#JL"!3S)J))#!)K#!)K!J)Q!J))#!)#"#-)#!)")3J")J)#!L%#!5B\r)#!)##!J")J))"#-)!J)")`J#!JJK#!%K!J%K#!8L!J)")3J#)JJ)!5B##!J#!JJ\r%)`J#!J%K#!3K!J)K#!)L#!J")J))!5%#!L%)!5%#!53)!J))!5%###8##!J#!J%\rK#!)K#!%N!J))#!)K#!3M#!)#!5%)!5)##!%K!J)K#!)L#!J")3)#)3)")`J)!J-\rL!J)#)`)##!)N!JJ)!J%L#!J")J))!L%#!5-)!J)&)JJ#!5%)!5%#"5%)!L%#!b%\r#!58)!J))#!3M!J))!5%#!L%)!LF)#!*!%)!3"5)3J!%L3"!#)8!#)4!#)i!33!%\rKJ!)L%)!$)B!")N!3!5%3!b)33!%KJ!)K%!%N%%!3J!%L3"!&)4!")4!#)8!"*)!\r33"!")4!#)B!#*"#!%%!))4!")K"!!5+!%!%Q%)!33"#!!5&!!L)33!3K%!3QJ""\r!%)!3!5%3!5333"#!!5&!!5'!!LF3J""!%)!3!5%3!5)33!)K%!3K3!8LJ"!")4!\r#)N!3!5%3!L'!!5&!"#33J""!!5@!%%!3J!-KJ!8K3!)K%!-P%%!3J"!")K#!!5*\r!%!)L3"!")4!")4!%)i!33!%KJ!%K3!%LJ"!$)a"!%!-L%)!")33#*!%%"!%$)3%\r")33")J%"!5%%!5)""!-K"!%L!3%")J3"!5%%!5%"!L%%!L)%"!8P!33%!3%#)J%\r"!b-""!3")3%&)33"*!%%"!%$)3%$*J%""!3"!3%K"!)K"!)M!33%!5)""!%K!3)\rP"!%""!3$)J3""5%%"#B%!3%%"!%$)3%%)3%")33%)J%"!5%%!5-""!3#)33")J%\r""#-%"!%#)J3"!5)%"!%K!3%K"!%L!33$*!3%!3%$)3%"*!3"!33#)J%%!b3%"!%\r"!5%%!L%%!5%"!5%%!5)"!3%L"!%")33")3%&)J3%!5%"!L-"!33#)3%")`3"!3)\rK!3%L"!3$*%!3#"!")4!%*3J33"!)"#)33!)K%!%L%!J")8!"*!J33"!")4!#)JJ\r3"5-3#"!#)3J")d!3#!%K3!)K%!-L%%!")3J")N!3!b%3"#%)!5*!%!%K%!%N%!J\r33!3K%!-L%!J&)8!"*!J33"!")4!")4!")K"!!58)%%!3#!%K3!)L%%!")3J#)K!\r)!5&!!L%3!L%)!5*!%!%K%!%K%!3M#""!!L%3!5)3#!BK%!)K3!%K#!3L%%!"*!J\r33"!$)4!")4!$*""!%!J")d!3#!%K3!)N%%!3#!-L#"!")4!#)d!3#!%K3!%K#!%\rL3"!")K"!!L%3!5)3#!)M%!J3!b%3!L3)%%!3!5%)"#%""#%%!5B)!33J#!%")L!\r)!5%%!L8""#!)!3-K!38L)!J#)5!")J%%!5%)!53%)!J"!53J#!%%"L)""!%K#!3\rK!3%K)!)M"#!)!5%%!L-""#!%)3J#)5!$)L!)!5B%)!J""#!")3%")b!)!33K"!-\rP"#!)!33")`J""!%K#!%L"#!")3%")b!)!3-K!38L)!J#)L!)!5%%!5%)"#)""!%\rN#!%%)!8N!33J#!8K"!)K!3%L)!J")J3J!L%%"5B)!33J#!%"*#!)!33$)J3J!5%\r"!b)""!%L#!%")L!)!5%%!b)%)!-K)!%P!33J#!%#)3J#)L#!!L&!!5%J!5&!"#1\r!)#!#)5!")8!#)5!")B!")L"!!5%J"#BJ3)!J)%!")L!J!5'!!b'!!5%J!5'!!L0\r!J#!$)b!J3!%K)!)KJ!%N)%#!)!%K3!BK)!3N3)!J)!%LJ#!"*d#!)#"!J#!#)B!\r&)L"!!b&!!5)J)!)N)#"!J!%K)!-M)%#!!b'!!5%J!LBJ)%#!)#!#)5!")8!%)B!\r")5!")B!&)5!")S!J!5&!!5%J!b%J!59!J#!J3!%L)#!%*8#!)#"!!5)J)!)K)!)\rKJ!%M)%#!!L0!J#!$)b!J3!BK)!%KJ!)L3)!"*5"!J#!J!5+!)!3L)%!$)d#!)!%\rK3!)K3!-K!J%K!B%$(3)!!3!%!8)%!%!%!%)!N!3"!!!"!J3!!J3"3!!!!!3"3J!\r"3!!!!J3"!J3!3!!!3!3"3J3!!!!"!J!"!!3!3J!"3!3!3J3"3J!!!!3!3J3"3!3\r!!J!""#0#"!'"!`T!!!&!"!!#"!"!!!!#!!%!!!&!"!%#"!"#"!"#!!!%)3)")3'\r"!a)!"!!!"!%#!*!%!3)%!3)!!%)!!!)%!%!!!8)%!3!!!8)!!!!%!%!%!8)%!3!\r%!8)!!8!!!#4!"##!J3-HJ###!!!#J!!!!#!#!!#!J##!!###J!!!J#!!!!##!!!\r#J!##J#!#J#!!J##!!!!#!!##J!#!J#!#!###J#!!J!#3"))!)!!!!)!!)!+!))#\r!!)!!!!)!)))%)B!")B!$)3)#)5!#)i!JJJ%KJ!%K!J%LJ#!))B)#)L#!!51!)!)\r")i!J!J-KJ!%MJ###"5'!!5'!J3-*J#!#!###J!#!!##!!#!!J!##!!!#J#!#J##\r!"#1!))+"!`F!!)+!!!!!)!!!))#!!!)!!)+!!!!!J@%L,(L#!LXXJ#b),@JLVLb\rB'QJCk#Xq,+JDVKQS,,JC+"NN'5!C("N8,-JXd"N''1`Bc#Xk,2!Xq#d!+V)UZLd\r3,4JY)!6'!-B!TJ"Q!#B!"Ld`,6JY3!c'%-B)aJ!J)Mmm!5-'UI!#)[rp%L)X3))\r#2J!`,%!!!La!8p`X3%dN,%"-lLa!5I3X3$"5,%![pLa!,eBX3#i`,%!XDLa!+rB\rX3#VX,%!TS#a!+5BX3#MH,%!SK#a!*k)X3#G',%!Qi#a!)fBX3"M8,%!ATLa!&U3\rX3"#F,%!,9La!!-)X3!#8,%!!6#a!+j!!9+S"5!$3'5)#!3%K#!3L-!%")3J%*%`\r"!3J%)T3"!5%)"#(#"L8Qi!%J#!-P*dB")!J$)bHL!3%K)!-P+)3"!3J$)LMH!L%\r)!b8T*J%"#!-L+D!")[m)!b)UEJBP+Z`"la!$*L[frrrXKJ)Q,'Vrrqc)!LBZ-2r\rrl-i#*5p@!@%)!b8[pJ&K#!-L-&)')dcZ!3%K#!-Q656rrqjS!L*1`!BP8p`"j`J\r$)P5U$2q3"!#3"`%!!#eJ!!!!!3!!,9J!!!!$!!!!%!!!!!%!!!$-!!!!h!!!!fJ\r!!!!%!!!!'J#3$`d!N!YQ!*!,!J!!!!d!N!HM!*!,!3!!!!m!N!3"!!!0!J!!&3)\r!!"X#!!!L!J!!+`)!!$)#!!!j!J!!2`)!!%B#!!",!J!!8J)!!&F#!!"I!J!!H3)\r!!)m#!!#`!!%!N!8(!*!%S!!V8%S23LZ!0dBG3J!!!%e*9&qP68P83daTBJ"IAfC\rTE'9c!'CRCA4c!("bD@jdCJ"ME'9KFQ9bFJ"QCQaeFfJ!Fh4bBfKb!(0bB@jN!(0\rdFQ0YF!"bB@jN!'ePE@0YF!"dD@eP!'C`FQPZG'B!E@9YFf9d!%e*9&qP68P88R9\rZG'PYC8aTBJ"IAh9ZFQ9RDA0dCA*ICR*KCfePER3!AepbC@GTFh4PFPpQFQ&RE@9\rZG!"*ER4PFQCKBf9-D@)!9'PMDd0[G@jd!'4PFepNC@*eC`"NCA0IFQ9KC&p`BA0\rcGfpbC!"NCA0IFf9dAh0PFA9PEQ0PAfjeE@*PFJ"NCA0IFf9dAfYPH3"NCA0IDA0\rIGf9KDepVCAN!C'9cAh0dFQPZCepdEepVCAN!C'9cAfjPGepbB@jNEfeIDf9j!'4\rPFepMBQa[BfYIF(*TER4ICQPXC3"NCA0ICQ0bHA"d!'4PFepMD'9MDepVCAPIF'&\rbDA4j!'4PFepQDAKeF&pVCAPIF'&bDA4j!'4PFepbB@jNEfeIDf9j!'4PFepMFRP\r`G!"NCA0IFQ9KC&p`GepcG(*TEQF!C'9cAfPZDA4IFQ&ZC'pYAfjeE@*PFPpRC@j\rPFQ&dEh)!C'9cAc0PBf*IC@jMFRP`G!"NCA0I-f0LBepPEQ0bHA"d!'4PFepcCA4\rIFQ&ZC'pYAfGPEQ9bBA4[FPpcC@9N!'4PFepVCAPIFf0SC@3!C'9cAh&eB@4IBfY\rcG@d!E@&VC9pVCAPIFf0SC@3!C'9cAf9MBPpPEQ0bHA"d!'4PFepMBQ0IC@jMFRP\r`G!"NCA0ICf9ZCA*KG'9IFQ&ZC'pYAf*XEf0V!'4PFep`Bf*MAf9ZBh*jF(3!C'9\rcAf0LBepMDh0eE3#3"J`!!!!-!!-!"!!'!!3!"`!-!!J!"!!,!!3!$!!!!!d!#!!\r0!"!!$`!)!"-!!!!9!!J!&3!!!"F!$!!A!!P&c3!4Ne3!&qjR!!X54J!2A8B!%@Z\rE!"+dQJ!92mJ!#SY3!"5G&!!8G43!$TIE!!P&F!!5*$S!)-,&!""&S!!38U!!(A6\r'!!e6#J!1K8m!$SX,!!pR`3!2I-%!'4$K!"!kT3!0A`m"!!#k!!!UVJ!"!J!!a!!\r!,0J!!3)!!0B!!#ci!!%#!!$Z!!!XU!!"!J!!qJ!!,,J!!3)!!3S!!#c)!!%#!!%\rF!!!Y%!!"!J!",`!!,-!!!3)!!88!!#bB!!%#!!&3!!!Y-!!"!J!"C3!!,6J!!3)\r!!AS!!#cJ!!%#!!'*!!!XS!!"!J!"N`!!,0!!!3)!!DB!!#d)!!%#!!((!!!XN!!\r!!3)!!GJ!!#b`!!%#!!(T!!!Y!!!"!J!#"`!!,4J!!3)!!K8!!#cS!!%#!!)N!!!\rY)!!"!J!#-`!!,8!!!3)!!N-!!#e3!!%#!!*6!!!Xm!!"!J!#E3!!,5J!!3)!!Ri\r!!#e)!!'Y-`!!!3!!!!&F!!!!A!!!!$)*H6d`1`S*G6d`H$J`1`S*BQ*E1&dp-$X\r+#@C[FL!SD6db1b"T2$%c1b"T+bXT#JN*H`S*#@-p-$X+#3PQEh)J+'Sp-$XJDM`\rf1b"U+bXT#JN*#AX+#3N*Bc`m26%l#JN*#@PQ)#KLBPYjA5!Q)(8T)'0m26%l#JN\r*#A8q2Mda1`S*#3PTCL!S)A8T#JQ3"(X+#C!%H5XV1`S*N!4e26"i1$!l#JQ3"(d\r+#3N*I3S*#A*PG&YTA6eMEhCI-Q0SBA*EBedl#JN*I3S*FQ9d@c%cA6dRA$!R1`S\r*FQ9dGA*Z+(*PG#Nl#Rd+#Jb+D!!!!&J!N!X"!*!6!@df1'X!N"-"!*!41!Y0594\rIT@4PFfaTBJ#3"!%!!!!"A!!!!&`!!!!b"Q)H3&b+!!!!(!!b!!"MCR*R!!!!#J!\r!rrm!N!Kaa!:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:%'4PFfaTBLif1%XZC'9LG@F!FfKXBMq3"!#3")8m!!!"NUpB5Qpj)A"PCQCY0MK\rV!!!!!E*@K4N!N!d$!!)!N!j8UJ!!9+S!!&5U!!!!P!!"!J#3"!8!N!BZB!!!,Q!\r!!#VF!!"93!)"!J#3"!i!N!i&)!!!J"`%!3)!6@&TEJ!P369AEh*XC!"-Ef&NCA)\r!N!41G5T46PErq#m0)!d[!#mYre`LEIp))&P1N!!UE[rd+d$r$'(rN!6FF!"1ANj\rd!!3U88j@rrJ[$5mYr``LEIp%)&P1N!!UE[rd6Pj1G5T46PErq%MR%!4f!#mZ!!J\rLEIpB)&P1N!!UE[rd0J!`!dM!C`3`!f!#-!-Q(djH6R3!"*0IAfPZDA4TB@aTHQ9\rIC'9cE'PL!!!U88j@rrJ[$5*Yre3J@8k3!#TZrr41ANjeNPpIG'9bE@PZBA4PAf4\rPFfaTBJ!!!#T46PEri%MR(cJX,J!)*Li!$#iZ!"!SEJ!B*'i!&%UZ!"aR!!8@*Na\rk!"SEFKMMVA!!%"Yb%11SLS"`!"!EiBL+J(!!%"Z+J(J!'"Yb'11XF!!3'h)3ikL\r)J(!!%"[KL)L!F!!3'iL!*NBS3f!!"-*`#,k!EAT`!"!E!S!!!!$rFKMMU,'&F!!\r3'`+!!!!!rh)3ikLaKA!!%"X#J!!!!2rKL,'&F!!3'`+!!!!!rl'&F!!3'`+!!!!\r!rh)BikLaK(!!%"X#J!!!!2pb%11SXB4`!"!E!S!!!!$riBLaK(!!%"X#J!!!!2q\raK&'(B!!!NYI()!F-J!!!!!GL!!##-$X#"Nll!!)!H!"S!&J!5J!q!#i!(J!3F!!\r3)`+!!!!!rq')XB4`!"!M!S!!!!$rFK$MU,'%F!!3)`+!!!!!rh)BikLaK(!!%#-\r#J!!!!2qaKA!!%#-#J!!!!2rKL,'&F!!3)`+!!!!!rh)3ikLaKA!!%#-#J!!!!2p\rb'11SXB9q!#!%!S#UN!6LL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4\rb%1+Y!S8!!!$r)'hrr#S`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!\r!rb"Yrr`L-"`!jBQ#K5S%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'h\rrr#J`6!$BK#)$G"MNU3+"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ\r#K#J$!S3!!!$r)'hrr#J`6!$RM)L"I!"J!!'B*J4b&H1V)J4d#q5TJS-Q'V1$F$m\rL!h3Bj+R#J#"YrrK`2b3$,8$ri(!3i+V%V[rJjBSLEIridm)J+3%!J,!F!()r*!2\rJLX5"jBSJEIridF+!U!)!FMr#Jq@*)'hrq0("J+J$!,'&*J4b#H1V)J4d&q5TJS-\rQ'V1$F$mL!h33j+R#J1@*)'hrq0("F$mL!h3Bj+R#J1@*)Qhrq02")#N%!)#S"3"\rb2b3$i)V%JH@+)'hrq0(#J+J'!()r`S2PL5"YrrM4`B#S"`#aK5B&FKAMUb)&G![\rNUB+$*KUcJh!r)J0d'15T`S!JEIriF$mN!be!rq"`%1#Ua+lri1@+)Qhrq02#)#N\r"!)#`(!"b2b3$i)V%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK#B&FJR\rMUb)&G"INUB+$*KUcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM\r6`5!T"!#!U!8!FMmN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB4\r5KR!)[)"Y!2jN)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+!+!%\rU"()3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+&+J6\rJM3+&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!!!2m\rJEIrd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"Yrr3\rS-%`!jBb)J5)$!S%!!!$r)'hrp)L`(!"&k[q!)!9b'1+S!S!!!!$r'-!J"A)3iUJ\r#J!!!!2mB`#!&i)J#J!!!!2mB`#!&!S!!!!$r'-!J"()BiUJ#J!!!!2mB`#!%FK$\rLU!+!!!!!raM!)!6JL!+!!!!!raM!)!3#J!!!!2mB`%U(EJ$l2'!!"6j+Kfi'F!"\rJ!!8f*Na`!"!EFKMMU#e!rr4`!"!EFK$MU)'Zrr4`!"!EiBL"V[rdF!!3'i'Zrr4\r`!"!EFKMMU#e!rr"`!"!EFK$MU)'Zrr"`!"!EiBL"V[r`F!!3'i'Zrr!Q4LK$HJ!\rD'h)Bike`!"!EFK$MU)U!F!!3'q')LS"`!"!ELS"i!"JEFKMMV(!!%"Yb%11SL)"\r`!"!EiBL)J(!!%"Z)J#e&rq`Y42rS)!3#J+U3"1+)*J8#JkU3")D!)!3#J&@3"#)\r&!S&9N!65JB+!+!%U"()3iUd#K3!!!2mJEIrm+M"F!0U&)J4d'15T!S%!!!$r)'h\rrr)U`(!!L"1#*!S%!!!$r)'hrr#)`(!$PLB+&+J3#K3!!!2mJEIrm+M"F!1H0LS%\rS!h)3iU`#K!!!!2mJEIrm+$"-!0L%)J0d'15T!S%!!!$r)'hrr)L`(!!L!q#*!S%\r!!!$r)'hrr#)`(!$PLB+%+!-#K!!!!2mJEIrm+$"-!1H-L)&&kJ#!I!"J!!()*J4\rb#H1V)J4d&q5TJS-Q)V1$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*YrrM6`#!T"`#\r!U!B!FMmN!be!rq"`%1#Ua)(PLL"YrrM4`L!S"3#!V[rJFMmN!be"rq4b'1+Ua+l\rrj1@+)'hrq0(#J+J%!,'&*J4b&H1V)J4d#q5TJS-Q)V1$F$mL!h3Bj+R#J#"YrrK\r`2b3$i)V%J1@+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)!G$mY32rN)!-\rY3IrJFK$LU-##jBJJEIridF!J+!%!J+lrj)#Zrq#aK5B&FJRMUb)&G"INUB+$*L+\rcJh!r)J2JLF+!jBNJEIridF&`2m#$jBJLEIridm!J+3F!J+J'!()r*!-Y32rNF"$\rJUX5"jBSJEIridF)J+!8!J+lrj()r*!-Y3IrJFKMLUX5Zrq$PLL"YrrM4`S#S"!#\raK#B&FKAMUb)&G![NUB+$*L+cJh!r)J0d'15T`S!JEIriF$mN!q#+a)$PLL*YrrM\r6`R!r`)2PL#)`(!!JEIridF!J+!-!J+N#!(3r,8$rj#!$,8(ri()3iUM!JZ@))'h\rrq0(!)#J"!)#Zrq5!V[rJXB45KR!)[)"Y!2id)!8#J2#3"1L)*J3#Jr#3")D!)!8\r#J!q3"#)%!S%2N!6TLB+!+!%U"()3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%\r!!!$r)'hrp#)`(!$YLB+&+J6JM3+&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'h\rrp)U`(!!S!h)3iU`#K!!!!2mJEIrd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$\rYLB+%+!2JM!+%!!!!rb"Yrr3S-%`!jBb)J5)$!S%!!!$r)'hrp)L`(!!J,[rdXB8\rJ,[r`XB4`#,k!EhC4Kb!&FKMLU!+!!!!!raM!)!9b%1+S!S!!!!$r'-!J"H#)!S!\r!!!$r'-!J"3+!!!!!raM!)!4b'1+S!S!!!!$r'-!J"()3iUJ#J!!!!2mB`#!%i)J\r#J!!!!2mB`#!%!S!!!!$r'-!YE[rXrr3YE[rSrr"J!2ZffFFJ"`b!!!!!#')!!)!\r`1`)'6[X!!J"f!'J!@J"1!%3!0J!S!"`!%L!%!S!!!!$r'3!J"1#)!S!!!!$r'3!\rJ"()3iUJ#J!!!!2mC!#!%FKMLU!+!!!!!raN!)!8#J!!!!2mC!#!&i)J#J!!!!2m\rC!#!&FK$LU!+!!!!!raN!)!9b'1+S!S!!!!$r'3"`!%cI(2K1ANjd!"L2C'9cAf0\rLBepPEQ0bHA"d!!!U88j@rr4)jami+'i!&#CZ!"Kk!"SEFKMMVA!!%"Yb%11SLS"\r`!"!EiBL+J(!!%"Z+J(J!'"Yb'11XF!!3'h)3ikL)J(!!%"[KL)L!F!!3'iL!*Qi\r!##iZ!""J!!4JF!LqJ'ekF!!3'`+!!!!!rh)BikLaKA!!%"X#J!!!!2pb%11SXB9\r`!"!E!S!!!!$riBLaKA!!%"X#J!!!!2qaKA!!%"X#J!!!!2pb'11SXB4`!"!E!S!\r!!!$rFK$MU,'%F!!3'`+!!!!!rq')XB4`!"!E!S!!!!$rXB44Kf!!!*,Aab!($)!\r!!!!(BJ!!JM!l!JC1q`!#!(J!D!"B!%S!2J!Z!"i!%(!!%#-#J!!!!2rKL,'%F!!\r3)`+!!!!!rh)3ikLaK(!!%#-#J!!!!2pb'11SXB4`!"!M!S!!!!$rXB9`!"!M!S!\r!!!$riBLaKA!!%#-#J!!!!2pb%11SXB9`!"!M!S!!!!$rFKMMU,'&IJ!N6#!%!S#\rUN!6LL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$r)'h\rrr#S`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`!jBQ\r#K5S%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)$G"M\rNU3+"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$r)'h\rrr#J`6!$RM)L"I!"J!!'B*J4b&H1V)J4d#q5TJS-Q'V1$F$mL!h3Bj+R#J#"YrrK\r`2b3$,8$rp(!3i+V%V[rdjBSLEIridm)J+3%!J,!F!()r*!2JLX5"jBSJEIridF+\r!U!)!FMr#Jq@*)'hrq0("J+J$!,'&*J4b#H1V)J4d&q5TJS-Q'V1$F$mL!h33j+R\r#J1@*)'hrq0("F$mL!h3Bj+R#J1@*)Qhrq02")#N%!)#S"3"b2b3$i)V%JH@+)'h\rrq0(#J+J'!()r`S2PL5"YrrM4`B#S"`#aK5B&FKAMUb)&G![NUB+$*KUcJh!r)J0\rd'15T`S!JEIriF$mN!be!rr4`%1#Ua+lrp1@+)Qhrq02#)#N"!)#`(!"b2b3$i)V\r%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK#B&FJRMUb)&G"INUB+$*KU\rcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!T"!#!U!8!FMm\rN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB45KR!)[)"Y!2jN)!8\r#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+!+!%U"()3iUd#K3!!!2m\rJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+&+J6JM3+&!!!!rb"Yrr3\rU-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!!!2mJEIrd+$"-!1Q-)J0\rd'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"Yrr3S-%`!jBb)J5)$!S%\r!!!$r)'hrp)L`(!"&k[q!5SGZ!2ZH*Qi!$#!&FKMLU!+!!!!!raE!)!9b%1+S!S!\r!!!$r&X!J"H#)!S!!!!$r&X!J"3+!!!!!raE!)!4b'1+S!S!!!!$r&X!J"()3iUJ\r#J!!!!2m@`#!%i)J#J!!!!2m@`#!%!S!!!!$r&X!J"%cI(2K1ANjd!"50C'9cAf0\rLBepMDh0eE3!!+P&19[r`51FH-#CZ!"!NEJ!)HJ!D'R)Bike`!"!DFK$MU)U!F!!\r3'Z')LS"`!"!DLS"i!"JDFKMMV(!!%"Tb%11SL)"`!"!DiBL)J(!!%"U)J#!%!S#\rUN!6LL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$r)'h\rrr#S`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`!jBQ\r#K5S%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)$G"M\rNU3+"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$r)'h\rrr#J`6!$RM)L"5Ui!&'F!!D`N5h`!B!!"Q#B%FKAMUb)%G![NUB+$*KUcJh!r)J0\rd'15T`S!JEIriF$mN!be!rr"`%1#Ua+lrm1@+)Qhrq02#)#N"!)#`(!"b2b3$i)V\r%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK5B%FJRMUb)%G"INUB+$*KU\rcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!T"!#!U!8!FMm\rN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB8Q"A)9ikXL"A3,j+Q\r#JbBDXi0`2b)$G"MNUF+!)'hrq(!r*!-Y32r`F"$JUX5Zrr$PLL*YrrM6`L!T!3#\r!X"`!FMmN!q#+a)(PLL"YrrM4`S#S!J"b2m+$jBNJEIridF'!U!-!XB3Q"A)*ikX\rL"A3Aj+Q#JbBDXi0`2b)$G"$NUF+!jBNJEIridF&`2b)$G"MNUF+!jBNLEIridm%\rJ+33!J+J&!()r*!2JLX5"jBSJEIridF+!U!B!FMr#Jq@*)'hrq0("J+J(!,'%8SC\r`#,b!E3$qC'!!!G`N5dAU!)"m!'!!!FJQ"()*ikXL"(3Aj+Q#JbBLXi0`2b)$i)R\r#J1@*)'hrq0("F$r!Jq@))Qhrq02!)#N(!)#S"J"b2b3$,8$rm(!3i+V%JH@+)'h\rrq0(#)#J&!)#Zrr"b2b3$,8(rp()BiUV%V[rdjBSJEIridF+!U!3!XB8Q"()9ikX\rL"(3,j+Q#JbBLXi0`2b)$G"MNUF+!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJ\rL-"`!)'hrq0(!)#J$!)#T!J"d2be!rr3J!be"rr"b%1+S`),PL#"YrrM4`#!S!3#\r!V[rdJ+lrm,'&*J9b#H1V)J9d&q5TJS-Q)V1$F$mL!q#*`S$PL5"YrrM4`A!r`)2\rPL#*YrrM6`#!T"`#!U!B!FMmN!be!rr4`%1#Ua)(PLL"YrrM4`L!S"3#!V[rdFMm\rN!be"rr"b'1+Ua+lrm1@+)'hrq0(#J+J%!,'%*J9b&H1V)J9d#q5TJS-Q)V1$F$m\rL!h3Bj+R#J#"YrrK`2b3$i)V%J1@+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#\r!U3)!G$mY32rd)!-Y3Ir`FK$LU-##jBJJEIridF!J+!%!J+lrp)#Zrr#aK&+'F!L\rmJ'd!rM3J"3+!m*!%k)JQ"!+$m*!%KS!J"3+!$j!%)J3#J3q3"1Q*JS!S!5S%FK$\rLV3+&!!!!rb"Yrr3U-&`!kBdL"(3Bj+N#J3!!!2mJEIrd)M!F!1f*JS8U"1#0!S8\r!!!$r)'hrp#S`A!$PMBU")J3#J3!!!2mJEIrdLV!F!#J$FK$LV!+%!!!!rb"Yrr3\rS-%`!kB`L!h3Bj+N#J3!!!2mJEIrd)M!F!1f*JS3S!q#-!S3!!!$r)'hrp#J`6!$\rPM)L")J-#J3!!!2mJEIrdL,!F!#4Z!!`J"A)BiUJ#J!!!!2m8`#!&FK$LU!+!!!!\r!ra6!)!AJL!+!!!!!ra6!)!8#J!!!!2m8`#!%FKMLU!+!!!!!ra6!)!4b%1+S!S!\r!!!$r&-!J"1#)!S!!!!$r&-!J"!+!!!!!ra6!F!"-h`ai6Pj1G!!3Mf4PFepPBf*\rIC@jMFRP`G!!!+P&19[rF,`-JEJ!)GJ"J!!$+!M!!rMJ!F!&b!h32,8$rh(!!%$!\ri!1L!`))8-$J!!S)!!!!2XB,NJX5"F!0b$be"rq"b!")`1!$SJF+Zrq!Y3[rN&$!\ri!!+#!!!!$l1#a)!J,[rNXB,LJX5Zrpa`!A)$,8$rk(!!%$!i!1L!!S!!!!!2,8(\rrl")`1!!#J3!!!!qaJH5"`Ulrl(!$,8,rm(3!&$!i!1L#!S)!!!!2,8$rp"!`1!!\r#J!!!!!qeJ-#Zrr5cJ-#ZrqJL,[r`Xi!+J!!!!!'"-$J!8S0`#,D!C3$r-LBI6Pj\r1G!!%P'4PFepQDAKeF&pVCAPIF'&bDA4j!!!!+P&19[rB,`-JEJ!)GJ"J!!$dF!&\rb!h32,8$rf"!`1!!#J!!!!2lSJ-##G!mY3IrF%M!i!!+"!!!!rX+#XB(NJF+Zrpa\r`!h32,8,ri"3`1!!#JJ!!!2lSJX5Zrq!Y32rN%$!i!!+!!!!!rJ+!!!!!$l@!`+l\rrj,1!iS$!V[rBFJ&d!be"rqJ5-$J!!S%!!!$qk)%#J3!!!!mY3[rX&$!i!!+#!!!\r!rJ+#!!!!$l1#j),%V[rXFJ-Y32r`%$!i!!+!!!!!rZL!!S!!!!!2,8(rp")`1!!\r#J3!!!2i#J3!!!!qaJF+Zrr5eJF+ZrqJJ,[r`XB%3-$J!G!(!JV#"CJ4`!'!-8S0\r`#,D!C3$r#(!"*Kp1ANjd!!58C'9cAf0SC@0VAfYPH9p`BA*TG(N!!!!U88j@rq"\r)jami,#i!##BZ!!`SEJ!B*'i!&%UZ!"aR!!8@*Nak!"SEFKMMVA!!%"Yb%11SLS"\r`!"!EiBL+J(!!%"Z+J(J!'"Yb'11XF!!3'h)3ikL)J(!!%"[KL)L!F!!3'iL!*NB\rS3f!!"-"`#,#Z!""X@Ri!(KYb'11[F!!3'h)3ikL1J(!!%"[KL)k!F!!3'ik!F!!\r3'h)BikJY32rdF!!3'h)3ikL"V[rdF!!3'q')JDlrp(!!%"Z"V[rd[i8J,[rdXB4\r4VJ!3B!!!TYIZ!"!J,J!3$)!!!!!)BJ!!N!!`1`)'6[X!!J#'!(B!CJ"B!%`!2!!\rX!"i!%R!!%#-#J!!!!2qaK(!!%#-#J!!!!2rKL,'%F!!3)`+!!!!!rh)3ikLaK(!\r!%#-#J!!!!2pb'11SXB4`!"!M!S!!!!$rXB9`!"!M!S!!!!$riBLaKA!!%#-#J!!\r!!2pb%11SXB9`!"!M!S!!!!$rFKMMU,'&3Ui!%#!%!S#UN!6LL#B&!S1UN!5'J#!\r%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$r)'hrr#S`A!$DK5)%G"MNU3+\r"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`!jBQ#K5S%!S8!!!$r)'hrr#S\r`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)$G"MNU3+"!!!!rb"Yrrb)X"`\r!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$r)'hrr#J`6!$RM)L"I!"J!!'\rB*J4b&H1V)J4d#q5TJS-Q'V1$F$mL!h3Bj+R#J#"YrrK`2b3$,8$ri(!3i+V%V[r\rJjBSLEIridm)J+3%!J,!F!()r*!2JLX5"jBSJEIridF+!U!)!FMr#Jq@*)'hrq0(\r"J+J$!,'&*J4b#H1V)J4d&q5TJS-Q'V1$F$mL!h33j+R#J1@*)'hrq0("F$mL!h3\rBj+R#J1@*)Qhrq02")#N%!)#S"3"b2b3$i)V%JH@+)'hrq0(#J+J'!()r`S2PL5"\rYrrM4`B#S"`#aK5B&FKAMUb)&G![NUB+$*KUcJh!r)J0d'15T`S!JEIriF$mN!be\r!rq"`%1#Ua+lri1@+)Qhrq02#)#N"!)#`(!"b2b3$i)V%JH@+)'hrq0(#J+J#!()\rr`S2PL5"YrrM4`B#S!`#aK#B&FJRMUb)&G"INUB+$*KUcJh!r)J0d%15T`S$PL5"\rYrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!T"!#!U!8!FMmN!q#+a)(PLL"YrrM4`S#\rS"J"b2m+$jBNJEIridF'!U!F!XB45KR!)[)"Y!2jN)!8#J2#3"1L)*J3#Jr#3")D\r!)!8#J!q3"#)%!S%2N!6TLB+!+!%U"()3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15\rT!S%!!!$r)'hrp#)`(!$YLB+&+J6JM3+&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$\rr)'hrp)U`(!!S!h)3iU`#K!!!!2mJEIrd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)\r`(!$YLB+%+!2JM!+%!!!!rb"Yrr3S-%`!jBb)J5)$!S%!!!$r)'hrp)L`(!"&k[q\r!)!9b'1+S!S!!!!$r'-!J"A)3iUJ#J!!!!2mB`#!&i)J#J!!!!2mB`#!&!S!!!!$\rr'-!J"()BiUJ#J!!!!2mB`#!%FK$LU!+!!!!!raM!)!6JL!+!!!!!raM!)!3#J!!\r!!2mB`,q&)#lrp,'%5Ui!%'i!qcaJ!!8q5Ui!%'i'F!"J!!8d*Naq!"iEFKMMVh!\r!%"Yb%11SMS"`!"!EiBL1J(!!%"Z1J(!!%"Yb'11S,8$rm(!!%"Yb%11SJDlrm(!\r!%"[KL)'Zrr"`!"!EJDlrm#C'+%0k!"SEFKMMVA!!%"Yb%11SLS"`!"!EiBL+J(!\r!%"Z+J(J!'"Yb'11XF!!3'h)3ikL)J(!!%"[KL)L!F!!3'iL!,8Arl#e%rqJJ"!+\r!UT!%iSJQ"3+$UT!%KS!J"!+!9C!%)J8#J9@3"0+"JS!S!5S%FK$LV3+&!!!!rb"\rYrr`U-&`!fS8L"(3Bj+N#J3!!!2mJEIrmLV!F!#)%i)N#J3!!!2mJEIrm)M!F!1@\r*JS8U"!+&!!!!rb"Yrr`U-&`!jif+J5J$FK$LV!+%!!!!rb"Yrr`S-%`!f)3L!h3\rBj+N#J3!!!2mJEIrmL,!F!#)$i)N#J3!!!2mJEIrm)M!F!1@*JS3S!`+%!!!!rb"\rYrr`S-%`!jib)J8AU!)"m!'!!!FJQ"()*ikXL"(3Aj+Q#JbBLXi0`2b)$i)R#J1@\r*)'hrq0("F$r!Jq@))Qhrq02!)#N(!)#S"J"b2b3$,8$ri(!3i+V%JH@+)'hrq0(\r#)#J&!)#Zrq"b2b3$,8(rj()BiUV%V[rNjBSJEIridF+!U!3!XB8Q"()9ikXL"(3\r,j+Q#JbBLXi0`2b)$G"MNUF+!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJL-"`\r!)'hrq0(!)#J$!)#T!J"d2be!rq3J!be"rq"b%1+S`),PL#"YrrM4`#!S!3#!V[r\rNJ+lri,'&*J9b#H1V)J9d&q5TJS-Q)V1$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*\rYrrM6`#!T"`#!U!B!FMmN!be!rq4`%1#Ua)(PLL"YrrM4`L!S"3#!V[rNFMmN!be\r"rq"b'1+Ua+lri1@+)'hrq0(#J+J%!,'%*J9b&H1V)J9d#q5TJS-Q)V1$F$mL!h3\rBj+R#J#"YrrK`2b3$i)V%J1@+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)\r!G$mY32rN)!-Y3IrJFK$LU-##jBJJEIridF!J+!%!J+lrj)#Zrq#aK&+'F!LmJ'd\r!rM3J"3+!m*!%k)JQ"!+$m*!%KS!J"3+!$j!%)J3#J3q3"1Q*JS!S!5S%FK$LV3+\r&!!!!rb"Yrr3U-&`!kBdL"(3Bj+N#J3!!!2mJEIrd)M!F!1f*JS8U"1#0!S8!!!$\rr)'hrp#S`A!$PMBU")J3#J3!!!2mJEIrdLV!F!#J$FK$LV!+%!!!!rb"Yrr3S-%`\r!kB`L!h3Bj+N#J3!!!2mJEIrd)M!F!1f*JS3S!q#-!S3!!!$r)'hrp#J`6!$PM)L\r")J-#J3!!!2mJEIrdL,!F!,q&)#lrm,'%F!L`VJ!3E(a4VJ!3)!9b'1+S!S!!!!$\rr'-!J"A)3iUJ#J!!!!2mB`#!&i)J#J!!!!2mB`#!&!S!!!!$r'-!J"()BiUJ#J!!\r!!2mB`#!%FK$LU!+!!!!!raM!)!6JL!+!!!!!raM!)!3#J!!!!2mB`#iZrqblKb!\rZrqLjJ#e!rr"J!2ZbfHi!%#!Z!"!-J!!!!!KL!!#!-$X#"Nll!!)!GJ"S!&S!6J"\r%!$B!+!!F!")J"!+!!!!!raN!)!6JL!+!!!!!raN!)!4b%1+S!S!!!!$r'3!J"()\rBiUJ#J!!!!2mC!#!&!S!!!!$r'3!J"H#)!S!!!!$r'3!J"A)3iUJ#J!!!!2mC!#!\r&FKMLU!+!!!!!raN!F!"-haci6Pj1G!!BN!"NCA0IF'0LBepPEQ0bHA"d!!!!+P&\r19[rS51FI%#*Z!!Kk!"SCFKMMVA!!%"Pb%11SLS"`!"!CiBL+J(!!%"Q+J(!(*J9\rd&H5VaS!JEIrN*M!m!0D$F!FN"5e!rqK`(H#Ua+lrk#"Yrq5'X#`!F!FN"5e$rqa\rf$HDUa)!JEIrN*$!X!1@+K+lrl(!(*JAULmD!)'hrj#B`2!$RLiD#F!mS"A34j+c\r)J#"Yrq!S-%`!f)4`$b3&,8$rl(!Ci+V%V[rX)'hri)L`,!"`$b3&,86rk(J*k+V\r%J#"Yrq!N-#`!jBU%V[rSF!mS"H+-b)!JEIrJ+$"-!1H-L)*k!"SCFKMMVA!!%"P\rb%11SLS"`!"!CiBL+J(!!%"Q+J(!2)J9d&15T`S!JEIrF)M!F!0+"F!mN"5e!rqa\r`(1#Ua+lrl#"Yrpb#X#`!F!mN"5e"rqKb$1+Ua)!JEIrF*$!X!1@+K+lrk(!2)JA\rSLF+!)'hrh#)`(!$RLB+#KS&`"b)&G"(NUF+!)'hrf#)`(!$5JA!(*!8Y32rXF"R\rJUX5Zrq`JEIrBJV!X!(!(*!8Y3IrSFJRLUX5!)'hrf#3`,!$PLS5ZrqK`"b)&iSR\r#J#"YrpJL-"`!jiQ#JSL")Qi!$#im!!"qr(!3*N"J!!'#F!(!KfFU)!0b'Z+S)J2\rPL3+"$rrrr)+!*J%J"()DiUJL"1@*!S%2rrrmJS!S!@!S)!0b'q+S)J25J3+"$rr\rrrS+!*J%J"()EiUJL"0+"!S%2rrrqJS!S!H+(HMmL!h3@j+R#K5"Yrp4k-#3$,8A\rrl(S3kUV%V[rXHJmYF"`!rqJL!be#rr"d$q5T`S@#V[r`jBNJEIr8dF%U+!%!LUl\rrk()m*!-Y4IrdHJRUUX5"HJ-L!qL*`S@#JZ@*)'hre0("+LJ#!)UZrr4b1#3$k)V\r%JA)(`S1#JZ@*)'hre0("LUJ$!(`r)J4d&Z5T`SBJEIr3I$!N"#e'rr4m$qbUa+l\rrp(`2,A!F!2r`)J3Y3[rXG!lNUF+'JUlrl1@*)'hrd0(",#J"!)bZrr"b2b3%lSV\r%JH@+)'hrd0(#M+J#!()m*!6LLX5"FJ2#K)+#jBNJEIr3dF'-U!-!)!B#J2m!!2m\rL"3+"!2rr!)+!)X%J"J+!!2rr!#)&!S(r!!$rJS!L`91,Y[`!!'i!rRT`!%cI#2K\r1ANjd!!L1E@&VC9pVCAPIFf0SC@3!!!!U88j@rrK)j`!N*'i!##mZ!!`[#L*Yrm`\rJ@8k3!#TZrr3[#L*YrqJJ@8k3!#TZrr4+J'B%F2pJ'#m+)QhrJ#"C6T!!+Qlrp%U\r!C`4`rQ!#F!!NAdjH6R3!#)eNCA0IDf9jAh0MD'9N!!!U88j@rrK)j`!N*'i!##m\r+)QhrX#"C6T!!+Qlrp#m+)Qhrl#"C6T!!+Qlrp#m+)QhrJ#"C6T!!+Qlrp%U!CY*\r`!#4I6Pj1G!!%NQ4PFepZCAGIFQ&ZC'pYAfYPH3!!!#T46PEri#m0)Qhr6#"C6T!\r!+Qlrh#e!rqJLEIp-)&P1N!!UE[rF,8$rl#mZ!!JLEIqi)&P1N!!UE[rF5'lrk#*\rYrl3J@8k3!#TZrpa)E[r`)Qhra#"C6T!!+Qlrh%KZrr!LEIqi)&P1N!!UE[rF5'l\rri#*YrcJJ@8k3!#TZrpa)E[rN)Qhr1#"C6T!!+Qlrh#mYrcJLEIqd)&P1N!!UE[r\rF5'lrm#*Yrm3J@8k3!#TZrpa)E[r`)QhrZ#"C6T!!+Qlrh%jH6R3!")!JC'9cAfP\rZDA4IFQ&ZC'pYAfjeE@*PFPpRC@jPFQ&dEh)!!#T46PErq%MR%!3[,Ir!,bi!##*\rYrmJJ@8k3!#TZrr4f!'!+)'hr[%)`1!"5Jh!)YS"Ym#BI6Pj1G!!%R@4PFepcCA4\rIFQ&ZC'pYAfGPEQ9bBA4[FPpcC@9N!!!U88j@rrJLEIqm)'i!#(!)FL#`J@8%SLj\rJ$NU!C`SL#4,B8i"QqL*"6Pj1G!!%Pf4PFepcCA4IFf9aG@9ZBf9IER9YBQ9b!!!\rU88j@rrK)ja!%5(J!!5mYrm![,J!),bhr[#*Yrr!J@8k3!#TZrr4f!'!Q)'hr[(!\r!%$!i!&+!!S!!!!$r)'hr["'!1!!JEIqm5M!i!'B)8S0`#,D!EG3Q(djH6R3!"*P\rNCA0ICf9ZCA*KG'9IFQ&ZC'pYAf*XEf0V!!!U88j@rrK)jami+'i!$#4Z!"J[#Q(\rr!!!!p#`!5'S!"'(r!!!!k#i!)!aQ"R!",8!!&(!"*N"JE#JZ!"!NEJ!)B&4`!EL\r!EaB[#Q(r!!!!K()!-J$5KLB"9)T9K'!)GJ!@'YD'H!!U"b!&6!8!!#)$6!-3!0+\r!6(`3!(rrrrmX!#!&"S!%r(-Y6!-!!%am!!&rrrrr,J&+K'DS)!aR"#M'+-G5Lh!\r%Ym"Z"VIZ!"4[L#!'60mFq%jH6R3!&)jNCA0IFA9KC&pMDh0eE3!!!#T46PErp#"\rZ!!JGD!!"rrBJEJ!)(9$rpc!ZrrC1ANjd!!59G(G[Af*jG'9cAhCKH&pdEepZCA4\rc!!!U88j@rr3JEJ!)(@J!!rrd(@J!![re(@J!!Irf(9$rpb!Zrr41ANjd!!5@CQp\reFPpLHA4PFepfBAKIG'pIEQ9dF`!!!#T46PErm%MR(M`SEJ!)*%`Q6%KZrr!LEIm\ri)&P1N!!UE[rX)Qhr6#"C6T!!+Qlrl#)Zrr#aJ5"Yrk`J%&+3!,1!,`!LEImS)&P\r1N!!UE[rX)Qhr-#"C6T!!+Qlrl#e!rr3L5d(Zrr4`"()JX)&P"+)ZB!j+J'F+)JN\r5f&1!C[SL39L,)Qhr-#"C6T!!+Qlrl#e!rr3L5d(Zrr4`"()JX)&P"+)ZB!j+J'F\r+)JN5f&1!C[SL3A`!B$4i!(B!&K*k!'!+iSY`!F#$XB45KA!'ZS"[m%U%CJS3%J!\r!!!%8J'!)%")#!!$q&)"5LP+'F!HmJ'r'F!"-haai6Pj1G!!%MQ4PFepbB@jNEfe\rIDf9j!!!!+P&19Zri51F3"#mZ!"![,J!-5(J3!%KZlrJLEIqF)&P1N!!UEZrd*J"\r+JfB8,bi!#%KZlrJLEIqB)&P1N!!UEZrd5(J3!%+R5'l[q#*Yrd!J@8k3!#TZlr3\rJ!bBI6Pj1G!!-N@4PFepbC@&NAh"KFh0hEh*N!!!U88j@lrK)ja`m*Qi!##JZ!!`\rSEJ!3+Li!&(B!$)3!!"!!E`!"+R$rB!!"I#m-)Qhr'#"C6T!!+Ql[p#"Yra")D!"\r')Qhr)#"C6T!!+Ql[p#mYra!["#m,)Qhr&#"C6T!!+Ql[p%U!@%pQ&#mYra!LEIm\rF)&P1N!!UEZrdB!!!e%Ki!!S[#b*Yrb3J@8k3!#TZlr3N3%U!C`*#%NU&C`!!XLm\r-,bhrU#*YraJJ@8k3!#TZlr3JEIm35'J!4L*Yrb!J@8k3!#TZlr3[,Im35(J3!%K\rZlrJLEIm8)&P1N!!UEZrd5S"36fB5,bhr%#*Yra`J@8k3!#TZlr4JA%Ki!!T)EZr\ri)Qhr*#"C6T!!+Ql[p#4!5S"R!N)55'l[q#m,)Qhr,#"C6T!!+Ql[p%U!CbJ[,Iq\rN)Qhr'#"C6T!!+Ql[p#"Yra")D!"')Qhr)#"C6T!!+Ql[p&K2B!*f!8U$C`$qfNU\r$CK)["%+R,`XLEIp!)&P1N!!UEZrd,bhrS#*YraJJ@8k3!#TZlr4+K9K2CaC)H"!\r!3UG)EZri)Qhr3#"C6T!!+Ql[p#!%8i"#-`J!)!0A`%3!5F"-ha`i6Pj1G!!3NQ4\rPFepbC@&NAh"hAh0dFQPZC`!!!#T46PEr0%MR(c`QEJ!)+'i!$#e,rc4k!8AZrlJ\rJ5h$r8S"+''Ek,J")H!"!3UG)E[qi)Qhr3#"C6T!!+Qlr-(`"B$S@'dR$H!"J'NU\r&C`SJ!h)"`)'a'Q!))!0b!F#"X5,LLe+%F!DiJ'rJF!I!KQB+)!9A`%3!5F!U!&+\r'[)GM`NAZrlJQ6(`!B"jf!(J!B!iJ"&+!%KT*`H'TKS&5K(!'Z)"[l"E$8SC`"lb\r!Bp`[$#*Yrq`J@8k3!#TZrc")E[mi,``LEIr))&P1N!!UE[m`,`a)E[mi,`F[$#m\rZrc4Krrrrh%T)H!#!3UG)E[mi)Qhr3#"C6T!!+Qlr-#m-)Qhrl#"C6T!!+Qlr-(!\r!60mFq%jH6R3!#*&NCA0IFh4bD@jRAh4[AfYPH3!!+P&19[ri51F30#4Z!!`QEJ!\r)GJ![,Iq8,`SLEImm)&P1N!!UE[rd8%pJ0R!!%"X[!#mYrj!!,`SLEImm)&P1N!!\rUE[rdF!LfJ%r[!!aX&#mYri`[#L*Yrc`J@8k3!#TZrr436b!$8S0b#,#"EF![,Iq\r),`SLEImm)&P1N!!UE[rd8%p-h``)6Pj1G!!)P@4PFepMBQa[BfYIF(*TER4ICQP\rXC3!!+P&19[ri51F30#CZ!!JNEIq%GJ"J)NKi!!J[#b"+8)T)8#*Yrc3J@8k3!#T\rZrr4+J'B%F!&J#P+$F"#fJ'ABF!"-h``)6Pj1G!!%Mf4PFepTFephC@&VAfYPH3!\r!+P&19[rF51FI1#`Z!!`Q,J!J*'i!&#CZ!"JSEJ!F5Ui!*'F!$)`Z!b"(8SGk!"S\r3FKMMV5"(8SG`!"!3FK$MU)U!)%G5Kh!!%"$KL)U!)%G5Kh!!%"#+J#"(8SGi!"J\r3FKMMV#"(8SG`!"!3FK$MU)L!)%G5Kh!!%"$KL)L!)%G5Kh!!%"#)J#iZ!!JY4[r\rdB!!-%R!)X+i!%'i!!*iJ4e+(F!!3%!+!!!!!rh)BikLaK5"(8SG`!"!3!S!!!!$\rrFK$MU,'&)%G5Kh!!%"!#J!!!!2rKL,'&)%G5Kh!!%"!#J!!!!2qaK5"(8SG`!"!\r3!S!!!!$rFKMMU,'%)%G5Kh!!%"!#J!!!!2pb%11SXB3J4e+(F!!3%!+!!!!!rq'\r)XB3J4e+(F!!3%!+!!!!!rl'%8Di!%'!!!,6HVJ!3)#i!%!b!!!!!"f)!!*i`1`)\r'6[X!!J#8!)!!E!"D!%S!0J!L!""6Kb"(F!!3%!+!!!!!rq')XB46Kb"(F!!3%!+\r!!!!!rh)3ikLaK&1()%G`!"!3!S!!!!$rFKMMU,'%8iFJ4h!!%"!#J!!!!2qaK91\r()%G`!"!3!S!!!!$riBLaK91()%G`!"!3!S!!!!$rFK$MU,'&8iFJ4h!!%"!#J!!\r!!2pb'11SXB9#VJ!3)!3#J+U3"1+)*J8#JkU3")D!)!3#J&@3"#)&!S&9N!65JB+\r!+!%U"()3iUd#K3!!!2mJEIrm+M"F!0U&)J4d'15T!S%!!!$r)'hrr)U`(!!L"1#\r*!S%!!!$r)'hrr#)`(!$PLB+&+J3#K3!!!2mJEIrm+M"F!1H0LS%S!h)3iU`#K!!\r!!2mJEIrm+$"-!0L%)J0d'15T!S%!!!$r)'hrr)L`(!!L!q#*!S%!!!$r)'hrr#)\r`(!$PLB+%+!-#K!!!!2mJEIrm+$"-!1H-L)&m!'!!!CJQ"()9ikXL"(3,j+Q#JbB\rDXi0`2b)$G"MNUF+!)'hrq(!r*!-Y32rFF"$JUX5ZrpcPLL*YrrM6`L!T!3#!X"`\r!FMmN!q#+a)(PLL"YrrM4`S#S!J"b2m+$jBNJEIridF'!U!-!XB8Q"()*ikXL"(3\rAj+Q#JbBDXi0`2b)$G"$NUF+!jBNJEIridF&`2b)$G"MNUF+!jBNLEIridm%J+33\r!J+J&!()r*!2JLX5"jBSJEIridF+!U!B!FMr#Jq@*)'hrq0("J+J(!,'&*J9b&H1\rV)J9d#q5TJS-Q'V1$F$mL!h3Bj+R#J#"YrrK`2b3$,8$rh(!3i+V%V[rFjBSLEIr\ridm)J+3%!J,!F!()r*!2JLX5"jBSJEIridF+!U!)!FMr#Jq@*)'hrq0("J+J$!,'\r%*J9b#H1V)J9d&q5TJS-Q'V1$F$mL!h33j+R#J1@*)'hrq0("F$mL!h3Bj+R#J1@\r*)Qhrq02")#N%!)#S"3"b2b3$i)V%JH@+)'hrq0(#J+J'!()r`S2PL5"YrrM4`B#\rS"`#aK&+'F!LmJ'd!rQ3J"3+!m*!%k)JQ"!+$m*!%KS!J"3+!$j!%)J3#J3q3"1Q\r*JS!S!5S%FK$LV3+&!!!!rb"Yrr3U-&`!kBdL"(3Bj+N#J3!!!2mJEIrd)M!F!1f\r*JS8U"1#0!S8!!!$r)'hrp#S`A!$PMBU")J3#J3!!!2mJEIrdLV!F!#J$FK$LV!+\r%!!!!rb"Yrr3S-%`!kB`L!h3Bj+N#J3!!!2mJEIrd)M!F!1f*JS3S!q#-!S3!!!$\rr)'hrp#J`6!$PM)L")J-#J3!!!2mJEIrdL,!F!%AUri!J"!+!UT!%iSJQ"3+$UT!\r%KS!J"!+!9C!%)J8#J9@3"0+"JS!S!5S%FK$LV3+&!!!!rb"Yrr`U-&`!fS8L"(3\rBj+N#J3!!!2mJEIrmLV!F!#)%i)N#J3!!!2mJEIrm)M!F!1@*JS8U"!+&!!!!rb"\rYrr`U-&`!jif+J5J$FK$LV!+%!!!!rb"Yrr`S-%`!f)3L!h3Bj+N#J3!!!2mJEIr\rmL,!F!#)$i)N#J3!!!2mJEIrm)M!F!1@*JS3S!`+%!!!!rb"Yrr`S-%`!jib)J8I\rV!)"m!'!!!FJQ"()*ikXL"(3Aj+Q#JbBMXi0`2b)$i)R#J1@*)'hrq0("F$r!Jq@\r))Qhrq02!)#N(!)#S"J"b2b3$,8$rh(!3i+V%JH@+)'hrq0(#)#J&!)#Zrpab2b3\r$,8(ri()BiUV%V[rJjBSJEIridF+!U!3!XB8Q"()9ikXL"(3,j+Q#JbBMXi0`2b)\r$G"MNUF+!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJL-"`!)'hrq0(!)#J$!)#\rT!J"d2be!rq!J!be"rpab%1+S`),PL#"YrrM4`#!S!3#!V[rJJ+lrh,'&*J9b#H1\rV)J9d&q5TJS-Q)l1$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*YrrM6`#!T"`#!U!B\r!FMmN!be!rq"`%1#Ua)(PLL"YrrM4`L!S"3#!V[rJFMmN!be"rpab'1+Ua+lrh1@\r+)'hrq0(#J+J%!,'%*J9b&H1V)J9d#q5TJS-Q)l1$F$mL!h3Bj+R#J#"YrrK`2b3\r$i)V%J1@+)Qhrq02#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)!G$mY32rJ)!-Y3Ir\rFFK$LU-##jBJJEIridF!J+!%!J+lri)#ZrpbaK&+'F!LmJ'd!rM3J"3+!m*!%k)J\rQ"!+$m*!%KS!J"3+!$j!%)J3#J3q3"1Q*JS!S!5S%FK$LV3+&!!!!rb"Yrr3U-&`\r!kBdL"(3Bj+N#J3!!!2mJEIrd)M!F!1f*JS8U"1#0!S8!!!$r)'hrp#S`A!$PMBU\r")J3#J3!!!2mJEIrdLV!F!#J$FK$LV!+%!!!!rb"Yrr3S-%`!kB`L!h3Bj+N#J3!\r!!2mJEIrd)M!F!1f*JS3S!q#-!S3!!!$r)'hrp#J`6!$PM)L")J-#J3!!!2mJEIr\rdL,!F!#!%!S#UN!6LL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+\rY!S8!!!$r)'hrr#S`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"\rYrr`L-"`!jBQ#K5S%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J\r`6!$BK#)$G"MNU3+"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J\r$!S3!!!$r)'hrr#J`6!$RM)L"I!"J!!'B*J4b&H1V)J4d#q5TJS-Q(,1$F$mL!h3\rBj+R#J#"YrrK`2b3$,8$ri(!3i+V%V[rJjBSLEIridm)J+3%!J,!F!()r*!2JLX5\r"jBSJEIridF+!U!)!FMr#Jq@*)'hrq0("J+J$!,'&*J4b#H1V)J4d&q5TJS-Q(,1\r$F$mL!h33j+R#J1@*)'hrq0("F$mL!h3Bj+R#J1@*)Qhrq02")#N%!)#S"3"b2b3\r$i)V%JH@+)'hrq0(#J+J'!()r`S2PL5"YrrM4`B#S"`#aK5B&FKAMUb)&G![NUB+\r$*KbcJh!r)J0d'15T`S!JEIriF$mN!be!rq"`%1#Ua+lri1@+)Qhrq02#)#N"!)#\r`(!"b2b3$i)V%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#S!`#aK#B&FJRMUb)\r&G"INUB+$*KbcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15T`S$PL5*YrrM6`5!\rT"!#!U!8!FMmN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIridF'!U!F!XB45KR!\r)[)"Y!2jN)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+!+!%U"()\r3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+&+J6JM3+\r&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!!!2mJEIr\rd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"Yrr3S-%`\r!jBb)J5)$!S%!!!$r)'hrp)L`(!"*l2q!)!9b'1+S!S!!!!$r)'lrp&+Zrr33J#!\r&FK$LU!+!!!!!rb"Zrr45V[rd%)!J"H#)!S!!!!$r)'lrp&+Zrr33J#!&!S!!!!$\rr)'lrp&+Zrr33J#!%FKMLU!+!!!!!rb"Zrr45V[rd%)!J"()3iUJ#J!!!!2mJE[r\rd8Ulrp"#!)!6JL!+!!!!!rb"Zrr45V[rd%)!J"!+!!!!!rb"Zrr45V[rd%)"+VJ!\r3EJ$ckQ!!$0C+VJ!3E`!-cLi$)%G5Kh!!%""b'11S,8$rm#"(8SG`!"!3FK$MU)'\rZrr!J4e+(F!!3%1')JDlrm#"(8SG`!"!3JDlrm#"(8SG`!"!3FKMMU#e!rq`J4e+\r(F!!3%()3ikL"V[rX)%G5Kh!!%"$KL)'Zrq`J4e+(F!!3%)'Zrq`Z,J!),8Erp#"\r(8SGk!"S3FKMMV5"(8SG`!"!3FK$MU)U!)%G5Kh!!%"$KL)U!)%G5Kh!!%"#+J#"\r(8SGi!"J3FKMMV#"(8SG`!"!3FK$MU)L!)%G5Kh!!%"$KL)L!)%G5Kh!!%"#)J#e\r&rqJY42rN)!3#J+U3"1+)*J8#JkU3")D!)!3#J&@3"#)&!S&9N!65JB+!+!%U"()\r3iUd#K3!!!2mJEIrm+M"F!0U&)J4d'15T!S%!!!$r)'hrr)U`(!!L"1#*!S%!!!$\rr)'hrr#)`(!$PLB+&+J3#K3!!!2mJEIrm+M"F!1H0LS%S!h)3iU`#K!!!!2mJEIr\rm+$"-!0L%)J0d'15T!S%!!!$r)'hrr)L`(!!L!q#*!S%!!!$r)'hrr#)`(!$PLB+\r%+!-#K!!!!2mJEIrm+$"-!1H-L)&*l!#!I!"J!!()*J4b#H1V)J4d&q5TJS-Q*,1\r$F$mL!q#*`S$PL5"YrrM4`A!r`)2PL#*YrrM6`#!T"`#!U!B!FMmN!be!rq"`%1#\rUa)(PLL"YrrM4`L!S"3#!V[rJFMmN!be"rpab'1+Ua+lrh1@+)'hrq0(#J+J%!,'\r&*J4b&H1V)J4d#q5TJS-Q*,1$F$mL!h3Bj+R#J#"YrrK`2b3$i)V%J1@+)Qhrq02\r#F$r!Jq@))M!F!#"YrrM4`#!S!`#!U3)!G$mY32rJ)!-Y3IrFFK$LU-##jBJJEIr\ridF!J+!%!J+lri)#ZrpbaK5B&FJRMUb)&G"INUB+$*L5cJh!r)J2JLF+!jBNJEIr\ridF&`2m#$jBJLEIridm!J+3F!J+J'!()r*!-Y32rJF"$JUX5"jBSJEIridF)J+!8\r!J+lri()r*!-Y3IrFFKMLUX5ZrpcPLL"YrrM4`S#S"!#aK#B&FKAMUb)&G![NUB+\r$*L5cJh!r)J0d'15T`S!JEIriF$mN!q#+a)$PLL*YrrM6`R!r`)2PL#)`(!!JEIr\ridF!J+!-!J+N#!(3r,8$ri#!$,8(rh()3iUM!JZ@))'hrq0(!)#J"!)#Zrq#!V[r\rFXB45KR!)[)"Y!2id)!8#J2#3"1L)*J3#Jr#3")D!)!8#J!q3"#)%!S%2N!6TLB+\r!+!%U"()3iUd#K3!!!2mJEIrd+M"F!1Q0)J4d'15T!S%!!!$r)'hrp#)`(!$YLB+\r&+J6JM3+&!!!!rb"Yrr3U-&`!jBf+J5)%!S%!!!$r)'hrp)U`(!!S!h)3iU`#K!!\r!!2mJEIrd+$"-!1Q-)J0d'15T!S%!!!$r)'hrp#)`(!$YLB+%+!2JM!+%!!!!rb"\rYrr3S-%`!jBb)J5)$!S%!!!$r)'hrp)L`(!!J"!+!UT!%iSJQ"3+$UT!%KS!J"!+\r!9C!%)J8#J9@3"0+"JS!S!5S%FK$LV3+&!!!!rb"Yrr`U-&`!fS8L"(3Bj+N#J3!\r!!2mJEIrmLV!F!#)%i)N#J3!!!2mJEIrm)M!F!1@*JS8U"!+&!!!!rb"Yrr`U-&`\r!jif+J5J$FK$LV!+%!!!!rb"Yrr`S-%`!f)3L!h3Bj+N#J3!!!2mJEIrmL,!F!#)\r$i)N#J3!!!2mJEIrm)M!F!1@*JS3S!`+%!!!!rb"Yrr`S-%`!jib)JA`!B!!"Q#B\r%FKAMUb)%G![NUB+$*KZcJh!r)J0d'15T`S!JEIriF$mN!be!rq"`%1#Ua+lri1@\r+)Qhrq02#)#N"!)#`(!"b2b3$i)V%JH@+)'hrq0(#J+J#!()r`S2PL5"YrrM4`B#\rS!`#aK5B%FJRMUb)%G"INUB+$*KZcJh!r)J0d%15T`S$PL5"YrrM4`A!r)J0d'15\rT`S$PL5*YrrM6`5!T"!#!U!8!FMmN!q#+a)(PLL"YrrM4`S#S"J"b2m+$jBNJEIr\ridF'!U!F!XB8Q"A)9ikXL"A3,j+Q#JbBEXi0`2b)$G"MNUF+!)'hrq(!r*!-Y32r\rJF"$JUX5Zrq$PLL*YrrM6`L!T!3#!X"`!FMmN!q#+a)(PLL"YrrM4`S#S!J"b2m+\r$jBNJEIridF'!U!-!XB3Q"A)*ikXL"A3Aj+Q#JbBEXi0`2b)$G"$NUF+!jBNJEIr\ridF&`2b)$G"MNUF+!jBNLEIridm%J+33!J+J&!()r*!2JLX5"jBSJEIridF+!U!B\r!FMr#Jq@*)'hrq0("J+J(!,'%8SC`#,b!E3$qC#!&!S$`N!6SL#B%!S2`N!5'J#!\r&!S!2N!3L"!+"$j!%kBQ#J#J"+J4b%1+Y!S8!!!$r)'hrp#S`A!$TM5)%G"MNU3+\r"!!!!rb"Yrr3L-"`!lBQ#K5S%i)d#K3!!!2mJEIrd+M"F!1@0LS%L"!+"!!!!rb"\rYrr5+X"`!+!0b%1+X!S3!!!$r)'hrp#J`6!$TM#)$G"MNU3+"!!!!rb"Yrr3L-"`\r!lBQ#K#J$i)`#K!!!!2mJEIrd+$"-!1@-L)%L!`+"!!!!rb"Yrr5)X"`!4q[rJ#!\r%!S#UN!6LL#B&!S1UN!5'J#!%!S"9N!3L"3+"9C!%dS'#J#J"+J4b%1+Y!S8!!!$\rr)'hrr#S`A!$DK5)%G"MNU3+"!!!!rb"Yrrb+X"`!)J6JL3+"!!!!rb"Yrr`L-"`\r!jBQ#K5S%!S8!!!$r)'hrr#S`A!$RMBU"+!0b%1+X!S3!!!$r)'hrr#J`6!$BK#)\r$G"MNU3+"!!!!rb"Yrrb)X"`!)J2JL3+"!!!!rb"Yrr`L-"`!jBQ#K#J$!S3!!!$\rr)'hrr#J`6!$RM)L"4HS!J(`!B!!"b#B%FJRMUb)%G"INUB+$*L+cJh!r)J2JLF+\r!jBNJEIridF&`2m#$jBJLEIridm!J+3F!J+J'!()r*!-Y32rJF"$JUX5"jBSJEIr\ridF)J+!8!J+lri()r*!-Y3IrFFKMLUX5ZrpcPLL"YrrM4`S#S"!#aK5B%FKAMUb)\r%G![NUB+$*L+cJh!r)J0d'15T`S!JEIriF$mN!q#+a)$PLL*YrrM6`R!r`)2PL#)\r`(!!JEIridF!J+!-!J+N#!(3r,8$ri#!$,8(rh()3iUM!JZ@))'hrq0(!)#J"!)#\rZrq#!V[rFXB8Q"A)*ikXL"A3Aj+Q#JbBLXi0`2b)$i)R#J1@*)'hrq0("F$r!Jq@\r))Qhrq02!)#N(!)#S"J"b2b3$,8$ri(!3i+V%JH@+)'hrq0(#)#J&!)#Zrq"b2b3\r$,8(rh()BiUV%V[rFjBSJEIridF+!U!3!XB3Q"A)9ikXL"A3,j+Q#JbBLXi0`2b)\r$G"MNUF+!)'hrq(!r*!2JLX5!jBSLEIridm*`2m#$jBJL-"`!)'hrq0(!)#J$!)#\rT!J"d2be!rq!J!be"rpab%1+S`),PL#"YrrM4`#!S!3#!V[rJJ+lrh,'%8SC`#,b\r!E3$q0#!&!S$`N!6SL#B%!S2`N!5'J#!&!S!2N!3L"!+"$j!%kBQ#J#J"+J4b%1+\rY!S8!!!$r)'hrp#S`A!$TM5)%G"MNU3+"!!!!rb"Yrr3L-"`!lBQ#K5S%i)d#K3!\r!!2mJEIrd+M"F!1@0LS%L"!+"!!!!rb"Yrr5+X"`!+!0b%1+X!S3!!!$r)'hrp#J\r`6!$TM#)$G"MNU3+"!!!!rb"Yrr3L-"`!lBQ#K#J$i)`#K!!!!2mJEIrd+$"-!1@\r-L)%L!`+"!!!!rb"Yrr5)X"`!)#lrm,'&)#lrl,'%F!L`VJ!3E!!!ZP'Z!"!J"A)\rBiUJ#J!!!!2mJE[rd8Ulrp"#!)!9b%1+S!S!!!!$r)'lrp&+Zrr33J#!&i)J#J!!\r!!2mJE[rd8Ulrp"#!)!8#J!!!!2mJE[rd8Ulrp"#!)!4b'1+S!S!!!!$r)'lrp&+\rZrr33J#!%FK$LU!+!!!!!rb"Zrr45V[rd%)!J"1#)!S!!!!$r)'lrp&+Zrr33J#!\r%!S!!!!$r)'lrp&+Zrr33J#eZrqMrm#eZrq6rl'!!p)JJ,J!3dDlrp#!Z!"!-J!!\r!!!KL!!$!-$X#"Nll!!)!YJ#J!)S!GJ"N!%i!1!!N!")J"!+!!!!!re1Zrr3JE[r\rd%)!J"1#)!S!!!!$r8klrp#"Zrr33J#!%FK$LU!+!!!!!re1Zrr3JE[rd%)!J"()\rBiUJ#J!!!!2p6V[rd)'lrp"#!)!8#J!!!!2p6V[rd)'lrp"#!)!AJL!+!!!!!re1\rZrr3JE[rd%)!J"A)3iUJ#J!!!!2p6V[rd)'lrp"#!)!9b'1+S!S!!!!$r8klrp#"\rZrr33J%cI(2K1ANjd!##3!'4PFemcBf*MAf9ZBh*jF(3!!!!U88j@rpK)jam`*Qi\r!$#4Z!!Kf!"BDF!!3'Z')KS"`!"!DFK$MU)D!F!!3'R)BikL'J(J!'"T`!"!DiBL\r)J(!!%"Tb%11SL)"`!"!DFKMMU)L!,!6SMVH'!SB2N!5pJb!'kBLaK#`$FK,MVVH\r'!SE-c!!!)!1pJ#)'G",NUE'"*J%X"()5ikkjKJ+'c-`!!#!%[B!L"R35j+QaJ5J\r",!6LMVH'!SC9N!5pJb!'d)#aK#`$i)kjKJ+'!2m!rlf%)!EKL,'$,!6LMVH'!SC\r9N!5pJb!'d)#aK#!%!S!!!2m!)J3#J3!!!2pd%1@TJS!J"!+!!2m!!(33j+L!J5)\r$!S(`!!!!k)Q#J#J"!S-2rrrrIJ"J!!(#)'hrI%U`I!"R(L!$FKVMU#)$j)Q#J#B\r")!4b'Z1S)J6NLB+!+!&J(#!$FK[MU#)$iSQ#J#B")!4b'q1S)J6LLB+!+!%#J`r\rrrrm#K!rrrrp`2m#$)'hrH()m*!2ZLX5"FJ-YF!`!rpJJ!qb)`)'!JZ@))'hrH0(\r!)#J"!)#ZrpKb-#3$,8(rh()1iUV%V[rFFJmY3[rJ*!-Y32rNF!hJUX5"K+lri1@\r+)'hrH0(#)#J#!)#Zrq4b"L3$,8(rk()9iUV%V[rSFJ%Y3[rX*!-Y32r`F"6JUX5\r"K+lrl(!i)J-Y3[rdG"ENUF+!JUlrp1@*)'hrH0(")#J$!)#Zrr!N3(`m)J6JLF+\r'I!-N"1k+a)D%JH@+)'hrH0(#I$r-K1@1)QhrH02',#N%!)bS"3"b2b3%,8Erp(`\r2l+V%JH@+)'hrH0(#,#J'!)bZrr4b-#3%,8(rm()@iUV%V[r`FJmY3[rX*!3Y4[r\rSI"AXUX5"K+lrl1@+)'hrH0(#,#J(!)bZrqJJ#J+!!!$rrbS'G"$PVBU!)!APL#)\r&G"lNUG+!*X%J"J+!rrm!!#S+G"$NVBU!)!AYL#)&G"VNUG+!*X&5Kh!3[S"Y!2i\rkF!"-h`ci6Pj1G!!)Lf4PFepcCA4IDf9j!!!U88j@rrJ[$5mYrh![,J!-,bi!##*\rYrf3J@8k3!#TZrr3J,Ip`6Pj1G!!)L@4PFepMFRP`G!!!+P&19[pF51FI2#KZ!!J\rS,J!-*'i!%%IZrqiJ4%S3CJ4`3@!')%33%%R!&)"*`#B!)'hrE(S!'M!i!1@0)%4\r++!!"CJ4`3@!))%33+!!"5F!93!!"5F!Q!#"Yrfam!"``1!$YMRi!B"BB(%S%Cb*\r`!"!%d)""l[rQ%B"i!&+(F!LqJ'ANB!T"l[rQ3M"i!&+(F!LqJ'A`5'lrANKZrqB\rLEIpd)&P1N!!UE[pB,`B["8KZrej)E[rHBIm!!!$Q*LlrhL!$!S!!!!$r&X!J!q#\r)!S!!!!$r&X!J!h)3iUJ#J!!!!2m@`#!$FKMLU!+!!!!!raE!*LlriL!$!S!!!!$\rr&X!J!q#)!S!!!!$r&X!J!h)3iUJ#J!!!!2m@`#!$FKMLU!+!!!!!raE!I!!@2!#\r!3LlrpRi#B%*i!(S!B#EB"(!!%!0"l[rZFJ!5-'J!`S"R"!!%!!(L#dS$CJC5KKB\rm!)"5KA!'ZS"Pe(!!%!3JEIpS&E!!!(J!8SG`$Ek!CEK#+J!0)!T-haci6Pj1G!!\r-LQ4PFepQBh*jF(3!!!!U88j@rma)j`mB)QhrB(S!I!!SEJ!-,@i!%2r8,@i!&2r\r33Ulrc'!!"%#Abf!!"#JJ"R33j+JN"V'#+!,)V[r8a+lrd#i%FK$MVb!')M5m!,1\r!XB5rK#i#FK$MVb!,8S!L"L!d$!#aJE1#[i)J"1#!,8$rp#i%!SF!!!$m!Ui!!!$\rmrr3J!R)FikJL!ZL*dS!N!A!3i+`J-AJ!XB8J5G(Zrr3J+!)!XB8J"1#),8$rm#i\r%!SF!!!$m!Ui!!!$mrr!J5G(()#J%!,'&)%R4l[r`)#J'!,'&)!,JJ#e!rr3Z!J+\r(!!!!r!+Z!!!!r2rdF"$JUL"*dFFJ+!%!XB8J5G(Zrr3J+!-!XB8J!Z#!,8$rm#i\r#!SF!!!$m!Ui!!!$mrr!J5G(()#J&!,'&)%R4l[r`)#J(!,'&)!9d%15S*!@aJLJ\r#b+lre-5Zrp!Z"()3ikmJ#e5!)J8J0!`!XB'cK,q%,J*b%11[)!Y@J#)&)$3-!,'\r"Xi+rJL!%i)!Y32rX,J3#K`!!!2`#VJ!!!2crl#!#FKcMU#)#k)R5J#3"F"$JV#!\raH!#aKL"*dHlrl#!S!J#aKL!%i)JY32rS,J3#K`!!!2`#VJ!!!2crk#"*dFFJ+!3\r!XBBJ5G(ZrqJJ+!B!XBBJ!Z#!,8$rl#i#!SF!!!$m!Ui!!!$mrqa`%1#U)%R4ab!\rS!3#aKL"*dHlrl#!S!`#aKL!#i)!Y32rS,J)#K`!!!2`#VJ!!!2crk#"*dFFJ+!8\r!XBBJ5G(ZrqJJ+!F!XBBJ"R33j+JN"V'#+!,)V[r8a+lrd#i%FK$MVb!,@)!L"L!\rd$!#aJE1%[i3Z!R)3ikmJ#eU!)JBJ0!`!XB'cJVq#)!6JJ#e!rq3Z"!+(!!!!r!+\rZ!!!!r2rN)!*b(11S)J,SLG+!*!&`%1#X)$&i!,'&)%R4l[rN)#J#!,'&)!6JL#e\r!rq!Z"!+(!!!!r!+Z!!!!r2rJ)%R4ab!S"!#aK5"*dHlri#!S"J#aK5!#i)!Y32r\rN,J)#K`!!!2`#VJ!!!2crj(!3i+SJ5G(()#J"!,'&)%R4l[rN)#J$!,'&)!,JJ#e\r!rq!Z!J+(!!!!r!+Z!!!!r2rJ)%R4ab!S"3#aK5"*dHlri#!S"`#aK5!&G"$NU#3\r&XB)S!XLZrp6%V[r3,J4b%11[)!YFJ#)&)$3-!,'"Xi5rK#i#FK$MVb!,AS!L"5!\rd$!#aJE1#[i)J"1#!,8$rh#i%!SF!!!$m!Ui!!!$mrp`J!R)FikJL!ZL*dS!N!A!\r3i+`J-AJ!XBBJ5G(Zrp`J+!)!XBBJ"1#),8$rf#i%!SF!!!$m!Ui!!!$mrpJJ5G(\r()#J%!,'')%R4l[rB)#J'!,'')!,JJ#e!rp`Z!J+(!!!!r!+Z!!!!r2rFF"$JUL"\r*dFFJ+!%!XBBJ5G(Zrp`J+!-!XBBJ!Z#!,8$rf#i#!SF!!!$m!Ui!!!$mrpJJ5G(\r()#J&!,'')%R4l[rB)#J(!,''8)Y`),I!E3$le#3&+JBX!P+Zrma`'E#ZrmaZ!2Z\rk)!9b(H1S)JAQLG+!+J%J"R)GikJL"ZD*dS!X!53&iSUpJJ+#9C!%YBBJ!Y#!XB8\rN"Z#+Zi)#JJ$r!2qeK5!#iBLaKL3&j)UpJJ+#-j!%YBBJ!Z@)XB8N"R)3iUUlJJ+\r#!!$rrl@&)!*b%11SXBBN"HL+[B)#JJq3",@')!,TL,'&)'i!###')'i!##&&!!4\r-haM`6Pj1G!!3LfCMFRP`G&pLEf4j!!!U88j@rrK)ja`m+Li!##4Z!!`S,J!3+'i\r!&#CZ!"JQ,J!F5S0R4Lm$,`3[#Lm&)Qhrm#"C6T!!+Qlrp#!$9m"%!%R!,`![$#m\r+,`SLEIr`)&P1N!!UE[rd,`-[#bm+,`SLEIr`)&P1N!!UE[rdB%3[!bm,,`S["5*\rYrr!J@8k3!#TZrr3J!eI!4!"*`#m!,``[#Lm+)Qhrm#"C6T!!+Qlrp#m$,`3[#Lm\r+)Qhrm#"C6T!!+Qlrp%cI($K1ANjd!"L3!'4PFemcC@0LAf9ZBh*jF(3!N!80)4#\r"!`B!%!!!%"!3!!!3!"!3%!!3%"!%)4!%)4!#)K!3"#%3J3-,%!!3!"#3"3!!!4!\r!!3!3!4!3!3!!%4!!%3!3%4!3%3BK!3)K!3-L!3%")3%$)3%")3%")J%"!L3"N!3\r$)3%#)J%"!5%"!5%"!53"N!3#)J%"!53"N!8N!C!%"#%""#%"!L)"!33K!3%K!3%\rK!3)L!3%")`%"!3JK")%$$3%!!!%!"!!%!!!%"!%%!!%%"!!!)!!!*!%!)!%!*!!\r%)!!%*!%%)#3""#3"!b%"!L-%!3%#)J%"!5)%!3%K"!%K!3%P"!3"!33"*3%""!3\r"!L)J!3)M*!%"!5-J!3%")L3"!5-%)!%"+J3N!3%%)!%""#5"!`m#!!!#!!3$!!!\r$!!3#"!!#"!3$"!!$"!3#!#!#!#3$!#!$!#3#"#!#"#3$"#!P!`3N!3)#)J%#!5-\r%!3-#)J%$!53%!3)%!5F"!J3%!3-%!5B"!`3%!3)")b!"!J%M*!%$!5-J!3-"-53\r"!J3J!3)%*!%$"#!"!`3N"#%#"5%)!5%#!5%)!L%)!L)##!-L#!J")`))#!3L!3)\r#)3%#)`J"!J%L#!%")3J")`%##!%K!3%R#!J"!JJ)!3)K!B%$"`)!!3!!#3)!#3!\r)!3))!3!)#3))#3)M!3%#!5)"!3)M#3%#!5)*!3%R#!%"!JJ"!3%S#!N"!JJ*!4!\r$)4)$)4!")3J")4)")3J")K!)!L)5#!)M%!J)!5-5#!J")4!#)J%5!L)"%!%M#!%\r5!53)!4!)!5-"%JJ"+J%3#!J"%JJ)!4!")3'"!`F5!!%3!!N5!!N3#!%5#!%3#!N\r5#!NK%!%M!3%5!5-"!4!")`N"%J%b#3%3#!%"%JJ"!4!)#3%5#!N""5%%"#%JJJ)\r%"#!3!"3!%#!L&##"!`JJ!!!J"!!J!#!J"#!J%!!J&!!J%#!J&#!$)3L"!`B%!!J\r!)!J%)!J3!!J8!!J3)!JN&#!))!)M##!%!5)))!%S)!JJ"#!))"!")`JJ&!%T##!\r3)!JJ&#!)J3-()!!!*!!!)#!!*#!!-!!!0!!!-#!!)M3JJ3-))#!!)#3!)*!%*#!\rJ-!!J0!!J-#!J0#!")5!")3L"!`BN!!JJ)!JN)!J`!!Jd!!J`)!JP0#!))#!")`J\rJ*!%V##!J)!JJ*#!))$!")`JJ0!%T##!`)!JJ0#!)"b)3#)%$2`!!#!!3!!)!!!)\r3#!)!#!)3!!!#!!!5#!!##!!5!!)#!!)5#!)##!)5"!!!"!!3$!!!$!!3"!)!"!)\r3$!)!$!)3"!!#"!!5$!!#$!!5"!)#"!)5$!)#$!)5!"!!!"!3#"!!#"!3!")!!")\r3#")!#")3!"!#!"!5#"!##"!5!")#!")5#")##")5""!!""!3$"!!$"!3"")!"")\r3$")!$")3""!#""!5$"!#$"!5"")#"")5$")#$")5!!!!!J-K!J)L!J)%)3%")3)\r")3%#)J)"!5-#!J%%)JJ#!L%)!5%#!5-)!J)")3J#)`%)!J%L!3J"*`)"#!)#!3J\r")5!#)J)J!b%L!L)#)J-L)!%")`)J!3)L)J%")`)L!3)K)!%M#!)J!5%)!5%L!5-\r)!L)")3J"*b!"#!)J!3J"*b)"#!)L!3J#)3+"!`F#!!)!!T!&!!!$!J!$!!)$!J)\r$!L-##!)")J))!5F#!JJ#!J))!L-$#!)")J-)!5F#!`J#!J-)!5)J!S%$"`)J!J!\rL!J)L!J!J!`)J!`!L!`)L!`%R)!))!L!##!%R)J))!L)##!%R)!-)!L!$#!%R)J-\r)!L)$#!BK%!3K)!)L%#!")4!$)K!3!L%3!5%J!533%#!)!b%)!5%3!5%)!L)J#!%\rN%#!)%!)M#"!3!5))%!%P)!J3%##"!`F!!!3!%!3!!#3!%#33!!33%!33!#3N%"!\rN#!)L"!J")a!%#!)L*!J"*"!N#"!"*`3)%"!%#"!"*53)%"!NJ3-(!!3!!"3!!!3\rJ!"3J%!3!%"3!%!3J*"!8)!J")33")3J")43")3J")`3J#!%P&#!)%!3")`J3&!%\rS#"!%)!J3&##"!`F!"!3!&!3!"#3!!"!33&!33"#3N%"3N#!%M"!3)!5-8"!J\r")`3N#!%b)%!3%#"!8"!J3"#3)%"3N"#%3"#%"!L)3!38L!K!#)3)")3%")`)\r3!3%K!J)K)!%K%!%K)!)L!5!")a!")!-M)!)3!5)J!J%R!5!#%!%J!J%K")%$"`!\r3"!!!"3!3"3!!"!)3"!)!"3)3"5%#!5)%)!%M%!3J!L)&)!%M%!8J!LF%)!)3"#!\r#!5J&)!)3"5!#)!-K-!-L)!%#)M!"!L%J!L)#-!)M!L!"!5-#-!%")J)J!5%J!5%\r`!5%J!5-J!5!")c!")!%K)!%M)!)`!5`J!L!")!)`!5!#)!5"!`F!-!3!)!8!-!8\r!)!3#-!3#)!8#-!8N!L!%)!%M-!3J!5-J"5!")c!&)!%`)!3J!M!%)!)J"5!#-!8\rJ!J3K"!BL!35#!J`"!3!&!!%""3%!%!33!"%%%3%3"4!"%38K%3%K#)%$$`!%#!!\r!#!%%#!%"#!!&#!!"#!%&#!%!#"!%#"!!#"%%#"%"#"!&#"!"#"%&##%4!L%)!5%\r%J3-1#!!!#!%%#!%"#!!&#!!"#!%&#!%!#"!%#"!!#"%%#"%"#"!&#"!"#"%&)JJ\r4!5))#!%M"!J)!LS)#!%%#!J"!3J)!5-&#!J"+!%)#!%&#!J"!5F)#"!%#!J3!6F\r)#"%%#!J4!3J)%!8)#"!"#!J4"3J)%3FK%))#$3!"!"%3!"!3%!%3%3%!!4!"!3%\r4%3!4%"%")K%4J3-[%!!!%!!3%!!"%!!4%"!!%*!&!4!3%4!"!"!"%"!"!4!"%4!\r4!"!4%"!4!4!4%3%!!!%!%!%!!3%!%3%3!!%3%!%3!3%3%3%"!!%"%!'3"4%"%3!\r"%4!"%3%"%4%4!!!4!"!4!!%4!"%4%!!4%"!4%!%4%"%4!3!4!4!4!3%4!4%4%3!\r4%4!4%3%N%4%4%)%$$`!!%!!3%!!"%!!4%"!!%*!&!4!3%4!"!"!"%"!"!4!"%4!\r4!"!4%"!4!4!N%4%3%!)L%"!")a!3%!%M!4!3!534%"!3!5m3N!F"%"!3%4!3!3%\r[%"!"%"!3!3%3%!%4%"!4!5i3%"%3%"!4!4!3%4%3!3)L%!%")a!3!3%M!4!"!53\r4%!%3!5m3!4!3%!%3!4!"%"%3!3%",a!"!4!3!3%"%!%"%4!"%3%Z%!%4%"!"%3%\r3!4%4%"%#)K!4!5-3%"%")`%3%3%N%4!4%!%[%"%3%"!4%!%3%4!4%"%"!5m3%3%\r3%"%"!4!4!4%3%4%",4!4%4!3%4%"%"%4%3'"!`m!!!%!%!%!!3%!%3%3!!%3%!%\r3!3%3%3%"!!%"%!'3"4%"%3!"%4!"%3%"*"%4!4!#)J%3!5-3!4!")`%"%!%N%3%\r3%!%[!4!3%!%3%!%"%"!4!4!"!5m"%!%3!4!"!3%3!4%"%"%",J%3%4!"%"%"!4!\r4%3%"!L)"!3%M%!%"!5-"N!3N%3%"%!%[!3%3%!%"%!%"!4!4!C!%,`%"!4!"N!F\r4!3%4!5i"!4%3!3%4!3%"%4%"%3)L!4%")a!"%3%M!3%4!534!4%3!5m"%4!3!4%\r3!3%4%"%"%3%",`%4!4!"%3%"!4%"%3%4%3%Y!4%4%!%4%3%"%C!%J3-2!!!4!"!\r4!!%4!"%4%!!4%"!4%!%4%"%4!3!4!4!4!3%4!4%4%3!4%4!4%3%4*"%4%4!#)K%\r3!5-3%4!")`%4%!%N%4%3%!%[%4!3%"%3%!%4%"!4%4!"!5m4%!%3%4!"!4%3!4%\r4%"%",K%3%4!4%"%"%4!4%4%"!L)4!3%M%"%"!5-"%3%"*"%4!4!",a%"%"!4!4!\r"%3%3%4%"!3%[%3%"%"%"!3%4!3%4%3%4!5i4!4%3%3%4!4%"%C!%!L)4%3%M%"%\r4!5-"%4%"*"%4%4!",a%4%"!4%4!"%4%3%4%4!3%[%4%"%"%4!3%4%3%4N!3","%\r4%4!4%4%"%C!%"#%#"#%#!L)#!J3K!J%K!J%K!J)L!J)")`)#!J3L!J)#)3)")3)\r")`)#!J%K!J)M!J)#!5)#!J%S!T!(!3-K!`-L!3)#)J-#!L%"!5%#!5%$!5%#!5-\r"!J)")`-#!J%K!3)L!J-#)`)"!J%M!J-#!5)#!3%M!J)$!5S#!J%#!J)$!J)#!5%\r"!L)#!3-K!`)L!J-$)J%#!5-#!3)#)J-#!5-#!`)#)3%")`)#!3%K!J%K!`%M!J)\r$!5%#!5F"!J)#!3)#!5N$!J)#!`)#!3%#)J-"!L)"!`)L!`-#)`%"!J%M!`%#!5-\r"!`)")`-$!J%L!3%")`)$!3%M!J%$!5-#!`-"-3)"!3)#!`%#!J%$!J)$!`)#!L%\r"J3-(!J!"!!)"!J)"!!!$!J!$!!)$!J)$!L-"!J)")J%#!5F#!3)#!J%#!L-$!J)\r")J-#!5J#!`)#!J-#!3%K!B%$"`-!!3%#!3-#!3%!!`-!!`%#!`-#!b%"!5-"!J-\r"+`%#!3)"!J-#!3)"!5-$!J-"+J-#!3)$!J-#!`)")J%"J3-(!J%"!!-"!J-"!!%\r$!J%$!!-$!J-$!5F"!3)#!3%#!5F$!3)#!`%#!5F"!`)#!3-#!5S$!`)#!`-#!3%\r"J3-(!`%"!3-"!`-"!3%$!`%$!313"5!J!3%"!J-"!3)"!`%#!`-"!J%"!`)$!3-\r#!3-$!J-$!`)$)J%#!L%"!5%#!5-"!J)")3%#)`)"!J%L!J%"*`)#!3)#!J%$)J-\r#!L%$!5%#!5-$!J)")3-#)`)$!J%L!J-"+!)#!`)#!J-"!L)"!`)M!3%#!5-"!`)\r")J%"!5-#!3-"+`)"!3)#!3-#!J%"!L)$!`)M!`%#!5-$!`)")J-"!5-#!`-"+J)\r$!3)#!`-#!J-")3%")`%#!3%K!3%K!`%M!3)$!5%"!5F"!J%#!3)"!5F$!J%#!`)\r"!5%"!5-$!J%")3-")3-")`-#!`%K!`%R!3)$!J%#!`%T!`)$!J-#!`%"!5-"!`%\r")`%"!`%M!3-$!6-"!3%#!3-"!J%"!`)"!`-#!C!%)`-$!3%M!`%$!5-$!`-"-3-\r"!3)$!`%#!`%$!J-$!`)$!L-"!3)")J%"!5F#!3%#!J%"!L-$!3)")J-"!5F#!`%\r#!J-"!L-"!`)")J%$!5F#!3-#!J%$!L-$!`)")J-$!5J#!`-#!J-$!3%M!3%$!5X\r"!3%#!3%$!J'3"#-$!3-"+`-"!3)$!3-#!`%"!5-"!`-"+`%$!3)"!`-#!3-"!5-\r$!`-"+J-$!3)$!`-#!`-"*`%"!3)"N!3R!`%"!J-"!3%R!3-"!J%$!3%R!`-"!J-\r$!3%R!3%$!J%"!`%R!`%$!J-"!`%R!3-$!J%$!`%J4`-$!`)$!`-"N!3$!C!%!`%\r"!`-"N!3$!3-"!`%"!`-"!`-$!C!%!`-"!3-"!`%$!`-"!`%"!`-$!3-$!313"`%\rK%!)L!K!")J%#!5)%!3BK"!%K!J%L"!%"*K!%!3)3"!%N!K!%!3%K%!BK!J)K!3-\rL!3)$)J)3!5%"!L-%!3)")33#)a!%!3%K%!%L!3)")33")3)#)`%#%!)M!K!%!L%\r3!5-"!K!%)33$*J3"!K!%!3%L%!3%)J%#"#)3"!%K!J3L%!3#)4!#)3)")`3"!J%\rN"!%#%!%M!3)3!5%"!b%"!5%3!5)"!J-K!J%K"!)K%!)M!K!%!b)%!3%Q%!3"!K!\r%!b-%!3)#*`%#%!3"!K!$)K!%##8"!K!%!38P%!3"!K!%)33")3)#)J%#!5%%!b%\r%!L%3!5%"!5+!JJFKJ!)MJ))#J3-BJ)!#!))#!!!#!)!!!!)!J))!J))#!!)!J!)\r#J)!#J!#3"!)!!J+!!J#!!J!!JJ!!JJ#!J!#!J!#!!J)!J!+!!!+!!!)!J!)&)J)\r#J3-G!))#J!!!!)!!J))#!!!#J)!!J))!J!!!J!!!!!)!J)!#!)!!!))!J!!#!!)\r!!!!#J!)#!))#J))#!)!#J)!!J!)#J!!#!!)#!))#J))!!!)#J!)!J!)!"5+!!J)\rKJJBMJ)!#!L8""!3"!38L"!%")J3%!5%""L3"!33%!5%"!L%"!5)%"!)L"!3#)33\r")3%#*!3"!33")3%")`3%!33M!33%"L3%"!%"!b%"!L)"!3%L"!%#)J3"!5%%!53\r"!33%!5)""!%L!3%#)3%#)33")J%%!b8%"!%""!)K!3%K"!-M"!%"!5%%"#%"!5%\r%!L)""!%K!3)M"!%"!5%%!5%""b%"!L%"!5B%"!%""!3")3%")33#)33#)3%&)J3\r"!5)%"!%L!33")3%#)33$*!3"!33$)33")`%""!%L!3%")33#)`3%!3)K"!%L!33\r#*!%%"!%$)`%""!-M"!3"!5%%!5)"!33MJ!%%!51!!33#)5%#)B!")33&)S!J!b)\r"")%$#`!J")!!"!!"!)!J")!K!)!K"!!!")!J!!!"!!!J"!!J"!8K)!)MJ#%%J3-\rIJ#%%J!%!J#%%!#!!J!!!!#%!!!%%J!%!!#%!!!!%J!!%!#%!J!!!J!%!!#!!!!%\r%!#%!J#!%J!%!J#!!!#%%!!%%J#!%J!!!J!%!!#%%!#%%J!!%J#%!!#%%J!%%"5)\rJ"!)K)33K"!%LJ!%#)S!J!L'!!5%%"L)J"!)L!33")S!J!L5!J%!3!5'!!5-33)!\r")K"!!b&!!59!%%#!3!%M3)"!!L'!!5%3"L*!%!)L3"!"*B"!%%#!!L&!"5&!!50\r!J%!#)B!&)4!#)8!#)i"!%!3K3!%K3!)KJ!%K%!-N%%#!3!%L3)!&)K"!!5&!!5&\r!!L%3!LK!%%#!3""!J!)K3!%K3!%M3)"!!b*!%!%PJ%!33)!#)8!*)N!3!b)33!%\rK3!%M3)"!!5*!J!-MJ%!3!5'!!5-33)!")K"!!bC!J%!33)!#)N#!"5%3!5+!3!)\rKJ!%K%!)P3""!J%!")N#!!5%3!b)33!%K3!)MJ%!3"#&!!5&!"#%3!L4!%%!3!L-\r)%#!%)5!"*K!J)!J3)!8P#"!J)!J")5!#)4!")5!#)b!J#!%K)!)K%!)K#!%K)!%\rL#"!")5!")4!&)L!)"5%J!5))%!%L)!J#)5!#)L!J!5%3!5)J#!-M#"!J!5-)%#!\r")3J&*L!J#"!J)!-L)!J")L!J!5-3)#!")4!$)4!")5!%)`J3)!%K#!%L)#!"*"!\rJ)!J")5!%)b!)%!)K#!%K)!)K%!%K)!%K%!8M)!J3!L8)%#!J#!%L)#!")K!J!bB\rJ)!J3)#!&)K!J!5%)!b%)!L%J!5)3)!-M)#!)!L%J!L%J!5))%!%L)!J%)a!J)!%\rK%!3K)!%L#"!")b!)#!%L##!#)3J#)3)#*3J###!)!b%)!5)))!-L)!J%)3)")b!\r)!J)N#!)))!%L!JJ")`J##!)M!JJJ!L%)"#-J#!)#)3J#)L!)!5%)!b)))!%L!JJ\r#)3)")b!)!J%N)!J##!-L##!))JJ#!5)J#!)L)!J")3J#)`)))!%K!J-M!JJJ!5%\r#!L-)!JJ$)3J%)b!)!J%K)!)K#!)N!JJJ#!%K#!3L)!J#)b!)!J)L#!)")L!)"#%\r#!L%)!5)))!3N#!)))!%K!J%L)!J#)b!)!J)K#!%K#!%K#!%L##!%*!J###!")J)\r)!L)##!-L##!#)JJJ!5%#!5)J#!-M#!))!59!#%!33!%K3!-K3!)M#%!3!5%)"5-\r33!J")K"!!50!%%!#+""!#%!33!K!!5&!!b&!!5&!!L%)"5-33!J")4!")JK!!L%\r)!5)33!%L3"!%)8!&)8!#*3K!%%!)!b%)!5)33!)K%!8L#%!$*8!33!K!!5*!#!3\rL3"!&*3K!%%!)!5%3!5%)!L&!!54!%%!)!L0!#%!$)8!")N!)!L&!!5&!"#833!K\r!%!%M#%!3!b%3!L&!!5&!"59!%%!)3!)K#!)K3!)K%!%K#!%L%%!")d!33!)K%!%\rK#!%K%!%L#%!&)8!")8!$)d!33!-L3!J"*4"!#%!3!5))3!%N!3'3!!J#2JT@CA*\rTCRPTEQFX)("XC@&cC5"bC5ePER4PFL!PF`)i#JF(6@PcE@&dBfJJ,5"dFRNJB@G\rKD@i+!L%+!53"jj!!#!)N!Iq!c!)Q)$"i)(XJ!L)PH!)L,#!#)L"p!L#"!!'3#2k\r3#"q3"!k3"1#3"2'3"!(q!Ii"rJ(qrJ(q!Ii"rJ%Ii"rJ$[%1mH!Ii"ra$[%1!H!\r"i!(a!I(J!H!"m3(a!4rq(ri1rJlqrKrq(ri1rJi"(`%I!3i"$Km"(`%1!3i"i2l\rJr[(qmIlqi2lJr[(qm3XK!B)#"3!"!!%!!3!"!!%&)3'#!J8!!3!"!!%!!3!"!L!\rZdY28eGEAf0RDfpcGhYrJiH,Mj1AQjqMTkZ[XlHl[m2(bmr6ep[IiqIVlr2hqr`%\rJJ48"!J-%"3B(#!N+#`8'"`J*#JX-$3i2%"%5%a39&KFB'4SE("dH(b!K)L-N*5!\rK)L-N*5BR+#NU+b`Y,Lm`-6)c0$8f0cJj1MXm26ir3%d3Z,c!a-M-d06Bh1$P\r"3N0%48C(5%P+5da06Np389*69&9@9eKC@Q&LBf4PCQGSD@TVE'eZEh"aFR0dGAC\rhH(Pk!Iq!T!NL%#!$)5!#)4!")3%$)3%")a!J!3)L)!%")4!#)3J$)`J3)!%K#!%\rK)!%L#"!")J%)!LB"#"!J!3J"*#!"#"!$)5!$)M!J!L)J)!)K-!%K!3%K)!%K!3%\rM-#!"!5-J)!%")6!#)JJJ!L-)-#!")`JJ)!%L#$!")`%))!%V!3J`)!%))#!"#$!\r")3L"!`F!!!J3)!J!)!J3!!N!!!N3)!N!)!NK%!%L#!J#*JJ)%#!)#!%N)!J)%!%\rL#3J#*JN)%#!*#!%N)!N)%!%K#)%$"b!!#$!J##!J#$!!#5!!#6!J#5!J#5%`!5-\r)##!"+`J)-#!)##!J#!J`!5-*##!"+`N)-#!*##!J#3J`"#%#"5%J!5%#!5%J!L%\rJ!L)#)!-L)#!")`)J)!3L"!)#)33#)b!%!J%L)!3")5!")`3#)!%K"!%R)#!%!L!\rJ"!)K")%$"`)!"!!!*!)!*!!J"!)J"!!J*!)J*!)M"!3#!5)%"!)M*!3#!5)N"!%\rR)!3%!L!%"!%S)#3%!L!N""!$)4)$)4!")5!")4)")5!")K!J!L)5)!)M%#!J!5-\r5)#!")4!#)J35!L)%%!%M)!35!53J""!J!5-%%L!"+J33)#!%%L!J""!")35"!`F\r5!!33!#35!#33)!35)!33)#35)#3K%!%M"!35!5-%""!")b3%%J%b*!33)!3%%L!\r%""!J*!35)#3%"b%"!5%%J3-0!!!%!3%!!!%!!3%%!!%%!3!!!J!!!`!%!J!%!`%\r!!J%!!`%%!J%%)3-#)3)$)J)"!5)%!J)N"!)"!3%K!J%K!3%P!J%""!)"*!%%!J%\r#)J)#!L)#!`%M"!)#!53%!J-"!5-#!J%"+`)$!33#!J%%!J-)!b%)!L-"#!5"!`d\r!#!3"#3!!#3!"#33!#33"#!!##!!$#!3##!3$#3!##3!$#33##33L!`J")3)")3J\r"*3)"#!3#!58)"!)"#3%K!J%K#3%P!J%*"!)"*3N%!J%)!5-#!JJ"+`)$#!3#!JJ\r%!J-*!5-#!JN"+J)$#33#!JN%!J-&)4!%)3%#)K!""#%)J3-+%!!)!!%)%!%)!"!\r!%"!!!"%!%"%!!"!)%"!)!"%)*"!4#!3$)J33!L%%!5%"!5-%%!%")33#)`J%%!%\rL#!3"*`%)""!"#!3")4!")`33%!%K"!%K%3%M""!4!5%%!5F3#!33%!J%!5B4#!3\r3%3L"!`m#!!!5!!!#!3!5!3!#!!J5!!J#!3J5!3J#%!!5%!!#%3!5%3!#%!J5%!J\r#%3JP%K%)"!)#)J35!L-%!J%")`35!3%L"!)")`J%%J%X#!3#!3J%%J%)"!)3!5-\r%%K!")`3#%3%M"")4!6!%!K!)"")3#!3#%3J%%K%)"#%3"#%"!L)3!38L""!#)33\r")3'"!aN%%!%%)!!!-!!!)!%!-!%!)!!%-!!%)!%%-!%%!"!!%"!!!"%!%"%!!"!\r%%"!%!"%%%"%%)"!!-"!!)"%!-"%!)"!%-"!%)"%%-"%K"!)K%!%K%!%K%!)L!4!\r")a!"%!-M%!33!5)3"!%S!4!%%!%3"#!")4!")6!")4!")b!"%!%M-!%3!5%J!5-\r3"$!"+K!%)!%3"$!"%!3")K!3!5-3%"!#)K%3!5-3%4!#*a!3""!3%!3"+K%3""!\r4%!3J%"!")c!3%!%M)"%3!5-`%4!"-#!3%!3`%"!%)"%3"$!4%!3%)3J')JJ)!L%\r)!L%%!5%)!5%%!b-%#!J")J3)!5%#!L))!J-K!J%M#!J#!5%)!5)#"!%M#!)%!LF\r#"!J)!J3)!b)"#)%$"J!"!!!*#!!*!!3"#!3"!!3*##)%#3%K!J%M!3J#!5%"!5%\r#!5-*#!)")3N"*`)%!3J#"!%"+!)%#3J#"!N#J3-(!!!+!!!#!!J+!!J#"!!+"!!\r#"!J+*!3)!J)#)JS#!L)#!J%M#!S#!53)!J)%!5-+!J3"+3)#"!J+!J3)!S%$"`!\r"#J!"!J!*#J!*!J3"#J3"!J3*#L3%#3)#!5-"#J)")`%#!J%M#3S#!6%*!J)%!3S\r#"!%#!J3*#J)%#3BK!B%$"J!)!!!)!3%!!!%!!3%)!!%)!3-K%!)L!4!")3J")4!\r"*!J"%!%#)K!"!53"%!%)!583!3J"%!%K)!-L)!'"!`B!+!!!+!%")!!")!%"+!!\r"+!%")5!")4!")b!"%!%K+!%K%!%P+!%3!5!"*a!")!%3!5J"*4!"+!%3!L%#J3-\r(!!!$!!J#!!J$!3!#!3!$!3J#!3J$!L)#%!)L!a!")`J#%!%N#!-3!3%M!K!"!5S\r$%!%)!K!"#!-3!5)J!S%$"`!J!`!S!J!S!`%J!J%J!`%S!J%S!`%M)!)3!5-J!a!\r")bJ#%!%c+!-3!5!#%!%J!a!"+!)3!5J$%!3K"!3K"!)L"!3&)J)%!L%#!5%%!5-\r#"!3")3)#)5!")33")5!#)J3J!5-%"#!$)b!#"!%L)!)"*`3J!J3%)!)$)L!%!L%\rJ!5%%!5-J"!3")5!$)L)%!L%L!5%%!5-L"!3")5)#)b!J"!%L)#!"*`3J)!3%)#!\r#)b!L"!%L)#)"*`3J)J3%)#)#)3J")33")3J#)J3)!5-%"!J$)`J#"!%L#!)"*`3\r)!J3%#!)#)5J")33")5J#)J3S!5-%"#J$)bJ#"!%L+!)"*`3S!J3%+!)#)`JJ"!%\rL##!"*`3))!3%##!#)`JL"!%L##)"*`3))J3%##)#)bJJ"!%L+#!"*`3S)!3%+#!\r#)bJL"!%L+#)"+J3S)J3%+#)##!J#)3J#)3)#*J)##!J#!J3M#!J#!5%)!5)#!J)\rK!J%Q#!J#!JJ)!5)##!3M#!)#!5-)!J)))3J")3)")3J&)J)#!5%)!L))#!%Q!JJ\r)!J))"#-)!J)")3J%)3)#)3J#)JJ)!5)##!%K!J)K#!%K!J%N#!)##!%K!JJP!JJ\r)!J)")3J#)3J"*!)##!J#)3J%)`J#!J%K#!%L!JJ")3)#)3J#)JJ)!5%#!L%#!5-\r)#!)$)J)#!L-#!JJ#*!))#!)")JJ)!5)##!)K!J%M#!)#"5))!J%K#!%K!J8K#!)\rK!J-K!J%P#!)##!J%)`)##!%K!J)K#!)R#!J#3"#!%!8L%)!")N!3!L&!!L%3!L1\r!%%!")B!#)K#!!b'!!5*!%!%K%!-L%%!")B!#)4!"*""!%)!")N!3"5%3!5%3!L&\r!!55!%%!3!5%3!L'!!L33J""!##%3!5)33!%LJ"!"*K#!%%!3J!%K3!)L%%!%)4!\r%*S!33"#!%!%K%!%N%%!3J!%K3!%KJ!)R%)!33"#!%!%K%!%L%%!#)4!%)8!&)S!\r3!5%3!L*!%!%K%!)KJ!%K3!3N%)!33!%PJ""!%)!$)B!&)8!#)4!$*4"!%)!3!5)\r3J!%L3"!#)N!3!5%3!5%3"#1!%%!")B!")8!")S!3!b-33"!$)K#!!5%%!L3""!3\r"!b%"!5%%!5)"!3%K"!%L!33$)33")J%"!5)%!3%K"!%K!3)K"!)L"!3&*3%%"!%\r"!L)"!3-M!33%!5%""5%%!53""!3"!b%"!bB"!33%!3%")33#)33#)`%%"!%L!33\r")3%#*33"!33%!b)%!38K"!3Q"!%""!3"!b%""#%"!5%%"#)"!3%K"!%M!33%!L%\r%!5)"!33M"!3"!L)%!3%L"!3")3%")33")J%%!b3%"!%"!b%"!53%!3%%!L)""!-\rN"!3"!3%K"!)K"!%K!3%K"!%L!3%")J3"!5%%!5%""5)%"!%K!3)M!3%%!L%"!5-\r%!3%#)3%")J3%!b4!%!J3!5%3"#8)%%!3#!3L%%!#)4!")K!)!5&!!53)%%!3!5%\r3!L))%!8M%!J3!L%)!50!%!J")8!#)4!$)K"!!5%)!5*!%!-K%!3K#!%L3"!")4!\r"*"!)%%!%)4!$)K!)"5&!!53)%%!3!5%3!5%3!5)33!%P#""!%!J")8!#)K"!!5%\r)!L)3#!%K3!)K%!)K#!%L3"!")4!")4!%)`J33!)K%!%L%!J')4!#)8!")3J%)K"\r!!53)%%!3!b%3!5%3!b333"!)!50!%!J")8!#*""!%!J$)JJ3!5%3!L0!%!J")8!\r")3J")N!3!5)33!)K%!%L%!J#)a!)%!-K%!)N#""!%!%K#!3K!33K"!%Q#!%%)!J\r"!5)J#!%K"!)P!33J#!%$)3%&)L!)!L%J!5)""!%K#!%N"#!)!3%N)!J""!BL!33\r")3J%)3%")5!#)`3J#!%K"!)M!33J"#%)!L%J!b)J#!%Q"#!)!33J!5%"!5-J#!%\r%)33$*33J#!%%!5-)!33")3J")J3J!5%"!5-J#!%$)3%&)L!)!L)J#!%K"!%K#!3\rL!33"*!J""#!&*!%%)!J&)33#)3%")L!)!5)%)!)K"!8Q#!%%)!J"!53J#!%%!b)\r%)!%K!3-L!33")JJ"!5)J#!%K"!-L"#!$)5!"*3%%)!J"!L%)!L)JJ!)K3!%K)!%\rK3!3MJ#!J!L%J!5&!!L%J!5'!!5)J3!%K)!3Q)%#!)#"!!5)J)!%KJ!-KJ!%K)!%\rKJ!)M3)!J!b-J)%!")5!#)B!"*#"!J#!")8!')5!%*%#!)#!")S!J!5G!J#!J3)!\rJ!L'!"5)J3!-K3!%L)#!#*#!J3)!")5!$)b"!J!-KJ!%K)!)Q)#"!J#!J!L%J!5&\r!"#'!!5%J!5'!"5%J!5+!)!%K3!%K)!-K)!%P3)!J)%!")L!J"#9!J#!J3!%L)#!\r#)5!#)B!")b"!J!)M3)!J!b-J)%!')5!")B!#)N#!!58J3)!J)!%LJ#!%)L"!!b0\r!J#!")8!#)8!$)3)")3'"!ad#!!%!"!&#"!"!"!"#!*!%!3!!!3)%!!)%!8!!!!!\r%!8)!!8!!!!)%!3)%!%!!!%!%!8)%!!!!!3)!!3!%!%)!!8!%!%)%!8)!!!!%!%)\r%!8!%!!)!!33M3J3"J3-+3!!"3!3!!J3!3!!!!J!"!!!"3!3"!J3!3J3!3J!!"#%\r#!5%"J3-5!!3!!!3"!J#3"!%#"!%#!!"#!!!#"!"!!!&#"!%!!!&#!!!!"!"!"!&\r#"!%!"!&#!!&!!!!N3!3JJ)%$(S!JJJ!!!S!!!!!J!J!!J)!JJ!!JJS!!!)!J!!!\r!JJ!!!S!!JS!J!S!J!)!JJ!!!!J!!JS!!J)!J!J!JJS!J!)!!N!5#!#!!!!#!!#!\r#J##!J!#!!!!#!###"#'!!5'!!b%#!L%J!L1!)))")B!")3)")S!J##'#!L)JJ!%\rMJ#!#!51!)!)$)B!")i!JJJ8KJ!%KJ)%$#B!J!J!JJS!!J!!JJ!!J!)!!JJ!!!S!\rJ!S!JJ!3MJ###J3-(!!##J!!!!#!!!##!J!!#!!##J!!!!)&K)LaiJJ)V,)!XL#e\rS)UiXQ"TS'HJV2LbS'UiCU#bi'5JC*"NJ'4`C&#c),0!C"KMX'-`V1Lc`,2JY!#U\rb+VSY%#dB,5!%aJ$'!+B!CJ!Q!!BY-#di,8!-aK$'#-B!)#)r2!%M"UR`!L,rr4)\rL,%##!Mi!-#a!!!)X3&2F,%"0*#a!61iX3%Rd,%!`8La!,rBX3#p@,%!Z-#a!,'S\rX3#[f,%!Ul#a!+D!X3#NQ,%!ShLa!+)3X3#HL,%!R4La!*Z!X3#0Q,%!Be#a!&kB\rX3"DN,%!3R#a!#eBX3!$#,%!!P#a!!%`X3#Z3!&5U!8J!d"NL!J%")3J%)M!"!5%\r)"#4-!3%)"#+8!3%K#!3K`JBP*Z!")!J$*5G'!5!)!b-RSJ%")5!$*5L%!3%)!b)\rShJ)K#!-P+5B"!3J$)LQJ!5,r#!-L+Qi'*5VX!Hm3!bBVp[rrl)B#*LaUrrrXb!)\rQ,M$rrqc1!L8[9J&K#!-P,rB"B3J$)M"5"L0-lJ%")3J$*NdNrrrZD!)L6X!'*92\rF!HF)!b*8UJcrN!3!N!F"!!!YB!!!!!%!!#eB!!!!!`!!!"!!!!!"!!!!c!!!!0`\r!!!0d!!!!"!!!!"S!N!m0!*!,E!#3#`)!!!!0!*!(V`#3#`%!!!!2!*!%!3!!%`)\r!!"X#!!!K!J!!+!)!!$%#!!!i!J!!2`)!!%8#!!"-!J!!83)!!&J#!!"G!J!!C3)\r!!)8#!!#E!J!![!!"!*!&"`#3"+!!+e"+$d)VJ$G'(8)!!!"0594IT8e*9%0-D@)\rZC'9LG@F!AepQD@aPF`"QCf9dF`"`FQPZG'B!BfaPBA*PFR)!CQCXGA0S!(0dFQ0\rSFJ"cFQ&ZC!"cG(*MEA!!FQ&ZC!"YC@eMEA!!G'PYC3"QF(*TER4Q!'ePEA0PG!"\r0594IT8e*9&*eER4TE@9-D@)ZC'9LG@F!AepeER*PCfPcG'9bAfCbB@GYC@jd!&p\rIFQ9RDA0dCA*ICR*KCfePER3!5@jdCA*QB@0P6'PL!&4TBfY$Eh9ZG!"NCA0IC'9\rLG@F!C'9cAh*PB@4IF'&cFhG[FQ3!C'9cAh0PG&pcCA&eC@jMC9pZG@eLCA)!C'9\rcAh0PG&pVCAN!C'9cAfPcAhGPB@YIDf9j!'4PFepcG(*TEQGIG'pIDf9j!'4PFep\rZCAGIFQ&ZC'pYAfYPH3"NCA0IBf*XEf0VAh"bD@jdAfCTE'8!C'9cAfCMFRP`G!"\rNCA0IBfKPBfYIDf9jAh"KFQPdH3"NCA0ICQPiGA"IDf9jAh"KFQPdH3"NCA0IFQ&\rZC'pYAfYPH3"NCA0IBh*jF(3!C'9cAh*PB@4IF(GIFh4bD@jR!'4PFepTEQPdAh*\rKEQ4[E9pZG@eLCA*ICf9ZCA*KG'pb!'4PFemcC@0LAf9ZBh*jF(3!C'9cAc0MBQ0\rIC@jMFRP`G!"NCA0IFf9dAh*KEQ4[E9pRC@jPFQ&dEh*IFf9PC!"NCA0IDf9jAh0\rMD'9N!'4PFepaG@&NAf0VFh9Y!'eKDf9IDf9jAh0MD'9N!'4PFepPBf*IC@jMFRP\r`G!"NCA0IBf*MAf9ZBh*jF(3!C'9cAfGPEQ9bBA4PAh*KEQ4[E9pLE'pMD`"NCA0\rIF'0LBepPEQ0bHA"d!'4PFepMBQ0IBfYcG@d!N!B-!!!!$!!$!!3!"J!%!!F!$!!\r)!!3!#`!%!!`!!!!0!!J!$3!3!!m!#!!6!!!!&3!)!"8!!!!A!!`!&`!*4Fd!%C0\r8!"IZC`!,%NB!$ee'!"&VQ`!5Y*S!&6r)!!U,8!!8R43!&(88!!kAf`!*4A!!%L3\rk!#$#a3!34D!!%&+J!"edaJ!08`S!$S92!!k,#`!2Cm%!$hc"!"N3i3!31U8!$9m\r2!3!!aJ!!+Ui!!3)!!0!!!#cB!!%#!!$L!!!Xq!!"!J!!qJ!!,+J!!3)!!3B!!#b\ri!!%#!!%@!!!Xb!!"!J!"+!!!,4!!!3)!!6X!!#c!!!%#!!&4!!!XQ!!"!J!"A!!\r!,6!!!3)!!A%!!#di!!%#!!''!!!Xi!!"!J!"P3!!,+!!!3)!!Cm!!#c3!!%#!!'\rb!!!Y#!!"!J!"d`!!,*!!!!%#!!(N!!!XX!!"!J!"p3!!,3!!!3)!!K-!!#dB!!%\r#!!)K!!!Xk!!"!J!#-!!!,5!!!3)!!Mm!!#e!!!%#!!*2!!!Y8!!"!J!#A`!!,2!\r!!3)!!RN!!#dS!!%#!!++!!!Y5!!"kh3!!!%!!!!"B!!!!'!!!!!bFf0KE#!f1%X\r!N"G849K8,R"MD!#3(%eA)%-[3bXV)$Bi5`#3&)!!!!"849K8,R"MD#XV!*!D69F\rJ3bp$+bXJ0MK,!*!8J!!!!&4&@&3ZF("e!*!F69FJ8'&cBf&X)$Bi5`#3%e`!N!X\r"!*!6!@df1'X!N"-"!*!42"&0594IT@4PFfaTBLjNC@*eC`!!!3!!!!&J!!!!B!!\r!!$)'Ce5-AJ)!!!!F!$)!!'0QFQF!!!!+!!$rr`#3##0I:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:#Q4PFfaTBLj38%-!FfKXBMq3"!#3")pK!!!"M[Q[5Qpj)A"PCQC`Gh"M!!!!!E*\rETlJ!N!d$!!)!N!6rN!3!N!CIH!!!AhJ!!&pi!!!&S!!%"!$rN!3!N!BYdJ!!,63\r!!#T"!!"P)!)""!$rN!3!N!i&)!!!!)!%"!3!N!ArN!3!N!F"!!!!p!!!!!%!!!$\rX!!!!!`!!!")!!!!"!!!!e!!!!23!!!0d!!!!"!!!!"S!N!m2!*!,$3#3#`)!!!!\r2!*!()!#3#`%!!!!4!*!%!J!!,3)!!$3#!!!l!J!!3J)!!%J#!!"2!J!!9!%!!&X\r#!!"M!J!!DJ)!!'m#!!"f!J!!I!)!!)8#!!#-!J!!P!)!!+S#!!#q!!%!N!83!*!\r%5JCJ#%S)3J*J"d)"3!&#!8!"3KL!%dBD3#UJ!"[`3""0594IT8e*9%0-D@)!68P\r8Ak905945G@jdD@eP6'PL!%PZG'9bCQ&MC8aTBJ"cG(*MEA!!Fh4bBfKb!'CQE(9\rcD!"cFQ&ZC!"YC@eMF(N!FQ&ZC!"YC@eMEA!!AepQD@aPF`"cG(*XC@i!G'PYC3"\r`FQPZG'B!CQGPG(-!BfaPBA*PFR)!E@9YFf9d!'C`FQPZG'B!AepeER*PCfPcG'9\rbAfCbB@GYC@jd!&pIFQ9RDA0dCA*ICR*KCfePER3!9'PMDd0[G@jd!'4PFepbC@&\rNAh"KFh0hEh*NC'9cAh0PG&pcCA&eC@jMC9pZG@eLCA*NCA0IC'9LG@GNCA0IFf9\rdAfYPH@4PFepTFephC@&VAfYPH@4PFepcG(*TEQGIG'pIDf9jC'9cAfjPGepbB@j\rNEfeIDf9jC'9cAf0LE'pMDep`FQPZG&pQD@aPC'9cAfCMFRP`G'4PFepQDAKeF&p\rVCAPIF'&bDA4jC'9cAf0SC@0VAfYPH9p`BA*TG(PNCA0IFQ&ZC'pYAfYPH@4PFep\rMFRP`G'4PFepbC@&NAh"hAh0dFQPZCf4PFepTEQPdAh*KEQ4[E9pZG@eLCA*ICf9\rZCA*KG'pbC'9cAc0PBf*IC@jMFRP`G'4PFemcBf*MAf9ZBh*jF(4NCA0IFf9dAh*\rKEQ4[E9pRC@jPFQ&dEh*IFf9PC'4PFepVCAPIFf0SC@4NCA0IFA9KC&pMDh0eE@e\rKDf9IDf9jAh0MD'9NC'9cAf9MBPpPEQ0bHA"dC'9cAf0LBepPEQ0bHA"dC'9cAfG\rPEQ9bBA4PAh*KEQ4[E9pLE'pMDf4PFep`Bf*MAf9ZBh*jF(4NCA0IBf*MAf0VFh9\rY!*!&$!!!!!`!!`!%!!B!"!!(!!`!#!!%!!X!"!!-!!!!$3!)!!d!%!!2!!J!%`!\r!!"8!#!!9!!!!&`!-!"F!%C08!"IZC`!*4Fd!#a*'!!pG4J!4DjX!%V5D!"8rb!!\r+Le!!&(88!"5G&!!1PpX!#89`!")N1J!J`X8!%%@J!""5S!!GG-B!$9-+!!k&6`!\r1L`X!$fI"!!pm`3!C%1%!%$UP!!eI$`)!!-J!!!&m!!%#!!$C!!!"4!!"!3!!m!!\r!,63!!3)!!2N!!!'N!!%#!!%%!!!"P!!"!J!"%`!!!B3!!3)!!53!!!&F!!%#!!%\rf!!!"M!!"!J!"5`!!!D`!!3)!!98!!!%F!!%#!!&T!!!"&!!"!J!"I3!!!@`!!3)\r!!BX!!!'d!!%#!!'8!!!"G!!"!J!"TJ!!!93!!3)!!FB!!!'m!!%#!!(@!!!"R!!\r"!J!"jJ!!!8`!!3)!!J-!!!%d!!%#!!)3!!!"C!!"!J!#(J!!!5`!!3)!!L`!!!%\r-!!%#!!)l!!!!r!!"!J!#5J!!!6`!!3)!!Q-!!!%N!!%#!!*c!!!""!!"I!J#TT!\r!!3!)P#(r`$JK!%#!!3!)I!J$TNk!!#"m#!+QNq(rr*!!!3!)P#(r`*!!B3"B1q!\r!!)"K!&K)!&`eB!!!!(ar'hKri`Fd,!-!!%'#!!arirYi5!!!#(rMqhL!!3")1#%\r!3(`)!kD$iIrm6S!!)!#3"L""J!%!N!98!"3ZAepTEQPdD@&XDATPAf4PFfaTBJ!\r!I!J#TT!!!3!)P#(r`%J!A#&J!!!!J!%!5$JK!%"m#!1Q6S!!)!#3"L""J!#3"L3\r!%bjIAh4PFQeTEQ&dC9pNCA0XD@)!!!#q)Ir%1Z)2-$[#%c!l!JX`I0XcH#`)!!"\r"JJA8I2BlH)Nf!!!keJ!"95N'2P8m`!k*9J!!1YB!!99+"Mj95S!HIja6H)Pf!!!\rkeJ!"9@X'2P9V3#jrR&YiLCB!!$V@!!&9M!BqIjaMH)Nf!!!keJ!"95N'2P8p`!k\r*9J!!1YB!!99+"Mj95S!HIle6H)Pf!!!keJ!"9@X'2P9V3#jr[9YiLCB!!$V@!!&\r9M!BqIleMH(af'hKmP50i5!!&+#`&!!K"J!$%L6B!!$V@!!&9+3Bq95N'2P8T`!j\rrR%TiL9B!!$V@!!&95JBq98S'2P9+J"jrR&*iLAB!!$V@!!&9D`Bq9@X'2P9V3#j\rrR&TiLCB!!$V@!!&9M!Bq9B`'2RqFBRL*0J!!1YB!!98T"Mj9+3Bq95R!$Rqp5RL\r*9J!!1YB!!99+"Mj95JBq98U!(Rqp8RL*GJ!!1YB!!99V"Mj9D`Bq9@Y!,Rqp@RL\r*PJ!!1YB!!9@-"Mj9M!BqIleLH$LPrrK)!!#`IYBU&#J&!!G"J3#J15)"k&5U%$T\rp+9!ZI5N$TNk!"#!ke[rrLAB!!&9V"Mj9Dd!ZIleDH$V@rrq*PJ!!9B`'2P@-J"j\rr[@*i1YErriNf!!"9+3Bq95R!$Rqp5RJke[rrL9B!!&9+"MjrR&*i1YErriPf!!"\r9D`Bq9@Y!,RqF@RJke[rrLCB!!&@-"Mj9M)!HIjaLH$V@rrq*0J!!95N'2P8T`!j\rrR%Ti1+!!!$e!UUXj5UUUIiT31$eJUUXjDkUUIkYB1&9Vq(jpAeYi2B"996Q-999\rrM'!i9B`)2$dJ998j+999IkP)1(fG5hKAUJBq98S31ReB8#j95KJi9k['2P9V%$T\rpH&JZ9@X31PHX4Mj9M"!kICKJ,PHTKMj9+4!kI6K),P8T#$apM%YiI@YMH(eF@hK\rAkJBq98S31ReB8#j95KJi9q['2P9V%$TpH&JZ9@X31PIX4Mj9M"!kICKJ,PITKMj\r9+4!kI6K),P8T#$apM%YiI@YMH(eG@hJl3!!!5!!"S)&E!!!lH`!%9kZUrPHXU"4\rpDf0iI9pDH&IT"Vj9+4!k15N$!(dq5#jAkXDq98S31MP+!J"pAP!Z9qZ'[P9V%$S\rjD`%!IAjB,PIX4Vj9M"!kICjJ,ReVBhKp5PYiI5P6H(qF5RL"1`!!1hX!"&HU6Ij\rAUdJXI8TEH(dr8RKAl!Dq9B`31MQ-"`"pRQ!Z9qR'[P8T%$Sj+3B!I6j),PIU4Vj\r95K!k18S%!(eH8#jAkiDq9@X31MPV"3"pIPJZI8TEH(dT8hKpM%YiIjaLH)'E!!!\rlH`!%9iQUrPH+U"4p+90iICp+H&IV"Vj9Da!k1@X$!(eq@#jAl-Dq9B`31MQ-!J"\rpRQ!Z9qQ'[P8T%$Sj+3%!I6j),PIU4Vj95K!kI9j3,RdT8hKpM%YiI@YMH(qp@RL\r"H`!!1hX!"&H-6IjAL8JXIBa,H(erBRKAkJDq98S31MP+"`"pAP!Z9q['[P9V%$S\rjD`B!IAjB,PIX4Vj9M"!k1B`%!(fHB#jAkBDq95N31MNT"3"p2NJZIBa,H(eVBhK\rp5PYiIle5H$YD!!%X'J!)3B$qB$e!m2%j5[$`IkT31$eJm2%jDr$`IiYB1&9Vi6j\rpAeYi2B!2$cQ-$`prV'!i9B`J0MdJ$`mj+3m2IiP)1(fG5hKAUJBq98S31ReA8#j\rAUmBq9@X31Reh@#j9Da!k9ka'2P@-%$TpPf!Z9B``-PHTKMj9+4!kI6G),P8T)$C\rpM%YiI@YMH(eF@hKAkJBq98S31ReA8#jAkmBq9@X31Reh@#j9Da!k9qa'2P@-%$T\rpPf!Z9B``-PITKMj9+4!kI6G),P8T)$CpM%YiI@YMH(eG@hJlHrq!9iT'2TP9!!!\rkY3!"9iZ'2TPe!!!kY3!"9ic'2TQ9!!!kY3!"9iN'2TNe!!!kY3!"9kT'2TP9!!!\rkY3!"9kZ'2TPe!!!kY3!"9kc'2TQ9!!!kY3!"9kN'2TNe!!!kY3!",!8!!%'"qYK\r)!!@B,!8!!%'"!!`iB!!!5!!&M(cf1hL*9J!!1YB!!99+"Mj99-!1LAB!!$V@!!&\r9D`Bq9@Z!(Rk8@hL*PJ!!1YB!!9@-"Mj9M%!ZIT4MH)Nf!!!keJ!"95N'2Rk85hL\r*9J!!1YB!!99+"Mj98m!1LAB!!$V@!!&9D`Bq9@Z!(Rjc@hL*PJ!!1YB!!9@-"Mj\r9M%!ZIR0MH)Nf!!!keJ!"95N'2Rjc5hKmGKYiI*8MH)P@!!!keJ!"98S'2P9F`!k\r*GJ!!1YB!!99V"Mj9Di!HIjaEH)Q@!!!keJ!"9B`'2P@-3#jrR'0iL6B!!$V@!!&\r9+3BqIja,H)P@!!!keJ!"98S'2P9G`!k*GJ!!1YB!!99V"Mj9Di!HIleEH)Q@!!!\rkeJ!"9B`'2P@-3#jr[@0iL6B!!$V@!!&9+3BqIle,H(q5ihKrXHYi28#UUcP+UUT\rrLP!i2@#UUcPVUUTrUeJi9@[iIReI@hJpJ&991Ba99Aq-B$K9M!Jm25"996NT999\rrU8JiICe,H&HU"Mj95K!kI9K3,P9+'$KAUmBq9@X31Rei@#j9Da!k9ka'2P@-%$T\rpQ'!Z9kQ'2P8T%$Tp1%JZ95N)2(f-5hKpDf0iI9aEH&IU"Mj95K!kI9K3,P9+'$K\rAkmBq9@X31Rei@#j9Da!k9qa'2P@-%$TpQ'!Z9qQ'2P8T%$Tp1%JZ95N)2(f-5hK\rpDf0iI9eEH$Yl!)!l)!!!5!!"S$Ylrrb"@`!!9kY0rPHX5#apDf0iI9pDH&IT4Vj\r9+4!k15N%!(dq5#jAkSDq98S31MP+"3"pAP!Z9qX'[P9V%$SjD`F!IAjB,PIXaVj\r9M"!k1B`'!(fHB#jpDf0iI8TEH(dT8hKrR%Ti1h[rr)%l!!"AUUVq9kZS&(e+@hK\rp2e*i9qb'[P@-%$SjM!%!ICjJ,PIT"Vj9+4!k15N$!(dq5#jAkXDq98S31MP+!J"\rpAP!ZI5P6H(f-5hKAkdDq9@X31Req@#jpM&YiIjaLH$Ylrrb"Q`!!9iP0rPH+5#a\rp+90iICp+H&IV4Vj9Da!k1@X%!(eq@#jAl)Dq9B`31MQ-"3"pRQ!Z9qN'[P8T%$S\rj+3F!I6j),PIUaVj95K!k18S'!(eH8#jp+90iIBa,H(eVBhKr[9Ti1h[rr)&l!!"\rAM+Vq9iQS&(f-5hKpIf*i9qU'[P9+%$Sj5J%!I9j3,PIV"Vj9Da!k1@X$!(eq@#j\rAl-Dq9B`31MQ-!J"pRQ!ZI@YMH(e+@hKAk8Dq95N31Rdq5#jp5NYiIle5H$Xj!!%\rX'3!)3B$qB$e!m2%j5[$`IkT31$eJm2%jDr$`IiYB1&9Vi6jpAeYi2B!2$cQ-$`p\rrV'!i9B`J0MdJ$`mj+3m2IiP)1(fG5hKAUJBq98S31ReA8#jAUmBq9@X31Reh@#j\r9Da!k9ka'2P@-%$TpPf!Z9B``-PHTKMj9+4!kI6G),P8T)$CpM%YiI@YMH(eF@hK\rAkJBq98S31ReA8#jAkmBq9@X31Reh@#j9Da!k9qa'2P@-%$TpPf!Z9B``-PITKMj\r9+4!kI6G),P8T)$CpM%YiI@YMH(eG@hKrR+*iIlfDH#`&!!K!J3"d1+Arq&H+4Mk\rC93!!1V8!!9H,KMkCG3!!1V8!!9H-aMkCP3!!1V8!!9H*"MkC03!!1V8!!9HU4Mk\rC93!!1V8!!9HVKMkCG3!!1V8!!9HXaMkCP3!!1V8!!9HT"MkC03!!1V8!!Aj8NhK\rq-iYi5rrlR(ke+K3S"3!)3B%!H$P#!F48Ua!kI8TB,Re*!kC1J!3J9k`'2MUerrq\rCP3!!9kR'2MUerrqC03!!9kU'2MUerrqC93!!9kY'2MUerrqCG3!!9i`'2MUerrq\rCP3!!9iR'2MUerrqC03!!9iU'2MUerrqC93!!9iY'2MUerrqCG3!!1'!!!,SKrm4\r1J!!J!*!')%!!$`#3"!Z-!"!ZC'9cAf0LBepPEQ0bHA"d!!#q`IrB1`)2-$[#%c!\rl)JX`I2FlH)NA!!!kp`!"93J'2P8F`!k*0`!!1[F!!98T"Mj9+B!HIja,H)PA!!!\rkp`!"98S'2P9+3#jrR&0iLAF!!$Vh!!&9D`BqIjaEH)QA!!!kp`!"9B`'2P@G`!k\r*&`!!1[F!!98)"Mj9#)!HIle$H)Nh!!!kp`!"95N'2P8T3#jr[8YiL9F!!$Vh!!&\r95JBqIle6H(ah'hKmYLYi5!!%c#`@!!K"J!$%LAF!!$Vh!!&9D`Bq9@X'2P9V`!j\rrR&TiLCF!!$Vh!!&9M!Bq9B`'2P@-J"jrR'*iL4F!!$Vh!!&9#!Bq93J'2P8)3#j\rrR%*iL6F!!$Vh!!&9+3Bq95N'2RqF5RL*9`!!1[F!!99+"Mj95JBq98V!$Rqp8RL\r*G`!!1[F!!99V"Mj9D`Bq9@Z!(Rqp@RL*P`!!1[F!!9@-"Mj9M!Bq9Ba!,RqpBRL\r*&`!!1[F!!98)"Mj9#!BqIle#H$V@rrK)!!#`I[Hb&#J@!!G"J3#J15)##&E+%$T\rp+9!ZI5N$TNk!"#!kprrrLAF!!&9V"Mj9Dd!ZIleDH$Vhrrq*P`!!9B`'2P@-J"j\rr[@*i1[IrriNA!!"9#!Bq93M!$Rqp3RJkprrrL6F!!&8T"MjrR%Ti1[IrriPA!!"\r95JBq98T!,RqF8RJkprrrLAF!!&9V"Mj9Di!HIjaDH$Vhrrq*P`!!9B`'2P@-`!j\rrR'*i1X!!!(cE-hJp!+UV13LUURq)3$Jp)+UV15QUURqT5$K9+IKqI4p,H$e!998\rj5P99IiT31&9+#$`pB&991@Y99AqV@$KpA9Yi9k`'2P@-%$TpQ@!Z9B`B1&HSaMj\r9#"!kI4P!,P8)%$TAU8Bq95N31Rdj5#jAUSBq98S31ReC8#j95JJmI5P6H(d)5hK\rpR%0i9qX'2P9V%$TpH9JZ9@XB1&IXaMj9M"!kICPJ,P@-%$TAk%Bq93J31RdC3#j\rAkBBq95N31Rdj5#j9+3JmI3K,H(f-3hKpI@0i1d!!!%J!!D#"@`!!1hX!"&HVU[j\rAV+J8I@YMH(eI@RKAk!Dq93J31MN)!`"p(N!Z9qR'[P8T%$Sj+3)!I6j),PIUKVj\r95K!k18S"!(eH8#jAkdDq9@X31Req@#jp5PYiI5P6H(d)5hKrR%*iJCX!!$Yl!!4\rAU%hq9kP),(d)5hKpRd*i9qS'[P9+%$Sj5JF!I9j3,PIVaVj9Da!k1@X'!(eq@#j\rAl%Dq9B`31MQ-"!"pRQ!Z9qL'[P8)%$Sj#!8!I4j!,Rf-3hKpDf0iI8TEH(qF8RL\r"1`!!1hX!"&H+U[jALkJ8I8TEH(dr8RKAl!Dq9B`31MQ-!`"pRQ!Z9qM'[P8)%$S\rj#!)!I4j!,PITKVj9+4!k15N"!(dq5#jAkNDq98S31ReH8#jp+90iI3K,H(f-3hK\rr[@*iJAX!!$Yl!!4AM%hq9iK),(f-3hKpIf*i9qN'[P8T%$Sj+3F!I6j),PIUaVj\r95K!k18S'!(eH8#jAkdDq9@X31MPV"!"pIPJZ9qb'[P@-%$SjM!8!ICjJ,ReVBhK\rp5PYiI5P6H(qp5RJl@J!","S!#%'!rQ!p!2$a13M`m(qS3$Jp)2$a15R`m(q*5$K\r9+H%qI4p,H$e!$`mj5Jm2IkT31&9+)$BpB!m21@X2$hq,@$KpA9Yi9k`'2P@-%$T\rpQ'!Z9kM'2P8)%$Tp'%!Z93J31PHT4Mj9+4!kI6K),P8T-$*AUSBq98S31ReB8#j\r95L!fI5P6H(d)5hKpR%0i9qX'2P9V%$TpH&JZ9qc'2P@-%$TpQ'!Z9B`31PIS4Mj\r9#"!kI4K!,P8)-$*AkBBq95N31Rdi5#j9+5!fI3K,H(f-3hKpI@0i1h[rJ#`@!!"\r"JIXdI*FMH&H+4MkC9`!!1[F!!9H,KMkCG`!!1[F!!9H-aMkCP`!!1[F!!9H)"Mk\rC&`!!1[F!!9HT4MkC0`!!1[F!!9HUKMkC9`!!1[F!!9HVaMkCG`!!1[F!!9HX"Mk\rCP`!!1[F!!AqMkhLk`IrB6S!!)!#3"L"!!!S!N!3&m!!1,Q4PFepMBQ0IBfYcG@f\rqSIr81U)2-$[#%c!k`JX`I(JEH)Mi!!!l'!!"91F'2P6m`!k*'!!!1aJ!!98)"Mj\r9#)!HIja$H)Ni!!!l'!!"95N'2P8T3#jrR%YiL9J!!$XB!!&95JBqIja6H)Pi!!!\rl'!!"9@X'2P9p`!k*Q!!!1aJ!!9@-"Mj9M)!HIleMH)Mi!!!l'!!"91F'2P6R3#j\rr[6YiL4J!!$XB!!&9#!BqIle$H$dJUUXj+DUUIiP)1$e!UUXj5UUUIkT31&9+q(j\rp2e0i2@"996PV999rLeJi9@X)2$f!998jM&99IkaJ1(epBhKAT`Bq91F31Rcf1#j\r8jaJi9kM'2P8)%$Tp&N!Z93J31PHT4Mj9+4!kI6C),PHUKMj95K!kI9C3,P9+#$a\rp+90iI3K,H(cm3hKAk`Bq9@X31Ref@#j9DaJi9qc'2P@-%$TpPQ!Z9B`31PIR4Mj\r8ja!kI2Bi,PISKMj9#"!kI4C!,P8)#$amjd0iIB`lH(epBhJX"J!!3B)"Z(bk+hJ\rlB!!!5!!"S)%k!!!l@J!%9kUUrPHVU"4p5PYiI6p5H&IX"Vj9M"!k1B`$!(fHB#j\rAjmDq91F31MMR!J"mrMJZ9qL'[P8)%$Sj#!%!I4j!,PIT4Vj9+4!kI6j),Rd)5hK\rmjd0iIB`lH(qFBRL"@J!!1eS!"&HV6IjAV%JXI@YMH(eI@RKAj`Dq91F31MMR"`"\rmrMJZ9qM'[P8)%$Sj#!B!I4j!,PIT4Vj9+4!k15N%!(dq5#jAkSDq98S31MP+"3"\rpAP!ZI5P6H(d)5hKmjd0iIj`kH)&k!!!l@J!%9ibUrPH(U"4pM$YiIApLH&IS"Vj\r9#"!k13J$!(dH3#jAkFDq95N31MNT!J"p2NJZ9qU'[P9+%$Sj5J%!I9j3,PIV4Vj\r9Da!kIAjB,Re+@hKp+90iI3K,H(qp3RL"QJ!!1eS!"&H(6IjAL%JXI1G$H(fI1RK\rAk3Dq95N31MNT"`"p2NJZ9qV'[P9+%$Sj5JB!I9j3,PIV4Vj9Da!k1@X%!(eq@#j\rAl)Dq9B`31MQ-"3"pRQ!ZI@YMH(e+@hKp+90iIle+H$Yl!!%X'`!)3B$qB%J!!E3\rl*3#!1f!!!%J!!D!l1IrmJ2N!!&HS6IjAU8JXI3K,H(cr3RKAkNDq98S31MP+"!"\rpAP!Z9qZ'[P9V%$SjD`8!IAjB,PIX"Vj9M"!k1B`(!(fHB#jAjmDq91F31MMR"J"\rmrMJZIB`lH(eVBhKp5PYiIja5H$Xjrrb"'3!!9kQUrPHUU"4p+90iI4p+H&IVKVj\r9Da!k1@X"!(eq@#jAl!Dq9B`31MQ-!`"pRQ!Z9qI'[P6R%$Sij`)!I2ii,Rf-1hK\rpDf0i9qK'[P8)%$Tp(N!ZI@Y$H(qF@RJl1IrmJ6N!!&H+6IjALdJXI8TEH(dr8RK\rAl%Dq9B`31MQ-"!"pRQ!Z9qH'[P6R%$Sij`8!I2ii,PIS"Vj9#"!k13J(!(dH3#j\rAkFDq95N31MNT"J"p2NJZI3K,H(cR3hKpM$YiIleLH$Xjrrb"@3!!9iZUrPH-U"4\rpDf0iI9pDH&IRKVj8ja!k11F"!(cq1#jAk!Dq93J31MN)!`"p(N!Z9qR'[P8T%$S\rj+3)!I6j),Rd)5hKmjd0i9qT'[P9+%$TpAP!ZI1G6H(qp1RJlH`!","X!#%'!rQ!\rpB2$a1@[`m(qV@$JpJ2$a1Bc`m(q-B$K9M1%qIApMH$cJ$`mij`m2IkFi1&6R)$B\rp!!m213J2$hq)3$Kmr80i9kN'2P8T%$Tp08JZ9kV'2P9+%$Tp99!Z98S31PHV4Mj\r9Da!kIA9B,P9V-$*AV)Bq9B`31Rf9B#j9M#!fI@YMH(e+@hKp2&0i9qF'2P6R%$T\rmp6JZ9qM'2P8)%$Tp&8!Z93J31PIT4Mj9+4!kI69),P8T-$*AkSBq98S31Re98#j\r95L!fI5P6H(d)5hKmr80iI*FMH&H,4MkCG`!!1[F!!9H-KMkCP`!!1[F!!9H(aMk\rBp`!!1[F!!9H)"MkC&`!!1[F!!9HT4MkC0`!!1[F!!9HUKMkC9`!!1[F!!9HVaMk\rCG`!!1[F!!9HX"MkCP`!!1[F!!6KJ!!#kSIr86S!!)!#3"L"!!!X!N!3')!!3,Q4\rPFepPBf*IC@jMFRP`G!!!Nq(rr$[J!!")!!#BI)2iVP5%"MamJrQZI+2iVP5P"cj\rm`rLZ9-ER2RbP-RK8T3HqI12iVP6R"cjp!rLZ93MR2RcR3RK8jrHqI+8kH&5P"rj\rp)rLZ95N(2Re$q+j95ZFqI5P5H&8T"ljpBrLZ9@X(2Rf$q+j9M1FqI@YLH&9Vplj\rp+9Ti95RrrRbP5RKST3!"I)2iVRb%+hKmJrQZ1rm!!5JI!!K"J2pSJq(rr%k!!#!\r!N!BJ3!!"!*!&X!!9,Q4PFepQDAKeF&pVCAPIF'&bDA4j!*2Krr`li!!!5!!!Y(b\r$q+j8K!IqI+2iVP5P"Ma8T3FqI-2iVP6'"Ma8aZFqI+8bH&5P"ljmirLZ91F'2&6\rR"cjp!rLZ93J'2&8)jcjmjd*i91Ih[RbP1RK8T3IqI52iVP8T"Ma9+3FqI82iVP9\r+"Ma95ZFqI5P5H&8T"ljpBrLZ9@X'2&9V"cjpJrLZ9B`'2&@-jcjpDf*i9@[h[Rd\rT@RK9+IrqI+9+H(`%+!"!JJ!-1'!!!%J!!"3lr`!"+"m!#%'!rd`iB!!"Jq(rr%k\r!!#!!N!BJ3!!"!*!&d!!9,Q4PFepMD'9MDepVCAPIF'&bDA4j!,i"rm!kiJm`1m)\r6-$X##c"mfc0i,!J!!%'#"FampMYiL6B!!$V@!!&9+3Bq96c!$SP@!!!keJ!"98S\r'2P9+J"jrR&0iLAB!!$V@!!&9D`Bq9@Y!,RqF@hL*PJ!!1YB!!9@-"MjrR'0iL6B\r!!$V@!!&9+3Bq96h!$SP@!!!keJ!"98S'2P9+J"jr[90iLAB!!$V@!!&9D`Bq9@Y\r!,Rqp@hL*PJ!!1YB!!9@-"Mjr[@0iI(BEH(b9)hK)!!8J,!8!#%#"!+5*0J!!1YB\r!!98T"Mj90-!1L9B!!$V@!!&95JBq98U!(Rk88hL*GJ!!1YB!!99V"Mj9Dd!ZIT4\rEH)Q@!!!keJ!"9B`'2Rk8BhL*0J!!1YB!!98T"Mj9-m!1L9B!!$V@!!&95JBq98U\r!(Rjc8hL*GJ!!1YB!!99V"Mj9Dd!ZIR0EH)Q@!!!keJ!"9B`'2RjcBhKrR+*iIlf\rDH$LPrrK)!!$!IYBU&#J&!!K"J3#`15)#6&5U%$Tp+9!ZI5N$TNk!"#!ke[rrLAB\r!!&9V"Mjr[9Ti1YErriQ@!!"9M!Bq9Ba!,RqpBRJke[rrL6B!!&8T"Mj9+B!HIle\r+H$V@rrq*9J!!98S'2P9+`!jr[9*i1YErriPf!!"9D`BqIjaDH$V@rrq*PJ!!9B`\r'2P@-3#jrR'*i1YErriNf!!"9+3Bq95Q!(RqF5RJke[rrL9B!!&9+"Mj95X!1Ija\r5H$LJ!!!pB+UV1@ZUURq,@$JpJ+UV1BbUURqXB$K9M2KqIApMH$dJ998j+999IiP\r)1&8T#$`p3&9918T99AqU8$Kp290i9kX'2P9V%$TpH&JZ9@XB1&HXaMj9M"!kICK\rJ,P@-%$TAU8Bq95N31Rdi5#jAUSBq98S31ReB8#j95JJmI5P6H(f-5hKpI'0i9qX\r'2P9V%$TpH&JZ9@XB1&IXaMj9M"!kICKJ,P@-%$TAk8Bq95N31Rdi5#jAkSBq98S\r31ReB8#j95JJmI5P6H(f-5hKpI@0i1d!!!%J!!D#"H`!!1hX!"&HXU[jAUDJ8IBa\r,H(erBRKAkJDq98S31MP+!`"pAP!Z9q['[P9V%$SjD`)!IAjB,PIXKVj9M"!k1B`\r"!(fHB#jAk8Dq95N31Rdq5#jpM%YiI@YMH(e+@hKrR&*iJ9X!!$Yl!!4AUdhq9ka\r),(eVBhKpAeTi9qN'[P8T%$Sj+3F!I6j),PIUaVj95K!k18S'!(eH8#jAkdDq9@X\r31MPV"!"pIPJZ9qb'[P@-%$SjM!8!ICjJ,ReVBhKp5PYiI5P6H(qF5RL"1`!!1hX\r!"&H+U[jALkJ8I8TEH(dr8RKAl!Dq9B`31MQ-!`"pRQ!Z9qR'[P8T%$Sj+3)!I6j\r),PIUKVj95K!k18S"!(eH8#jAkdDq9@X31Req@#jp5PYiI5P6H(f-5hKr[@*iJCX\r!!$Yl!!4AL8hq9iT),(dT8hKpRdTi9qX'[P9V%$SjD`F!IAjB,PIXaVj9M"!k1B`\r'!(fHB#jAk8Dq95N31MNT"!"p2NJZ9qU'[P9+%$Sj5J8!I9j3,RdT8hKpM%YiI@Y\rMH(qp@RJl@J!","S!#%'!rQ!pB2$a1@[`m(qV@$JpJ2$a1Bc`m(q-B$K9M1%qIAp\rMH$dJ$`mj+3m2IkP)1&8T)$Bp3!m218S2$hq+8$Kp290i9kX'2P9V%$TpGeJZ9kc\r'2P@-%$TpPf!Z9B`31PHT4Mj9+4!kI6G),P8T-$*AUSBq98S31ReA8#j95L!fI5P\r6H(f-5hKpI'0i9qX'2P9V%$TpGeJZ9qc'2P@-%$TpPf!Z9B`31PIT4Mj9+4!kI6G\r),P8T-$*AkSBq98S31ReA8#j95L!fI5P6H(f-5hKpI@0i1h[rJ&H,4MkCG3!!1V8\r!!9H-KMkCP3!!1V8!!9H*aMkC03!!1V8!!9H+"MkC93!!1V8!!9HV4MkCG3!!1V8\r!!9HXKMkCP3!!1V8!!9HTaMkC03!!1V8!!9HU"MkC93!!1V8!!AqFSRKr[CTi,!8\r!!%'"qZ")!!@F,!8!!%'"!!`iB!!!5!!&N!"mpMYiLAB!!$V@!!&9D`Bq9A,!$SQ\r@!!!keJ!"9B`'2P@-J"jq8Q0iL6B!!$V@!!&9+3Bq95P!,Rj55hL*9J!!1YB!!99\r+"Mjq8P0iLAB!!$V@!!&9D`Bq9A(!$SQ@!!!keJ!"9B`'2P@-J"jq-@0iL6B!!$V\r@!!&9+3Bq95P!,Ria5hL*9J!!1YB!!99+"Mjq-90iI(BEH(b9)hL*GJ!!1YB!!99\rV"Mj9I-!1LCB!!$V@!!&9M!Bq9Bb!(RqFBhL*0J!!1YB!!98T"Mj9+8!ZIja,H)P\r@!!!keJ!"98S'2RqF8hL*GJ!!1YB!!99V"Mj9IF!1LCB!!$V@!!&9M!Bq9Bb!(Rq\rpBhL*0J!!1YB!!98T"Mj9+8!ZIle,H)P@!!!keJ!"98S'2Rqp8hKrN!$MH*1Krl!\rpB+UV1@ZUURq,@$JpJ+UV1BbUURqXB$K9M2KqIApMH$dJ998j+999IiP)1&8T#$`\rp3&9918T99AqU8$Kp290i9kX'2P9V%$TpH&JZ9@XB1&HXaMj9M"!kICKJ,P@-%$T\rAU8Bq95N31Rdi5#jAUSBq98S31ReB8#j95JJmI5P6H(f-5hKpI'0i9qX'2P9V%$T\rpH&JZ9@XB1&IXaMj9M"!kICKJ,P@-%$TAk8Bq95N31Rdi5#jAkSBq98S31ReB8#j\r95JJmI5P6H(f-5hKpI@0i1hX!J$XJ!!")!!'J1h[rr)&l!!"AV%hq9kP),(f-5hK\rpIf*i9qT'[P9+%$Sj5J3!I9j3,PIVKVj9Da!k1@X&!(eq@#jAl!Dq9B`31MQ-"`"\rpRQ!Z9qR'[P8T%$Sj+3B!I6j),Rf-5hKpDf0iI8TEH(qF8RJlHrrmJ9X!!&HVU[j\rAV+J8I@YMH(eI@RKAkBDq95N31MNT!3"p2NJZ9qS'[P9+%$Sj5J-!I9j3,PIVaVj\r9Da!k1@X#!(eq@#jp5PYiI5P6H&IX4Vj9M"!kICjJ,RdTBhKrR%Ti1h[rr)%l!!"\rALNhq9iY),(e+@hKp2e*i9qa'[P@-%$SjM!3!ICjJ,PITKVj9+4!k15N&!(dq5#j\rAkJDq98S31MP+"`"pAP!Z9q['[P9V%$SjD`B!IAjB,Re+@hKp+90iIBa,H(qpBRJ\rlHrrmJCX!!&H*U[jALUJ8I5P6H(fI5RKAkiDq9@X31MPV!3"pIPJZ9q`'[P@-%$S\rjM!-!ICjJ,PITaVj9+4!k15N#!(dq5#jpM%YiI@YMH&IU4Vj95K!kI9j3,ReV8hK\rr[9Ti1cN!!5`C!!K"J2jJ2@$`m6PVm2"rUeJi2B$`m6Q-m2"rM'!i9BcK2RerBhJ\rp)!m215N2$hqT5$K9+5!f28!2$cP+$`prLP!iI6e6H&HV"Mj9Da!kIAGB,PHXaMj\r9M"!kICGJ,P@-%$TAU8Bq95N31Rdh5#j9+6!b9kU'2P9+%$Tp9e!Z98SJ0RdT8hK\rpM%YiIAaMH&IV"Mj9Da!kIAGB,PIXaMj9M"!kICGJ,P@-%$TAk8Bq95N31Rdh5#j\r9+6!b9qU'2P9+%$Tp9e!Z98SJ0RdT8hKpM%YiIAeMH(qFNRKr[BTi,!8!#%#"!(J\riTIri9iY'2TPe!!!kY3!"9ib'2TQ9!!!kY3!"9iR'2TNe!!!kY3!"9iS'2TP9!!!\rkY3!"9kY'2TPe!!!kY3!"9kb'2TQ9!!!kY3!"9kR'2TNe!!!kY3!"9kS'2TP9!!!\rkY3!"IK,LH)&Krl"pFHTi5rrlQ(ke+K3S"3!)3B%!H$Q#!LK8U4!kIBa),Rf*!kC\r1J!3J9kS'2MUerrqC93!!9k['2MUerrqCG3!!9kb'2MUerrqCP3!!9kP'2MUerrq\rC03!!9iS'2MUerrqC93!!9i['2MUerrqCG3!!9ib'2MUerrqCP3!!9iP'2MUerrq\rC03!!1'!!!,S"rm"1J!!J!*!')%!!%!#3"!Z)!"%ZC'9cAh"MBQ0IC@jMFRP`G!#\rq)Ir%1U)(-$V#!c!k)J-31N)#d$TL!T!!1S)#F(ah'hL)Y`!!1[F!!95P"Mj8[F!\r1L0F!!$Vh!!&8aJBq9-D!(Rqp-hL)p`!!1[F!!96R"Mj8jd!ZIldlH)NA!!!kp`!\r"93J'2Rqp3hKAUGpq95N31Rdd5#j9+4Ji9kUIIP9+%$Tp9&!Z98S31PHV(hj9Da!\rkIA4B,PHXAhj9M"!kIC4J,P@-#$apDf0iI8TEH(dr8hKATImq9+831Rbc+#j8T4J\ri9kDr2P6'%$Tmdc!Z9-B31PHR2cj8ja!kI2-i,PHSIcj9#"!kI40!,P8)#$amjd0\riI-BlH(bq-hL*0`!!1[F!!98T"Mj92F!1L9F!!$Vh!!&95JBq98U!(Rqp8hL*G`!\r!1[F!!99V"Mj9Dd!ZIleEH)QA!!!kp`!"9B`'2RqpBhKATHFq9+831Rbb+#j8T4J\ri9kDR2P6'%$TmdM!Z9-B31PHR*cj8ja!kI2)i,PHSCcj9#"!kI4*!,P8)#$amjd0\riI-BlH(bP-hKrrbYi9kRrIP8T%$Tp-8JZ95NB1&HU[hj95K!kI9&3,P9+%$TAUcp\rq9@X31Rea@#jAV(pq9B`31Rf4B#j9M!JmI@YMH(e+@hKp+90iIpj,H(bD)hJl)(l\rm1`!!%%J!!5aA*3Iq,!8!!%'#!#"AjK%k9qFf[RcI1hKAb"%k9mNf[RdH5hK)!!!\rF9qS*2&IV,[jpAeYi9m`*2&I&,[jpRLYiIcN1F&IQ"hjAjqDiI-BlH&6'%$SiaJ-\r!I0B`,PISjljAkEkkI3K,H&8)%$Sj#!)!I4C!,PIUMcjAkiDfI8TEH&9+%$Sj5J%\r!I9C3,PIX9Vj9M"!kICCJ,Re+BhKp#&0iI0a$H&I&"ljAa[kkI+8cH&5P%$SiT3-\r!I,8S,PI(cVj8ja!k11F#!(ce1#jAb*Fq9mQ1YRd)5hK9#"!k13J"!(d93#jAbPD\rq98S31Re98#jp#&0iI1G$H(bl1hKAL`)Z9f`'$ReVBhL4HJ!!1eS!"&H&"JjACJ)\rZI+8cH*!!ZJ!!1eS!"$XBrrmX'!!!3B(qe$KJ!!#k)Ir%6S!!)!#3"L"!!!m!N!3\r$*!!2,QeKDf9IDf9jAh0MD'9N!!!!I!J#TT2Krrb3!!%!#*3Krm"mIaYiN!#"!&a\rrirYiJ)%!A%[rr*PJ!!!!Iq2lH%[rlqPJ!!!!,!-!!%##!!`iB2rr5!!!*(rMqhK\r)!!Z&B!!!!#`$!!""JJ!-1'$rrNJ!!!JiB!!!J!%!5$JK!%"m#!1QJq(rr%k!!#!\r!N!BJ3B!"!*!&H!!1,Q4PFepVCAPIFf0SC@4m#!+QNq(rr*!!!3!)P#(r`(ar'hK\rrirYi5!!#+@!!!!"rirYi5rrZJ@!!!!"rirYi5!!,"@!!!!!X!`!!3),rf$KJ!!#\r!!3")1#%!3(`)!kD$iIrm6S!!)!#3"L""J!%!N!9B!"-ZC'9cAfjPGepbB@jNEfe\rIDf9j!!!!I!J#TT!!!3!)P#(rX*!!B3"S5!!bIB""!"53!'%!5%J!-R'!33!8N!"\rK!%b!B3"S5!!!T@!!!!!iB3")5!!"+@!!!!!iB3!i5rrr26KK!$K)!!#&B!!!!$K\rK!%")!$*0J%%!&$KK!%4)!$*"J%%!&)"L!#")!!$aB!!!!$KK!$K,rrm&1'%!1%J\r!!%eJ!!!!J!%!@$JK!&"m#!1Q6S!!)!#3"L""J!#3"T`!)5jNCA0ID@jTG&pbB@j\rNEfeIER9YBQ9bAfGPEQ9bBA4[FJ"m#!+QNq(rr*2"rrL3!!%!#*3Krm#3!'%!@$[\r#,EL!B3"B1))Y1%[rrI9J!!!!1q!!!%J!!"!iB!!!I(ljVM[r!!%X(`!)3B$rm)!\r"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)!#3"L""J!)!N!9J!"iZC'9cAh0PG&pbB@j\rNEfeICf9ZCA*KG'pbAh0PC@4m#!+QN!!"!!L8)Ir!N!"K!&JiBLfiJ)%!@$LJ!!K\r)!$$jJ%%!&)!"!%Ji)3"!I!J$TNk!!#!!N!BJ3B!!N!Bd!"JZC'9cAh0PG&pcCA&\reC@jMC9pZG@eLCA)!!(`)!UD6iIrmNm(rq*!!!3!)P#(r`*!!B3"B1m)YZ(r$mhL\r!J3"B1+)Y1$M!!!&,rqAeB!!!!$[J!!")!!!NI(liVMKM!!&8B`BqI(ljVRbHq+i\rS"!!!3))!%$[r!!%X(`!)3B$rh)!"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)!#3"L"\r"J!)!N!9m!"SZC'9cAfGPEQ9bBA4PAh*KEQ4[E9pLE'pMDh`)!UDqJIr3N!!"!!L\r8)Iq3!(ae'hKmQ#0iI,BVH(cA-hKmp$YiIS1MH%J!!@&mI"Yi1(3!"%J!!99mHKY\ri+"J!!%##!!Jki!!"1b!!!8J!!,"qhV0iIVZVH%J!!)!X(J!"3)%!)(pMfhK)!!$\rK9'-%2Rrm'K3lH`!#1plrrNJ!!"L)H`!!1hX!!94M"Mjrr"S81m!!!(pGdhKmRrR\r@I,hTeRb%+K3m`)!!1-Errhq%-jCrR$(@Ij`J8$cp"2`ijh-YI2mjeMd!J!!j#2r\rrIdG$PRpD3GCr@MK3,"i!!%##ri!S'!!!3B)!&*1B!!!l'!!%NeJ!!$XB!!3l13!\r","N!"%'"!!am'EJ!3)(r5(q$ihL!!3"i1#%!F(`)!kDkJIr36S!!)!#3"L""J!`\r!N!3"*!!2,Q4PFepaG@&NAf0VFh9Y!!!!L)-!!CL"rr#)S`!!Q+(rmD"Krr"1J!!\rJ!*!')%!!N!FB!"BZG(G[Af*jG'9cAhCKH&pdEepZCA4cL)-!!jL"rr#)S`!#Q+(\rrmBM$!!'B`IrbL1-!!*MKrr1!BIr`6S!!)!#3"L"!!*!(+!!A,QC[GA*IBRPdCA0\rIGQ&iAh4[AfjPG(-!!!"m#!+Q[`(ri*!!!3!)P#(rS(aj'hKr2-YiIcV,H$KK!$K\r)!#j"J%%!&%J!,L'!33!8J)%!1(b%'RL!SJ#SJ-8!!(c(-hJiaJ!"N!$&!!"mjb*\riI2JlH(m$`hK)!#iKJ%%!&%J!,M'!33!8N!"K!$ar3p0i1)%!2$LJ!!4)!#fjJ%%\r!&$YD!!4)!#i0J%%!&*!!B3!mId26H$L"!$`iS!!%5!!YPB""!"3lB!!!5!!!@$[\r!!!#,r!!!1k!!!%J!!"4ArrKq9qJ(rRrH3RJl[3!","d!"N#"rq`X(J!!3))!&)N\rm!!"K+3!"Q6`!!%J!!"#*A!!!98S'2*PF!!!lR!!"1hX!!5`E!!G!JIqS1'!!!)!\r"!'Ji)3"JI!J$TVX"rq"1J!!J!*!')%'!#!#3"!%J!!mZC'9cAh*KEQ4[E9pVCAN\r!!!"m#!+QNq(rr*!!!3!)P#([`*!!B4"BN!#"%&b3!+%3B$KK!$JiJ"!!J+%3A)$\r"%'")!!"eB!!!!(ar'hJX(`!!3))!&$KK!$L!J4"B5!!#9@!!!!!iB3!i1)!!!$L\rJ%!")!#fCJ%%!&(rMqhL!!4")1#%33(`)!kD$iIrm6S!!)!#3"L""J!%!N!9m!")\rZC'9cAh*PB@4IF'&cFhG[FQ4m#!+Q[Z(rh*!!!3!)P#([S(ap'hKmQL0iI,XVH(c\rC-hJkiKY21`)E-)2L!&!lJ!!!,"S3!%#"!5!iB2rr5!!"K(pMfhK)!#b"J%%!&$K\rr!%K)!#b0J%%!&(qMkhKr400iIqAlH%J!,*'!33!8+!-!!%##!"4rirYi5!!XPB"\r"!"4)!!$8Ik2VH$L!!!T)!#bCJ%%!&(aq'hJS(J!!3B)!$$KJ!!#BIJ!!,"N!!%'\r#!+4r!m0iIf6EH%J!,!f!33!81(m!5%J!,"Q!33!81'%!1$L!%!"rjIYi5!!X(B"\r"!"3S!`!!3))!&(rMqhK)!#`KJ%%!&%J!!'!iB3!i1)!!#NJ!,#@!33!8I(iEH#J\rH!!""JJ!-1)!!!*LH!!"rSqYi1)%!1%J!,"Q!33!8,!-!!%'#!#"qilYi5!!VMB"\r"!"3iI`")5!!VQB""!"4)!!!)1i!!!5`F!!""J[lS,"`!!%##!"KrSqYi1)!!!(p\r&dhK)!#[PJ%%!&$KL!0a)!#Y*J%%!&#`C!!""JJ!B1'%!1$L!!!!iS"!!5!!V[B"\r"!"3iS!!!I0VU&*LQrrmii!!!,"`!!%##!!Jii!!"I1-lH)!"%'Ji)4"JI!J$TVV\rKrpa1J!!J!*!')%'!#3#3"!(8!"-ZC'9cAh*PB@4IF(GIFh4bD@jR!!!!I!J#TVl\r"rpL3!!%!#*3KrZ"mH4YiI*FMH(mfbhJlJ!!"1k%!Z(mMbhK)!#Y*J%%!&(ak'hJ\riB3#i1)!!!$LJ!%")!#XCJ%%!&$YJ!!&)!!#%L(N!!$Xj!!&mI`Gd1m!!!%J!!%3\rX(!!!3B)!)&IN"rjrTHYi1ld!!BM&!!"maL*iQ-8!!%J!!"KAj`Iq1lhrriNG!!"\rp#$TiQ4d!!&Irq(ilhJ!","i!"N#"rlaAD3Gq+!N!!%##!"Jj3!!!,"`!!%##!!J\rj3!!"I9a6H$Yl!!&m'p"!3)(rI$ZK!,Kqq,Yi1f!!!%J!!%!li!!!1m!!!%J!!##\r*I3!!1ld!!AeV"h3jRJ!"I@YJ-(rr@hJlhJ!","i!"N#"rq#Eq!!!1aJ!!6Yl!!%\rS'`!(3)(r`(lMZhK,rq64B!!!!(lMZhJiJ3!i5rreK@!!!!"q`l0iIZ5lH(p&dhJ\ri`3!iIZHlH%[rf&&J!!!!1'%!1$L!!!!iS!#!5!!TkB""!"4qilYi5rrNK@!!!!!\riB!!!J!%"+$JK!5"m#!1QZX(rf%k!!#!!N!BJ3B!+!*!%!C`!%LjNCA0IFh4bD@j\rRAh4[AfYPHA`)!UD6iIrmNm(rq*1Krr53!!%!#*3Krl#3!'%!D(bI)hL$S3"S1m!\r!!(rMqhJiJKYS5!!TQB""!"4)!!!iIq2lH$L#!0k)h3!!1ld!!96&"Mj)!#PjJ%%\r!&#`H!!K!J!!8Iq2lH$L#!1&)!#PKJ%%!&#`H!!JlhJ!"3B$ra(rMqhJiJJ$N5!!\rT4B""!"5!!3"B1#%!8(`)!kD$iIrmJm(rq)1Krr41J!!J!*!')%'!!`#3"DJ!&Lj\rNCA0IBf*XEf0VAh"bD@jdAfCTE'9m#!+QNq(rr*2"rrL6SIrdN!!"!!L8)Iq`I(d\rEH$[#'fmli!!!5!!!-(r$mhJlhJ!)Ik6VH$LJ!!K)!#GaJ%%!&#`$!!"!JJ!-1'!\r!!8J!!"3lr`!"+"m!%%'!rp!iB!!!J!%!@$JK!&"m#!1QJq(rr)2"rrL$SIrd6S!\r!)!#3"L""J!-!N!9m!"!ZC'9cAfPcAhGPB@YIDf9j!!#p`Iqi1Z)2-$[#%c!l!JX\r`I0XcH(ck1hKp'80i,!S!!%'#$04p-%YiLA!!!$S3!!&9D`Bq9Ac!$SQ3!!!!1K!\r!!9@-"Mj9M)!HIjaMH)P`!!!k%!!"9@X'2P9V3#jrR&YiLC!!!!!k%!!"9B`'2Rq\rFBhL*F!!!1K!!!99V"Mj9IF!1LC!!!!!k%!!"9B`'2P@-J"jr[@0iLA!!!$S3!!&\r9D`Bq9@Y!,Rqp@hL*N!!!!$S3!!&9M!BqIleMH(a`'hL3!)(rX%J!$#JX"3!)3B!\r!a)P`!!!k%!!"9@X'2P9V"Mj9Dm!1IjaDH)Q3!!!!1K!!!9@-"Mj9M!Bq9Bb!(Rq\rFBRL*F!!!1K!!!99V"Mj9D`Bq9@Y!,RqF@RL*N!!!!$S3!!&9M!Bq9B`'2RqFBRL\r*F!!!1K!!!99V"Mj9D`Bq9@[!$Rqp@RL*N!!!!$S3!!&9M!Bq9B`'2P@-J"jr[@*\riLA!!!$S3!!&9D`Bq9@X'2P9V3#jr[9TiLC!!!!!k%!!"9B`'2P@-"Mjr[@*i1+A\rrq%J!!,"q%#S8+!8!"d'"!+!jBK`89+`31ReVB#jpD31Q6S!%)$S3rrq*F!!!9@X\r'2P9V3#jr[9Ti1K$rriQ3!!!!9B`'2P@-J"jr[@*i1K$rriP`!!"9D`Bq9@[!$Rq\rp@RJk%2rrLC!!!!"9M!BqIjaLH$S3rrq*F!!!9@X'2P9V3#jrR&Ti1K$rriQ3!!!\r!9B`'2P@-J"jrR'*i1K$rriP`!!"9D`Bq9@[!$RqF@RJiS!!!2B#UUcQ-UUTrM'!\ri2@#UUcPVUUTrUeJi9@[iIRfI@hJpJ&991Ba99Aq-B$K9M!Jm2@"996PV999rUeJ\riICeEH&HX"Mj9M"!kICKJ,P@-'$KAUmBq9@X31Rei@#j9Da!k9kp'2PA[%$Tpq(J\rZ9kk'2PA1%$Tpf(!Z9Fi)2(h[FhKpDhYiICaEH&IX"Mj9M"!kICKJ,P@-'$KAlXB\rq9Fi31RhBF#j9cK!k9qp'2PA[%$Tpq(JZ9qZ'2P9V%$TpH&JZ9@X)2(h[@hKpcRY\riICecH$V!!!")!!'JJCX!!$Yl!!4AVUVq9kqS&(h1HhKpRh*i9qX'[P9V%$SjD`-\r!IAjB,PIXaVj9M"!k1B`#!(fHB#jAlSDq9Fi31MR1!3"phR!Z9qp'[PA[%$TprRJ\rZIFjlH(f-FhKpDf0iIjaDH)&l!!!lH`!%9ka0rPHZ5#apM(0iIApLH&I["Vj9la!\rk1Hm(!(hqH#jAkmDq9@X31MPV"J"pIPJZ9qa'[P@-%$SjM!3!ICjJ,PIZKVj9cK!\rk1Fi&!(hHF#jpM(0iI@YMH(h[@hKrR(TiJIX!!$Yl!!4ALkVq9ibS&(eVBhKpreT\ri9qi'[PA1%$SjcJ-!IGj`,PI[aVj9la!k1Hm#!(hqH#jAkiDq9@X31MPV!3"pIPJ\rZ9qa'[P@-%$TpRQ!ZI@YMH(h[@hKpcRYiIlebH)(E!!!lH`!%9ip0rPH,5#apleY\riIGpkH&IX"Vj9M"!k1B`(!(fHB#jAlXDq9Fi31MR1"J"phR!Z9qp'[PA[%$Sjl`3\r!IIji,PIVKVj9Da!k1@X&!(eq@#jpleYiIFjlH(f-FhKr[@*i1YB!!5`@!!K"J2j\rJ2B$`m6Q-m2"rV'!i2F$`m6R1m2"rMR!i9FlK2RfIFhJpi!m21Hm2$hq[H$K9lb!\rf2@!2$cPV$`prLeJiIIeEH&HX"Mj9M"!kICGJ,PHZaMj9cK!kIGG`,PA1%$TAVdB\rq9Hm31RhhH#j9lc!b9kZ'2P9V%$TpGeJZ9@XJ0Rh[@hKpcRYiICacH&IX"Mj9M"!\rkICGJ,PIZaMj9cK!kIGG`,PA1%$TAldBq9Hm31RhhH#j9lc!b9qZ'2P9V%$TpGeJ\rZ9@XJ0Rh[@hKpcRYiICecH$Ylri!pJ+UV1BbUURq-B$Jp`+UV1FkUURqZF$K9c[K\rqICpcH$hJ998jle99Iipi1&A[#$`pB&991@Y99AqV@$Kpr9Yi9k`'2P@-%$TpQ'!\rZ9B`B1&HZaMj9cK!kIGK`,PA1%$TAVdBq9Hm31RhiH#jAUiBq9@X31Rei@#j9D`J\rmIHpEH(h1HhKpR(0i9q`'2P@-%$TpQ'!Z9B`B1&IZaMj9cK!kIGK`,PA1%$TAldB\rq9Hm31RhiH#jAkiBq9@X31Rei@#j9D`JmIHpEH(h1HhKpRA0i1eS!J$UJ!!")!!'\rJ1eVrr)'D!!"AVNhq9kp),(h1HhKpRh*i9qY'[P9V%$SjD`3!IAjB,PIXKVj9M"!\rk1B`&!(fHB#jAlJDq9Fi31MR1"`"phR!Z9qr'[PA[%$Sjl`B!IIji,Rh1HhKpM(0\riI@YMH(qF@RJl@[rmJAS!!&HXU[jAVUJ8IBacH(erBRKAliDq9Hm31MR[!3"prRJ\rZ9qX'[P9V%$SjD`-!IAjB,PIXaVj9M"!k1B`#!(fHB#jpDf0iIHpEH&IZ4Vj9cK!\rkIGj`,Rh[FhKrR(Ti1eVrr)(k!!"ALdhq9ia),(eVBhKpreTi9qj'[PA1%$SjcJ3\r!IGj`,PI[KVj9la!k1Hm&!(hqH#jAk`Dq9@X31MPV"`"pIPJZ9qc'[P@-%$SjM!B\r!ICjJ,ReVBhKpleYiIFjlH(qpFRJl@[rmJGS!!&H2U[jALkJ8IHpEH(hIHRKAl)D\rq9B`31MQ-!3"pRQ!Z9qi'[PA1%$SjcJ-!IGj`,PI[aVj9la!k1Hm#!(hqH#jpcRY\riIBacH&IV4Vj9Da!kIAjB,Rf-@hKr[@*i1V8!!5`9!!K"J2jJ2B$`m6Q-m2"rV'!\ri2F$`m6R1m2"rMR!i9FlK2RfIFhJpi!m21Hm2$hq[H$K9lb!f2@!2$cPV$`prLeJ\riIIeEH&HX"Mj9M"!kICGJ,PHZaMj9cK!kIGG`,PA1%$TAVdBq9Hm31RhhH#j9lc!\rb9kZ'2P9V%$TpGeJZ9@XJ0Rh[@hKpcRYiICacH&IX"Mj9M"!kICGJ,PIZaMj9cK!\rkIGG`,PA1%$TAldBq9Hm31RhhH#j9lc!b9qZ'2P9V%$TpGeJZ9@XJ0Rh[@hKpcRY\riICecH$f!UUXjM+UUIiaJ1$h!UUXjcUUUIkj`1&A1q(jpRh0i2H"996R[999rMhJ\ri9Hm)2$eJ998jDe99IkYB1(hp@hKAV!Bq9B`31RfBB#j9M"Ji9kl'2PA1%$Tpf(!\rZ9Fi31PH[4Mj9la!kIIKi,PHVKMj9Da!kIAKB,P9V#$apleYiIFjlH(fFFhKAl!B\rq9B`31RfBB#j9M"Ji9ql'2PA1%$Tpf(!Z9Fi31PI[4Mj9la!kIIKi,PIVKMj9Da!\rkIAKB,P9V#$apleYiIFjlH(fGFhJkJ!!!5!!"S)'C!!!l13!%9kkUrPH[U"4pcRY\riICpbH&IV"Vj9Da!k1@X$!(eq@#jAl-Dq9B`31MQ-!J"pRQ!Z9qk'[PA1%$SjcJ%\r!IGj`,PI[4Vj9la!kIIji,Rh1HhKpM(0iI@YMH(qF@RL"H3!!1cN!"&HX6IjAVNJ\rXIBacH(erBRKAl`Dq9Hm31MR["`"prRJZ9q['[P9V%$SjD`B!IAjB,PIX4Vj9M"!\rk1B`%!(fHB#jAlSDq9Fi31MR1"3"phR!ZIBacH(eVBhKpleYiIjakH)(j!!!l13!\r%9iZUrPH-U"4pDf0iIIpDH&IZ"Vj9cK!k1Fi$!(hHF#jAlmDq9Hm31MR[!J"prRJ\rZ9qZ'[P9V%$SjD`%!IAjB,PIX4Vj9M"!kICjJ,ReVBhKpleYiIFjlH(qpFRL"f3!\r!1cN!"&H26IjALdJXIHpEH(hIHRKAl!Dq9B`31MQ-"`"pRQ!Z9ql'[PA1%$SjcJB\r!IGj`,PI[4Vj9la!k1Hm%!(hqH#jAkiDq9@X31MPV"3"pIPJZIHpEH(h1HhKpM(0\riIleLH$U8!!%X&!!)3B$qB$f!m2%jM2$`IkaJ1$h!m2%jc[$`Iij`1&A1i6jpRh0\ri2H!2$cR[$`prVhJi9HmJ0MeJ$`mjD`m2IiYB1(hp@hKAV!Bq9B`31RfAB#jAVXB\rq9Fi31RhAF#j9cK!k9kp'2PA[%$TpphJZ9Hm`-PHVKMj9Da!kIAGB,P9V)$CpleY\riIFjlH(fFFhKAl!Bq9B`31RfAB#jAlXBq9Fi31RhAF#j9cK!k9qp'2PA[%$TpphJ\rZ9Hm`-PIVKMj9Da!kIAGB,P9V)$CpleYiIFjlH(fGFhJl1Iq!9ia'2S("rl"pch0\ri1Fi!!C("rl#CM`!!9iZ'2S'"rl"pMQ0i1B`!!C'"rl#CEJ!!9ir'2S&Krl"pE&Y\ri1@X!!C&Krl#Cl!!!9ii'2S(Krl"pkhYi1Hm!!C(Krl#Cb`!!9ka'2S("rl"pch0\ri1Fi!!C("rl#CM`!!9kZ'2S'"rl"pMQ0i1B`!!C'"rl#CEJ!!9kr'2S&Krl"pE&Y\ri1@X!!C&Krl#Cl!!!9ki'2S(Krl"pkhYi1Hm!!C(Krl#Cb`!!,!8!!%'"mpK)!!d\rJ,!8!!%#"$4Kp-%YiLC!!!!!k%!!"9B`'2P@-`!k4JIqXLG!!!$S3!!&9cJBq9Fk\r!(S(Krkaplh0iNH(rV)P`!!!k%!!"9@X'2P9V3#k"JIqXIBaEH*'"rkb*d!!!1K!\r!!9A1"Mk"iIqXIHpcH*(Krkb*F!!!1K!!!99V"Mj9Dm!1N@(rU)Q3!!!!1K!!!9@\r-"Mj9M)!HJF(rU(h1BhL4`IqSLI!!!$S3!!&9l`Bq9Hp!,S&KrkKpDhYiN@(rU)Q\r3!!!!1K!!!9@-"Mk"`IqSIFjMH*("rkKmF"YiN!#"rl#*m!!!1K!!!9A["Mj9r-!\r1LA!!!$S3!!&9D`Bq9@Z!(RqF@hL*N!!!!$S3!!&9M!Bq9Ba!,RqFBhL*d!!!1K!\r!!9A1"MjrR(0iLI!!!$S3!!&9l`Bq9Ih!$SP`!!!k%!!"9@X'2P9VJ"jr[9YiLC!\r!!!!k%!!"9B`'2P@-3#jr[@0iLG!!!$S3!!&9cJBqIlecH*1"rk56SIqJ2H#UUcR\r[UUTrMhJi2@#UUcPVUUTrUeJi9@[iIRhr@hJpJ&991Ba99Aq-B$K9M!Jm2F"996R\r1999rVR!iICecH&H["Mj9la!kIIKi,PA['$KAUmBq9@X31Rei@#j9Da!k9ka'2P@\r-%$TpQ'!Z9kk'2PA1%$Tpf(!Z9Fi)2(f-FhKpDf0iIIaEH&I["Mj9la!kIIKi,PA\r['$KAkmBq9@X31Rei@#j9Da!k9qa'2P@-%$TpQ'!Z9qk'2PA1%$Tpf(!Z9Fi)2(f\r-FhKpDf0iIIeEH$Xj!)!kB!!!5!!"S$Xjrrb"q3!!9kY0rPHX5#apDf0iIIpDH&I\rZ4Vj9cK!k1Fi%!(hHF#jAliDq9Hm31MR["3"prRJZ9qX'[P9V%$SjD`F!IAjB,PI\rXaVj9M"!k1B`'!(fHB#jpDf0iIHpEH(h1HhKrR(*i1cRrr)(C!!"AVkVq9kZS&(h\r[@hKphhTi9qb'[P@-%$SjM!%!ICjJ,PIZ"Vj9cK!k1Fi$!(hHF#jAlmDq9Hm31MR\r[!J"prRJZIFjlH(f-FhKAkdDq9@X31Req@#jpM&YiIjaLH$Xjrrb"Q3!!9ij0rPH\r25#apcRYiICpbH&IV4Vj9Da!k1@X%!(eq@#jAl)Dq9B`31MQ-"3"pRQ!Z9qi'[PA\r1%$SjcJF!IGj`,PI[aVj9la!k1Hm'!(hqH#jpcRYiIBacH(eVBhKr[9Ti1cRrr)&\rj!!"AM+Vq9ikS&(f-FhKpIf*i9qq'[PA[%$Sjl`%!IIji,PIV"Vj9Da!k1@X$!(e\rq@#jAl-Dq9B`31MQ-!J"pRQ!ZI@YMH(h[@hKAlNDq9Fi31RhHF#jplh0iIlekH$T\rc!!%X%`!)3B$qB$hJm2%jlr$`Ikpi1$eJm2%jDr$`IiYB1&9Vi6jpreYi2B!2$cQ\r-$`prV'!i9B`J0Mh!$`mjcJm2Iij`1(fGFhKAV`Bq9Hm31RhhH#jAUmBq9@X31Re\rh@#j9Da!k9ka'2P@-%$TpPf!Z9B``-PHZKMj9cK!kIGG`,PA1)$CpM(0iI@YMH(h\rm@hKAl`Bq9Hm31RhhH#jAkmBq9@X31Reh@#j9Da!k9qa'2P@-%$TpPf!Z9B``-PI\rZKMj9cK!kIGG`,PA1)$CpM(0iI@YMH(hp@hJpi+UV1HqUURq2H$JpB+UV1@ZUURq\rV@$K9DrKqIIpEH$f!998jM&99IiaJ1&@-#$`p`&991Fj99AqZF$KpRA0i9km'2PA\r[%$Tpq(JZ9HmB1&HVaMj9Da!kIAKB,P9V%$TAV%Bq9B`31RfBB#jAVSBq9Fi31Rh\rBF#j9cJJmIBacH(eVBhKpr&Yi9qm'2PA[%$Tpq(JZ9HmB1&IVaMj9Da!kIAKB,P9\rV%$TAl%Bq9B`31RfBB#jAlSBq9Fi31RhBF#j9cJJmIBacH(eVBhKpr9Yi1N!!!%J\r!!D#"qJ!!1eS!"&HVU[jAV+J8I@YMH(hr@RKAlJDq9Fi31MR1!`"phR!Z9qr'[PA\r[%$Sjl`)!IIji,PIVKVj9Da!k1@X"!(eq@#jAl%Dq9B`31RfHB#jpDf0iIHpEH(h\r1HhKrR(*iJGS!!$YD!!4AVdhq9kY),(h[@hKphhTi9q`'[P@-%$SjM!F!ICjJ,PI\rZaVj9cK!k1Fi'!(hHF#jAldDq9Hm31MR["!"prRJZ9qZ'[P9V%$SjD`8!IAjB,Rh\r[@hKpcRYiIBacH(qFBRL"QJ!!1eS!"&H1U[jAMkJ8IFjlH(fIFRKAk`Dq9@X31MP\rV!`"pIPJZ9qc'[P@-%$SjM!)!ICjJ,PIZKVj9cK!k1Fi"!(hHF#jAldDq9Hm31Rh\rqH#jpcRYiIBacH(eVBhKr[9TiJAS!!$YD!!4AM%hq9ij),(f-FhKpIf*i9qm'[PA\r[%$Sjl`F!IIji,PIVaVj9Da!k1@X'!(eq@#jAl%Dq9B`31MQ-"!"pRQ!Z9qk'[PA\r1%$SjcJ8!IGj`,Rf-FhKpDf0iIHpEH(qpHRJk8J!",")!#%'!rQ!pi2$a1Hr`m(q\r[H$JpB2$a1@[`m(q,@$K9Dq%qIIpEH$f!$`mjM!m2IkaJ1&@-)$Bp`!m21Fi2$hq\r1F$KpRA0i9km'2PA[%$TpphJZ9k['2P9V%$TpGeJZ9@X31PHX4Mj9M"!kICGJ,P@\r--$*AVSBq9Fi31RhAF#j9cL!fIBacH(eVBhKpr&Yi9qm'2PA[%$TpphJZ9q['2P9\rV%$TpGeJZ9@X31PIX4Mj9M"!kICGJ,P@--$*AlSBq9Fi31RhAF#j9cL!fIBacH(e\rVBhKpr9Yi1eVrJ$hJUUXjlkUUIipi1$eJUUXjDkUUIkYB1&9Vq(jpreYi2B"996Q\r-999rM'!i9B`)2$h!998jcP99Ikj`1(fGFhKAV`Bq9Hm31RhiH#j9laJi9k['2P9\rV%$TpH&JZ9@X31PHX4Mj9M"!kICKJ,PHZKMj9cK!kIGK`,PA1#$apM(0iI@YMH(h\rm@hKAl`Bq9Hm31RhiH#j9laJi9q['2P9V%$TpH&JZ9@X31PIX4Mj9M"!kICKJ,PI\rZKMj9cK!kIGK`,PA1#$apM(0iI@YMH(hp@hJlH`#!1L!!!%J!!D!lHrrmJIX!!&H\rV6IjAV%JXI@YMH(hr@RKAlNDq9Fi31MR1"!"phR!Z9qq'[PA[%$Sjl`8!IIji,PI\rV"Vj9Da!k1@X(!(eq@#jAl-Dq9B`31MQ-"J"pRQ!ZI@YMH(h[@hKpcRYiIjabH$Y\rlrrb"f`!!9kqUrPHVU"4pleYiIGpkH&IXKVj9M"!k1B`"!(fHB#jAlJDq9Fi31MR\r1!`"phR!Z9qr'[PA[%$Sjl`)!IIji,Rh1HhKpM(0i9qY'[P9V%$TpIPJZIBaEH(q\rFBRJlHrrmJCX!!&H16IjAMdJXIFjlH(fIFRKAkdDq9@X31MPV"!"pIPJZ9qb'[P@\r-%$SjM!8!ICjJ,PIZ"Vj9cK!k1Fi(!(hHF#jAlmDq9Hm31MR["J"prRJZIFjlH(f\r-FhKpDf0iIleDH$Ylrrb"H`!!9ibUrPH1U"4pM(0iIApLH&I[KVj9la!k1Hm"!(h\rqH#jAk`Dq9@X31MPV!`"pIPJZ9qc'[P@-%$SjM!)!ICjJ,ReVBhKpleYi9qj'[PA\r1%$TphR!ZIHpcH(qpHRJk-3!","%!#%'!rQ!pi2$a1Hr`m(q[H$JpB2$a1@[`m(q\r,@$K9Dq%qIIpEH$f!$`mjM!m2IkaJ1&@-)$Bp`!m21Fi2$hq1F$KpRA0i9km'2PA\r[%$TpphJZ9k['2P9V%$TpGeJZ9@X31PHX4Mj9M"!kICGJ,P@--$*AVSBq9Fi31Rh\rAF#j9cL!fIBacH(eVBhKpr&Yi9qm'2PA[%$TpphJZ9q['2P9V%$TpGeJZ9@X31PI\rX4Mj9M"!kICGJ,P@--$*AlSBq9Fi31RhAF#j9cL!fIBacH(eVBhKpr9YiJH(rV(q\rFHRL"BIqSIleDH#`&!!K!J3$F1+Arq&H-4Mk"`Iq`IFpcH$R1!!'4`Iq`QBm!!&H\r,KMk"JIq`IBjMH$Q-!!'4JIq`Q@i!!&H2aMk"BIq`I@aEH$PV!!'4BIq`QH`!!&H\r1"Mk"iIq`IHYlH$R[!!'4iIq`QFX!!&HX4Mk"`Iq`IFpcH$R1!!'4`Iq`QBm!!&H\rVKMk"JIq`IBjMH$Q-!!'4JIq`Q@i!!&H[aMk"BIq`I@aEH$PV!!'4BIq`QH`!!&H\rZ"Mk"iIq`IHYlH$R[!!'4iIq`QFX!!)'"rk54JIqXJF(rS*("rkK,rr5-JH(rX(h\r[+K54iIq`+!8!#%'"!,JjBK[`9+`31ReVB#jpD31Q6S!%)&HZ"Mk"iIq`1Hrrrj(\rKrl#Cc`!!9k['2S'"rl!jM2rrNB(rX*PX!!"AVSBqJH(rX$R[rrq4iIq`QFm!!&H\rV4Mk"JIq`1Bcrrj'"rl#CE!!!9ii'2S(Krl!jlrrrNH(rX*R2!!"ALmBqJB(rX$Q\r-rrq4JIq`Q@`!!&H1KMk"iIq`1Hrrrj(Krl#Cc`!!9iY'2S'"rl!jM2rrNB(rX*P\rX!!#j`Iqi6S!!)!#3"L"!!")!N!3D'!!4,Q4PFemcBf*MAf9ZBh*jF(3![X(rf$V\rL(63k`K`dI*NMH(ai'hL)Z!!!1aJ!!95r"Mk)f!!!1aJ!!96'"Mj8aN!ZIrmcH)M\ri!!!l'!!"91F'2P6RJ"jrrcYiL4J!!$XB!!&9#!Bq93M!$Rrr3hL*1!!!1aJ!!98\rq"Mk*@!!!1aJ!!99+"Mj95N!ZIpj6H)Pi!!!l'!!"9@X'2P9VJ"jrhPYiLCJ!!$X\rB!!&9M!Bq9Bc!$RrHBhKAaH%qI+AkH$c!$`miaJm2I,``1(rriRKAKb!fIpikH&I\rSN!!DI3MkH(8Fc-aALA5qIqVLH(dr8RKAbj!!'ReVmRKeI-c-9iad[Rr&iRKpRLT\ri9mEiIRc'qRJmi&9911G99AcF1$Krrq*i9iJ)2(rH3RKAkF)qI5RbH$e!!2mj5J$\rrI6a31(rHiRKALd!ZIrpDH&I-q(jpM2Ti2+"996LP999pR#JiIrrLH&H'#$arhM*\ri9qF!"P6Ri6jAb!)H93L%2PI*"Mj9+B!H9mS%,RdT8hKp#%YiI2j$H&Ir!6ilB!!\r!5!!"@&GV%$TpGPJZ,!X!!%'#!#"Al2#q9qA3#RfI+hKAa[#q9mI3#RcH1hK)!!!\rF9qMiIPITf!Kp(dYi9mViIPI,f!KpAPYi9rm"2PIH!6jAl&Di9q9RrPIQAhamT60\riIB`VH&@-%$SjM!-!ICGJ,PIRRcjAk*DfI1G$H&6R%$Sij`)!I2Fi,PITeljAkXk\rkI5P6H&8T%$Sj+3%!I6G),PIV"Vj9Da!kIAGB,RdT@hKmjdYiICSlH&I-AcjAa9D\rfIB`VH&@-%$SjM!F!ICGJ,PI'MVj8aK!k1-B'!(cA-#jAa`Dq91F31MMR"!"mpcJ\rZ9mM2[PI*aVTp#%Yi93J31MN)"3"p&d!ZI1G$H(c'1hKpR$0i9iU!(PG,"$jpA9Y\ri9k`A[PHP%$TpM#S8NCN!!$Xj!!4A4S3q9iF!(RcG1hKAU$Dq9kN`-Rd)5K54'3!\r!1cN!"$Yl!!%X'`!33B$qU$KJ!!#k`IrB6S!!)!#3"L"!!!S!N!3#m!!-,Q4PFep\rcCA4IDf9j!!"m#!+QN!!"!!L8)Ir!N!"K!&L3!)%!A)"K!&L!J3"F1+)Y`%J!!$P\rJ!!!!1')Y`)!"!%Ji)3"!I!J$TNk!!#!!N!BJ3B!!N!Bm!!SZC'9cAf0bHA"dI!J\r#TVj"rmL3!!%!#*3Kr["mGKYiI*3MH(bk+hJkiKcd1`%!1)Kd!!"mB`Gd,!-!!%#\r#!!`iJ!""5!!!$)L8!!"mK!GdQ*S!!(b9"h3iSKadI+@SVP5c%$U)e!!"I-B(G#`\r'!!"!JJ!-11!!38J!!!b)p!!"I1F(G*Mk!!&mp3Gd13)FG(d)U+j9%M!b1f!!!%J\r!!#b,eJ!!1YB!!9I*"MiS#3!!3B)!0&I+"Mj95JJm1@%!a(e,fDilH`!"+"X!#%'\r!rp4)!!!81B!!!$KK!-4pJpQZ1hX!!5JE!!K"J2rX1'%!a$L"!%4,rrZaB!!!!$K\rK!-`iJ3"%IQ@EH(j'NhK)!!%aB!!!!)-K!-aA*!BqQ*J!!$XB!!&A*FBqQ,J!!$X\rB!!&A*SBqQ0J!!$XB!!&A*dBqQ2J!!$XB!!'$)3$39bJ'2TNB!!!l'!!"9bR'2TN\ri!!!l'!!"9bU'2TPB!!!l'!!"9bY'2TPi!!!l'!!"1i!!!$[J!)!jJ!!!QB%!3$Y\rJ!!*)!!"N1m!!!$ZJ!!")!!"!9pi)2$KK!$KmBq#Z9q3'2RaM)$JX!`!!3B)!#'2\rH!!&Arrjq9q8'2LJ&!!"!JJ!-1j`!!6[J!)!l[3!"+"d!"N'!rm"AaJBqI0F`VRc\rDfDilH`!"+"X!$8'!rj`ii!!!Q2S!$Ap$dhL!!3%B1#%"%(`)!kDk3Ir)6S!!)!#\r3"L""J!i!N!3#%!!,,Q4PFepQBh*jF(3!!!#q!Ir!1k)P0$Z!!!!lB!!!I*8MH*!\r!SIq`N!$"rk`ii!!!N!$Krl4)!!4-1X!!!%J!"#4AD)3qIhp#H)%Krl"rrNJiJ8(\rrV(rr8$KAfS!H9XX31Ree@#jrDeTiIpjDH(rHdRKAqS!H1CB!!9@-%$TpP@!ZIfa\rLH(rrBRKrrp*iIp4'F&ID"MT@P!Bk9qIK2PISi!Crjd)89pk%2Rdpd#jrR%Ti193\r#!(eG8#jrR&*i9p2#2PID"MT@F`Bk1AS%!(ep@#jrR&Ti1C-'!(fGB#jrR'*iIr4\r'F&Ik"MT@P!Bk9rq%2MMk!3"mr6JZIj`kH$N8!`"p(8!ZIja#H(rc4R"AqJBk9R-\r'1MNk"3"p28JZIja+H$P6"`"pA9!ZIja5H&H,K$jrReTiJB(rX(rqB$L!iIqXIrm\ri1&ICJ"ij&J!#93J31Rd93#jrL%*iIpj#H(rHbRKAqB!H16B!!e8T%$Tp08JZIiP\r+H(rr5RKrrmTiIp*'F&IC"MT@8JBk9qVK2PIVi!CrkPS89pk%2RfGb#jrHf*i12)\r#!(cp1#jrHcTi9p(#2PIC"MT@-3Bk14N%!(dG3#jrHd*i16%'!(dp5#jrHdTiIr*\r'F&Ij"MT@8JBk9rq%2MPC!3"pA9!ZIhY5H$Pb!`"pI9JZIhYDH(ra4R"Aq3Bk9M%\r'1MQC"3"pR@!ZIhYLH$Ma"`"mr6JZIhXkH&GSK$jrId*iJ5(rX(rq5$L"3IqXIrp\r31&IBJ"ijGJ!%9@X31Ree@#jrDeTiIpjDH(rH`RKAq)!H1CB!"9@-%$TpP@!ZIfa\rLH(rrBRKrrm*iIp"'F&IB"MT@%!Bk9qIK2PISi!Crjd)89pk%2Rdp`#jrR%Ti19!\r#!(eG8#jrR&*i9m[#2T&KrkKAf!BkJB(rU&@-"MU4JIqS12J%!(cp1#jrR$TiJ3(\rrU$N)"J"p(8!ZIja#H(r`4R"Aq!Bk9K!'1PIrK$ij1!%!I6e),RqF5RJj8!-!I9e\r3,RqF8RKrkdC`N@(rU&Ii"MU"JIqS9B`'1T'"rkJiq!8!I2di,RqF1RL"!IqS13J\r(!(dG3#jrR%*i9iQ%2RqI5RL"3Iq`Irj31)&KrkarreJi9pH!(MQ@!!C9M"!kIC9\rJ,Rq-BRKrhQ*iIpkkH&IhJ"iipJ!(91F31Rce1#jrKcTiIrmkH(rrZRKrb%C`N3(\rrT&IA"MU")IqN95N'1T%Krk4AkZ%q9q[J"RrU@K4AhS3qICfi,RplBRL!iIqN11F\r#!(cp1#jrHcTi9mM#2T%"rk"Ae`BkJ5(rS&8T"MU4)IqJ19F%!(eG8#jrHe*iJ@(\rrS$PV"J"pI9JZIhYDH(rX4R#4JIqN9rF'1S$Krk48j`BkN!$Krk4Ari3q14F"!(d\rG3#jrHd*iJ5(rT$NT!`"p28JZIhY+H(rU4R#43IqJ9rF'1S&Krk"9D`BkN@(rS$Q\rA"3"pR@!ZIhYLH)$Krk!ij`F!I2di,Rpl1RJkeJ!),"B!)%'!qparRq0iIhcEH(r\rlqhL"!Iqd13J!!C%"rl5")Iqd,!N!'8'!ql"ALZMq9i[S"(q+@K4AE1Mq9fIS"(p\rX1K4AL2KqI3MDH$dJ998j+999I4p)1(plqRKAkJJmIja5H&GV`MjpDq*i2B!!rcQ\r-!2ppIf!iIjckH&IR3#jrHcTi9iM`[Rd)fRJp)$-c15Nc-hdI5$KrHrTi9qS31Rq\rF8RKADi3qI@[LH&9r"$jrR2Ti9qb!(RplBRKAKq%qI1IDH$d!$`mj#!m2I2p!1(p\rlqRKAk5!fIja+H*0M!!#6J`!%ZJ(r`%k!!#!!N!BJ3!!3!*!%"6`!$#jQBh*jF(4\rIBQpNH3!!I!J#TVp"rqL3!!%!#*3Krl"mHKYiI*mMH(bl+hKmh$0iI2dlH(dH3hJ\rX(J!!3B)!B(p$dhKrj2YiIfAEH(r'mhK,rlFGB!!!!(rMqhKrj2YiIiAMH$MJ!!!\rX(J!!3))!#$MJ!!&mjMYi5rqfp@!!!!"rirYiIq6lH(qPkhKra[0i5rqfh@!!!!"\r)!!"FId26H(rNqhKrTHYiImEcH%[rYX&J!!!!Iq2lH(rNqhKrKH0i13!!!#`H!!"\r!JJ!)13!!!Ad'3hK,rlDCB!!!!(rMqhKrj2YiIfAEH(r'mhK,rlD"B!!!!)!"!&J\ri)3"3I!J$TVY"rqK1J!!J!*!')%'!"J#3"IJ!%5jNCA0I-f9MBPpPEQ0bHA"d!(a\r$%hK1J!!JI!J#TT!!!3!)P#(r`%[rrqemD4YiJ')!F)##!'`iSJ!!1-)YcS$L!'#\r"!J"F5!!!@B""!"5!JJ$8N!"N!!",rk0CB!!!!$KJ!!#!!3")1#%!3(`)!kC1J!!\rJI!J#TT!!!3!)P#(r`)"L!05!B`!!5!!!-B""!"5!!3")1#%!3(`)!kC1J!!JJB)\r!2*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!$L3!%%!&)!-!!#!6!!%I!N$TNk!"##\r"JJ!BN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!%*!!33!8J!`!!)"-!!4m#31Q6S!\r%))'#!%#3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!JN!""!"5!$!!!J%`!"(`*!kC\r1J!3JJB)!$*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!"53!%%!&)!-!!#!6!!%I!N\r$TNk!"##"JJ!NN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!#*!!33!8J!`!!)"-!!4\rm#31Q6S!%))'#!#L3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!XN!""!"5!$!!!J%`\r!"(`*!kC1J!3JJB)!"*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!!#3!%%!&)!-!!#\r!6!!%I!N$TNk!"##"JJ!`N!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!(*!!33!8J!`\r!!)"-!!4m#31Q6S!%))'#!$53!%%!&)!-!!#!6!!%I!N$TNk!"#!!!!!FJ!!!I!J\r!N!DBJ!!!6!#3"LQXJ!!!Q!J!N!8U4)!!!)!)!*!&+X5!!!$3!*!'+j5!!!#3!"!\r!N!8X*)!!!'!!N!BXK)!!!+J3!*!&,5b!!!&)B!#3"5m)J!!"4%!!N!8`6)!!!+!\r)!*!&-1b!!!(m5!#3"6,SJ!!"`&!!N!8dU)!!!0!B!*!&0AL!!!#J'!#3"90NJ!!\r!@!#3"P1mJ!!#-(!!N!9E5)!!!4``!*!&A'b!!!"B!*!'A-5!!!!X!*!04L)2-!)\rL%c!#)JX`"L)G0))#"#8dAhKHL#h1"#*IH!BL!F5#!KJ"k!))!LJ#6!F`!c!$%!,\r3!T!!!R!YZ#di!0JE6aX`'fJEEa[`("3F0"cd((3Y`!$S!L%+!5)PH!%L,#!")L"\rp#5'BKJ)D!"`!j!b8%U3C`"MS'VJQC#QX,)3X*#Z8+X3U4#dX,`J`l$"--ZJdU$9\ri0KK39&1m8f4E5#)-C))#+JaB$%`-3!`d$#J-(!`3$!3$%!,m!ZJ#e!,%!V!#R!+\r)$V31S!k-$RJ1D!j8$N!1,#Bd*LJQ(#B3*J3Pq#AX*H!Pe"c8(-!FV"bB()JFG"a\rJ(%`F2!8K%)%$"J!3!!!3%"!!!"!!%"!3!"!3%!3K%!3K%!)L%"!%)4#"!`X3!"!\r!%*!&!!!"%!!"!"!"%"!"!!!4%!!4!"!4%"!4"L%"!L%"!b)"!3%K!3-K!3%K!3%\rL!3%#*!'3"!-K!3)L!3%")3%")3%"*!'3"!)L!3%"*!'3"53"N!3%)3%%)3%#)J%\r""#%"!5%"!5%"!L)"!3%M!3%"##%%J3-0!3!!!3!%!!3!!!3%!33!!33%!!!J!!!\rN!3!J!3!N!!3J!!3N!33J*!%%*!%$)3%#)`3"!3)L!3%")J3"!5%%!5%"!58%"!%\r""!%P!3%%"!%#)L!"!L-N!3%")b!"!3%L*!%")`3J!3%U"#3"!33J!3%%*)%$$`)\r!!!)!"!-!!!-!"!)%!!)%"!-%!!-%"!)!)!)!*!-!)!-!*!)%)!)%*!-%)#8$"#3\r"!J)L!3)")`3"!`)L!3-"*!3"!J3"*`%#"!3"!`3"*J%$"!3"!J%M)!%#!5-N!3-\r")b!"!`%a*!%#"#!"!J3N!3-%)!%$"#3%)3)&)3J")3)")3J#)3J#)J))!b))#!%\rM!JJ)"#)"!J)K!3)M#!%#!5))!3%K#!%M!3))!5%"!5F)#!%##!J"!L%"J3-(!J!\r"!!!*!J!*!!J"!JJ"!!J*!JJ*!L-"!3)")J%"!L-*!3)")JN"!5F)!3%##!%"!5J\r)#3%##!N"%!-K%J-K%!%K#!%K%J%K#!%L%!J#)K))!L-3#!J")a))#!%K%!)L!4)\r#)J%3!5-)!4)"*!J"%!J")`%5#!%U!4!)#!%5#!J"%!%K!B%$"a)!!4!!#4)!#4!\r)!4))!4!)#4))#5%3!5-"!4)")`%"%!%M#3%5!6)*!4!)!3%5#!%"%!J*!4))#3%\r&)33%)5##!J3%)"!!&!!3)#)8))%$##!!!#!%!#!!)#!%)#!3!#!8!#!3)#!8)!-\rK#)%$"J3!#!!J#!3J#"!!#"3!#"!J##38)!JJ!L-))!3")JJJ!5JJ##!%)!JJ%!%\rM##!8!5N))"!J##!8)!L"!`FJ!!!N!!!J)!!N)!!`!!!d!!!`)!!L0##"!`JJ)!!\rJ*!!JN!3N)#!`!#!d!#!`)#!d)!%K)!%K#)%$"L3!##!J##3J#$!!#$3!#$!J##8\rd)!JJ)!%M##!N!5X))#!J##!N)!JJ-!%M##!d!5N))$!J##!d)!J()K!)J3-r!!!\r)!"!!!J!!!K!)!J!)!K!!!!)!!"))!!))!")!!J)!!K))!J))!K)%!!!%!"!-!!!\r-!"!%!J!%!K!-!J!-!K!%!!)%!")-!!)-!")%!J)%!K)-!J)-!K)!%!!!%"!)%!!\r)%"!!%J!!%K!)%J!)%K!!%!)!%"))%!))%")!%J)!%K))%J))%K)%%!!%%"!-%!!\r-%"!%%J!%%K!-%J!-%K!%%!)%%")-%!)-%")%%J)%%K)-%J)-%K)!!!!#!b%#!L)\r#!J3K!3%K!J%K!3)L!J%")`)#!33L#!)#)3J")3)")`J#!J%K#!)M!3J#!5)"#!%\rR!J%)!J)"#!%K)!)L!L!$)5)#)J)L!b)J!3%M!L!"!L)L!3%M!L)"!L%J!5-)!L!\r")3J")5)")`J#)J%K#!%R)!%)!L!"#!%R)J%)!L)"#!)K!S%$"`)!!J!#N!8!!!-\r#!!-!!J-#!J-#)`))!J%L!JJ"*`)##!)#!JJ#)`-)!J%L!`J"*`)$#!)#!`J")L!\r#J3-(!L!#!#)#!L)#!#!$!L!$!#)$!L)$!5FJ!JJ#)!))!5FL!JJ#)J))!5FJ!`J\r#)!-)!5FL!`J#)J-)"L%3"#%J!L)3)!%K%!-L%"!#)4!")5!"*"!3)!J$)3J")4!\r")3J#)L!)!533)!J3!L-)%"!")JJ3!58J#"!3))%$"`!!"!!3"!!!*!!3*"!!""!\r3""!!*#33%#3)!L)%#!%M%!3)!L)N#!%N%#3)%!%R"!J3%!3)%!%P*!J3%#5"!`F\r!"!!!&!!!"#!!&#!3"!!3&!!3"#!N%"3J#!%K"!%K#!%K&!%K#!%M"#!)!588)!J\r3"!%M#"!8!5J)%!3J#"!8))%$"`!%"!!8"!!%*!!8*"!%""!8""!%*#33)!5-\r%"!J")a3%#!%M"#3)!6)8*!J3"!3)%"3%#"!%*!J3%)4!%)3%#)K!""5)#%!)\rK!J%K!3%M!K!"!5%#!L%J!5%3!5%J!L)")!%M%!%J!b-J!K!")L!#!5F")!)3!5!\r#!5%%J3-(!"!%!!!&!"!&!!!%!K!%!J!&!K!&)3)")J3J!5-3"#!#)J8J!5-3"5!\r#*`3J!K!%)!)"+!8J!K!&)!)J!b%`!b)J!3)L-!%#)5!#)J)`!L-#)!%")`)`!3%\rL!L!")5!")6!")5!")b!")!%M-!%J!5%J!5-J!M!",#!#)!%J!M!")!)J")%$"`!\r`"!!J"3!`"3!J"!)`"!)J"3)`"53#)!3J!5-`"#!")b!&)!%M-!8J!6!J"#!#-!3\rJ!L!&)!)`"5!#"#%%"L)""))#$!%"!!8!!3%&!3!3""!!%334!4!&%!%4"5%4!5%\r)J3-2!!3)!!!)!33)!3%)!!8)!!%)!38)!3!)%!3)%!!)%33)%3%)%!8)%!%)%38\r))4%#)3J")35"!`i)!!!)!33)!3%)!!8)!!%)!38)!3!)%!3)%!!)%33)%3%)%!8\r)%!%)%38L#"%")JJ)!5-%#!J#+JJ)!33)#!%"#!J")`8)#!%S!3J)!38)#!%"*`J\r)%!3)#"!"0`J)%33)#"%"#!J3"3J)%!%)#"%&#!J4"b%3JJ)0!!%!%4!!%"!3!4!\r4!3!"%!%"!4%4!"%3%3%L%4'"!bm3!!!3!"!3!!%3!"%3%!!3N!8"%"!4%!%!%!%\r3%!%"%!%4%"%!%"%3%"%"%"%4!3!!!3!3!3!"!3!4!4!!!4!3!4!"!4!4!3%!!3%\r3!C!&%3%4!!%4%!%4!3%4%4%!!"%!%"%!!4%!%4%3!"%3%"%3!4%3%4%"!"%"%"%\r"!4%"%4%4!"%4%"%4!534%4%3J3-2!!!3!"!3!!%3!"%3%!!3N!8"%"!4%!%!%!%\r3%!%"%!%4%"%!%"%3%"%"%#34%4!3!L)3%!%M%"!3!5-"%"!"*"%3%"!",a#3"`%\r3%"!4%"!"!5m3%!%3%"!"!4!3!4%3%"%",K!3%4!3%"%"%"!4%4!"!L)3!3%M%"!\r"!5-"%!%"*"%3!4!",a!"%"!3!4!"%!%3%4!"!3%[%!%"%"!"!3%3!3%4%!%4!5i\r3!4%3%!%4!4!"%4%3%3)L%"%")a!3%3%M!4!4!534%"%3!5m3%4!3%"%3!4!4%"%\r3%3%",a!4!4!3%3%"%"%"%4!4%3%Y%"%4%"!4%3%3%4%4!B%$$`!!!3!3!3!"!3!\r4!4!!!4!3!4!"!4!4!3%!!3%3!C!&%3%4!!%4%!%4!3%N%4%"%!)L!4!")a!"%!%\rM!3%3!534!4!3!5m"%"!3!4!3!3%3%"%"%!%",`%3!4!"%!%"!4!"%3%3%3%Z!4!\r4%!%3%3%"%"%4!3%#)J%"!5-3!3%")`'3"#34!3%3!5m"!4!3!3%3!3%"%"%"N!3\r[!3%"%!'3"a%"!4%",J%"%4!"!4%"!3%4%3%4!L)"%3%M%!%4!5-"!4%"*"%"%4!\r",`%4%"!"%4!"!4%3%3%4!3%[!4%"%!%4!3%"%3%4!4%4!5d"%4%3!4%4!3%4N!5\r"!`m!!"%!%"%!!4%!%4%3!"%3%"%3!4%3%4%"!"%"%"%"!4%"%4%4!"%4%"%4!4%\rN%4%4%!)L%4!")a!4%!%M!4%3!534%4!3!5m4%"!3%4!3!4%3%"%4%!%",a%3!4!\r4%!%"%4!"%4%3%3%Z%4!4%"%3%3%4%"%4%3%#)K%"!5-3%3%")`%4!3%N%4%"%!%\r[%3%3%"%"%!%4!4!4%3%"!5m4!3%3%3%"!4%"!4%4!4%",K%"%4!4!4%"%3%4N!3\r#)K%4!5-3%4%")`%4%3%N%4%4%!%[%4%3%"%4%!%4%4!4%4%"!5m4%3%3%4%"!4%\r4!4'3"!%X%4%4%"%4%3%4N!3%)3)%)3)#)J)#"#%#!5%#!5%#!L)#!J%M!J)#"#)\r#!J)K!J%K!J%M!J)#!5%#!L-#!J)")J)#!5J#N!F"!b%$!b)"!J)L!`)#)3%")3)\r")3-")3)")`%#!J%M!`)#!5%"!L)#!`)M!J%#!5-#!`)")J)"!5-#!J-"+J)#!3)\r#!J-#!J)")3%#)J)"!b%$!L)#!`-L!3)")`)"!J)L!`)")`)$!J)K!3%M!J)"!5%\r#!5%$!5-#!J-")3)"*`%#!J)"!J)"+3-#!J)$!J)"!3)L!`%#)J%$!L)$!`)M!3%\r#!5-$!3)")`%$!J%M!`-#!5)"!3%M!J-"!5-#!3-")`)$!`%a!J%"!J)$!3)#!3-\r#!J-$!J)#)3'"!`F#!!%!!J%#!J%!!!-#!!-!!J-#!J-#)`%#!J%L!3)"*`)"!J)\r#!3)#)`-#!J%L!`)"+!)$!J)#!`)"!5%"J3-(!`!"!3)"!`)"!3!$!`!$!3)$!`)\r$)3%")`%#!`%V!3)"!J%#!`)"!J%")`-#!`%U!`)"!J-#!`)$!J%L!3'"!`F#!3%\r!!`%#!`%!!3-#!3-!!`-#!`-"*`%"!J)"!3)"*`-"!J)$!3)"*`%$!J)"!`)"+J-\r$!J)$!`)"!3'"!`F$!3%"!`%$!`%"!3-$!3-"!j!&)#!"!3%#!`%"!J%$!3)$!`%\r#!3%$!J-"!`)"!`-#!`-$!J-L!3)#)3%")3)")`%#!J%K!3)M!J%#!5)#!3%R!J)\r"!J)#!3-L!`)#)3-")3)")`-#!J%K!`)M!J-#!5)#!`%S!J)$!J)#!`%#)J%$!L-\r"!3)")`%$!J%L!3%")`)"!`%V!J%"!J)"!`)#!3%#)J-$!L-$!3)")`-$!J%L!`%\r")`)$!`%U!J-"!J)$!`)#!`%K!3%M!3)"!5%"!5%$!5-"!J-")3%"*`%#!3)"!J%\r"*`-#!3)$!J%")3%")`-#!3%K!`%K!`%M!`)$!5%$!5F"!J-#!3)$!5N$!J-#!`)\r$!3%")`%$!3%M!3%$!5-"!`-"-`%"!3)"!`%#!3%$!J%$!`)"N!3M!`-"!5-$!3-\r")`-$!`%a!`%"!J-$!3)$!3-#!`-$!J-#)`%"!J%L!3%"*`)"!3)#!3%#)`-"!J%\rL!`%"*`)$!3)#!`%#)`%$!J%L!3-"*`)"!`)#!3-#)`-$!J%L!`-"+!)$!`)#!`-\r"!5-"!3-"+`%"!3)"!3-#!C!%)`-"!`%V!`%"!J-"!`)$!3%")`%$!`%V!3-"!J%\r$!`)"!`%")`-$!`%U!`-"!J-$!`)$!`%R!3%"!J'3"#F$!3%#!`%"!5F"!`%#!3-\r"!5F$!`%#!`-"!5F"!3-#!3%$!5F$!3-#!`%$!5F"!`-#!3-$!5"(!`-$!J-$!`'\r3"!-"N!3$!3%$!`'3"!-"!`%$!3%$!`%$!`-"N!3$!`%"!`%$!3-$!`%$!3%$!`-\r"!`-"!j!(!5%3!L)#%!%L!3)")J3""L%%!5%#!5)%!3%Q%!3"!K!%!53#%!3"!5%\r3"L%#!L%"!b)"!J-L!K!")3%#)`3"!J%K"!)M%!3"!5%3!5)"!J%K"!%K!J)M!3)\r3!L-#%!3#)4!")`%#%!3K"!-Q"!%#%!3"!5)3"!3L!3)%)K!%!5%#"#)3"!)K%!)\rK!J%M"!%#!53%!3)3!5-"!K!")3%$)3%")4!")J%#!b%#!5%%!L%3!L-#%!3$)J3\r"!5B3"!%#%!3$)`3"!J)R!3)3"!%#%!-L%!3)*3%#%!3""583"!%#%!3K"!%K!J)\rL!3)")33$)33#)4!")3%")S##"b'!!L1!JJ+"!aL!J!)!JJ)!!!)!J!!!!J#!JJ#\r!JJ)!!J#!!J+!J!+!!*!%!J!#!S!#!)!#!!##!!##!)#!!)#!!)!#!J#!!S!!!S!\r!!J#!!J8L!J+"!ad!JJ+!!!!!J!#!JJ)!!!+!J!#!JJ#!!!#!!!!!!J#!J!)!J!!\r!JJ#!!!)!!J!!!!+!!J)!JJ+!JJ)!J!+!J!#!!J+!!!)!!J)!JJ+!JJ!!!J+!!J#\r!!J!&)S!#!L'#"L1!J!)#*3%%"!%""5)%!3%L"!3")3%'*!%""!3")3%#)3%")J3\r%!L)%"!)K"!%K!3)N"!%""!%K!3%M"!3""#-""!3'*!3%!3%$)3%#)J%"!5)%!3)\rL"!%")33"*!%""!3")J%%!5)"!3)K!3)K"!%L!33$*33%!3%%!L%"!5%%!b-%!3%\r")33%)3%")33#)J%%!5%"!L-%!3%")33")3%()3%#)3%"*J3%!3%%"!%K!3%K"!)\rK"!)K!38L"!%")J3%!5)""!%K!3)K"!-N"!%""!-K"!%M!3%%!5)"!3%K"!)M"!3\r"!L%%!5)""!)N!33%!3-M!3%%!b-%"!%")33")J%""#1!!33")i!""!)K)3)KJ!%\rK"!8LJ#!$)J%%J3-,!#!%J!!%!!%!J#!%J#%!J#%%!!!%J#!!!!%!!#!%!#!%"5%\rJ!L1!)35"!aq!)35!!3#!)33!)!#!!!!!)3!!!35!!3!!)3!!!!5!!!3!)3#!!!#\r!!3!!)!!!!33!)3#!)!5!!3#!)!!!)33!!35!)!5!!!#!!3!!)33!)35!!!5!)3!\r!)35!!33&)L!%!L%K"#%%!5+!!3)LJ#!#)B!")33')L!%!L)""!%LJ#!#*)#!3"!\r")B!")a"!J!%L%%!$)8!"*8!33)"!!50!J%!#)B!")4!')N!3!L*!%!%PJ%!33)!\r#)8!&)8!")d#!3!)KJ!8K%!)K3!)MJ%!3"#&!!5&!!L'!!5%3!b333)"!!5*!J!8\rL%%!")8!")8!#)4!#+%!33)"!%%#!!L&!!5&!!50!J%!$)N!3!5@!3""!J!)K3!N\rL3"!$)K"!!5&!!50!J%!")N#!!b1!3"!")B!")a"!J!%L%%!$*N#!3""!J!)L3)!\r&)4!")S"!!L'!!5%3!L9!%%#!3!%L3)!")4!$)K"!!5&!!L1!3"!%)8!")8!%)4!\r#*%!33"!#)`J3)!3K)!%Q%#!J#"!J"58)%#!J#!%K)!)K%!%K)!)M)#!)!5%J!L%\r3!L%)!5%J!5))%!%K)!%K%!8L)!J&)5!")JJ3!5)J#!)K)!)L)#!")4!")L!)!b-\r)%#!")`J3)!%K#!8Q)#!)%#!J!b)J#!%L)#!")a!J)!%K%!-K%!%K)!3M#"!J!5%\r)!5)J)!%N%#!J#!%K)!3M)!J3!L%)!5%J!L%3!5%J!5%3"5-J#"!#*3J3)#!)!5)\rJ)!%L%#!$*L!J#"!J)!8L%#!")3J$)3J#)5!")K!J!b-J)!J#)5!#)5!")JJ3!5)\rJ#!3M%#!J!5%3"#%J!5))%!%M)!J)!5)))!)K#!)K!J)P#!)))!J$)3J")JJJ!b)\rJ#!3K!J%M)!J#!L3)!JJJ!5)##!%M#!))!L-###!#)3J%)b!)!J)K#!)L)!J")3J\r$)JJJ!5)##!)K!J%M)!J#!53J#!))!b)))!JL#!)")L!)!L)J#!%K#!)M!JJJ!5%\r#!b-###!")3)#)`J##!-K#!3M)!J#!5%J!L%)!L3###!)!5%)"#)J#!)M)!J#!L)\r)!J%L)!J%)3)#)3J")JJJ"#3)!JJJ!5%#!5)J#!)M)!J#!L%)!5%)!5%)!5)))!3\rN#!)))!%L!JJ#)J))!b)))!)L##!")3)")L!)!b-)!JJ"*8!)3""!!5&!!b&!!L-\r)3"!")3J&)a"!#!%L%%!")d!33!)S%%!)3""!#%!")8!$)8!")8!#)3J&)a"!#!%\rK%!%L#%!#)3J")K"!!5*!%!3K3!8K3!)P#%!33!J$)3J")K"!!L%3"5))3!-P3""\r!#%!")N!)"#*!%!8P#%!33!J")4!")3J#)8!"*%!33!J#)d!)3!-K3!%L3!J#)8!\r")8!%*4"!#%!3!5-)3"!$)4!#)8!")8!&*8!33!K!!L%)!L&!!L%3!5%)!5)33!%\rM3""!!L%3!5%)!5%3!5))3!8K3!%K3!-M3""!!b*!#!%P%%!)3"!")JK!!6i+9Q9\rbD@CjD@jR,#"`E'9KFf8JFQ8YC@jdCA)J*A-"1!S("deTFfeKG'0S)#dJG(*j)'&\rRB@PZ#J%Q)$"i)(XJ!5#"!!'3#2k3#"q3"!k3"1#3"2'3"!(q!Ii"rJ(qrJ(q!Ii\r"rJ%Ii"rJ$[%1mH!Ii"ra$[%1!H!"i!(a!I(J!H!"m3(a!4rq(ri1rJlqrKrq(ri\r1rJi"(`%I!3i"$Km"(`%1!3i"i2lJr[(qmIlqi2lJr[(qm3-L8#L#!K"3&&!!6qa\r2f%r%6l"2R%q)1%`i1$JN1"!i!$IX0pJha!NK!B)#"3!"!!%!!3!"!!%&)3'#!J8\r!!3!"!!%!!3!"!L!ZdY28eGEAf0RDfpcGhYrJiH,Mj1AQjqMTkZ[XlHl[m2(bmr6\rep[IiqIVlr2hqr`%JJ4%"!J-%"3B(#!N+#`8'"`J*#JX-$3i2%"%5%a39&KFB'4S\rE("dH(b!K)L-N*5!K)L-N*5BR+#NU+b`Y,Lm`-6)c0$8f0cJj1MXm26ir3%d3\rZ,c!a-M-d06Bh1$P"3N0%48C(5%P+5da06Np389*69&9@9eKC@Q&LBf4PCQGSD@T\rVE'eZEh"aFR0dGAChH(Pk"b)3)!-K)!)K%!%K!3-K!3%M%#!"!L)J!3%K%!)K#!-\rM#"!J!5%)!5%J!5))%!%L!3J#*J%)%#!"#!%N)!%)%!-K)!-L-#!#)L!J!L%`!5%\r"!5%J!5%"!5-`)!%")b!J!3%K-!)L##!#)`J`)!%M##!J!5))-!%M!3JJ!5X"#$!\rJ!3JJ)!%)-!%K#)%$"`!!#"!J#!!J#"!!#3!!#4!J#3!J#5%3!5))#!)Q#!J3)!J\r)!53J#!J3!5)*#!)Q#3J3)!N)!53J#3J3!5%)J3-()!!)-#!))#!)-!!*)!!*-#!\r*)#!*)6!")`J))!%V#!J`)!J))#!)#$!")`N))!%V#3J`)!N))#!*#$!%)3)&)5!\r")3)")5!#)5!#)J)J!b)J)!%M!L!J"#)%!J)K"!)M)!3#!5)J"!%K)!%M"!)J!5%\r%!5FJ)!3#)#!%!L%%J3-(!J!%!!!N!J!N!#!%!L!%!#!N!L!N!L-%"!)")J3%!L-\rN"!)")L3%!5FJ"!3#)!3%!5JJ*!3#)#3%%!-K%J-K%!%K)!%K%J%K)!%L%#!#)K)\rJ!L-3)#!")a)J)!%K%!)L"")#)J33!5-J"")"*#!%%#!")`35)!%U""!J)!35)#!\r%%!%K")%$"a)!""!!*")!*"!J"")J""!J*")J*#%3!5-%"")")`3%%!%M*!35!6)\rN""!J"!35)!3%%#!N"")J*!3()3%")35"!`d!!!3"!3!!!3!"!33!!33"!!!#!!!\r$!!3#!!3$!3!#!3!$!33#!33K!`)K!J-L!J%")J3#!L3%!J%"!5%#!5%"!58#!3%\r%!J%N!33#!3)L!J)#)J)$!5-%!J)"*!3#!`%")`)#!3%V!J-""!)#!33#!`J$)3J\r#)`%)")%$$3!)"!%*!!!*!!%*"!!*"!%)!!))!!-)"!))"!-*!!)*!!-*"!)*"#)\r$#!%K!J%K#!%P!J%)"!)"*3J%!J%*!5%#!5%*!58#!3N%!J%P#33#!3J")`)##!%\rV!J-)"!)##!3#!`N")`)##3%U!J-*"!)##33#!`8K%!3K!3)L%!%%)3L"!`S3!!J\r!!3J3!3J!%!!3%!!!%3!3%3!!%!J3%!J!%3JN%"%)"!-L""!#)33")3%")`33!3%\rK"!)M#!33!5))"!%R!3J%%!%)"!%K%!%M""!3!5%%!5%4!5-%%"%")33"*a!)""!\r3#!3"*K%)""!4#)%$$`)!!")!!!)"!")"!!)!#")!#!)"#")"#!)3!")3!!)4!")\r4!!)3#")3#!)4##85%3J%!J)L"")#)`3#!3%M"")"!5)%!J%M#!35!5`)"!)"#!3\r5!3J%!K!")`35%!%M"!)4!5-%%K%"-!3#%!J%%K!)"!)4#!35%3J%)4!%)3%#)K!\r""5)%%!)K"!%K!B%$'333!33J!!!`!!!J!3!`!3!J!!3`!!3J!33`!33!%!!3%!!\r!%3!3%3!!%!33%!3!%333%33J%!!`%!!J%3!`%3!J%!3`%!3J%33`%5%%!L%3!5%\r3!5%3!L)"%!%M%!%3!b-3""!")K!%!5J"%!33!4!%)!%K%!%K-!%K%!%M)!%3!5-\r`!4!")5!")a!%-!%U%!3J!4!%-!%3"!%L%"!")a!3%!)L%4!")a!4%!)R%"!%%"!\r3"!%U%4!%%"%3"#!3%!%M-"!3!5-J%4!")c!4%!%`)"!3"$!3%!3J%4!%-"%3"!3\rK#!BL#!J#)3J#)33")3J")33$)`3)#!%L"!J")3)#)JJ#!b%#!5-)#!)")3J")J)\r%!5-)!J3#*`)%#!J#"!J$)J%)J3-'!!%!!!N)!!N!"!%)"!%!"!N))J3*!5%#!5-\r"#!)")3%")3)")`N)!J%K#3%R!J3"#!)%!3%S!J3*#!)%#3+"!`F!!!S!!!)!#!S\r!#!)%!!S%!!)%#!SN"!J#!J)L#J)#)J)#!5-)#J)"*!J#!J3")`S#"!%T!J)%#!S\r#"!J#J3-(!!%+!!%#!!N+!!N#"!%+"!%#"!N+*!3*!J)")`%+!J%M!3)#!5-*#J)\r"-3N#!J3"#J)%!3)#"!N+!J3*"L%"J3-'!!J!!!J"!3!!!3!"!3J!!3J"!b%3!L)\r"%!%K#!%K%!%N#!%3!3)L%!%"*!%3!3J"*4!"#!%3!5%J!b)J!B%$"J!S!!!S!3%\rJ!!%J!3%S!!%S!3%K)!%K%!%M)!%3!5%S!5%3!58S!4!")!%R%!%J!4!"+!%P%!%\rS!4!#)3+"!`F!!!-!#!)!#!-"!!)"!!-"#!)"#!-#)J)3!L)$%!%M#!)3!53)!a!\r"!5-#%!%"+J-3!3J#%!%)!a!")L!#J3-(!#!$!#J#!#J$!5!#!5!$!5J#!5J$!5-\rJ!K!")b!$%!%M+!)3!6-S!a!")!)3!5!$%!%S!K!"+!-3"#%%"#%%!L)%"!8L!J3\r#)3)")33")`)%"!%K!J)K)!%K"!%K)!)L"#!")`3%)!-M)!)%!5)J!J%R"#!#"!3\rJ!J-L)!3#)5!")33")b!%"!%K)!-L)J3#)5)")33")b)%"!%K)J)M)#!%!5)J)!%\rR"#!J"!3J)!)M)#)%!5)J)J%R"#!L"!3J)J)K#!%K"!%K#!)L"!J")`3%#!-M#!)\r%!5))!J%R"!J#"!3)!J)K+!%K"!%K+!)L"#J")`3%+!-M+!)%!5)S!J%R"#J#"!3\rS!J)M##!%!5)))!%R"!JJ"!3))!)M##)%!5)))J%R"!JL"!3))J)M+#!%!5)S)!%\rR"#JJ"!3S)!)M+#)%!5)S)J%U"#JL"!3S)J))#!)K#!)K!J)Q!J))#!)#"#-)#!)\r")3J")J)#!L%#!5B)#!)##!J")J))"#-)!J)")`J#!JJK#!%K!J%K#!8L!J)")3J\r#)JJ)!5B##!J#!JJ%)`J#!J%K#!3K!J)K#!)L#!J")J))!5%#!L%)!5%#!53)!J)\r)!5%###8##!J#!J%K#!)K#!%N!J))#!)K#!3M#!)#!5%)!5)##!%K!J)K#!)L#!J\r")3)#)3)")`J)!J-L!J)#)`)##!)N!JJ)!J%L#!J")J))!L%#!5-)!J)&)JJ#!5%\r)!5%#"5%)!L%#!b%#!58)!J))#!3M!J))!5%#!L%)!LF)#!*!%)!3"5)3J!%L3"!\r#)8!#)4!#)i!33!%KJ!)L%)!$)B!")N!3!5%3!b)33!%KJ!)K%!%N%%!3J!%L3"!\r&)4!")4!#)8!"*)!33"!")4!#)B!#*"#!%%!))4!")K"!!5+!%!%Q%)!33"#!!5&\r!!L)33!3K%!3QJ""!%)!3!5%3!5333"#!!5&!!5'!!LF3J""!%)!3!5%3!5)33!)\rK%!3K3!8LJ"!")4!#)N!3!5%3!L'!!5&!"#33J""!!5@!%%!3J!-KJ!8K3!)K%!-\rP%%!3J"!")K#!!5*!%!)L3"!")4!")4!%)i!33!%KJ!%K3!%LJ"!$)a"!%!-L%)!\r")33#*!%%"!%$)3%")33")J%"!5%%!5)""!-K"!%L!3%")J3"!5%%!5%"!L%%!L)\r%"!8P!33%!3%#)J%"!b-""!3")3%&)33"*!%%"!%$)3%$*J%""!3"!3%K"!)K"!)\rM!33%!5)""!%K!3)P"!%""!3$)J3""5%%"#B%!3%%"!%$)3%%)3%")33%)J%"!5%\r%!5-""!3#)33")J%""#-%"!%#)J3"!5)%"!%K!3%K"!%L!33$*!3%!3%$)3%"*!3\r"!33#)J%%!b3%"!%"!5%%!L%%!5%"!5%%!5)"!3%L"!%")33")3%&)J3%!5%"!L-\r"!33#)3%")`3"!3)K!3%L"!3$*%!3#"!")4!%*3J33"!)"#)33!)K%!%L%!J")8!\r"*!J33"!")4!#)JJ3"5-3#"!#)3J")d!3#!%K3!)K%!-L%%!")3J")N!3!b%3"#%\r)!5*!%!%K%!%N%!J33!3K%!-L%!J&)8!"*!J33"!")4!")4!")K"!!58)%%!3#!%\rK3!)L%%!")3J#)K!)!5&!!L%3!L%)!5*!%!%K%!%K%!3M#""!!L%3!5)3#!BK%!)\rK3!%K#!3L%%!"*!J33"!$)4!")4!$*""!%!J")d!3#!%K3!)N%%!3#!-L#"!")4!\r#)d!3#!%K3!%K#!%L3"!")K"!!L%3!5)3#!)M%!J3!b%3!L3)%%!3!5%)"#%""#%\r%!5B)!33J#!%")L!)!5%%!L8""#!)!3-K!38L)!J#)5!")J%%!5%)!53%)!J"!53\rJ#!%%"L)""!%K#!3K!3%K)!)M"#!)!5%%!L-""#!%)3J#)5!$)L!)!5B%)!J""#!\r")3%")b!)!33K"!-P"#!)!33")`J""!%K#!%L"#!")3%")b!)!3-K!38L)!J#)L!\r)!5%%!5%)"#)""!%N#!%%)!8N!33J#!8K"!)K!3%L)!J")J3J!L%%"5B)!33J#!%\r"*#!)!33$)J3J!5%"!b)""!%L#!%")L!)!5%%!b)%)!-K)!%P!33J#!%#)3J#)L#\r!!L&!!5%J!5&!"#1!)#!#)5!")8!#)5!")B!")L"!!5%J"#BJ3)!J)%!")L!J!5'\r!!b'!!5%J!5'!!L0!J#!$)b!J3!%K)!)KJ!%N)%#!)!%K3!BK)!3N3)!J)!%LJ#!\r"*d#!)#"!J#!#)B!&)L"!!b&!!5)J)!)N)#"!J!%K)!-M)%#!!b'!!5%J!LBJ)%#\r!)#!#)5!")8!%)B!")5!")B!&)5!")S!J!5&!!5%J!b%J!59!J#!J3!%L)#!%*8#\r!)#"!!5)J)!)K)!)KJ!%M)%#!!L0!J#!$)b!J3!BK)!%KJ!)L3)!"*5"!J#!J!5+\r!)!3L)%!$)d#!)!%K3!)K3!-K!J%K!B%$(3)!!3!%!8)%!%!%!%)!N!3"!!!"!J3\r!!J3"3!!!!!3"3J!"3!!!!J3"!J3!3!!!3!3"3J3!!!!"!J!"!!3!3J!"3!3!3J3\r"3J!!!!3!3J3"3!3!!J!""#0#"!'"!`T!!!&!"!!#"!"!!!!#!!%!!!&!"!%#"!"\r#"!"#!!!%)3)")3'"!a)!"!!!"!%#!*!%!3)%!3)!!%)!!!)%!%!!!8)%!3!!!8)\r!!!!%!%!%!8)%!3!%!8)!!8!!!#4!"##!J3-HJ###!!!#J!!!!#!#!!#!J##!!##\r#J!!!J#!!!!##!!!#J!##J#!#J#!!J##!!!!#!!##J!#!J#!#!###J#!!J!#3"))\r!)!!!!)!!)!+!))#!!)!!!!)!)))%)B!")B!$)3)#)5!#)i!JJJ%KJ!%K!J%LJ#!\r))B)#)L#!!51!)!)")i!J!J-KJ!%MJ###"5'!!5'!J3-*J#!#!###J!#!!##!!#!\r!J!##!!!#J#!#J##!"#1!))+"!`B!!)+!!!!!)!!!))#!!!)!!))KJ2rf!!!"!!!\r!!9`!!!"F!!!!-R3JG'KP)'CTEQ&X)(0PC@3JGA0TEQFJG'KP$5!J)#SJBh9bFQ9\rZG#"bB@jNEfdJER9YBQ9b)(0dFQ9KE6S0)#!J+Lm0)#"NCA0IEQ9hAh*KEQ4[E9p\rVCANSEQ9hAfYPH5Nl$5!JC'9cAh0PG&pbB@jNEfeICf9ZCA*KG'pbAh0PC@3SEQ9\rhAfYPH5Nl$Ad0$3d[+JdJ+L"8D'Pc)'e[C(9XC5"TEA"XC@ePER4c)'%JFQ&ZC'p\rY)'jeE@*PFL"RC@jPFQ&dEh)JCQ&MG@adH5"cG@0S)(4SBA3JG'KP)'jPH(30)#S\rJER9YBQ9b)'PZ)!!!!&J!N!X"!*!6!A"hF'-!N"-"!*!41!Y0594IT@4PFfaTBJ#\r3"!%!!!!"A!!!!&`!!!!b"QG8M&fN!!!!(!!b!!"MCR*R!!!!#J!!rrm!N!3'Ce2\rJ@38:\r
\ No newline at end of file
+++ /dev/null
-(This file must be converted with BinHex 4.0)\r:%'4PFfaTBLj38%-ZC'9LG@F!FfKXBMq3"!#3")pa!!!"NVNR5Qpj)A"PCQC`Gh"\rM!!!!!E*ETmN!N!d$!!)!N!6rN!3!N!CIH!!!AhJ!!&pi!!!&X!!%"!$rN!3!N!B\rYdJ!!,63!!#T"!!"P-!)""!$rN!3!N!i&,!!!!)!%"!3!N!ArN!3!N!F"!!!!p!!\r!!!%!!!$X!!!!!`!!!")!!!!"!!!!e!!!!23!!!1!!!!!"!!!!"S!N!m2!*!,%`#\r3#`)!!!!2!*!(,!#3#`%!!!!4!*!%!J!!13)!!%!#!!"(!J!!6J)!!&3#!!"E!J!\r!B!%!!'F#!!"[!J!!GJ)!!(X#!!##!J!!L!)!!*%#!!#B!J!!S!)!!,B#!!$+!!%\r!N!83!*!%5JCJ#%S)3J*J"d)"3!&#!8!"3KL!%dBD3#UJ!"[`3""0594IT8e*9%0\r-D@)ZC'9LG@F!68P8Ak905945G@jdD@eP6'PL,Q4PBR9R!%PZG'9bCQ&MC8aTBJ"\rcG(*MEA!!Fh4bBfKb!'CQE(9cD!"cFQ&ZC!"YC@eMF(N!FQ&ZC!"YC@eMEA!!Aep\rQD@aPF`"cG(*XC@i!G'PYC3"`FQPZG'B!CQGPG(-!BfaPBA*PFR)!E@9YFf9d!'C\r`FQPZG'B!AepeER*PCfPcG'9bAfCbB@GYC@jd!&pIFQ9RDA0dCA*ICR*KCfePER3\r!9'PMDd0[G@jd!'4PFepbC@&NAh"KFh0hEh*NC'9cAh0PG&pcCA&eC@jMC9pZG@e\rLCA*NCA0IC'9LG@GNCA0IFf9dAfYPH@4PFepTFephC@&VAfYPH@4PFepcG(*TEQG\rIG'pIDf9jC'9cAfjPGepbB@jNEfeIDf9jC'9cAf0LE'pMDep`FQPZG&pQD@aPC'9\rcAfCMFRP`G'4PFepQDAKeF&pVCAPIF'&bDA4jC'9cAf0SC@0VAfYPH9p`BA*TG(P\rNCA0IFQ&ZC'pYAfYPH@4PFepMFRP`G'4PFepbC@&NAh"hAh0dFQPZCf4PFepTEQP\rdAh*KEQ4[E9pZG@eLCA*ICf9ZCA*KG'pbC'9cAc0PBf*IC@jMFRP`G'4PFemcBf*\rMAf9ZBh*jF(4NCA0IFf9dAh*KEQ4[E9pRC@jPFQ&dEh*IFf9PC'4PFepVCAPIFf0\rSC@4NCA0IFA9KC&pMDh0eE@eKDf9IDf9jAh0MD'9NC'9cAf9MBPpPEQ0bHA"dC'9\rcAf0LBepPEQ0bHA"dC'9cAfGPEQ9bBA4PAh*KEQ4[E9pLE'pMDf4PFep`Bf*MAf9\rZBh*jF(4NCA0IBf*MAf0VFh9Y!*!&$!!!!!`!!`!%!!B!"!!(!!`!#!!%!!X!"!!\r-!!!!$3!)!!d!%!!2!!J!%`!!!"8!#!!9!!!!&`!-!"F!%C08!"IZC`!*4Fd!#a*\r'!!pG4J!4DjX!%V5D!"8rb!!+Le!!&(88!"5G&!!1PpX!#89`!")N1J!J`X8!%%@\rJ!""5S!!GG-B!$9-+!!k&6`!1L`X!$fI"!!pm`3!C%1%!%$UP!!eI$`)!!03!!!&\rm!!%#!!$P!!!"4!!"!3!!r!!!,63!!3)!!38!!!'N!!%#!!%3!!!"P!!"!J!"(`!\r!!B3!!3)!!6!!!!&F!!%#!!&#!!!"M!!"!J!"9`!!!D`!!3)!!@%!!!%F!!%#!!&\re!!!"&!!"!J!"L3!!!@`!!3)!!CF!!!'d!!%#!!'J!!!"G!!"!J!"XJ!!!93!!3)\r!!G)!!!'m!!%#!!(L!!!"R!!"!J!"mJ!!!8`!!3)!!Jm!!!%d!!%#!!)F!!!"C!!\r"!J!#+J!!!5`!!3)!!MJ!!!%-!!%#!!*(!!!!r!!"!J!#9J!!!6`!!3)!!Qm!!!%\rN!!%#!!*r!!!""!!"!*!%I!J#TT!!!3!)P#(r`$JK!%#!!3!)I!J$TNk!!#"m#!+\rQNq(rr*!!!3!)P#(r`*!!B3"B1q!!!)"K!&K)!&`eB!!!!(ar'hKri`Fd,!-!!%'\r#!!arirYi5!!!#(rMqhL!!3")1#%!3(`)!kD$iIrm6S!!)!#3"L""J!%!N!98!"3\rZAepTEQPdD@&XDATPAf4PFfaTBJ!!I!J#TT!!!3!)P#(r`%J!A#&J!!!!J!%!5$J\rK!%"m#!1Q6S!!)!#3"L""J!#3"L3!%bjIAh4PFQeTEQ&dC9pNCA0XD@)!!!#q)Ir\r%1Z)2-$[#%c!l!JX`I0XcH#`)!!""JJA8I2BlH)Nf!!!keJ!"95N'2P8m`!k*9J!\r!1YB!!99+"Mj95S!HIja6H)Pf!!!keJ!"9@X'2P9V3#jrR&YiLCB!!$V@!!&9M!B\rqIjaMH)Nf!!!keJ!"95N'2P8p`!k*9J!!1YB!!99+"Mj95S!HIle6H)Pf!!!keJ!\r"9@X'2P9V3#jr[9YiLCB!!$V@!!&9M!BqIleMH(af'hKmP50i5!!&+#`&!!K"J!$\r%L6B!!$V@!!&9+3Bq95N'2P8T`!jrR%TiL9B!!$V@!!&95JBq98S'2P9+J"jrR&*\riLAB!!$V@!!&9D`Bq9@X'2P9V3#jrR&TiLCB!!$V@!!&9M!Bq9B`'2RqFBRL*0J!\r!1YB!!98T"Mj9+3Bq95R!$Rqp5RL*9J!!1YB!!99+"Mj95JBq98U!(Rqp8RL*GJ!\r!1YB!!99V"Mj9D`Bq9@Y!,Rqp@RL*PJ!!1YB!!9@-"Mj9M!BqIleLH$LPrrK)!!#\r`IYBU&#J&!!G"J3#J15)"k&5U%$Tp+9!ZI5N$TNk!"#!ke[rrLAB!!&9V"Mj9Dd!\rZIleDH$V@rrq*PJ!!9B`'2P@-J"jr[@*i1YErriNf!!"9+3Bq95R!$Rqp5RJke[r\rrL9B!!&9+"MjrR&*i1YErriPf!!"9D`Bq9@Y!,RqF@RJke[rrLCB!!&@-"Mj9M)!\rHIjaLH$V@rrq*0J!!95N'2P8T`!jrR%Ti1+!!!$e!UUXj5UUUIiT31$eJUUXjDkU\rUIkYB1&9Vq(jpAeYi2B"996Q-999rM'!i9B`)2$dJ998j+999IkP)1(fG5hKAUJB\rq98S31ReB8#j95KJi9k['2P9V%$TpH&JZ9@X31PHX4Mj9M"!kICKJ,PHTKMj9+4!\rkI6K),P8T#$apM%YiI@YMH(eF@hKAkJBq98S31ReB8#j95KJi9q['2P9V%$TpH&J\rZ9@X31PIX4Mj9M"!kICKJ,PITKMj9+4!kI6K),P8T#$apM%YiI@YMH(eG@hJl3!!\r!5!!"S)&E!!!lH`!%9kZUrPHXU"4pDf0iI9pDH&IT"Vj9+4!k15N$!(dq5#jAkXD\rq98S31MP+!J"pAP!Z9qZ'[P9V%$SjD`%!IAjB,PIX4Vj9M"!kICjJ,ReVBhKp5PY\riI5P6H(qF5RL"1`!!1hX!"&HU6IjAUdJXI8TEH(dr8RKAl!Dq9B`31MQ-"`"pRQ!\rZ9qR'[P8T%$Sj+3B!I6j),PIU4Vj95K!k18S%!(eH8#jAkiDq9@X31MPV"3"pIPJ\rZI8TEH(dT8hKpM%YiIjaLH)'E!!!lH`!%9iQUrPH+U"4p+90iICp+H&IV"Vj9Da!\rk1@X$!(eq@#jAl-Dq9B`31MQ-!J"pRQ!Z9qQ'[P8T%$Sj+3%!I6j),PIU4Vj95K!\rkI9j3,RdT8hKpM%YiI@YMH(qp@RL"H`!!1hX!"&H-6IjAL8JXIBa,H(erBRKAkJD\rq98S31MP+"`"pAP!Z9q['[P9V%$SjD`B!IAjB,PIX4Vj9M"!k1B`%!(fHB#jAkBD\rq95N31MNT"3"p2NJZIBa,H(eVBhKp5PYiIle5H$YD!!%X'J!)3B$qB$e!m2%j5[$\r`IkT31$eJm2%jDr$`IiYB1&9Vi6jpAeYi2B!2$cQ-$`prV'!i9B`J0MdJ$`mj+3m\r2IiP)1(fG5hKAUJBq98S31ReA8#jAUmBq9@X31Reh@#j9Da!k9ka'2P@-%$TpPf!\rZ9B``-PHTKMj9+4!kI6G),P8T)$CpM%YiI@YMH(eF@hKAkJBq98S31ReA8#jAkmB\rq9@X31Reh@#j9Da!k9qa'2P@-%$TpPf!Z9B``-PITKMj9+4!kI6G),P8T)$CpM%Y\riI@YMH(eG@hJlHrq!9iT'2TP9!!!kY3!"9iZ'2TPe!!!kY3!"9ic'2TQ9!!!kY3!\r"9iN'2TNe!!!kY3!"9kT'2TP9!!!kY3!"9kZ'2TPe!!!kY3!"9kc'2TQ9!!!kY3!\r"9kN'2TNe!!!kY3!",!8!!%'"qYK)!!@B,!8!!%'"!!`iB!!!5!!&M(cf1hL*9J!\r!1YB!!99+"Mj99-!1LAB!!$V@!!&9D`Bq9@Z!(Rk8@hL*PJ!!1YB!!9@-"Mj9M%!\rZIT4MH)Nf!!!keJ!"95N'2Rk85hL*9J!!1YB!!99+"Mj98m!1LAB!!$V@!!&9D`B\rq9@Z!(Rjc@hL*PJ!!1YB!!9@-"Mj9M%!ZIR0MH)Nf!!!keJ!"95N'2Rjc5hKmGKY\riI*8MH)P@!!!keJ!"98S'2P9F`!k*GJ!!1YB!!99V"Mj9Di!HIjaEH)Q@!!!keJ!\r"9B`'2P@-3#jrR'0iL6B!!$V@!!&9+3BqIja,H)P@!!!keJ!"98S'2P9G`!k*GJ!\r!1YB!!99V"Mj9Di!HIleEH)Q@!!!keJ!"9B`'2P@-3#jr[@0iL6B!!$V@!!&9+3B\rqIle,H(q5ihKrXHYi28#UUcP+UUTrLP!i2@#UUcPVUUTrUeJi9@[iIReI@hJpJ&9\r91Ba99Aq-B$K9M!Jm25"996NT999rU8JiICe,H&HU"Mj95K!kI9K3,P9+'$KAUmB\rq9@X31Rei@#j9Da!k9ka'2P@-%$TpQ'!Z9kQ'2P8T%$Tp1%JZ95N)2(f-5hKpDf0\riI9aEH&IU"Mj95K!kI9K3,P9+'$KAkmBq9@X31Rei@#j9Da!k9qa'2P@-%$TpQ'!\rZ9qQ'2P8T%$Tp1%JZ95N)2(f-5hKpDf0iI9eEH$Yl!)!l)!!!5!!"S$Ylrrb"@`!\r!9kY0rPHX5#apDf0iI9pDH&IT4Vj9+4!k15N%!(dq5#jAkSDq98S31MP+"3"pAP!\rZ9qX'[P9V%$SjD`F!IAjB,PIXaVj9M"!k1B`'!(fHB#jpDf0iI8TEH(dT8hKrR%T\ri1h[rr)%l!!"AUUVq9kZS&(e+@hKp2e*i9qb'[P@-%$SjM!%!ICjJ,PIT"Vj9+4!\rk15N$!(dq5#jAkXDq98S31MP+!J"pAP!ZI5P6H(f-5hKAkdDq9@X31Req@#jpM&Y\riIjaLH$Ylrrb"Q`!!9iP0rPH+5#ap+90iICp+H&IV4Vj9Da!k1@X%!(eq@#jAl)D\rq9B`31MQ-"3"pRQ!Z9qN'[P8T%$Sj+3F!I6j),PIUaVj95K!k18S'!(eH8#jp+90\riIBa,H(eVBhKr[9Ti1h[rr)&l!!"AM+Vq9iQS&(f-5hKpIf*i9qU'[P9+%$Sj5J%\r!I9j3,PIV"Vj9Da!k1@X$!(eq@#jAl-Dq9B`31MQ-!J"pRQ!ZI@YMH(e+@hKAk8D\rq95N31Rdq5#jp5NYiIle5H$Xj!!%X'3!)3B$qB$e!m2%j5[$`IkT31$eJm2%jDr$\r`IiYB1&9Vi6jpAeYi2B!2$cQ-$`prV'!i9B`J0MdJ$`mj+3m2IiP)1(fG5hKAUJB\rq98S31ReA8#jAUmBq9@X31Reh@#j9Da!k9ka'2P@-%$TpPf!Z9B``-PHTKMj9+4!\rkI6G),P8T)$CpM%YiI@YMH(eF@hKAkJBq98S31ReA8#jAkmBq9@X31Reh@#j9Da!\rk9qa'2P@-%$TpPf!Z9B``-PITKMj9+4!kI6G),P8T)$CpM%YiI@YMH(eG@hKrR+*\riIlfDH#`&!!K!J3"d1+Arq&H+4MkC93!!1V8!!9H,KMkCG3!!1V8!!9H-aMkCP3!\r!1V8!!9H*"MkC03!!1V8!!9HU4MkC93!!1V8!!9HVKMkCG3!!1V8!!9HXaMkCP3!\r!1V8!!9HT"MkC03!!1V8!!Aj8NhKq-iYi5rrlR(ke+K3S"3!)3B%!H$P#!F48Ua!\rkI8TB,Re*!kC1J!3J9k`'2MUerrqCP3!!9kR'2MUerrqC03!!9kU'2MUerrqC93!\r!9kY'2MUerrqCG3!!9i`'2MUerrqCP3!!9iR'2MUerrqC03!!9iU'2MUerrqC93!\r!9iY'2MUerrqCG3!!1'!!!,SKrm41J!!J!*!')%!!$`#3"!Z-!"!ZC'9cAf0LBep\rPEQ0bHA"d!!#q`IrB1`)2-$[#%c!l)JX`I2FlH)NA!!!kp`!"93J'2P8F`!k*0`!\r!1[F!!98T"Mj9+B!HIja,H)PA!!!kp`!"98S'2P9+3#jrR&0iLAF!!$Vh!!&9D`B\rqIjaEH)QA!!!kp`!"9B`'2P@G`!k*&`!!1[F!!98)"Mj9#)!HIle$H)Nh!!!kp`!\r"95N'2P8T3#jr[8YiL9F!!$Vh!!&95JBqIle6H(ah'hKmYLYi5!!%c#`@!!K"J!$\r%LAF!!$Vh!!&9D`Bq9@X'2P9V`!jrR&TiLCF!!$Vh!!&9M!Bq9B`'2P@-J"jrR'*\riL4F!!$Vh!!&9#!Bq93J'2P8)3#jrR%*iL6F!!$Vh!!&9+3Bq95N'2RqF5RL*9`!\r!1[F!!99+"Mj95JBq98V!$Rqp8RL*G`!!1[F!!99V"Mj9D`Bq9@Z!(Rqp@RL*P`!\r!1[F!!9@-"Mj9M!Bq9Ba!,RqpBRL*&`!!1[F!!98)"Mj9#!BqIle#H$V@rrK)!!#\r`I[Hb&#J@!!G"J3#J15)##&E+%$Tp+9!ZI5N$TNk!"#!kprrrLAF!!&9V"Mj9Dd!\rZIleDH$Vhrrq*P`!!9B`'2P@-J"jr[@*i1[IrriNA!!"9#!Bq93M!$Rqp3RJkprr\rrL6F!!&8T"MjrR%Ti1[IrriPA!!"95JBq98T!,RqF8RJkprrrLAF!!&9V"Mj9Di!\rHIjaDH$Vhrrq*P`!!9B`'2P@-`!jrR'*i1X!!!(cE-hJp!+UV13LUURq)3$Jp)+U\rV15QUURqT5$K9+IKqI4p,H$e!998j5P99IiT31&9+#$`pB&991@Y99AqV@$KpA9Y\ri9k`'2P@-%$TpQ@!Z9B`B1&HSaMj9#"!kI4P!,P8)%$TAU8Bq95N31Rdj5#jAUSB\rq98S31ReC8#j95JJmI5P6H(d)5hKpR%0i9qX'2P9V%$TpH9JZ9@XB1&IXaMj9M"!\rkICPJ,P@-%$TAk%Bq93J31RdC3#jAkBBq95N31Rdj5#j9+3JmI3K,H(f-3hKpI@0\ri1d!!!%J!!D#"@`!!1hX!"&HVU[jAV+J8I@YMH(eI@RKAk!Dq93J31MN)!`"p(N!\rZ9qR'[P8T%$Sj+3)!I6j),PIUKVj95K!k18S"!(eH8#jAkdDq9@X31Req@#jp5PY\riI5P6H(d)5hKrR%*iJCX!!$Yl!!4AU%hq9kP),(d)5hKpRd*i9qS'[P9+%$Sj5JF\r!I9j3,PIVaVj9Da!k1@X'!(eq@#jAl%Dq9B`31MQ-"!"pRQ!Z9qL'[P8)%$Sj#!8\r!I4j!,Rf-3hKpDf0iI8TEH(qF8RL"1`!!1hX!"&H+U[jALkJ8I8TEH(dr8RKAl!D\rq9B`31MQ-!`"pRQ!Z9qM'[P8)%$Sj#!)!I4j!,PITKVj9+4!k15N"!(dq5#jAkND\rq98S31ReH8#jp+90iI3K,H(f-3hKr[@*iJAX!!$Yl!!4AM%hq9iK),(f-3hKpIf*\ri9qN'[P8T%$Sj+3F!I6j),PIUaVj95K!k18S'!(eH8#jAkdDq9@X31MPV"!"pIPJ\rZ9qb'[P@-%$SjM!8!ICjJ,ReVBhKp5PYiI5P6H(qp5RJl@J!","S!#%'!rQ!p!2$\ra13M`m(qS3$Jp)2$a15R`m(q*5$K9+H%qI4p,H$e!$`mj5Jm2IkT31&9+)$BpB!m\r21@X2$hq,@$KpA9Yi9k`'2P@-%$TpQ'!Z9kM'2P8)%$Tp'%!Z93J31PHT4Mj9+4!\rkI6K),P8T-$*AUSBq98S31ReB8#j95L!fI5P6H(d)5hKpR%0i9qX'2P9V%$TpH&J\rZ9qc'2P@-%$TpQ'!Z9B`31PIS4Mj9#"!kI4K!,P8)-$*AkBBq95N31Rdi5#j9+5!\rfI3K,H(f-3hKpI@0i1h[rJ#`@!!""JIXdI*FMH&H+4MkC9`!!1[F!!9H,KMkCG`!\r!1[F!!9H-aMkCP`!!1[F!!9H)"MkC&`!!1[F!!9HT4MkC0`!!1[F!!9HUKMkC9`!\r!1[F!!9HVaMkCG`!!1[F!!9HX"MkCP`!!1[F!!AqMkhLk`IrB6S!!)!#3"L"!!!S\r!N!3&m!!1,Q4PFepMBQ0IBfYcG@fqSIr81U)2-$[#%c!k`JX`I(JEH)Mi!!!l'!!\r"91F'2P6m`!k*'!!!1aJ!!98)"Mj9#)!HIja$H)Ni!!!l'!!"95N'2P8T3#jrR%Y\riL9J!!$XB!!&95JBqIja6H)Pi!!!l'!!"9@X'2P9p`!k*Q!!!1aJ!!9@-"Mj9M)!\rHIleMH)Mi!!!l'!!"91F'2P6R3#jr[6YiL4J!!$XB!!&9#!BqIle$H$dJUUXj+DU\rUIiP)1$e!UUXj5UUUIkT31&9+q(jp2e0i2@"996PV999rLeJi9@X)2$f!998jM&9\r9IkaJ1(epBhKAT`Bq91F31Rcf1#j8jaJi9kM'2P8)%$Tp&N!Z93J31PHT4Mj9+4!\rkI6C),PHUKMj95K!kI9C3,P9+#$ap+90iI3K,H(cm3hKAk`Bq9@X31Ref@#j9DaJ\ri9qc'2P@-%$TpPQ!Z9B`31PIR4Mj8ja!kI2Bi,PISKMj9#"!kI4C!,P8)#$amjd0\riIB`lH(epBhJX"J!!3B)"Z(bk+hJlB!!!5!!"S)%k!!!l@J!%9kUUrPHVU"4p5PY\riI6p5H&IX"Vj9M"!k1B`$!(fHB#jAjmDq91F31MMR!J"mrMJZ9qL'[P8)%$Sj#!%\r!I4j!,PIT4Vj9+4!kI6j),Rd)5hKmjd0iIB`lH(qFBRL"@J!!1eS!"&HV6IjAV%J\rXI@YMH(eI@RKAj`Dq91F31MMR"`"mrMJZ9qM'[P8)%$Sj#!B!I4j!,PIT4Vj9+4!\rk15N%!(dq5#jAkSDq98S31MP+"3"pAP!ZI5P6H(d)5hKmjd0iIj`kH)&k!!!l@J!\r%9ibUrPH(U"4pM$YiIApLH&IS"Vj9#"!k13J$!(dH3#jAkFDq95N31MNT!J"p2NJ\rZ9qU'[P9+%$Sj5J%!I9j3,PIV4Vj9Da!kIAjB,Re+@hKp+90iI3K,H(qp3RL"QJ!\r!1eS!"&H(6IjAL%JXI1G$H(fI1RKAk3Dq95N31MNT"`"p2NJZ9qV'[P9+%$Sj5JB\r!I9j3,PIV4Vj9Da!k1@X%!(eq@#jAl)Dq9B`31MQ-"3"pRQ!ZI@YMH(e+@hKp+90\riIle+H$Yl!!%X'`!)3B$qB%J!!E3l*3#!1f!!!%J!!D!l1IrmJ2N!!&HS6IjAU8J\rXI3K,H(cr3RKAkNDq98S31MP+"!"pAP!Z9qZ'[P9V%$SjD`8!IAjB,PIX"Vj9M"!\rk1B`(!(fHB#jAjmDq91F31MMR"J"mrMJZIB`lH(eVBhKp5PYiIja5H$Xjrrb"'3!\r!9kQUrPHUU"4p+90iI4p+H&IVKVj9Da!k1@X"!(eq@#jAl!Dq9B`31MQ-!`"pRQ!\rZ9qI'[P6R%$Sij`)!I2ii,Rf-1hKpDf0i9qK'[P8)%$Tp(N!ZI@Y$H(qF@RJl1Ir\rmJ6N!!&H+6IjALdJXI8TEH(dr8RKAl%Dq9B`31MQ-"!"pRQ!Z9qH'[P6R%$Sij`8\r!I2ii,PIS"Vj9#"!k13J(!(dH3#jAkFDq95N31MNT"J"p2NJZI3K,H(cR3hKpM$Y\riIleLH$Xjrrb"@3!!9iZUrPH-U"4pDf0iI9pDH&IRKVj8ja!k11F"!(cq1#jAk!D\rq93J31MN)!`"p(N!Z9qR'[P8T%$Sj+3)!I6j),Rd)5hKmjd0i9qT'[P9+%$TpAP!\rZI1G6H(qp1RJlH`!","X!#%'!rQ!pB2$a1@[`m(qV@$JpJ2$a1Bc`m(q-B$K9M1%\rqIApMH$cJ$`mij`m2IkFi1&6R)$Bp!!m213J2$hq)3$Kmr80i9kN'2P8T%$Tp08J\rZ9kV'2P9+%$Tp99!Z98S31PHV4Mj9Da!kIA9B,P9V-$*AV)Bq9B`31Rf9B#j9M#!\rfI@YMH(e+@hKp2&0i9qF'2P6R%$Tmp6JZ9qM'2P8)%$Tp&8!Z93J31PIT4Mj9+4!\rkI69),P8T-$*AkSBq98S31Re98#j95L!fI5P6H(d)5hKmr80iI*FMH&H,4MkCG`!\r!1[F!!9H-KMkCP`!!1[F!!9H(aMkBp`!!1[F!!9H)"MkC&`!!1[F!!9HT4MkC0`!\r!1[F!!9HUKMkC9`!!1[F!!9HVaMkCG`!!1[F!!9HX"MkCP`!!1[F!!6KJ!!#kSIr\r86S!!)!#3"L"!!!X!N!3')!!3,Q4PFepPBf*IC@jMFRP`G!!!Nq(rr$[J!!")!!#\rBI)2iVP5%"MamJrQZI+2iVP5P"cjm`rLZ9-ER2RbP-RK8T3HqI12iVP6R"cjp!rL\rZ93MR2RcR3RK8jrHqI+8kH&5P"rjp)rLZ95N(2Re$q+j95ZFqI5P5H&8T"ljpBrL\rZ9@X(2Rf$q+j9M1FqI@YLH&9Vpljp+9Ti95RrrRbP5RKST3!"I)2iVRb%+hKmJrQ\rZ1rm!!5JI!!K"J2pSJq(rr%k!!#!!N!BJ3!!"!*!&X!!9,Q4PFepQDAKeF&pVCAP\rIF'&bDA4j!*2Krr`li!!!5!!!Y(b$q+j8K!IqI+2iVP5P"Ma8T3FqI-2iVP6'"Ma\r8aZFqI+8bH&5P"ljmirLZ91F'2&6R"cjp!rLZ93J'2&8)jcjmjd*i91Ih[RbP1RK\r8T3IqI52iVP8T"Ma9+3FqI82iVP9+"Ma95ZFqI5P5H&8T"ljpBrLZ9@X'2&9V"cj\rpJrLZ9B`'2&@-jcjpDf*i9@[h[RdT@RK9+IrqI+9+H(`%+!"!JJ!-1'!!!%J!!"3\rlr`!"+"m!#%'!rd`iB!!"Jq(rr%k!!#!!N!BJ3!!"!*!&d!!9,Q4PFepMD'9MDep\rVCAPIF'&bDA4j!,i"rm!kiJm`1m)6-$X##c"mfc0i,!J!!%'#"FampMYiL6B!!$V\r@!!&9+3Bq96c!$SP@!!!keJ!"98S'2P9+J"jrR&0iLAB!!$V@!!&9D`Bq9@Y!,Rq\rF@hL*PJ!!1YB!!9@-"MjrR'0iL6B!!$V@!!&9+3Bq96h!$SP@!!!keJ!"98S'2P9\r+J"jr[90iLAB!!$V@!!&9D`Bq9@Y!,Rqp@hL*PJ!!1YB!!9@-"Mjr[@0iI(BEH(b\r9)hK)!!8J,!8!#%#"!+5*0J!!1YB!!98T"Mj90-!1L9B!!$V@!!&95JBq98U!(Rk\r88hL*GJ!!1YB!!99V"Mj9Dd!ZIT4EH)Q@!!!keJ!"9B`'2Rk8BhL*0J!!1YB!!98\rT"Mj9-m!1L9B!!$V@!!&95JBq98U!(Rjc8hL*GJ!!1YB!!99V"Mj9Dd!ZIR0EH)Q\r@!!!keJ!"9B`'2RjcBhKrR+*iIlfDH$LPrrK)!!$!IYBU&#J&!!K"J3#`15)#6&5\rU%$Tp+9!ZI5N$TNk!"#!ke[rrLAB!!&9V"Mjr[9Ti1YErriQ@!!"9M!Bq9Ba!,Rq\rpBRJke[rrL6B!!&8T"Mj9+B!HIle+H$V@rrq*9J!!98S'2P9+`!jr[9*i1YErriP\rf!!"9D`BqIjaDH$V@rrq*PJ!!9B`'2P@-3#jrR'*i1YErriNf!!"9+3Bq95Q!(Rq\rF5RJke[rrL9B!!&9+"Mj95X!1Ija5H$LJ!!!pB+UV1@ZUURq,@$JpJ+UV1BbUURq\rXB$K9M2KqIApMH$dJ998j+999IiP)1&8T#$`p3&9918T99AqU8$Kp290i9kX'2P9\rV%$TpH&JZ9@XB1&HXaMj9M"!kICKJ,P@-%$TAU8Bq95N31Rdi5#jAUSBq98S31Re\rB8#j95JJmI5P6H(f-5hKpI'0i9qX'2P9V%$TpH&JZ9@XB1&IXaMj9M"!kICKJ,P@\r-%$TAk8Bq95N31Rdi5#jAkSBq98S31ReB8#j95JJmI5P6H(f-5hKpI@0i1d!!!%J\r!!D#"H`!!1hX!"&HXU[jAUDJ8IBa,H(erBRKAkJDq98S31MP+!`"pAP!Z9q['[P9\rV%$SjD`)!IAjB,PIXKVj9M"!k1B`"!(fHB#jAk8Dq95N31Rdq5#jpM%YiI@YMH(e\r+@hKrR&*iJ9X!!$Yl!!4AUdhq9ka),(eVBhKpAeTi9qN'[P8T%$Sj+3F!I6j),PI\rUaVj95K!k18S'!(eH8#jAkdDq9@X31MPV"!"pIPJZ9qb'[P@-%$SjM!8!ICjJ,Re\rVBhKp5PYiI5P6H(qF5RL"1`!!1hX!"&H+U[jALkJ8I8TEH(dr8RKAl!Dq9B`31MQ\r-!`"pRQ!Z9qR'[P8T%$Sj+3)!I6j),PIUKVj95K!k18S"!(eH8#jAkdDq9@X31Re\rq@#jp5PYiI5P6H(f-5hKr[@*iJCX!!$Yl!!4AL8hq9iT),(dT8hKpRdTi9qX'[P9\rV%$SjD`F!IAjB,PIXaVj9M"!k1B`'!(fHB#jAk8Dq95N31MNT"!"p2NJZ9qU'[P9\r+%$Sj5J8!I9j3,RdT8hKpM%YiI@YMH(qp@RJl@J!","S!#%'!rQ!pB2$a1@[`m(q\rV@$JpJ2$a1Bc`m(q-B$K9M1%qIApMH$dJ$`mj+3m2IkP)1&8T)$Bp3!m218S2$hq\r+8$Kp290i9kX'2P9V%$TpGeJZ9kc'2P@-%$TpPf!Z9B`31PHT4Mj9+4!kI6G),P8\rT-$*AUSBq98S31ReA8#j95L!fI5P6H(f-5hKpI'0i9qX'2P9V%$TpGeJZ9qc'2P@\r-%$TpPf!Z9B`31PIT4Mj9+4!kI6G),P8T-$*AkSBq98S31ReA8#j95L!fI5P6H(f\r-5hKpI@0i1h[rJ&H,4MkCG3!!1V8!!9H-KMkCP3!!1V8!!9H*aMkC03!!1V8!!9H\r+"MkC93!!1V8!!9HV4MkCG3!!1V8!!9HXKMkCP3!!1V8!!9HTaMkC03!!1V8!!9H\rU"MkC93!!1V8!!AqFSRKr[CTi,!8!!%'"qZ")!!@F,!8!!%'"!!`iB!!!5!!&N!"\rmpMYiLAB!!$V@!!&9D`Bq9A,!$SQ@!!!keJ!"9B`'2P@-J"jq8Q0iL6B!!$V@!!&\r9+3Bq95P!,Rj55hL*9J!!1YB!!99+"Mjq8P0iLAB!!$V@!!&9D`Bq9A(!$SQ@!!!\rkeJ!"9B`'2P@-J"jq-@0iL6B!!$V@!!&9+3Bq95P!,Ria5hL*9J!!1YB!!99+"Mj\rq-90iI(BEH(b9)hL*GJ!!1YB!!99V"Mj9I-!1LCB!!$V@!!&9M!Bq9Bb!(RqFBhL\r*0J!!1YB!!98T"Mj9+8!ZIja,H)P@!!!keJ!"98S'2RqF8hL*GJ!!1YB!!99V"Mj\r9IF!1LCB!!$V@!!&9M!Bq9Bb!(RqpBhL*0J!!1YB!!98T"Mj9+8!ZIle,H)P@!!!\rkeJ!"98S'2Rqp8hKrN!$MH*1Krl!pB+UV1@ZUURq,@$JpJ+UV1BbUURqXB$K9M2K\rqIApMH$dJ998j+999IiP)1&8T#$`p3&9918T99AqU8$Kp290i9kX'2P9V%$TpH&J\rZ9@XB1&HXaMj9M"!kICKJ,P@-%$TAU8Bq95N31Rdi5#jAUSBq98S31ReB8#j95JJ\rmI5P6H(f-5hKpI'0i9qX'2P9V%$TpH&JZ9@XB1&IXaMj9M"!kICKJ,P@-%$TAk8B\rq95N31Rdi5#jAkSBq98S31ReB8#j95JJmI5P6H(f-5hKpI@0i1hX!J$XJ!!")!!'\rJ1h[rr)&l!!"AV%hq9kP),(f-5hKpIf*i9qT'[P9+%$Sj5J3!I9j3,PIVKVj9Da!\rk1@X&!(eq@#jAl!Dq9B`31MQ-"`"pRQ!Z9qR'[P8T%$Sj+3B!I6j),Rf-5hKpDf0\riI8TEH(qF8RJlHrrmJ9X!!&HVU[jAV+J8I@YMH(eI@RKAkBDq95N31MNT!3"p2NJ\rZ9qS'[P9+%$Sj5J-!I9j3,PIVaVj9Da!k1@X#!(eq@#jp5PYiI5P6H&IX4Vj9M"!\rkICjJ,RdTBhKrR%Ti1h[rr)%l!!"ALNhq9iY),(e+@hKp2e*i9qa'[P@-%$SjM!3\r!ICjJ,PITKVj9+4!k15N&!(dq5#jAkJDq98S31MP+"`"pAP!Z9q['[P9V%$SjD`B\r!IAjB,Re+@hKp+90iIBa,H(qpBRJlHrrmJCX!!&H*U[jALUJ8I5P6H(fI5RKAkiD\rq9@X31MPV!3"pIPJZ9q`'[P@-%$SjM!-!ICjJ,PITaVj9+4!k15N#!(dq5#jpM%Y\riI@YMH&IU4Vj95K!kI9j3,ReV8hKr[9Ti1cN!!5`C!!K"J2jJ2@$`m6PVm2"rUeJ\ri2B$`m6Q-m2"rM'!i9BcK2RerBhJp)!m215N2$hqT5$K9+5!f28!2$cP+$`prLP!\riI6e6H&HV"Mj9Da!kIAGB,PHXaMj9M"!kICGJ,P@-%$TAU8Bq95N31Rdh5#j9+6!\rb9kU'2P9+%$Tp9e!Z98SJ0RdT8hKpM%YiIAaMH&IV"Mj9Da!kIAGB,PIXaMj9M"!\rkICGJ,P@-%$TAk8Bq95N31Rdh5#j9+6!b9qU'2P9+%$Tp9e!Z98SJ0RdT8hKpM%Y\riIAeMH(qFNRKr[BTi,!8!#%#"!(JiTIri9iY'2TPe!!!kY3!"9ib'2TQ9!!!kY3!\r"9iR'2TNe!!!kY3!"9iS'2TP9!!!kY3!"9kY'2TPe!!!kY3!"9kb'2TQ9!!!kY3!\r"9kR'2TNe!!!kY3!"9kS'2TP9!!!kY3!"IK,LH)&Krl"pFHTi5rrlQ(ke+K3S"3!\r)3B%!H$Q#!LK8U4!kIBa),Rf*!kC1J!3J9kS'2MUerrqC93!!9k['2MUerrqCG3!\r!9kb'2MUerrqCP3!!9kP'2MUerrqC03!!9iS'2MUerrqC93!!9i['2MUerrqCG3!\r!9ib'2MUerrqCP3!!9iP'2MUerrqC03!!1'!!!,S"rm"1J!!J!*!')%!!%!#3"!Z\r)!"%ZC'9cAh"MBQ0IC@jMFRP`G!#q)Ir%1U)(-$V#!c!k)J-31N)#d$TL!T!!1S)\r#F(ah'hL)Y`!!1[F!!95P"Mj8[F!1L0F!!$Vh!!&8aJBq9-D!(Rqp-hL)p`!!1[F\r!!96R"Mj8jd!ZIldlH)NA!!!kp`!"93J'2Rqp3hKAUGpq95N31Rdd5#j9+4Ji9kU\rIIP9+%$Tp9&!Z98S31PHV(hj9Da!kIA4B,PHXAhj9M"!kIC4J,P@-#$apDf0iI8T\rEH(dr8hKATImq9+831Rbc+#j8T4Ji9kDr2P6'%$Tmdc!Z9-B31PHR2cj8ja!kI2-\ri,PHSIcj9#"!kI40!,P8)#$amjd0iI-BlH(bq-hL*0`!!1[F!!98T"Mj92F!1L9F\r!!$Vh!!&95JBq98U!(Rqp8hL*G`!!1[F!!99V"Mj9Dd!ZIleEH)QA!!!kp`!"9B`\r'2RqpBhKATHFq9+831Rbb+#j8T4Ji9kDR2P6'%$TmdM!Z9-B31PHR*cj8ja!kI2)\ri,PHSCcj9#"!kI4*!,P8)#$amjd0iI-BlH(bP-hKrrbYi9kRrIP8T%$Tp-8JZ95N\rB1&HU[hj95K!kI9&3,P9+%$TAUcpq9@X31Rea@#jAV(pq9B`31Rf4B#j9M!JmI@Y\rMH(e+@hKp+90iIpj,H(bD)hJl)(lm1`!!%%J!!5aA*3Iq,!8!!%'#!#"AjK%k9qF\rf[RcI1hKAb"%k9mNf[RdH5hK)!!!F9qS*2&IV,[jpAeYi9m`*2&I&,[jpRLYiIcN\r1F&IQ"hjAjqDiI-BlH&6'%$SiaJ-!I0B`,PISjljAkEkkI3K,H&8)%$Sj#!)!I4C\r!,PIUMcjAkiDfI8TEH&9+%$Sj5J%!I9C3,PIX9Vj9M"!kICCJ,Re+BhKp#&0iI0a\r$H&I&"ljAa[kkI+8cH&5P%$SiT3-!I,8S,PI(cVj8ja!k11F#!(ce1#jAb*Fq9mQ\r1YRd)5hK9#"!k13J"!(d93#jAbPDq98S31Re98#jp#&0iI1G$H(bl1hKAL`)Z9f`\r'$ReVBhL4HJ!!1eS!"&H&"JjACJ)ZI+8cH*!!ZJ!!1eS!"$XBrrmX'!!!3B(qe$K\rJ!!#k)Ir%6S!!)!#3"L"!!!m!N!3$*!!2,QeKDf9IDf9jAh0MD'9N!!!!I!J#TT2\rKrrb3!!%!#*3Krm"mIaYiN!#"!&arirYiJ)%!A%[rr*PJ!!!!Iq2lH%[rlqPJ!!!\r!,!-!!%##!!`iB2rr5!!!*(rMqhK)!!Z&B!!!!#`$!!""JJ!-1'$rrNJ!!!JiB!!\r!J!%!5$JK!%"m#!1QJq(rr%k!!#!!N!BJ3B!"!*!&H!!1,Q4PFepVCAPIFf0SC@4\rm#!+QNq(rr*!!!3!)P#(r`(ar'hKrirYi5!!#+@!!!!"rirYi5rrZJ@!!!!"rirY\ri5!!,"@!!!!!X!`!!3),rf$KJ!!#!!3")1#%!3(`)!kD$iIrm6S!!)!#3"L""J!%\r!N!9B!"-ZC'9cAfjPGepbB@jNEfeIDf9j!!!!I!J#TT!!!3!)P#(rX*!!B3"S5!!\rbIB""!"53!'%!5%J!-R'!33!8N!"K!%b!B3"S5!!!T@!!!!!iB3")5!!"+@!!!!!\riB3!i5rrr26KK!$K)!!#&B!!!!$KK!%")!$*0J%%!&$KK!%4)!$*"J%%!&)"L!#"\r)!!$aB!!!!$KK!$K,rrm&1'%!1%J!!%eJ!!!!J!%!@$JK!&"m#!1Q6S!!)!#3"L"\r"J!#3"T`!)5jNCA0ID@jTG&pbB@jNEfeIER9YBQ9bAfGPEQ9bBA4[FJ"m#!+QNq(\rrr*2"rrL3!!%!#*3Krm#3!'%!@$[#,EL!B3"B1))Y1%[rrI9J!!!!1q!!!%J!!"!\riB!!!I(ljVM[r!!%X(`!)3B$rm)!"!%Ji)3"!I!J$TS2Krrb$`Iri6S!!)!#3"L"\r"J!)!N!9J!"iZC'9cAh0PG&pbB@jNEfeICf9ZCA*KG'pbAh0PC@4m#!+QN!!"!!L\r8)Ir!N!"K!&JiBLfiJ)%!@$LJ!!K)!$$jJ%%!&)!"!%Ji)3"!I!J$TNk!!#!!N!B\rJ3B!!N!Bd!"JZC'9cAh0PG&pcCA&eC@jMC9pZG@eLCA)!!(`)!UD6iIrmNm(rq*!\r!!3!)P#(r`*!!B3"B1m)YZ(r$mhL!J3"B1+)Y1$M!!!&,rqAeB!!!!$[J!!")!!!\rNI(liVMKM!!&8B`BqI(ljVRbHq+iS"!!!3))!%$[r!!%X(`!)3B$rh)!"!%Ji)3"\r!I!J$TS2Krrb$`Iri6S!!)!#3"L""J!)!N!9m!"SZC'9cAfGPEQ9bBA4PAh*KEQ4\r[E9pLE'pMDh`)!UDqJIr3N!!"!!L8)Iq3!(ae'hKmQ#0iI,BVH(cA-hKmp$YiIS1\rMH%J!!@&mI"Yi1(3!"%J!!99mHKYi+"J!!%##!!Jki!!"1b!!!8J!!,"qhV0iIVZ\rVH%J!!)!X(J!"3)%!)(pMfhK)!!$K9'-%2Rrm'K3lH`!#1plrrNJ!!"L)H`!!1hX\r!!94M"Mjrr"S81m!!!(pGdhKmRrR@I,hTeRb%+K3m`)!!1-Errhq%-jCrR$(@Ij`\rJ8$cp"2`ijh-YI2mjeMd!J!!j#2rrIdG$PRpD3GCr@MK3,"i!!%##ri!S'!!!3B)\r!&*1B!!!l'!!%NeJ!!$XB!!3l13!","N!"%'"!!am'EJ!3)(r5(q$ihL!!3"i1#%\r!F(`)!kDkJIr36S!!)!#3"L""J!`!N!3"*!!2,Q4PFepaG@&NAf0VFh9Y!!!!L)-\r!!CL"rr#)S`!!Q+(rmD"Krr"1J!!J!*!')%!!N!FB!"BZG(G[Af*jG'9cAhCKH&p\rdEepZCA4cL)-!!jL"rr#)S`!#Q+(rmBM$!!'B`IrbL1-!!*MKrr1!BIr`6S!!)!#\r3"L"!!*!(+!!A,QC[GA*IBRPdCA0IGQ&iAh4[AfjPG(-!!!"m#!+Q[`(ri*!!!3!\r)P#(rS(aj'hKr2-YiIcV,H$KK!$K)!#j"J%%!&%J!,L'!33!8J)%!1(b%'RL!SJ#\rSJ-8!!(c(-hJiaJ!"N!$&!!"mjb*iI2JlH(m$`hK)!#iKJ%%!&%J!,M'!33!8N!"\rK!$ar3p0i1)%!2$LJ!!4)!#fjJ%%!&$YD!!4)!#i0J%%!&*!!B3!mId26H$L"!$`\riS!!%5!!YPB""!"3lB!!!5!!!@$[!!!#,r!!!1k!!!%J!!"4ArrKq9qJ(rRrH3RJ\rl[3!","d!"N#"rq`X(J!!3))!&)Nm!!"K+3!"Q6`!!%J!!"#*A!!!98S'2*PF!!!\rlR!!"1hX!!5`E!!G!JIqS1'!!!)!"!'Ji)3"JI!J$TVX"rq"1J!!J!*!')%'!#!#\r3"!%J!!mZC'9cAh*KEQ4[E9pVCAN!!!"m#!+QNq(rr*!!!3!)P#([`*!!B4"BN!#\r"%&b3!+%3B$KK!$JiJ"!!J+%3A)$"%'")!!"eB!!!!(ar'hJX(`!!3))!&$KK!$L\r!J4"B5!!#9@!!!!!iB3!i1)!!!$LJ%!")!#fCJ%%!&(rMqhL!!4")1#%33(`)!kD\r$iIrm6S!!)!#3"L""J!%!N!9m!")ZC'9cAh*PB@4IF'&cFhG[FQ4m#!+Q[Z(rh*!\r!!3!)P#([S(ap'hKmQL0iI,XVH(cC-hJkiKY21`)E-)2L!&!lJ!!!,"S3!%#"!5!\riB2rr5!!"K(pMfhK)!#b"J%%!&$Kr!%K)!#b0J%%!&(qMkhKr400iIqAlH%J!,*'\r!33!8+!-!!%##!"4rirYi5!!XPB""!"4)!!$8Ik2VH$L!!!T)!#bCJ%%!&(aq'hJ\rS(J!!3B)!$$KJ!!#BIJ!!,"N!!%'#!+4r!m0iIf6EH%J!,!f!33!81(m!5%J!,"Q\r!33!81'%!1$L!%!"rjIYi5!!X(B""!"3S!`!!3))!&(rMqhK)!#`KJ%%!&%J!!'!\riB3!i1)!!#NJ!,#@!33!8I(iEH#JH!!""JJ!-1)!!!*LH!!"rSqYi1)%!1%J!,"Q\r!33!8,!-!!%'#!#"qilYi5!!VMB""!"3iI`")5!!VQB""!"4)!!!)1i!!!5`F!!"\r"J[lS,"`!!%##!"KrSqYi1)!!!(p&dhK)!#[PJ%%!&$KL!0a)!#Y*J%%!&#`C!!"\r"JJ!B1'%!1$L!!!!iS"!!5!!V[B""!"3iS!!!I0VU&*LQrrmii!!!,"`!!%##!!J\rii!!"I1-lH)!"%'Ji)4"JI!J$TVVKrpa1J!!J!*!')%'!#3#3"!(8!"-ZC'9cAh*\rPB@4IF(GIFh4bD@jR!!!!I!J#TVl"rpL3!!%!#*3KrZ"mH4YiI*FMH(mfbhJlJ!!\r"1k%!Z(mMbhK)!#Y*J%%!&(ak'hJiB3#i1)!!!$LJ!%")!#XCJ%%!&$YJ!!&)!!#\r%L(N!!$Xj!!&mI`Gd1m!!!%J!!%3X(!!!3B)!)&IN"rjrTHYi1ld!!BM&!!"maL*\riQ-8!!%J!!"KAj`Iq1lhrriNG!!"p#$TiQ4d!!&Irq(ilhJ!","i!"N#"rlaAD3G\rq+!N!!%##!"Jj3!!!,"`!!%##!!Jj3!!"I9a6H$Yl!!&m'p"!3)(rI$ZK!,Kqq,Y\ri1f!!!%J!!%!li!!!1m!!!%J!!##*I3!!1ld!!AeV"h3jRJ!"I@YJ-(rr@hJlhJ!\r","i!"N#"rq#Eq!!!1aJ!!6Yl!!%S'`!(3)(r`(lMZhK,rq64B!!!!(lMZhJiJ3!\ri5rreK@!!!!"q`l0iIZ5lH(p&dhJi`3!iIZHlH%[rf&&J!!!!1'%!1$L!!!!iS!#\r!5!!TkB""!"4qilYi5rrNK@!!!!!iB!!!J!%"+$JK!5"m#!1QZX(rf%k!!#!!N!B\rJ3B!+!*!%!C`!%LjNCA0IFh4bD@jRAh4[AfYPHA`)!UD6iIrmNm(rq*1Krr53!!%\r!#*3Krl#3!'%!D(bI)hL$S3"S1m!!!(rMqhJiJKYS5!!TQB""!"4)!!!iIq2lH$L\r#!0k)h3!!1ld!!96&"Mj)!#PjJ%%!&#`H!!K!J!!8Iq2lH$L#!1&)!#PKJ%%!&#`\rH!!JlhJ!"3B$ra(rMqhJiJJ$N5!!T4B""!"5!!3"B1#%!8(`)!kD$iIrmJm(rq)1\rKrr41J!!J!*!')%'!!`#3"DJ!&LjNCA0IBf*XEf0VAh"bD@jdAfCTE'9m#!+QNq(\rrr*2"rrL6SIrdN!!"!!L8)Iq`I(dEH$[#'fmli!!!5!!!-(r$mhJlhJ!)Ik6VH$L\rJ!!K)!#GaJ%%!&#`$!!"!JJ!-1'!!!8J!!"3lr`!"+"m!%%'!rp!iB!!!J!%!@$J\rK!&"m#!1QJq(rr)2"rrL$SIrd6S!!)!#3"L""J!-!N!9m!"!ZC'9cAfPcAhGPB@Y\rIDf9j!!#p`Iqi1Z)2-$[#%c!l!JX`I0XcH(ck1hKp'80i,!S!!%'#$04p-%YiLA!\r!!$S3!!&9D`Bq9Ac!$SQ3!!!!1K!!!9@-"Mj9M)!HIjaMH)P`!!!k%!!"9@X'2P9\rV3#jrR&YiLC!!!!!k%!!"9B`'2RqFBhL*F!!!1K!!!99V"Mj9IF!1LC!!!!!k%!!\r"9B`'2P@-J"jr[@0iLA!!!$S3!!&9D`Bq9@Y!,Rqp@hL*N!!!!$S3!!&9M!BqIle\rMH(a`'hL3!)(rX%J!$#JX"3!)3B!!a)P`!!!k%!!"9@X'2P9V"Mj9Dm!1IjaDH)Q\r3!!!!1K!!!9@-"Mj9M!Bq9Bb!(RqFBRL*F!!!1K!!!99V"Mj9D`Bq9@Y!,RqF@RL\r*N!!!!$S3!!&9M!Bq9B`'2RqFBRL*F!!!1K!!!99V"Mj9D`Bq9@[!$Rqp@RL*N!!\r!!$S3!!&9M!Bq9B`'2P@-J"jr[@*iLA!!!$S3!!&9D`Bq9@X'2P9V3#jr[9TiLC!\r!!!!k%!!"9B`'2P@-"Mjr[@*i1+Arq%J!!,"q%#S8+!8!"d'"!+!jBK`89+`31Re\rVB#jpD31Q6S!%)$S3rrq*F!!!9@X'2P9V3#jr[9Ti1K$rriQ3!!!!9B`'2P@-J"j\rr[@*i1K$rriP`!!"9D`Bq9@[!$Rqp@RJk%2rrLC!!!!"9M!BqIjaLH$S3rrq*F!!\r!9@X'2P9V3#jrR&Ti1K$rriQ3!!!!9B`'2P@-J"jrR'*i1K$rriP`!!"9D`Bq9@[\r!$RqF@RJiS!!!2B#UUcQ-UUTrM'!i2@#UUcPVUUTrUeJi9@[iIRfI@hJpJ&991Ba\r99Aq-B$K9M!Jm2@"996PV999rUeJiICeEH&HX"Mj9M"!kICKJ,P@-'$KAUmBq9@X\r31Rei@#j9Da!k9kp'2PA[%$Tpq(JZ9kk'2PA1%$Tpf(!Z9Fi)2(h[FhKpDhYiICa\rEH&IX"Mj9M"!kICKJ,P@-'$KAlXBq9Fi31RhBF#j9cK!k9qp'2PA[%$Tpq(JZ9qZ\r'2P9V%$TpH&JZ9@X)2(h[@hKpcRYiICecH$V!!!")!!'JJCX!!$Yl!!4AVUVq9kq\rS&(h1HhKpRh*i9qX'[P9V%$SjD`-!IAjB,PIXaVj9M"!k1B`#!(fHB#jAlSDq9Fi\r31MR1!3"phR!Z9qp'[PA[%$TprRJZIFjlH(f-FhKpDf0iIjaDH)&l!!!lH`!%9ka\r0rPHZ5#apM(0iIApLH&I["Vj9la!k1Hm(!(hqH#jAkmDq9@X31MPV"J"pIPJZ9qa\r'[P@-%$SjM!3!ICjJ,PIZKVj9cK!k1Fi&!(hHF#jpM(0iI@YMH(h[@hKrR(TiJIX\r!!$Yl!!4ALkVq9ibS&(eVBhKpreTi9qi'[PA1%$SjcJ-!IGj`,PI[aVj9la!k1Hm\r#!(hqH#jAkiDq9@X31MPV!3"pIPJZ9qa'[P@-%$TpRQ!ZI@YMH(h[@hKpcRYiIle\rbH)(E!!!lH`!%9ip0rPH,5#apleYiIGpkH&IX"Vj9M"!k1B`(!(fHB#jAlXDq9Fi\r31MR1"J"phR!Z9qp'[PA[%$Sjl`3!IIji,PIVKVj9Da!k1@X&!(eq@#jpleYiIFj\rlH(f-FhKr[@*i1YB!!5`@!!K"J2jJ2B$`m6Q-m2"rV'!i2F$`m6R1m2"rMR!i9Fl\rK2RfIFhJpi!m21Hm2$hq[H$K9lb!f2@!2$cPV$`prLeJiIIeEH&HX"Mj9M"!kICG\rJ,PHZaMj9cK!kIGG`,PA1%$TAVdBq9Hm31RhhH#j9lc!b9kZ'2P9V%$TpGeJZ9@X\rJ0Rh[@hKpcRYiICacH&IX"Mj9M"!kICGJ,PIZaMj9cK!kIGG`,PA1%$TAldBq9Hm\r31RhhH#j9lc!b9qZ'2P9V%$TpGeJZ9@XJ0Rh[@hKpcRYiICecH$Ylri!pJ+UV1Bb\rUURq-B$Jp`+UV1FkUURqZF$K9c[KqICpcH$hJ998jle99Iipi1&A[#$`pB&991@Y\r99AqV@$Kpr9Yi9k`'2P@-%$TpQ'!Z9B`B1&HZaMj9cK!kIGK`,PA1%$TAVdBq9Hm\r31RhiH#jAUiBq9@X31Rei@#j9D`JmIHpEH(h1HhKpR(0i9q`'2P@-%$TpQ'!Z9B`\rB1&IZaMj9cK!kIGK`,PA1%$TAldBq9Hm31RhiH#jAkiBq9@X31Rei@#j9D`JmIHp\rEH(h1HhKpRA0i1eS!J$UJ!!")!!'J1eVrr)'D!!"AVNhq9kp),(h1HhKpRh*i9qY\r'[P9V%$SjD`3!IAjB,PIXKVj9M"!k1B`&!(fHB#jAlJDq9Fi31MR1"`"phR!Z9qr\r'[PA[%$Sjl`B!IIji,Rh1HhKpM(0iI@YMH(qF@RJl@[rmJAS!!&HXU[jAVUJ8IBa\rcH(erBRKAliDq9Hm31MR[!3"prRJZ9qX'[P9V%$SjD`-!IAjB,PIXaVj9M"!k1B`\r#!(fHB#jpDf0iIHpEH&IZ4Vj9cK!kIGj`,Rh[FhKrR(Ti1eVrr)(k!!"ALdhq9ia\r),(eVBhKpreTi9qj'[PA1%$SjcJ3!IGj`,PI[KVj9la!k1Hm&!(hqH#jAk`Dq9@X\r31MPV"`"pIPJZ9qc'[P@-%$SjM!B!ICjJ,ReVBhKpleYiIFjlH(qpFRJl@[rmJGS\r!!&H2U[jALkJ8IHpEH(hIHRKAl)Dq9B`31MQ-!3"pRQ!Z9qi'[PA1%$SjcJ-!IGj\r`,PI[aVj9la!k1Hm#!(hqH#jpcRYiIBacH&IV4Vj9Da!kIAjB,Rf-@hKr[@*i1V8\r!!5`9!!K"J2jJ2B$`m6Q-m2"rV'!i2F$`m6R1m2"rMR!i9FlK2RfIFhJpi!m21Hm\r2$hq[H$K9lb!f2@!2$cPV$`prLeJiIIeEH&HX"Mj9M"!kICGJ,PHZaMj9cK!kIGG\r`,PA1%$TAVdBq9Hm31RhhH#j9lc!b9kZ'2P9V%$TpGeJZ9@XJ0Rh[@hKpcRYiICa\rcH&IX"Mj9M"!kICGJ,PIZaMj9cK!kIGG`,PA1%$TAldBq9Hm31RhhH#j9lc!b9qZ\r'2P9V%$TpGeJZ9@XJ0Rh[@hKpcRYiICecH$f!UUXjM+UUIiaJ1$h!UUXjcUUUIkj\r`1&A1q(jpRh0i2H"996R[999rMhJi9Hm)2$eJ998jDe99IkYB1(hp@hKAV!Bq9B`\r31RfBB#j9M"Ji9kl'2PA1%$Tpf(!Z9Fi31PH[4Mj9la!kIIKi,PHVKMj9Da!kIAK\rB,P9V#$apleYiIFjlH(fFFhKAl!Bq9B`31RfBB#j9M"Ji9ql'2PA1%$Tpf(!Z9Fi\r31PI[4Mj9la!kIIKi,PIVKMj9Da!kIAKB,P9V#$apleYiIFjlH(fGFhJkJ!!!5!!\r"S)'C!!!l13!%9kkUrPH[U"4pcRYiICpbH&IV"Vj9Da!k1@X$!(eq@#jAl-Dq9B`\r31MQ-!J"pRQ!Z9qk'[PA1%$SjcJ%!IGj`,PI[4Vj9la!kIIji,Rh1HhKpM(0iI@Y\rMH(qF@RL"H3!!1cN!"&HX6IjAVNJXIBacH(erBRKAl`Dq9Hm31MR["`"prRJZ9q[\r'[P9V%$SjD`B!IAjB,PIX4Vj9M"!k1B`%!(fHB#jAlSDq9Fi31MR1"3"phR!ZIBa\rcH(eVBhKpleYiIjakH)(j!!!l13!%9iZUrPH-U"4pDf0iIIpDH&IZ"Vj9cK!k1Fi\r$!(hHF#jAlmDq9Hm31MR[!J"prRJZ9qZ'[P9V%$SjD`%!IAjB,PIX4Vj9M"!kICj\rJ,ReVBhKpleYiIFjlH(qpFRL"f3!!1cN!"&H26IjALdJXIHpEH(hIHRKAl!Dq9B`\r31MQ-"`"pRQ!Z9ql'[PA1%$SjcJB!IGj`,PI[4Vj9la!k1Hm%!(hqH#jAkiDq9@X\r31MPV"3"pIPJZIHpEH(h1HhKpM(0iIleLH$U8!!%X&!!)3B$qB$f!m2%jM2$`Ika\rJ1$h!m2%jc[$`Iij`1&A1i6jpRh0i2H!2$cR[$`prVhJi9HmJ0MeJ$`mjD`m2IiY\rB1(hp@hKAV!Bq9B`31RfAB#jAVXBq9Fi31RhAF#j9cK!k9kp'2PA[%$TpphJZ9Hm\r`-PHVKMj9Da!kIAGB,P9V)$CpleYiIFjlH(fFFhKAl!Bq9B`31RfAB#jAlXBq9Fi\r31RhAF#j9cK!k9qp'2PA[%$TpphJZ9Hm`-PIVKMj9Da!kIAGB,P9V)$CpleYiIFj\rlH(fGFhJl1Iq!9ia'2S("rl"pch0i1Fi!!C("rl#CM`!!9iZ'2S'"rl"pMQ0i1B`\r!!C'"rl#CEJ!!9ir'2S&Krl"pE&Yi1@X!!C&Krl#Cl!!!9ii'2S(Krl"pkhYi1Hm\r!!C(Krl#Cb`!!9ka'2S("rl"pch0i1Fi!!C("rl#CM`!!9kZ'2S'"rl"pMQ0i1B`\r!!C'"rl#CEJ!!9kr'2S&Krl"pE&Yi1@X!!C&Krl#Cl!!!9ki'2S(Krl"pkhYi1Hm\r!!C(Krl#Cb`!!,!8!!%'"mpK)!!dJ,!8!!%#"$4Kp-%YiLC!!!!!k%!!"9B`'2P@\r-`!k4JIqXLG!!!$S3!!&9cJBq9Fk!(S(Krkaplh0iNH(rV)P`!!!k%!!"9@X'2P9\rV3#k"JIqXIBaEH*'"rkb*d!!!1K!!!9A1"Mk"iIqXIHpcH*(Krkb*F!!!1K!!!99\rV"Mj9Dm!1N@(rU)Q3!!!!1K!!!9@-"Mj9M)!HJF(rU(h1BhL4`IqSLI!!!$S3!!&\r9l`Bq9Hp!,S&KrkKpDhYiN@(rU)Q3!!!!1K!!!9@-"Mk"`IqSIFjMH*("rkKmF"Y\riN!#"rl#*m!!!1K!!!9A["Mj9r-!1LA!!!$S3!!&9D`Bq9@Z!(RqF@hL*N!!!!$S\r3!!&9M!Bq9Ba!,RqFBhL*d!!!1K!!!9A1"MjrR(0iLI!!!$S3!!&9l`Bq9Ih!$SP\r`!!!k%!!"9@X'2P9VJ"jr[9YiLC!!!!!k%!!"9B`'2P@-3#jr[@0iLG!!!$S3!!&\r9cJBqIlecH*1"rk56SIqJ2H#UUcR[UUTrMhJi2@#UUcPVUUTrUeJi9@[iIRhr@hJ\rpJ&991Ba99Aq-B$K9M!Jm2F"996R1999rVR!iICecH&H["Mj9la!kIIKi,PA['$K\rAUmBq9@X31Rei@#j9Da!k9ka'2P@-%$TpQ'!Z9kk'2PA1%$Tpf(!Z9Fi)2(f-FhK\rpDf0iIIaEH&I["Mj9la!kIIKi,PA['$KAkmBq9@X31Rei@#j9Da!k9qa'2P@-%$T\rpQ'!Z9qk'2PA1%$Tpf(!Z9Fi)2(f-FhKpDf0iIIeEH$Xj!)!kB!!!5!!"S$Xjrrb\r"q3!!9kY0rPHX5#apDf0iIIpDH&IZ4Vj9cK!k1Fi%!(hHF#jAliDq9Hm31MR["3"\rprRJZ9qX'[P9V%$SjD`F!IAjB,PIXaVj9M"!k1B`'!(fHB#jpDf0iIHpEH(h1HhK\rrR(*i1cRrr)(C!!"AVkVq9kZS&(h[@hKphhTi9qb'[P@-%$SjM!%!ICjJ,PIZ"Vj\r9cK!k1Fi$!(hHF#jAlmDq9Hm31MR[!J"prRJZIFjlH(f-FhKAkdDq9@X31Req@#j\rpM&YiIjaLH$Xjrrb"Q3!!9ij0rPH25#apcRYiICpbH&IV4Vj9Da!k1@X%!(eq@#j\rAl)Dq9B`31MQ-"3"pRQ!Z9qi'[PA1%$SjcJF!IGj`,PI[aVj9la!k1Hm'!(hqH#j\rpcRYiIBacH(eVBhKr[9Ti1cRrr)&j!!"AM+Vq9ikS&(f-FhKpIf*i9qq'[PA[%$S\rjl`%!IIji,PIV"Vj9Da!k1@X$!(eq@#jAl-Dq9B`31MQ-!J"pRQ!ZI@YMH(h[@hK\rAlNDq9Fi31RhHF#jplh0iIlekH$Tc!!%X%`!)3B$qB$hJm2%jlr$`Ikpi1$eJm2%\rjDr$`IiYB1&9Vi6jpreYi2B!2$cQ-$`prV'!i9B`J0Mh!$`mjcJm2Iij`1(fGFhK\rAV`Bq9Hm31RhhH#jAUmBq9@X31Reh@#j9Da!k9ka'2P@-%$TpPf!Z9B``-PHZKMj\r9cK!kIGG`,PA1)$CpM(0iI@YMH(hm@hKAl`Bq9Hm31RhhH#jAkmBq9@X31Reh@#j\r9Da!k9qa'2P@-%$TpPf!Z9B``-PIZKMj9cK!kIGG`,PA1)$CpM(0iI@YMH(hp@hJ\rpi+UV1HqUURq2H$JpB+UV1@ZUURqV@$K9DrKqIIpEH$f!998jM&99IiaJ1&@-#$`\rp`&991Fj99AqZF$KpRA0i9km'2PA[%$Tpq(JZ9HmB1&HVaMj9Da!kIAKB,P9V%$T\rAV%Bq9B`31RfBB#jAVSBq9Fi31RhBF#j9cJJmIBacH(eVBhKpr&Yi9qm'2PA[%$T\rpq(JZ9HmB1&IVaMj9Da!kIAKB,P9V%$TAl%Bq9B`31RfBB#jAlSBq9Fi31RhBF#j\r9cJJmIBacH(eVBhKpr9Yi1N!!!%J!!D#"qJ!!1eS!"&HVU[jAV+J8I@YMH(hr@RK\rAlJDq9Fi31MR1!`"phR!Z9qr'[PA[%$Sjl`)!IIji,PIVKVj9Da!k1@X"!(eq@#j\rAl%Dq9B`31RfHB#jpDf0iIHpEH(h1HhKrR(*iJGS!!$YD!!4AVdhq9kY),(h[@hK\rphhTi9q`'[P@-%$SjM!F!ICjJ,PIZaVj9cK!k1Fi'!(hHF#jAldDq9Hm31MR["!"\rprRJZ9qZ'[P9V%$SjD`8!IAjB,Rh[@hKpcRYiIBacH(qFBRL"QJ!!1eS!"&H1U[j\rAMkJ8IFjlH(fIFRKAk`Dq9@X31MPV!`"pIPJZ9qc'[P@-%$SjM!)!ICjJ,PIZKVj\r9cK!k1Fi"!(hHF#jAldDq9Hm31RhqH#jpcRYiIBacH(eVBhKr[9TiJAS!!$YD!!4\rAM%hq9ij),(f-FhKpIf*i9qm'[PA[%$Sjl`F!IIji,PIVaVj9Da!k1@X'!(eq@#j\rAl%Dq9B`31MQ-"!"pRQ!Z9qk'[PA1%$SjcJ8!IGj`,Rf-FhKpDf0iIHpEH(qpHRJ\rk8J!",")!#%'!rQ!pi2$a1Hr`m(q[H$JpB2$a1@[`m(q,@$K9Dq%qIIpEH$f!$`m\rjM!m2IkaJ1&@-)$Bp`!m21Fi2$hq1F$KpRA0i9km'2PA[%$TpphJZ9k['2P9V%$T\rpGeJZ9@X31PHX4Mj9M"!kICGJ,P@--$*AVSBq9Fi31RhAF#j9cL!fIBacH(eVBhK\rpr&Yi9qm'2PA[%$TpphJZ9q['2P9V%$TpGeJZ9@X31PIX4Mj9M"!kICGJ,P@--$*\rAlSBq9Fi31RhAF#j9cL!fIBacH(eVBhKpr9Yi1eVrJ$hJUUXjlkUUIipi1$eJUUX\rjDkUUIkYB1&9Vq(jpreYi2B"996Q-999rM'!i9B`)2$h!998jcP99Ikj`1(fGFhK\rAV`Bq9Hm31RhiH#j9laJi9k['2P9V%$TpH&JZ9@X31PHX4Mj9M"!kICKJ,PHZKMj\r9cK!kIGK`,PA1#$apM(0iI@YMH(hm@hKAl`Bq9Hm31RhiH#j9laJi9q['2P9V%$T\rpH&JZ9@X31PIX4Mj9M"!kICKJ,PIZKMj9cK!kIGK`,PA1#$apM(0iI@YMH(hp@hJ\rlH`#!1L!!!%J!!D!lHrrmJIX!!&HV6IjAV%JXI@YMH(hr@RKAlNDq9Fi31MR1"!"\rphR!Z9qq'[PA[%$Sjl`8!IIji,PIV"Vj9Da!k1@X(!(eq@#jAl-Dq9B`31MQ-"J"\rpRQ!ZI@YMH(h[@hKpcRYiIjabH$Ylrrb"f`!!9kqUrPHVU"4pleYiIGpkH&IXKVj\r9M"!k1B`"!(fHB#jAlJDq9Fi31MR1!`"phR!Z9qr'[PA[%$Sjl`)!IIji,Rh1HhK\rpM(0i9qY'[P9V%$TpIPJZIBaEH(qFBRJlHrrmJCX!!&H16IjAMdJXIFjlH(fIFRK\rAkdDq9@X31MPV"!"pIPJZ9qb'[P@-%$SjM!8!ICjJ,PIZ"Vj9cK!k1Fi(!(hHF#j\rAlmDq9Hm31MR["J"prRJZIFjlH(f-FhKpDf0iIleDH$Ylrrb"H`!!9ibUrPH1U"4\rpM(0iIApLH&I[KVj9la!k1Hm"!(hqH#jAk`Dq9@X31MPV!`"pIPJZ9qc'[P@-%$S\rjM!)!ICjJ,ReVBhKpleYi9qj'[PA1%$TphR!ZIHpcH(qpHRJk-3!","%!#%'!rQ!\rpi2$a1Hr`m(q[H$JpB2$a1@[`m(q,@$K9Dq%qIIpEH$f!$`mjM!m2IkaJ1&@-)$B\rp`!m21Fi2$hq1F$KpRA0i9km'2PA[%$TpphJZ9k['2P9V%$TpGeJZ9@X31PHX4Mj\r9M"!kICGJ,P@--$*AVSBq9Fi31RhAF#j9cL!fIBacH(eVBhKpr&Yi9qm'2PA[%$T\rpphJZ9q['2P9V%$TpGeJZ9@X31PIX4Mj9M"!kICGJ,P@--$*AlSBq9Fi31RhAF#j\r9cL!fIBacH(eVBhKpr9YiJH(rV(qFHRL"BIqSIleDH#`&!!K!J3$F1+Arq&H-4Mk\r"`Iq`IFpcH$R1!!'4`Iq`QBm!!&H,KMk"JIq`IBjMH$Q-!!'4JIq`Q@i!!&H2aMk\r"BIq`I@aEH$PV!!'4BIq`QH`!!&H1"Mk"iIq`IHYlH$R[!!'4iIq`QFX!!&HX4Mk\r"`Iq`IFpcH$R1!!'4`Iq`QBm!!&HVKMk"JIq`IBjMH$Q-!!'4JIq`Q@i!!&H[aMk\r"BIq`I@aEH$PV!!'4BIq`QH`!!&HZ"Mk"iIq`IHYlH$R[!!'4iIq`QFX!!)'"rk5\r4JIqXJF(rS*("rkK,rr5-JH(rX(h[+K54iIq`+!8!#%'"!,JjBK[`9+`31ReVB#j\rpD31Q6S!%)&HZ"Mk"iIq`1Hrrrj(Krl#Cc`!!9k['2S'"rl!jM2rrNB(rX*PX!!"\rAVSBqJH(rX$R[rrq4iIq`QFm!!&HV4Mk"JIq`1Bcrrj'"rl#CE!!!9ii'2S(Krl!\rjlrrrNH(rX*R2!!"ALmBqJB(rX$Q-rrq4JIq`Q@`!!&H1KMk"iIq`1Hrrrj(Krl#\rCc`!!9iY'2S'"rl!jM2rrNB(rX*PX!!#j`Iqi6S!!)!#3"L"!!")!N!3D'!!4,Q4\rPFemcBf*MAf9ZBh*jF(3![X(rf$VL(63k`K`dI*NMH(ai'hL)Z!!!1aJ!!95r"Mk\r)f!!!1aJ!!96'"Mj8aN!ZIrmcH)Mi!!!l'!!"91F'2P6RJ"jrrcYiL4J!!$XB!!&\r9#!Bq93M!$Rrr3hL*1!!!1aJ!!98q"Mk*@!!!1aJ!!99+"Mj95N!ZIpj6H)Pi!!!\rl'!!"9@X'2P9VJ"jrhPYiLCJ!!$XB!!&9M!Bq9Bc!$RrHBhKAaH%qI+AkH$c!$`m\riaJm2I,``1(rriRKAKb!fIpikH&ISN!!DI3MkH(8Fc-aALA5qIqVLH(dr8RKAbj!\r!'ReVmRKeI-c-9iad[Rr&iRKpRLTi9mEiIRc'qRJmi&9911G99AcF1$Krrq*i9iJ\r)2(rH3RKAkF)qI5RbH$e!!2mj5J$rI6a31(rHiRKALd!ZIrpDH&I-q(jpM2Ti2+"\r996LP999pR#JiIrrLH&H'#$arhM*i9qF!"P6Ri6jAb!)H93L%2PI*"Mj9+B!H9mS\r%,RdT8hKp#%YiI2j$H&Ir!6ilB!!!5!!"@&GV%$TpGPJZ,!X!!%'#!#"Al2#q9qA\r3#RfI+hKAa[#q9mI3#RcH1hK)!!!F9qMiIPITf!Kp(dYi9mViIPI,f!KpAPYi9rm\r"2PIH!6jAl&Di9q9RrPIQAhamT60iIB`VH&@-%$SjM!-!ICGJ,PIRRcjAk*DfI1G\r$H&6R%$Sij`)!I2Fi,PITeljAkXkkI5P6H&8T%$Sj+3%!I6G),PIV"Vj9Da!kIAG\rB,RdT@hKmjdYiICSlH&I-AcjAa9DfIB`VH&@-%$SjM!F!ICGJ,PI'MVj8aK!k1-B\r'!(cA-#jAa`Dq91F31MMR"!"mpcJZ9mM2[PI*aVTp#%Yi93J31MN)"3"p&d!ZI1G\r$H(c'1hKpR$0i9iU!(PG,"$jpA9Yi9k`A[PHP%$TpM#S8NCN!!$Xj!!4A4S3q9iF\r!(RcG1hKAU$Dq9kN`-Rd)5K54'3!!1cN!"$Yl!!%X'`!33B$qU$KJ!!#k`IrB6S!\r!)!#3"L"!!!S!N!3#m!!-,Q4PFepcCA4IDf9j!!"m#!+QN!!"!!L8)Ir!N!"K!&L\r3!)%!A)"K!&L!J3"F1+)Y`%J!!$PJ!!!!1')Y`)!"!%Ji)3"!I!J$TNk!!#!!N!B\rJ3B!!N!Bm!!SZC'9cAf0bHA"dI!J#TVj"rmL3!!%!#*3Kr["mGKYiI*3MH(bk+hJ\rkiKcd1`%!1)Kd!!"mB`Gd,!-!!%##!!`iJ!""5!!!$)L8!!"mK!GdQ*S!!(b9"h3\riSKadI+@SVP5c%$U)e!!"I-B(G#`'!!"!JJ!-11!!38J!!!b)p!!"I1F(G*Mk!!&\rmp3Gd13)FG(d)U+j9%M!b1f!!!%J!!#b,eJ!!1YB!!9I*"MiS#3!!3B)!0&I+"Mj\r95JJm1@%!a(e,fDilH`!"+"X!#%'!rp4)!!!81B!!!$KK!-4pJpQZ1hX!!5JE!!K\r"J2rX1'%!a$L"!%4,rrZaB!!!!$KK!-`iJ3"%IQ@EH(j'NhK)!!%aB!!!!)-K!-a\rA*!BqQ*J!!$XB!!&A*FBqQ,J!!$XB!!&A*SBqQ0J!!$XB!!&A*dBqQ2J!!$XB!!'\r$)3$39bJ'2TNB!!!l'!!"9bR'2TNi!!!l'!!"9bU'2TPB!!!l'!!"9bY'2TPi!!!\rl'!!"1i!!!$[J!)!jJ!!!QB%!3$YJ!!*)!!"N1m!!!$ZJ!!")!!"!9pi)2$KK!$K\rmBq#Z9q3'2RaM)$JX!`!!3B)!#'2H!!&Arrjq9q8'2LJ&!!"!JJ!-1j`!!6[J!)!\rl[3!"+"d!"N'!rm"AaJBqI0F`VRcDfDilH`!"+"X!$8'!rj`ii!!!Q2S!$Ap$dhL\r!!3%B1#%"%(`)!kDk3Ir)6S!!)!#3"L""J!i!N!3#%!!,,Q4PFepQBh*jF(3!!!#\rq!Ir!1k)P0$Z!!!!lB!!!I*8MH*!!SIq`N!$"rk`ii!!!N!$Krl4)!!4-1X!!!%J\r!"#4AD)3qIhp#H)%Krl"rrNJiJ8(rV(rr8$KAfS!H9XX31Ree@#jrDeTiIpjDH(r\rHdRKAqS!H1CB!!9@-%$TpP@!ZIfaLH(rrBRKrrp*iIp4'F&ID"MT@P!Bk9qIK2PI\rSi!Crjd)89pk%2Rdpd#jrR%Ti193#!(eG8#jrR&*i9p2#2PID"MT@F`Bk1AS%!(e\rp@#jrR&Ti1C-'!(fGB#jrR'*iIr4'F&Ik"MT@P!Bk9rq%2MMk!3"mr6JZIj`kH$N\r8!`"p(8!ZIja#H(rc4R"AqJBk9R-'1MNk"3"p28JZIja+H$P6"`"pA9!ZIja5H&H\r,K$jrReTiJB(rX(rqB$L!iIqXIrmi1&ICJ"ij&J!#93J31Rd93#jrL%*iIpj#H(r\rHbRKAqB!H16B!!e8T%$Tp08JZIiP+H(rr5RKrrmTiIp*'F&IC"MT@8JBk9qVK2PI\rVi!CrkPS89pk%2RfGb#jrHf*i12)#!(cp1#jrHcTi9p(#2PIC"MT@-3Bk14N%!(d\rG3#jrHd*i16%'!(dp5#jrHdTiIr*'F&Ij"MT@8JBk9rq%2MPC!3"pA9!ZIhY5H$P\rb!`"pI9JZIhYDH(ra4R"Aq3Bk9M%'1MQC"3"pR@!ZIhYLH$Ma"`"mr6JZIhXkH&G\rSK$jrId*iJ5(rX(rq5$L"3IqXIrp31&IBJ"ijGJ!%9@X31Ree@#jrDeTiIpjDH(r\rH`RKAq)!H1CB!"9@-%$TpP@!ZIfaLH(rrBRKrrm*iIp"'F&IB"MT@%!Bk9qIK2PI\rSi!Crjd)89pk%2Rdp`#jrR%Ti19!#!(eG8#jrR&*i9m[#2T&KrkKAf!BkJB(rU&@\r-"MU4JIqS12J%!(cp1#jrR$TiJ3(rU$N)"J"p(8!ZIja#H(r`4R"Aq!Bk9K!'1PI\rrK$ij1!%!I6e),RqF5RJj8!-!I9e3,RqF8RKrkdC`N@(rU&Ii"MU"JIqS9B`'1T'\r"rkJiq!8!I2di,RqF1RL"!IqS13J(!(dG3#jrR%*i9iQ%2RqI5RL"3Iq`Irj31)&\rKrkarreJi9pH!(MQ@!!C9M"!kIC9J,Rq-BRKrhQ*iIpkkH&IhJ"iipJ!(91F31Rc\re1#jrKcTiIrmkH(rrZRKrb%C`N3(rT&IA"MU")IqN95N'1T%Krk4AkZ%q9q[J"Rr\rU@K4AhS3qICfi,RplBRL!iIqN11F#!(cp1#jrHcTi9mM#2T%"rk"Ae`BkJ5(rS&8\rT"MU4)IqJ19F%!(eG8#jrHe*iJ@(rS$PV"J"pI9JZIhYDH(rX4R#4JIqN9rF'1S$\rKrk48j`BkN!$Krk4Ari3q14F"!(dG3#jrHd*iJ5(rT$NT!`"p28JZIhY+H(rU4R#\r43IqJ9rF'1S&Krk"9D`BkN@(rS$QA"3"pR@!ZIhYLH)$Krk!ij`F!I2di,Rpl1RJ\rkeJ!),"B!)%'!qparRq0iIhcEH(rlqhL"!Iqd13J!!C%"rl5")Iqd,!N!'8'!ql"\rALZMq9i[S"(q+@K4AE1Mq9fIS"(pX1K4AL2KqI3MDH$dJ998j+999I4p)1(plqRK\rAkJJmIja5H&GV`MjpDq*i2B!!rcQ-!2ppIf!iIjckH&IR3#jrHcTi9iM`[Rd)fRJ\rp)$-c15Nc-hdI5$KrHrTi9qS31RqF8RKADi3qI@[LH&9r"$jrR2Ti9qb!(RplBRK\rAKq%qI1IDH$d!$`mj#!m2I2p!1(plqRKAk5!fIja+H*0M!!#6J`!%ZJ(r`%k!!#!\r!N!BJ3!!3!*!%"6`!$#jQBh*jF(4IBQpNH3!!I!J#TVp"rqL3!!%!#*3Krl"mHKY\riI*mMH(bl+hKmh$0iI2dlH(dH3hJX(J!!3B)!B(p$dhKrj2YiIfAEH(r'mhK,rlF\rGB!!!!(rMqhKrj2YiIiAMH$MJ!!!X(J!!3))!#$MJ!!&mjMYi5rqfp@!!!!"rirY\riIq6lH(qPkhKra[0i5rqfh@!!!!")!!"FId26H(rNqhKrTHYiImEcH%[rYX&J!!!\r!Iq2lH(rNqhKrKH0i13!!!#`H!!"!JJ!)13!!!Ad'3hK,rlDCB!!!!(rMqhKrj2Y\riIfAEH(r'mhK,rlD"B!!!!)!"!&Ji)3"3I!J$TVY"rqK1J!!J!*!')%'!"J#3"IJ\r!%5jNCA0I-f9MBPpPEQ0bHA"d!(a$%hK1J!!JI!J#TT!!!3!)P#(r`%[rrqemD4Y\riJ')!F)##!'`iSJ!!1-)YcS$L!'#"!J"F5!!!@B""!"5!JJ$8N!"N!!",rk0CB!!\r!!$KJ!!#!!3")1#%!3(`)!kC1J!!JI!J#TT!!!3!)P#(r`)"L!05!B`!!5!!!-B"\r"!"5!!3")1#%!3(`)!kC1J!!JJB)!2*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!$L\r3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!BN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)\r!%*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!%#3!%%!&)!-!!#!6!!%I!N$TNk!"##\r"JJ!JN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!$*!!33!8J!`!!)"-!!4m#31Q6S!\r%))'#!"53!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!NN!""!"5!$!!!J%`!"(`*!kC\r1J!3JJB)!#*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!#L3!%%!&)!-!!#!6!!%I!N\r$TNk!"##"JJ!XN!""!"5!$!!!J%`!"(`*!kC1J!3JJB)!"*!!33!8J!`!!)"-!!4\rm#31Q6S!%))'#!!#3!%%!&)!-!!#!6!!%I!N$TNk!"##"JJ!`N!""!"5!$!!!J%`\r!"(`*!kC1J!3JJB)!(*!!33!8J!`!!)"-!!4m#31Q6S!%))'#!$53!%%!&)!-!!#\r!6!!%I!N$TNk!"#!!!!!FJ!!!I!J!N!DBJ!!!6!#3"LQXJ!!!Q!J!N!8U4)!!!)!\r)!*!&+X5!!!$3!*!'+j5!!!#3!"!!N!8X*)!!!'!!N!BXK)!!!+J3!*!&,5b!!!&\r)B!#3"5m)J!!"4%!!N!8`6)!!!+!)!*!&-1b!!!(m5!#3"6,SJ!!"`&!!N!8dU)!\r!!0!B!*!&0AL!!!#J'!#3"90NJ!!!@!#3"P1mJ!!#-(!!N!9E5)!!!4``!*!&A'b\r!!!"B!*!'A-5!!!!X!*!04L)2-!)L%c!#)JX`"L)G0))#"#8dAhKHL#h1"#*IH!B\rL!F5#!KJ"k!))!LJ#6!F`!c!$%!,3!T!!!R!YZ#di!0JE6aX`'fJEEa[`("3F0"c\rd((3Y`!$S!L%+!5)PH!%L,#!")L"p#5'BKJ)D!"`!j!b8%U3C`"MS'VJQC#QX,)3\rX*#Z8+X3U4#dX,`J`l$"--ZJdU$9i0KK39&1m8f4E5#)-C))#+JaB$%`-3!`d$#J\r-(!`3$!3$%!,m!ZJ#e!,%!V!#R!+)$V31S!k-$RJ1D!j8$N!1,#Bd*LJQ(#B3*J3\rPq#AX*H!Pe"c8(-!FV"bB()JFG"aJ(%`F2!8K%)%$"J!3!!!3%"!!!"!!%"!3!"!\r3%!3K%!3K%!)L%"!%)4#"!`X3!"!!%*!&!!!"%!!"!"!"%"!"!!!4%!!4!"!4%"!\r4"L%"!L%"!b)"!3%K!3-K!3%K!3%L!3%#*!'3"!-K!3)L!3%")3%")3%"*!'3"!)\rL!3%"*!'3"53"N!3%)3%%)3%#)J%""#%"!5%"!5%"!L)"!3%M!3%"##%%J3-0!3!\r!!3!%!!3!!!3%!33!!33%!!!J!!!N!3!J!3!N!!3J!!3N!33J*!%%*!%$)3%#)`3\r"!3)L!3%")J3"!5%%!5%"!58%"!%""!%P!3%%"!%#)L!"!L-N!3%")b!"!3%L*!%\r")`3J!3%U"#3"!33J!3%%*)%$$`)!!!)!"!-!!!-!"!)%!!)%"!-%!!-%"!)!)!)\r!*!-!)!-!*!)%)!)%*!-%)#8$"#3"!J)L!3)")`3"!`)L!3-"*!3"!J3"*`%#"!3\r"!`3"*J%$"!3"!J%M)!%#!5-N!3-")b!"!`%a*!%#"#!"!J3N!3-%)!%$"#3%)3)\r&)3J")3)")3J#)3J#)J))!b))#!%M!JJ)"#)"!J)K!3)M#!%#!5))!3%K#!%M!3)\r)!5%"!5F)#!%##!J"!L%"J3-(!J!"!!!*!J!*!!J"!JJ"!!J*!JJ*!L-"!3)")J%\r"!L-*!3)")JN"!5F)!3%##!%"!5J)#3%##!N"%!-K%J-K%!%K#!%K%J%K#!%L%!J\r#)K))!L-3#!J")a))#!%K%!)L!4)#)J%3!5-)!4)"*!J"%!J")`%5#!%U!4!)#!%\r5#!J"%!%K!B%$"a)!!4!!#4)!#4!)!4))!4!)#4))#5%3!5-"!4)")`%"%!%M#3%\r5!6)*!4!)!3%5#!%"%!J*!4))#3%&)33%)5##!J3%)"!!&!!3)#)8))%$##!!!#!\r%!#!!)#!%)#!3!#!8!#!3)#!8)!-K#)%$"J3!#!!J#!3J#"!!#"3!#"!J##38)!J\rJ!L-))!3")JJJ!5JJ##!%)!JJ%!%M##!8!5N))"!J##!8)!L"!`FJ!!!N!!!J)!!\rN)!!`!!!d!!!`)!!L0##"!`JJ)!!J*!!JN!3N)#!`!#!d!#!`)#!d)!%K)!%K#)%\r$"L3!##!J##3J#$!!#$3!#$!J##8d)!JJ)!%M##!N!5X))#!J##!N)!JJ-!%M##!\rd!5N))$!J##!d)!J()K!)J3-r!!!)!"!!!J!!!K!)!J!)!K!!!!)!!"))!!))!")\r!!J)!!K))!J))!K)%!!!%!"!-!!!-!"!%!J!%!K!-!J!-!K!%!!)%!")-!!)-!")\r%!J)%!K)-!J)-!K)!%!!!%"!)%!!)%"!!%J!!%K!)%J!)%K!!%!)!%"))%!))%")\r!%J)!%K))%J))%K)%%!!%%"!-%!!-%"!%%J!%%K!-%J!-%K!%%!)%%")-%!)-%")\r%%J)%%K)-%J)-%K)!!!!#!b%#!L)#!J3K!3%K!J%K!3)L!J%")`)#!33L#!)#)3J\r")3)")`J#!J%K#!)M!3J#!5)"#!%R!J%)!J)"#!%K)!)L!L!$)5)#)J)L!b)J!3%\rM!L!"!L)L!3%M!L)"!L%J!5-)!L!")3J")5)")`J#)J%K#!%R)!%)!L!"#!%R)J%\r)!L)"#!)K!S%$"`)!!J!#N!8!!!-#!!-!!J-#!J-#)`))!J%L!JJ"*`)##!)#!JJ\r#)`-)!J%L!`J"*`)$#!)#!`J")L!#J3-(!L!#!#)#!L)#!#!$!L!$!#)$!L)$!5F\rJ!JJ#)!))!5FL!JJ#)J))!5FJ!`J#)!-)!5FL!`J#)J-)"L%3"#%J!L)3)!%K%!-\rL%"!#)4!")5!"*"!3)!J$)3J")4!")3J#)L!)!533)!J3!L-)%"!")JJ3!58J#"!\r3))%$"`!!"!!3"!!!*!!3*"!!""!3""!!*#33%#3)!L)%#!%M%!3)!L)N#!%N%#3\r)%!%R"!J3%!3)%!%P*!J3%#5"!`F!"!!!&!!!"#!!&#!3"!!3&!!3"#!N%"3J#!%\rK"!%K#!%K&!%K#!%M"#!)!588)!J3"!%M#"!8!5J)%!3J#"!8))%$"`!%"!!8"!!\r%*!!8*"!%""!8""!%*#33)!5-%"!J")a3%#!%M"#3)!6)8*!J3"!3)%"3%#"!\r%*!J3%)4!%)3%#)K!""5)#%!)K!J%K!3%M!K!"!5%#!L%J!5%3!5%J!L)")!%\rM%!%J!b-J!K!")L!#!5F")!)3!5!#!5%%J3-(!"!%!!!&!"!&!!!%!K!%!J!&!K!\r&)3)")J3J!5-3"#!#)J8J!5-3"5!#*`3J!K!%)!)"+!8J!K!&)!)J!b%`!b)J!3)\rL-!%#)5!#)J)`!L-#)!%")`)`!3%L!L!")5!")6!")5!")b!")!%M-!%J!5%J!5-\rJ!M!",#!#)!%J!M!")!)J")%$"`!`"!!J"3!`"3!J"!)`"!)J"3)`"53#)!3J!5-\r`"#!")b!&)!%M-!8J!6!J"#!#-!3J!L!&)!)`"5!#"#%%"L)""))#$!%"!!8!!3%\r&!3!3""!!%334!4!&%!%4"5%4!5%)J3-2!!3)!!!)!33)!3%)!!8)!!%)!38)!3!\r)%!3)%!!)%33)%3%)%!8)%!%)%38))4%#)3J")35"!`i)!!!)!33)!3%)!!8)!!%\r)!38)!3!)%!3)%!!)%33)%3%)%!8)%!%)%38L#"%")JJ)!5-%#!J#+JJ)!33)#!%\r"#!J")`8)#!%S!3J)!38)#!%"*`J)%!3)#"!"0`J)%33)#"%"#!J3"3J)%!%)#"%\r&#!J4"b%3JJ)0!!%!%4!!%"!3!4!4!3!"%!%"!4%4!"%3%3%L%4'"!bm3!!!3!"!\r3!!%3!"%3%!!3N!8"%"!4%!%!%!%3%!%"%!%4%"%!%"%3%"%"%"%4!3!!!3!3!3!\r"!3!4!4!!!4!3!4!"!4!4!3%!!3%3!C!&%3%4!!%4%!%4!3%4%4%!!"%!%"%!!4%\r!%4%3!"%3%"%3!4%3%4%"!"%"%"%"!4%"%4%4!"%4%"%4!534%4%3J3-2!!!3!"!\r3!!%3!"%3%!!3N!8"%"!4%!%!%!%3%!%"%!%4%"%!%"%3%"%"%#34%4!3!L)3%!%\rM%"!3!5-"%"!"*"%3%"!",a#3"`%3%"!4%"!"!5m3%!%3%"!"!4!3!4%3%"%",K!\r3%4!3%"%"%"!4%4!"!L)3!3%M%"!"!5-"%!%"*"%3!4!",a!"%"!3!4!"%!%3%4!\r"!3%[%!%"%"!"!3%3!3%4%!%4!5i3!4%3%!%4!4!"%4%3%3)L%"%")a!3%3%M!4!\r4!534%"%3!5m3%4!3%"%3!4!4%"%3%3%",a!4!4!3%3%"%"%"%4!4%3%Y%"%4%"!\r4%3%3%4%4!B%$$`!!!3!3!3!"!3!4!4!!!4!3!4!"!4!4!3%!!3%3!C!&%3%4!!%\r4%!%4!3%N%4%"%!)L!4!")a!"%!%M!3%3!534!4!3!5m"%"!3!4!3!3%3%"%"%!%\r",`%3!4!"%!%"!4!"%3%3%3%Z!4!4%!%3%3%"%"%4!3%#)J%"!5-3!3%")`'3"#3\r4!3%3!5m"!4!3!3%3!3%"%"%"N!3[!3%"%!'3"a%"!4%",J%"%4!"!4%"!3%4%3%\r4!L)"%3%M%!%4!5-"!4%"*"%"%4!",`%4%"!"%4!"!4%3%3%4!3%[!4%"%!%4!3%\r"%3%4!4%4!5d"%4%3!4%4!3%4N!5"!`m!!"%!%"%!!4%!%4%3!"%3%"%3!4%3%4%\r"!"%"%"%"!4%"%4%4!"%4%"%4!4%N%4%4%!)L%4!")a!4%!%M!4%3!534%4!3!5m\r4%"!3%4!3!4%3%"%4%!%",a%3!4!4%!%"%4!"%4%3%3%Z%4!4%"%3%3%4%"%4%3%\r#)K%"!5-3%3%")`%4!3%N%4%"%!%[%3%3%"%"%!%4!4!4%3%"!5m4!3%3%3%"!4%\r"!4%4!4%",K%"%4!4!4%"%3%4N!3#)K%4!5-3%4%")`%4%3%N%4%4%!%[%4%3%"%\r4%!%4%4!4%4%"!5m4%3%3%4%"!4%4!4'3"!%X%4%4%"%4%3%4N!3%)3)%)3)#)J)\r#"#%#!5%#!5%#!L)#!J%M!J)#"#)#!J)K!J%K!J%M!J)#!5%#!L-#!J)")J)#!5J\r#N!F"!b%$!b)"!J)L!`)#)3%")3)")3-")3)")`%#!J%M!`)#!5%"!L)#!`)M!J%\r#!5-#!`)")J)"!5-#!J-"+J)#!3)#!J-#!J)")3%#)J)"!b%$!L)#!`-L!3)")`)\r"!J)L!`)")`)$!J)K!3%M!J)"!5%#!5%$!5-#!J-")3)"*`%#!J)"!J)"+3-#!J)\r$!J)"!3)L!`%#)J%$!L)$!`)M!3%#!5-$!3)")`%$!J%M!`-#!5)"!3%M!J-"!5-\r#!3-")`)$!`%a!J%"!J)$!3)#!3-#!J-$!J)#)3'"!`F#!!%!!J%#!J%!!!-#!!-\r!!J-#!J-#)`%#!J%L!3)"*`)"!J)#!3)#)`-#!J%L!`)"+!)$!J)#!`)"!5%"J3-\r(!`!"!3)"!`)"!3!$!`!$!3)$!`)$)3%")`%#!`%V!3)"!J%#!`)"!J%")`-#!`%\rU!`)"!J-#!`)$!J%L!3'"!`F#!3%!!`%#!`%!!3-#!3-!!`-#!`-"*`%"!J)"!3)\r"*`-"!J)$!3)"*`%$!J)"!`)"+J-$!J)$!`)"!3'"!`F$!3%"!`%$!`%"!3-$!3-\r"!j!&)#!"!3%#!`%"!J%$!3)$!`%#!3%$!J-"!`)"!`-#!`-$!J-L!3)#)3%")3)\r")`%#!J%K!3)M!J%#!5)#!3%R!J)"!J)#!3-L!`)#)3-")3)")`-#!J%K!`)M!J-\r#!5)#!`%S!J)$!J)#!`%#)J%$!L-"!3)")`%$!J%L!3%")`)"!`%V!J%"!J)"!`)\r#!3%#)J-$!L-$!3)")`-$!J%L!`%")`)$!`%U!J-"!J)$!`)#!`%K!3%M!3)"!5%\r"!5%$!5-"!J-")3%"*`%#!3)"!J%"*`-#!3)$!J%")3%")`-#!3%K!`%K!`%M!`)\r$!5%$!5F"!J-#!3)$!5N$!J-#!`)$!3%")`%$!3%M!3%$!5-"!`-"-`%"!3)"!`%\r#!3%$!J%$!`)"N!3M!`-"!5-$!3-")`-$!`%a!`%"!J-$!3)$!3-#!`-$!J-#)`%\r"!J%L!3%"*`)"!3)#!3%#)`-"!J%L!`%"*`)$!3)#!`%#)`%$!J%L!3-"*`)"!`)\r#!3-#)`-$!J%L!`-"+!)$!`)#!`-"!5-"!3-"+`%"!3)"!3-#!C!%)`-"!`%V!`%\r"!J-"!`)$!3%")`%$!`%V!3-"!J%$!`)"!`%")`-$!`%U!`-"!J-$!`)$!`%R!3%\r"!J'3"#F$!3%#!`%"!5F"!`%#!3-"!5F$!`%#!`-"!5F"!3-#!3%$!5F$!3-#!`%\r$!5F"!`-#!3-$!5"(!`-$!J-$!`'3"!-"N!3$!3%$!`'3"!-"!`%$!3%$!`%$!`-\r"N!3$!`%"!`%$!3-$!`%$!3%$!`-"!`-"!j!(!5%3!L)#%!%L!3)")J3""L%%!5%\r#!5)%!3%Q%!3"!K!%!53#%!3"!5%3"L%#!L%"!b)"!J-L!K!")3%#)`3"!J%K"!)\rM%!3"!5%3!5)"!J%K"!%K!J)M!3)3!L-#%!3#)4!")`%#%!3K"!-Q"!%#%!3"!5)\r3"!3L!3)%)K!%!5%#"#)3"!)K%!)K!J%M"!%#!53%!3)3!5-"!K!")3%$)3%")4!\r")J%#!b%#!5%%!L%3!L-#%!3$)J3"!5B3"!%#%!3$)`3"!J)R!3)3"!%#%!-L%!3\r)*3%#%!3""583"!%#%!3K"!%K!J)L!3)")33$)33#)4!")3%")S##"b'!!L1!JJ+\r"!aL!J!)!JJ)!!!)!J!!!!J#!JJ#!JJ)!!J#!!J+!J!+!!*!%!J!#!S!#!)!#!!#\r#!!##!)#!!)#!!)!#!J#!!S!!!S!!!J#!!J8L!J+"!ad!JJ+!!!!!J!#!JJ)!!!+\r!J!#!JJ#!!!#!!!!!!J#!J!)!J!!!JJ#!!!)!!J!!!!+!!J)!JJ+!JJ)!J!+!J!#\r!!J+!!!)!!J)!JJ+!JJ!!!J+!!J#!!J!&)S!#!L'#"L1!J!)#*3%%"!%""5)%!3%\rL"!3")3%'*!%""!3")3%#)3%")J3%!L)%"!)K"!%K!3)N"!%""!%K!3%M"!3""#-\r""!3'*!3%!3%$)3%#)J%"!5)%!3)L"!%")33"*!%""!3")J%%!5)"!3)K!3)K"!%\rL!33$*33%!3%%!L%"!5%%!b-%!3%")33%)3%")33#)J%%!5%"!L-%!3%")33")3%\r()3%#)3%"*J3%!3%%"!%K!3%K"!)K"!)K!38L"!%")J3%!5)""!%K!3)K"!-N"!%\r""!-K"!%M!3%%!5)"!3%K"!)M"!3"!L%%!5)""!)N!33%!3-M!3%%!b-%"!%")33\r")J%""#1!!33")i!""!)K)3)KJ!%K"!8LJ#!$)J%%J3-,!#!%J!!%!!%!J#!%J#%\r!J#%%!!!%J#!!!!%!!#!%!#!%"5%J!L1!)35"!aq!)35!!3#!)33!)!#!!!!!)3!\r!!35!!3!!)3!!!!5!!!3!)3#!!!#!!3!!)!!!!33!)3#!)!5!!3#!)!!!)33!!35\r!)!5!!!#!!3!!)33!)35!!!5!)3!!)35!!33&)L!%!L%K"#%%!5+!!3)LJ#!#)B!\r")33')L!%!L)""!%LJ#!#*)#!3"!")B!")a"!J!%L%%!$)8!"*8!33)"!!50!J%!\r#)B!")4!')N!3!L*!%!%PJ%!33)!#)8!&)8!")d#!3!)KJ!8K%!)K3!)MJ%!3"#&\r!!5&!!L'!!5%3!b333)"!!5*!J!8L%%!")8!")8!#)4!#+%!33)"!%%#!!L&!!5&\r!!50!J%!$)N!3!5@!3""!J!)K3!NL3"!$)K"!!5&!!50!J%!")N#!!b1!3"!")B!\r")a"!J!%L%%!$*N#!3""!J!)L3)!&)4!")S"!!L'!!5%3!L9!%%#!3!%L3)!")4!\r$)K"!!5&!!L1!3"!%)8!")8!%)4!#*%!33"!#)`J3)!3K)!%Q%#!J#"!J"58)%#!\rJ#!%K)!)K%!%K)!)M)#!)!5%J!L%3!L%)!5%J!5))%!%K)!%K%!8L)!J&)5!")JJ\r3!5)J#!)K)!)L)#!")4!")L!)!b-)%#!")`J3)!%K#!8Q)#!)%#!J!b)J#!%L)#!\r")a!J)!%K%!-K%!%K)!3M#"!J!5%)!5)J)!%N%#!J#!%K)!3M)!J3!L%)!5%J!L%\r3!5%J!5%3"5-J#"!#*3J3)#!)!5)J)!%L%#!$*L!J#"!J)!8L%#!")3J$)3J#)5!\r")K!J!b-J)!J#)5!#)5!")JJ3!5)J#!3M%#!J!5%3"#%J!5))%!%M)!J)!5)))!)\rK#!)K!J)P#!)))!J$)3J")JJJ!b)J#!3K!J%M)!J#!L3)!JJJ!5)##!%M#!))!L-\r###!#)3J%)b!)!J)K#!)L)!J")3J$)JJJ!5)##!)K!J%M)!J#!53J#!))!b)))!J\rL#!)")L!)!L)J#!%K#!)M!JJJ!5%#!b-###!")3)#)`J##!-K#!3M)!J#!5%J!L%\r)!L3###!)!5%)"#)J#!)M)!J#!L))!J%L)!J%)3)#)3J")JJJ"#3)!JJJ!5%#!5)\rJ#!)M)!J#!L%)!5%)!5%)!5)))!3N#!)))!%L!JJ#)J))!b)))!)L##!")3)")L!\r)!b-)!JJ"*8!)3""!!5&!!b&!!L-)3"!")3J&)a"!#!%L%%!")d!33!)S%%!)3""\r!#%!")8!$)8!")8!#)3J&)a"!#!%K%!%L#%!#)3J")K"!!5*!%!3K3!8K3!)P#%!\r33!J$)3J")K"!!L%3"5))3!-P3""!#%!")N!)"#*!%!8P#%!33!J")4!")3J#)8!\r"*%!33!J#)d!)3!-K3!%L3!J#)8!")8!%*4"!#%!3!5-)3"!$)4!#)8!")8!&*8!\r33!K!!L%)!L&!!L%3!5%)!5)33!%M3""!!L%3!5%)!5%3!5))3!8K3!%K3!-M3""\r!!b*!#!%P%%!)3"!")JK!!6i+9Q9bD@CjD@jR,#"`E'9KFf8JFQ8YC@jdCA)J*A-\r"1!S("deTFfeKG'0S)#dJG(*j)'&RB@PZ#J%Q)$"i)(XJ!5#"!!'3#2k3#"q3"!k\r3"1#3"2'3"!(q!Ii"rJ(qrJ(q!Ii"rJ%Ii"rJ$[%1mH!Ii"ra$[%1!H!"i!(a!I(\rJ!H!"m3(a!4rq(ri1rJlqrKrq(ri1rJi"(`%I!3i"$Km"(`%1!3i"i2lJr[(qmIl\rqi2lJr[(qm3-L8#L#!K"3&&!!6qa2f%r%6l"2R%q)1%`i1$JN1"!i!$IX0pJha!N\rK!B)#"3!"!!%!!3!"!!%&)3'#!J8!!3!"!!%!!3!"!L!ZdY28eGEAf0RDfpcGhYr\rJiH,Mj1AQjqMTkZ[XlHl[m2(bmr6ep[IiqIVlr2hqr`%JJ4%"!J-%"3B(#!N+#`8\r'"`J*#JX-$3i2%"%5%a39&KFB'4SE("dH(b!K)L-N*5!K)L-N*5BR+#NU+b`Y,Lm\r`-6)c0$8f0cJj1MXm26ir3%d3Z,c!a-M-d06Bh1$P"3N0%48C(5%P+5da06Np\r389*69&9@9eKC@Q&LBf4PCQGSD@TVE'eZEh"aFR0dGAChH(Pk"b)3)!-K)!)K%!%\rK!3-K!3%M%#!"!L)J!3%K%!)K#!-M#"!J!5%)!5%J!5))%!%L!3J#*J%)%#!"#!%\rN)!%)%!-K)!-L-#!#)L!J!L%`!5%"!5%J!5%"!5-`)!%")b!J!3%K-!)L##!#)`J\r`)!%M##!J!5))-!%M!3JJ!5X"#$!J!3JJ)!%)-!%K#)%$"`!!#"!J#!!J#"!!#3!\r!#4!J#3!J#5%3!5))#!)Q#!J3)!J)!53J#!J3!5)*#!)Q#3J3)!N)!53J#3J3!5%\r)J3-()!!)-#!))#!)-!!*)!!*-#!*)#!*)6!")`J))!%V#!J`)!J))#!)#$!")`N\r))!%V#3J`)!N))#!*#$!%)3)&)5!")3)")5!#)5!#)J)J!b)J)!%M!L!J"#)%!J)\rK"!)M)!3#!5)J"!%K)!%M"!)J!5%%!5FJ)!3#)#!%!L%%J3-(!J!%!!!N!J!N!#!\r%!L!%!#!N!L!N!L-%"!)")J3%!L-N"!)")L3%!5FJ"!3#)!3%!5JJ*!3#)#3%%!-\rK%J-K%!%K)!%K%J%K)!%L%#!#)K)J!L-3)#!")a)J)!%K%!)L"")#)J33!5-J"")\r"*#!%%#!")`35)!%U""!J)!35)#!%%!%K")%$"a)!""!!*")!*"!J"")J""!J*")\rJ*#%3!5-%"")")`3%%!%M*!35!6)N""!J"!35)!3%%#!N"")J*!3()3%")35"!`d\r!!!3"!3!!!3!"!33!!33"!!!#!!!$!!3#!!3$!3!#!3!$!33#!33K!`)K!J-L!J%\r")J3#!L3%!J%"!5%#!5%"!58#!3%%!J%N!33#!3)L!J)#)J)$!5-%!J)"*!3#!`%\r")`)#!3%V!J-""!)#!33#!`J$)3J#)`%)")%$$3!)"!%*!!!*!!%*"!!*"!%)!!)\r)!!-)"!))"!-*!!)*!!-*"!)*"#)$#!%K!J%K#!%P!J%)"!)"*3J%!J%*!5%#!5%\r*!58#!3N%!J%P#33#!3J")`)##!%V!J-)"!)##!3#!`N")`)##3%U!J-*"!)##33\r#!`8K%!3K!3)L%!%%)3L"!`S3!!J!!3J3!3J!%!!3%!!!%3!3%3!!%!J3%!J!%3J\rN%"%)"!-L""!#)33")3%")`33!3%K"!)M#!33!5))"!%R!3J%%!%)"!%K%!%M""!\r3!5%%!5%4!5-%%"%")33"*a!)""!3#!3"*K%)""!4#)%$$`)!!")!!!)"!")"!!)\r!#")!#!)"#")"#!)3!")3!!)4!")4!!)3#")3#!)4##85%3J%!J)L"")#)`3#!3%\rM"")"!5)%!J%M#!35!5`)"!)"#!35!3J%!K!")`35%!%M"!)4!5-%%K%"-!3#%!J\r%%K!)"!)4#!35%3J%)4!%)3%#)K!""5)%%!)K"!%K!B%$'333!33J!!!`!!!J!3!\r`!3!J!!3`!!3J!33`!33!%!!3%!!!%3!3%3!!%!33%!3!%333%33J%!!`%!!J%3!\r`%3!J%!3`%!3J%33`%5%%!L%3!5%3!5%3!L)"%!%M%!%3!b-3""!")K!%!5J"%!3\r3!4!%)!%K%!%K-!%K%!%M)!%3!5-`!4!")5!")a!%-!%U%!3J!4!%-!%3"!%L%"!\r")a!3%!)L%4!")a!4%!)R%"!%%"!3"!%U%4!%%"%3"#!3%!%M-"!3!5-J%4!")c!\r4%!%`)"!3"$!3%!3J%4!%-"%3"!3K#!BL#!J#)3J#)33")3J")33$)`3)#!%L"!J\r")3)#)JJ#!b%#!5-)#!)")3J")J)%!5-)!J3#*`)%#!J#"!J$)J%)J3-'!!%!!!N\r)!!N!"!%)"!%!"!N))J3*!5%#!5-"#!)")3%")3)")`N)!J%K#3%R!J3"#!)%!3%\rS!J3*#!)%#3+"!`F!!!S!!!)!#!S!#!)%!!S%!!)%#!SN"!J#!J)L#J)#)J)#!5-\r)#J)"*!J#!J3")`S#"!%T!J)%#!S#"!J#J3-(!!%+!!%#!!N+!!N#"!%+"!%#"!N\r+*!3*!J)")`%+!J%M!3)#!5-*#J)"-3N#!J3"#J)%!3)#"!N+!J3*"L%"J3-'!!J\r!!!J"!3!!!3!"!3J!!3J"!b%3!L)"%!%K#!%K%!%N#!%3!3)L%!%"*!%3!3J"*4!\r"#!%3!5%J!b)J!B%$"J!S!!!S!3%J!!%J!3%S!!%S!3%K)!%K%!%M)!%3!5%S!5%\r3!58S!4!")!%R%!%J!4!"+!%P%!%S!4!#)3+"!`F!!!-!#!)!#!-"!!)"!!-"#!)\r"#!-#)J)3!L)$%!%M#!)3!53)!a!"!5-#%!%"+J-3!3J#%!%)!a!")L!#J3-(!#!\r$!#J#!#J$!5!#!5!$!5J#!5J$!5-J!K!")b!$%!%M+!)3!6-S!a!")!)3!5!$%!%\rS!K!"+!-3"#%%"#%%!L)%"!8L!J3#)3)")33")`)%"!%K!J)K)!%K"!%K)!)L"#!\r")`3%)!-M)!)%!5)J!J%R"#!#"!3J!J-L)!3#)5!")33")b!%"!%K)!-L)J3#)5)\r")33")b)%"!%K)J)M)#!%!5)J)!%R"#!J"!3J)!)M)#)%!5)J)J%R"#!L"!3J)J)\rK#!%K"!%K#!)L"!J")`3%#!-M#!)%!5))!J%R"!J#"!3)!J)K+!%K"!%K+!)L"#J\r")`3%+!-M+!)%!5)S!J%R"#J#"!3S!J)M##!%!5)))!%R"!JJ"!3))!)M##)%!5)\r))J%R"!JL"!3))J)M+#!%!5)S)!%R"#JJ"!3S)!)M+#)%!5)S)J%U"#JL"!3S)J)\r)#!)K#!)K!J)Q!J))#!)#"#-)#!)")3J")J)#!L%#!5B)#!)##!J")J))"#-)!J)\r")`J#!JJK#!%K!J%K#!8L!J)")3J#)JJ)!5B##!J#!JJ%)`J#!J%K#!3K!J)K#!)\rL#!J")J))!5%#!L%)!5%#!53)!J))!5%###8##!J#!J%K#!)K#!%N!J))#!)K#!3\rM#!)#!5%)!5)##!%K!J)K#!)L#!J")3)#)3)")`J)!J-L!J)#)`)##!)N!JJ)!J%\rL#!J")J))!L%#!5-)!J)&)JJ#!5%)!5%#"5%)!L%#!b%#!58)!J))#!3M!J))!5%\r#!L%)!LF)#!*!%)!3"5)3J!%L3"!#)8!#)4!#)i!33!%KJ!)L%)!$)B!")N!3!5%\r3!b)33!%KJ!)K%!%N%%!3J!%L3"!&)4!")4!#)8!"*)!33"!")4!#)B!#*"#!%%!\r))4!")K"!!5+!%!%Q%)!33"#!!5&!!L)33!3K%!3QJ""!%)!3!5%3!5333"#!!5&\r!!5'!!LF3J""!%)!3!5%3!5)33!)K%!3K3!8LJ"!")4!#)N!3!5%3!L'!!5&!"#3\r3J""!!5@!%%!3J!-KJ!8K3!)K%!-P%%!3J"!")K#!!5*!%!)L3"!")4!")4!%)i!\r33!%KJ!%K3!%LJ"!$)a"!%!-L%)!")33#*!%%"!%$)3%")33")J%"!5%%!5)""!-\rK"!%L!3%")J3"!5%%!5%"!L%%!L)%"!8P!33%!3%#)J%"!b-""!3")3%&)33"*!%\r%"!%$)3%$*J%""!3"!3%K"!)K"!)M!33%!5)""!%K!3)P"!%""!3$)J3""5%%"#B\r%!3%%"!%$)3%%)3%")33%)J%"!5%%!5-""!3#)33")J%""#-%"!%#)J3"!5)%"!%\rK!3%K"!%L!33$*!3%!3%$)3%"*!3"!33#)J%%!b3%"!%"!5%%!L%%!5%"!5%%!5)\r"!3%L"!%")33")3%&)J3%!5%"!L-"!33#)3%")`3"!3)K!3%L"!3$*%!3#"!")4!\r%*3J33"!)"#)33!)K%!%L%!J")8!"*!J33"!")4!#)JJ3"5-3#"!#)3J")d!3#!%\rK3!)K%!-L%%!")3J")N!3!b%3"#%)!5*!%!%K%!%N%!J33!3K%!-L%!J&)8!"*!J\r33"!")4!")4!")K"!!58)%%!3#!%K3!)L%%!")3J#)K!)!5&!!L%3!L%)!5*!%!%\rK%!%K%!3M#""!!L%3!5)3#!BK%!)K3!%K#!3L%%!"*!J33"!$)4!")4!$*""!%!J\r")d!3#!%K3!)N%%!3#!-L#"!")4!#)d!3#!%K3!%K#!%L3"!")K"!!L%3!5)3#!)\rM%!J3!b%3!L3)%%!3!5%)"#%""#%%!5B)!33J#!%")L!)!5%%!L8""#!)!3-K!38\rL)!J#)5!")J%%!5%)!53%)!J"!53J#!%%"L)""!%K#!3K!3%K)!)M"#!)!5%%!L-\r""#!%)3J#)5!$)L!)!5B%)!J""#!")3%")b!)!33K"!-P"#!)!33")`J""!%K#!%\rL"#!")3%")b!)!3-K!38L)!J#)L!)!5%%!5%)"#)""!%N#!%%)!8N!33J#!8K"!)\rK!3%L)!J")J3J!L%%"5B)!33J#!%"*#!)!33$)J3J!5%"!b)""!%L#!%")L!)!5%\r%!b)%)!-K)!%P!33J#!%#)3J#)L#!!L&!!5%J!5&!"#1!)#!#)5!")8!#)5!")B!\r")L"!!5%J"#BJ3)!J)%!")L!J!5'!!b'!!5%J!5'!!L0!J#!$)b!J3!%K)!)KJ!%\rN)%#!)!%K3!BK)!3N3)!J)!%LJ#!"*d#!)#"!J#!#)B!&)L"!!b&!!5)J)!)N)#"\r!J!%K)!-M)%#!!b'!!5%J!LBJ)%#!)#!#)5!")8!%)B!")5!")B!&)5!")S!J!5&\r!!5%J!b%J!59!J#!J3!%L)#!%*8#!)#"!!5)J)!)K)!)KJ!%M)%#!!L0!J#!$)b!\rJ3!BK)!%KJ!)L3)!"*5"!J#!J!5+!)!3L)%!$)d#!)!%K3!)K3!-K!J%K!B%$(3)\r!!3!%!8)%!%!%!%)!N!3"!!!"!J3!!J3"3!!!!!3"3J!"3!!!!J3"!J3!3!!!3!3\r"3J3!!!!"!J!"!!3!3J!"3!3!3J3"3J!!!!3!3J3"3!3!!J!""#0#"!'"!`T!!!&\r!"!!#"!"!!!!#!!%!!!&!"!%#"!"#"!"#!!!%)3)")3'"!a)!"!!!"!%#!*!%!3)\r%!3)!!%)!!!)%!%!!!8)%!3!!!8)!!!!%!%!%!8)%!3!%!8)!!8!!!#4!"##!J3-\rHJ###!!!#J!!!!#!#!!#!J##!!###J!!!J#!!!!##!!!#J!##J#!#J#!!J##!!!!\r#!!##J!#!J#!#!###J#!!J!#3"))!)!!!!)!!)!+!))#!!)!!!!)!)))%)B!")B!\r$)3)#)5!#)i!JJJ%KJ!%K!J%LJ#!))B)#)L#!!51!)!)")i!J!J-KJ!%MJ###"5'\r!!5'!J3-*J#!#!###J!#!!##!!#!!J!##!!!#J#!#J##!"#1!))+"!`B!!)+!!!!\r!)!!!))#!!!)!!))KJ16@!!!"!!!!!@!!!!"J!!!!-J#3&&4&@&3ZC'9Q!*"!9%9\rB9#jNEf-!N$`3!!!!9%9B9#jS!*"#9%9B9!!!!&`!N!X"!*!6!A"hF'-!N"-"!*!\r42"&0594IT@4PFfaTBLjNC@*eC`!!!3!!!!&J!!!!B!!!!$)'Ce5-Aa`!!!!F!$)\r!!'0QFQF!!!!+!!$rr`#3"!CRA"$$eJ:\r
\ No newline at end of file
+++ /dev/null
-Wed Jul 26 19:25:10 1995 Ken Raeburn <raeburn@cygnus.com>
-
- * quad_cksum.c: Include string.h for memcpy declaration.
- * random_key.c: Ditto.
-
-Wed Feb 1 12:00:00 1995 John Rivlin <jrivlin@cygnus.com>
-
- * Makefile.in: Create install-windows target
-
-Tue Nov 22 10:53:16 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
-
- * random_key.c (des_random_key): Don't assume that the argument is
- aligned on an integer boundary.
-
-Mon Oct 31 19:40:21 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
-
- * Makefile.in (CODE): Remove Imakefile.
-
-Fri Oct 28 15:21:01 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
-
- * read_password.c (old_sigfunc): Use sigtype in declaration,
- rather than guessing based on POSIX define.
-
-Mon Oct 10 19:18:48 1994 Julia Menapace (jcm at toad.com)
-
- * mac_time.c: Include des.h and AddressXlation.h. Put
- gettimeofdaynet wrapper on gettimeofday_no_offset so it can be
- returned as a DES pointer with the expected calling sequence.
-
- * new_rnd_key.c: Make forward declarations and function
- definitions match the function prototypes that were added as
- new external declarations to des.h: des_set_sequence_number,
- des_generate_random_block, des_new_random_key,
- des_init_random_number_generator. des_set_random_generator_seed
-
- (des_init_random_number_generator): Changes to port routine
- to the Mac. Initialize the seed using RANDOM_KRB_INT32_1
- and RANDOM_KRB_INT32_2 instead of gethostid and getpid. Use a
- KRB_INT32 instead of a timeval and set it using TIME_GMT_UNIXSEC
- instead of gettimeofday.
-
-Tue Aug 9 12:00:00 John Rivlin (jrivlin@fusion.com)
-
- * win_time.c: Removed copy of time structure as stack
- is now set up properly.
-
- * Makefile.In: Broke up clean target to not do useless
- deletes on unix.
-
-Mon Aug 29 10:12:42 1994 Mark Eichin (eichin@perdiem)
-
- * key_sched.c (des_key_sched): even if we return an error, build
- the key schedule anyway. This helps with testing, and avoids
- garbage encryptions in cases where the error isn't checked.
-
-Fri Jul 29 17:18:55 1994 Mark Eichin (eichin@cygnus.com)
-
- * random_key.c (des_random_key): use KRB_INT32 for half-key
- manipulation, so the upper half really gets set.
-
-Tue Jul 19 20:06:14 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
-
- * random_key.c (des_random_key): Don't initialize static local
- variable n. Fiddled with whitespace in srandom call.
-
-Fri Jul 15 17:35:30 1994 John Rivlin (jrivlin@fusion.com)
-
- * ren.msg: updated to handle all files (changelogs, makefiles etc)
-
- * Makefile.in: added "-" on clean: to avoid stupid messages
-
-Fri Jul 8 02:40:54 1994 John Rivlin (jrivlin@fusion.com)
-
- * makefile.in: Updated file with portable directory syntax for PC.
- Changed .o and .a references to portable syntax
- Removed all response files which needed to be generated under unix
- to simplify configure process so that it may be run on the PC.
- Placed objects in .lib file so that DLL construction can take place
- without a response file. This solves a problem with running out of
- memory on the PC during builds.
- Updated clean: target to place rm commands on seperate lines for
- compatibility with PC DEL command.
-
-Tue Jul 5 11:31:59 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
-
- * string_to_key.c (des_string_to_key): Deleted static and (some)
- register decls.
- * quad_cksum.c (four_bytes_vax_to_nets): Ditto.
- * util.c (des_cblock_print_file): Ditto.
-
- * weak_key.c (weak): Now const.
- (des_is_weak_key): Compensate.
-
-Fri Jul 1 03:12:31 1994 John Gilmore (gnu@cygnus.com)
-
- Make Kerberos build using Think C on Macintosh.
-
- * mac_time.c: Use GetDateTime, not time.
- * quad_cksum.c: Avoid using printf().
- * %DesLib-project: New Think C project file for building
- the DES library as an ordinary library. (Unfortunately this
- is a binary file -- there are no textual makefiles in Think C).
- This makes it semi-possible to debug the code.
- * %DesLib-project-A4: Ditto, for building as a library to go
- into a device driver.
-
-Thu Jun 30 23:11:11 1994 John Gilmore (gnu@tweedledumb.cygnus.com)
-
- * *.c: Remove remaining RCS ID strings. Strings used as `char *'
- initializers upset Think C when building device drivers, since it
- doesn't have a good way to relocate the pointers when the driver
- is loaded.
-
- * f_parity.c: Clarify public domain ownership.
-
- * *.c: Use #include "..." rather than #include <...> for
- our own local include files, because Think C can't find them
- when enclosed in <...>.
-
-Wed Jun 22 18:29:48 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
-
- * new_rnd_key.c, string_to_key.c: Include <string.h>.
-
-Tue Jun 21 00:15:31 1994 John Gilmore (gnu@cygnus.com)
-
- * new_rnd_key.c: Lint.
-
-Sat Jun 18 09:05:30 1994 John Gilmore (gnu@cygnus.com)
-
- Make DES library independent of krb library again.
-
- * Makefile.in (SRCS, OBJS): Use DES_TIME_SRCS and DES_TIME_OBJS.
- * unix_time.c, mac_time.c, win_time.c: New files implement
- TIME_GMT_UNIXSEC for the various hosts. Code moved from *_glue.c
- in lib/krb.
-
-Fri Jun 17 05:01:03 1994 John Gilmore (gnu@cygnus.com)
-
- * Makefile.in (DESSRCS): Move read_password.c to SERVER_DES_SRCS,
- since we don't use it on micro clients. Clarify comments.
- (Links of test routines): Add $(LDFLAGS) to the line so that
- mac-mf.sed can find these and modify them to run "Link".
-
-Thu Jun 16 17:08:58 1994 John Gilmore (gnu@cygnus.com)
-
- * Makefile.in (unixmac): New target.
-
-Fri Jun 10 23:03:08 1994 John Gilmore (gnu@cygnus.com)
-
- * f_tables.h: Add comments on the DEB macro.
- * new_rnd_key.c: Remove RCS crud, update export notice.
- * random_key.c: Clean out obsolete config crud.
- Use TIME_GMT_UNIXSEC_US rather than gettimeofday. Use
- RANDOM_KRB_INT32_1 and RANDOM_KRB_INT32_2 rather than
- getpid() and gethostid(). Remove RCS crud, update export notice.
- * string_to_key.c (des_string_to_key): Int functions return results.
- * testit.c: Print usage message if no args.
- * verify.c, testit.c: Declare des_debug extern, not common.
-
-Wed Jun 8 13:09:14 1994 John Gilmore (gnu@cygnus.com)
-
- * Makefile.in (DBG): Move to where it will actually work.
- * testit.c, verify.c: Include <krb.h>. Remove raw extern
- declarations. Pull RCS crud.
- * verify.c: In Windows, set screen buffer to keep all output.
-
- * string_to_key.c (des_string_to_key): Fix argument type to match
- correct prototype. Pull RCS crud.
-
-Fri May 27 16:55:33 1994 John Gilmore (gnu@cygnus.com)
-
- * Makefile.in (DBG): Override with library-building flags.
-
- * des_internal.h: Include krb.h when compiling the DES
- routines, since it describes some of the DES routines when
- documenting the external interface of Kerberos.
- * f_cbc.c, f_ecb.c, f_parity.c, f_pcbc.c, key_sched.c,
- quad_cksum.c, string_to_key.c, weak_key.c: Add INTERFACE to
- definitions of functions visible in the programmer interface.
- * string_to_key.c: Remove some error printf's for environments
- that don't have printf; put them under #ifdef DEBUG.
-
-Tue May 24 06:10:57 1994 John Gilmore (gnu@cygnus.com)
-
- * enc.c: Pull RCS crud.
- * f_pcbc.c (des_pcbc_encryption): Lint ivec.
- * key_test.c: Toss the ridiculous doubled IBMPC/BSDUNIX printf's,
- use a simple portable printf. Typo in msg. Pull RCS crud.
- * new_rnd_key.c, quad_cksum.c, string_to_key.c: Lint.
- * quad_cksum.c: Pull RCS crud.
-
-Sat May 21 03:37:01 1994 John Gilmore (gnu@cygnus.com)
-
- Microsoft Windows port.
-
- * Makefile.in (c-libdes.${LIBEXT)): Typo; and fix .o to .obj.
- * des_internal.h: Remove pre-Fergusen stuff, leaving one #define.
- * f_tables.h (FF_UINT32): Add this, which makes a KRB_UINT32 out
- of a constant that might otherwise only be int or less.
- * f_cbc.c, f_cksum.c, f_pcbc.c: Use it. Line up code neatly.
- * key_sched.c: Lint, pull RCS crud.
- * ren.msg: Insert column of entries for MIT PC release.
-
-Thu May 19 22:18:24 1994 John Gilmore (gnu@cygnus.com)
-
- More MS-Windows and Mac support.
-
- * cbc_noop.c, epc_encrypt.c: Delete two more unused remnants.
- * ren.msg, Makefile.in: Remove references to remnants.
-
- * Makefile.in (OTHERSRCS, OTHEROBJS): Rename to FERG_* for clarity.
- (SERVER_DES_{SRCS,OBJS}): Split out routines used only on servers.
- (####): Move host-configuration insertion point so that the
- per-host Makefile fragments can override the above.
- (LIBEXT): Use it everywhere rather than ".a".
- (libdes.$(LIBEXT)): Avoid making a .bak file. Add and
- use $(ARCHIVEARGS) to allow making the incredible MSC LIB
- command work.
- (c-libdes.$(LIBEXT)): Add rule to build control file for MSC LIB.
- This rule must run on Unix (FIXME) since it uses sed and tr. I
- didn't know the equivalent DOS commands...
-
- * f_tables.h (DES_IP_RIGHT_BITS, DES_FP_RIGHT_BITS): Insert a cast
- to unsigned, to circumvent a bug in the Macintosh MPW 3.2 C
- compiler which loses the unsignedness and then does an arithmetic
- shift rather than a logical shift.
- (DEB): Add debug macro for very nested macro defns.
- (DES_DO_ENCRYPT): Insert DEB calls to make it possible to
- debug when DES fails.
-
-Fri May 13 01:59:09 1994 John Gilmore (gnu@cygnus.com)
-
- * Makefile.in: Change {} to () for Microsoft NMAKE.
- * Makefile: Remove remnant of old config scheme.
- * ren.msg: Specify short and long names for DOS file systems.
- * key_test.c, quad_cksum.c, testit.c, verify.c: Pull unused
- errmsg, errno.
-
-Sun May 8 17:21:50 1994 John Gilmore (gnu@cygnus.com)
-
- * read_password.c: Remove `sigtype', use typedef from osconf.h.
-
-Sat May 7 17:32:43 1994 John Gilmore (gnu@tweedledumb.cygnus.com)
-
- * Makefile.in: Don't build verify, key_test, and testit every
- time we build the library.
-
- * Makefile.in: Update CODE for the removal.
-
- * cbc_encrypt.c, cksum.c, dbg_prt.c, des.c, desglue.c, destest.c,
- key_parity.c, make_e.c, make_fp.c, make_ip.c, make_key_perm.c,
- make_key_sched.c, make_odd.c, make_p.c, make_p_table.c, make_s.c,
- make_s_table.c, misc.c, noop.c, pcbc_encrypt.c, s_table.h.ibm,
- tables.h: Remove remnants of non-Fergusen DES code. These are all
- unused, have long, non-DOSlike names, and confuse people (me
- anyway) into thining that they're live code.
-
-Fri May 6 02:04:48 1994 John Gilmore (gnu@cygnus.com)
-
- * desglue.c (quad_cksum): Put argument declarations in order.
- * pcbc_encrypt.c (des_pcbc_encrypt): Ditto.
- * quad_cksum.c (des_quad_cksum): Ditto.
-
-Tue Oct 26 12:21:05 1993 Ken Raeburn (raeburn@rover.cygnus.com)
-
- * f_tables.h: Define const if not already defined and not
- __STDC__.
-
-Sun Oct 17 13:47:28 1993 Ken Raeburn (raeburn@cambridge.cygnus.com)
-
- * f_*.c, f_tables.h, quad_cksum.c, testit.c, verify.c: Use
- KRB_INT32 instead of long for 4-byte type.
-
- * f_tables.c: Include des.h.
-
- * string_to_key.c (des_string_to_key): Mask values to 32 bits
- before printing.
-
- * testit.c (nflag): Set to 1; running 1000 identical iterations
- was silly.
-
- * verify.c (print8): New routine.
- (main): Clean up output formatting.
-
-Thu Feb 11 13:05:12 1993 Ken Raeburn (raeburn@cambridge.cygnus.com)
-
- * testit.c (main): Fix usage message.
-
- * Imakefile: Delete references to assembly code.
- * key_sched.c: Ditto. Get rid of useless BIT macro.
-
-Wed Feb 10 14:17:31 1993 Ken Raeburn (raeburn@cambridge.cygnus.com)
-
- * des.c (des_ecb_encrypt): Fix pointer type lossage, and NULL/0
- confusion. Discard VAX-specific stuff. Add a couple of minor
- optimizations, including some based on DES_SHIFT_SHIFT
- conditional.
-
- * key_sched.c (make_key_sched): Fix inconsistent fwd declaration.
-
-Fri Jun 19 13:37:35 1992 Mark Eichin (eichin at tweedledumber.cygnus.com)
-
- * Imakefile (library_ro_object): punt the read-only object linker
- mangling as it interferes with debugging.
-
-Tue Nov 8 12:12:32 1988 William Sommerfeld (wesommer at binkley)
-
- * (util) Remove \ before { and } characters (causes RT
- compiler warning)
-
- * (read_password) Print a newline after saying "try again".
-
- * (read_password) Merge in changes by Jim Bloom to do a clearerr
- after a read fails, and protect against an RTM attack by
- changing gets to fgets.
-
-Fri Sep 16 16:26:55 1988 Bill Sommerfeld (wesommer at ra)
-
- * (read_password) fix dependancies for BSDUNIX.
-
-Mon Sep 12 14:55:23 1988 Bill Sommerfeld (wesommer at ra)
-
- * (*) debug->des_debug
-
- * (*) debug_print() -> des_debug_print()
-
- * (Makefile) add dbg_prt.o to list of files included in build.
-
- * (des.c) remove debug_print; it's in dbg_prt.c
-
- * (des_internal.h) contains definitions of AUTH_DES_ITER,
- s-box structures, which aren't part of the encryption interface.
-
- * (*) #include "conf.h" -> #include "des_internal.h"
-
- * (*) C_Block -> des_cblock
-
- * (*) Key_schedule -> des_key_schedule
-
- * (noop.c) remove #includes for unused include files.
-
- * (des.c, random_key.c, string_to_key.c) add #include of "des_conf.h"
-
-Fri Sep 9 15:46:13 1988 Bill Sommerfeld (wesommer at ra)
-
- * (*) string_to_key() -> des_string_to_key()
-
- * (*) read_pw_string() -> des_read_pw_string()
-
- * (*) random_key() -> des_random_key()
-
- * (*) pcbc_encrypt() -> des_pcbc_encrypt()
-
- * (*) key_sched() -> des_key_sched()
-
- * (*) cbc_encrypt() -> des_cbc_encrypt()
-
- * (*) cbc_cksum() -> des_cbc_cksum()
-
- * (quad_cksum.c) make {four,two}_bytes_vax_to_nets be static to
- avoid namespace pollution.
-
- * (*.c) Rename C_Block_print() to des_cblock_print().
-
- * (make_key_perm.c) Make "key_perm" be static to avoid namespace
- pollution.
-
- * (quad_cksum.c) Make "short_conv" and "long_conv" local
- variables, to avoid namespace pollution.
+++ /dev/null
-This directory contains the sources for the DES encryption library and
-test programs.
-
-Two precautions--
-
-1) under US law, DES software and hardware may not be
- exported without license from the US Dept of Commerce.
-
-2) The only way to get a significant speedup of the algorithm is to
- use considerably more space, traded against time. Dont play
- with the code -- there is a high probability you will either
- make it slower, or wrong, or both. This implementation was
- optimized for the UVAX 2. Other architectures could benefit from
- some "asm" tweaking.
-
-3) If you do play with the code, make sure that the test program
- "verify" still yields the expected answers. Otherwise, your
- ciphertext will not decrypt under a standard implementation, such
- as on the VLSI chips that have been certified.
-
- Project Athena Steve Miller 3/86
+++ /dev/null
-/*
- * Copyright (c) 1990 Dennis Ferguson. All rights reserved.
- *
- * Commercial use is permitted only if products which are derived from
- * or include this software are made available for purchase and/or use
- * in Canada. Otherwise, redistribution and use in source and binary
- * forms are permitted.
- */
-
-Sorry about the poor quality of installation instructions. Included
-here are replacements for the DES portions of Eric Young's kerberos
-DES library replacement. To use this you will need his distribution.
-Untar the latter and:
-
-(1) Copy all .c and .h files into the distribution directory. This will
- overwrite some files and add others.
-
-(2) Apply the patch included here to set_key.c in the distribution directory.
-
-(3) Edit the Imakefile (or the Makefile) to include the following files
- on the SRCS= line:
-
- des_tables.c ecb_buffer.c make_sched.c
-
- Add the following files to the OBJS= line:
-
- des_tables.o ecb_buffer.o make_sched.o
-
- Add the following file to the CODE= line:
-
- des_tables.h
-
-Recompile and you're done.
-
-The salient differences between this DES and Eric Young's are as follows:
-
-(1) There are no dependencies on byte ordering, the ability to do
- unaligned loads and stores, or any other machine dependencies
- that I know of. There are no #ifdef's. The code could probably
- be made faster by adding such things, but not enough to be worth
- it.
-
-(2) Combined S and P tables are used for the inner loop of the cipher
- routine and the E expansion is computed on the fly, like Eric
- Young's code, but the computation is reordered from the standard
- to save instructions.
-
-(3) The initial and final permutations are table driven, and take
- about the same amount of work as a single round of the inner
- loop (i.e. only about 12% of the work done for an ecb encryption
- is spent in the IP and FP code).
-
-(4) Since NTP (for which this DES was originally implemented) uses
- lots of keys to encrypt small things, the key permutation code
- has been well worked over and is quite speedy (the amount of
- work required to permute a key is on the order of that required
- to do a single ECB encryption, more or less).
-
-(5) Since the code required to do an ECB encryption using the tables
- is actually fairly compact, even with lots of inlining, it was
- implemented as a macro and is expanded in situ where needed.
-
-On the one machine I ran a comparison on this code ran 80% faster than
-Eric's, compiled into a slightly smaller space, and did pass destest.
-I suspect this stuff is also faster, and not a lot larger, than the
-library MIT doesn't export with kerberos. You mileage may vary.
-
-The silly copyright was a (probably ineffective) afterthought. If it
-really inconveniences you give me a call.
+++ /dev/null
- MIT K4 patch10 MIT K4 PC PROPOSED NAME (trunc to 8.3) old Cyg
-$1 $2 $3 $4 $5 $6
-
-@ - - ChangeLog changelo
-@ - debug.c debug_decl.c debug_de.c
-@ - des_intn.h des_internal.h des_inte.h
-@ - - doc doc
-@ - enc.c enc.c enc.c
-@ - - f_README f_readme
-@ - - f_cbc.c f_cbc.c
-@ - - f_cksum.c f_cksum.c
-@ - - f_ecb.c f_ecb.c
-@ - - f_parity.c f_parity.c
-@ - - f_pcbc.c f_pcbc.c
-@ - - f_sched.c f_sched.c
-@ - - f_tables.c f_tables.c
-@ - - f_tables.h f_tables.h
-@ - keysched.c key_sched.c key_sche.c
-@ - key_test.c key_test.c key_test.c
-@ - - Makefile.in makefile.in
-@ - newrndky.c new_rnd_key.c new_rnd_.c
-@ - qd_cksum.c quad_cksum.c quad_cks.c
-@ - rand_key.c random_key.c random_k.c
-@ - rdpasswd.c read_password.c read_pas.c
-@ - - READ_ME read_me
-@ - - ren.msg ren.msg
-@ - strtokey.c string_to_key.c string_t.c
-@ - testit.c testit.c testit.c
-@ - - unix_time.c unix_tim.c
-@ - util.c util.c util.c
-@ - verify.c verify.c verify.c
-@ - weak_key.c weak_key.c weak_key.c
+++ /dev/null
-/*
- * des.h
- *
- * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
- *
- * For copying and distribution information, please see the file
- * <mit-copyright.h> (Except for those files which contain other copyright information).
- *
- * Include file for the Data Encryption Standard library.
- */
-
-/* only do the whole thing once */
-#ifndef DES_DEFS
-#define DES_DEFS
-
-#include "mit-copyright.h"
-#include <stdio.h>
-
-#ifndef DES_INT32
-#define DES_INT32 SInt32
-#endif
-#ifndef DES_UINT32
-#define DES_UINT32 UInt32
-#endif
-
-/* There are some declarations in the system-specific header files which
- can't be done until DES_INT32 is defined. So they are in a macro,
- which we expand here if defined. */
-
-#ifdef DECL_THAT_NEEDS_DES_INT32
-DECL_THAT_NEEDS_DES_INT32
-#endif
-
-typedef unsigned char des_cblock[8]; /* crypto-block size */
-/* Key schedule */
-typedef struct des_ks_struct { union { DES_INT32 pad; des_cblock _;} __; } des_key_schedule[16];
-
-#define DES_KEY_SZ (sizeof(des_cblock))
-#define DES_ENCRYPT 1
-#define DES_DECRYPT 0
-
-#ifndef NCOMPAT
-#define C_Block des_cblock
-#define Key_schedule des_key_schedule
-#define ENCRYPT DES_ENCRYPT
-#define DECRYPT DES_DECRYPT
-#define KEY_SZ DES_KEY_SZ
-#define string_to_key des_string_to_key
-#define read_pw_string des_read_pw_string
-#define random_key des_random_key
-#define pcbc_encrypt des_pcbc_encrypt
-#define key_sched des_key_sched
-#define cbc_encrypt des_cbc_encrypt
-#define cbc_cksum des_cbc_cksum
-#define C_Block_print des_cblock_print
-#define quad_cksum des_quad_cksum
-typedef struct des_ks_struct bit_64;
-#endif
-
-#define des_cblock_print(x) des_cblock_print_file(x, stdout)
-
-/* Function declarations */
-
-/* This is CFM magic that has to be done in order for the library to work under CFM-68K */
-#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
-# pragma import on
-#endif
-
-#if !GENERATINGCFM
-# pragma d0_pointers on
-#endif
-
-int des_cbc_encrypt(des_cblock *in,
- des_cblock *out,
- long length,
- des_key_schedule schedule,
- des_cblock ivec,
- int encrypt);
-
-void des_3cbc_encrypt(des_cblock *in,
- des_cblock *out,
- long length,
- des_key_schedule ks1,
- des_key_schedule ks2,
- des_key_schedule ks3,
- des_cblock ivec,
- int encrypt);
-
-unsigned long des_cbc_cksum(des_cblock *in,
- des_cblock *out,
- long length,
- des_key_schedule schedule,
- des_cblock *ivec);
-
-int des_ecb_encrypt(des_cblock *in,
- des_cblock *out,
- des_key_schedule schedule,
- int encrypt);
-
-void des_3ecb_encrypt(des_cblock *in,
- des_cblock *out,
- des_key_schedule ks1,
- des_key_schedule ks2,
- des_key_schedule ks3,
- int encrypt);
-
-void des_fixup_key_parity(register des_cblock key);
-int des_check_key_parity(register des_cblock key);
-
-int des_pcbc_encrypt(des_cblock *in,
- des_cblock *out,
- long length,
- des_key_schedule schedule,
- des_cblock ivec,
- int encrypt);
-
-int make_key_sched(des_cblock *key, des_key_schedule schedule);
-
-int des_key_sched(des_cblock k, des_key_schedule schedule);
-
-int des_new_random_key(des_cblock key);
-void des_init_random_number_generator(des_cblock key);
-void des_set_random_generator_seed(des_cblock key);
-void des_set_sequence_number(des_cblock new_sequence_number);
-void des_generate_random_block(des_cblock block);
-
-unsigned long des_quad_cksum(unsigned char *in,
- unsigned long *out,
- long length,
- int out_count,
- des_cblock *c_seed);
-
-int des_random_key(des_cblock *key);
-
-int des_read_password(des_cblock *k, char *prompt, int verify);
-int des_read_pw_string(char *s, int max, char *prompt, int verify);
-
-int des_string_to_key(char *str, des_cblock key);
-
-void des_cblock_print_file(des_cblock *x, FILE *fp);
-
-int des_is_weak_key(des_cblock key);
-
-char *des_crypt(const char *buf, const char *salt);
-char *des_fcrypt(const char *buf, const char *salt, char *ret);
-
-int des_set_key(des_cblock *key, des_key_schedule schedule);
-
-#if !GENERATINGCFM
-# pragma d0_pointers reset
-#endif
-
-/* CFM magic again */
-#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
-# pragma import reset
-#endif
-
-#endif /* DES_DEFS */
+++ /dev/null
-#include <CodeFragments.h>
-#include <Gestalt.h>
-#include <Errors.h>
-
-#include "des.h"
-#include "deslib.CFMGlue.h"
-
-/* These functions must obey CFM calling conventions. Functions which return
- pointers must return them in D0, not A0 like ThinkC static 68k does. This way
- we can call CFM functions by pointer from here (if they are called by pointer
- then the compiler can't tell ahead of time to do D0->A0 translation because it
- doesn't know what calling convention the functions use).
-
- Note that if it is necessary (if you don't use MPWC calling conventions)
- the D0->A0 translation will be done by the compiler in the places where
- the application calls these glue routines. */
-#pragma d0_pointers on
-
-/* Hardcode library fragment name here */
-#define kLibraryName "\pMIT_Â¥deslib"
-
-/* Private function prototypes */
-
-static OSErr Find_Symbol(
- Ptr* pSymAddr,
- Str255 pSymName,
- ProcInfoType pProcInfo);
-
-static pascal Boolean HaveCFM(void);
-
-static pascal OSErr GetSystemArchitecture(OSType *archType);
-
-
-/* This code is directly from Technote 1077 */
-/* changed Library name to be hardcoded at the top of the file
- instead in the middle of the code */
-
-/* Private functions */
-
-static pascal OSErr GetSystemArchitecture(OSType *archType)
-{
- static long sSysArchitecture = 0; // static so we only Gestalt once.
- OSErr tOSErr = noErr;
-
- *archType = kAnyCFragArch; // assume wild architecture
-
- // If we don't know the system architecture yet...
- if (sSysArchitecture == 0)
- // ...Ask Gestalt what kind of machine we are running on.
- tOSErr = Gestalt(gestaltSysArchitecture, &sSysArchitecture);
-
- if (tOSErr == noErr) // if no errors
- {
- if (sSysArchitecture == gestalt68k) // 68k?
- *archType = kMotorola68KCFragArch;
- else if (sSysArchitecture == gestaltPowerPC) // PPC?
- *archType = kPowerPCCFragArch;
- else
- tOSErr = gestaltUnknownErr; // who knows what might be next?
- }
- return tOSErr;
-}
-
-static pascal Boolean HaveCFM(void)
-{
- long response;
- return ( (Gestalt (gestaltCFMAttr, &response) == noErr) &&
- (((response >> gestaltCFMPresent) & 1) != 0));
-}
-
-static OSErr Find_Symbol(
- Ptr* pSymAddr,
- Str255 pSymName,
- ProcInfoType pProcInfo)
-{
- static CFragConnectionID sCID = 0;
- static OSType sArchType = kAnyCFragArch;
- static OSErr sOSErr = noErr;
-
- Str255 errMessage;
- Ptr mainAddr;
- CFragSymbolClass symClass;
- ISAType tISAType;
-
- if (sArchType == kAnyCFragArch) // if architecture is undefined...
- {
- sCID = 0; // ...force (re)connect to library
- sOSErr = GetSystemArchitecture(&sArchType); // determine architecture
- if (sOSErr != noErr)
- return sOSErr; // OOPS!
- }
-
- if (!HaveCFM()) {
- // If we don't have CFM68K, return a reasonable-looking error.
- sOSErr = cfragLibConnErr;
- return sOSErr;
- }
-
- if (sArchType == kMotorola68KCFragArch) // ...for CFM68K
- tISAType = kM68kISA | kCFM68kRTA;
- else if (sArchType == kPowerPCCFragArch) // ...for PPC CFM
- tISAType = kPowerPCISA | kPowerPCRTA;
- else
- sOSErr = gestaltUnknownErr; // who knows what might be next?
-
- if (sCID == 0) // If we haven't connected to the library yet...
- {
- // NOTE: The library name is hard coded here.
- // I try to isolate the glue code, one file per library.
- // I have had developers pass in the Library name to allow
- // plug-in type support. Additional code has to be added to
- // each entry points glue routine to support multiple or
- // switching connection IDs.
- sOSErr = GetSharedLibrary(kLibraryName, sArchType, kLoadCFrag,
- &sCID, &mainAddr, errMessage);
- if (sOSErr != noErr)
- return sOSErr; // OOPS!
- }
-
- // If we haven't looked up this symbol yet...
- if ((Ptr) *pSymAddr == (Ptr) kUnresolvedCFragSymbolAddress)
- {
- // ...look it up now
- sOSErr = FindSymbol(sCID,pSymName,pSymAddr,&symClass);
- if (sOSErr != noErr) // in case of error...
- // ...clear the procedure pointer
- *(Ptr*) &pSymAddr = (Ptr) kUnresolvedCFragSymbolAddress;
-# if !GENERATINGCFM // if this is classic 68k code...
- *pSymAddr = (Ptr)NewRoutineDescriptorTrap((ProcPtr) *pSymAddr,
- pProcInfo, tISAType); // ...create a routine descriptor...
-# endif
- }
- return sOSErr;
-}
-
-
-/* CFM Glue Code for exported functions! */
-
-/**** des_random_key ****/
-/* int des_random_key(des_cblock *key); */
-
-enum {
- des_random_key_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
-};
-
-typedef int (*des_random_key_ProcPtrType)(des_cblock *);
-int des_random_key (
- des_cblock * key)
-{
- static des_random_key_ProcPtrType des_random_key_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_random_key_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_random_key_ProcPtr, "\pdes_random_key", des_random_key_ProcInfo);
- if((Ptr) des_random_key_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_random_key_ProcPtr(key);
-}
-
-
-/**** des_cbc_cksum ****/
-/* unsigned long des_cbc_cksum(des_cblock *in, des_cblock *out, long length, des_key_schedule schedule, des_cblock *ivec); */
-
-enum {
- des_cbc_cksum_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(unsigned long)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(long)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(struct des_ks_struct *)))
- | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(des_cblock *)))
-};
-
-typedef unsigned long (*des_cbc_cksum_ProcPtrType)(des_cblock *, des_cblock *, long, des_key_schedule, des_cblock *);
-unsigned long des_cbc_cksum (
- des_cblock * in,
- des_cblock * out,
- long length,
- des_key_schedule schedule,
- des_cblock * ivec)
-{
- static des_cbc_cksum_ProcPtrType des_cbc_cksum_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_cbc_cksum_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_cbc_cksum_ProcPtr, "\pdes_cbc_cksum", des_cbc_cksum_ProcInfo);
- if((Ptr) des_cbc_cksum_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_cbc_cksum_ProcPtr(in, out, length, schedule, ivec);
-}
-
-
-/**** des_is_weak_key ****/
-/* int des_is_weak_key(des_cblock key); */
-
-enum {
- des_is_weak_key_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef int (*des_is_weak_key_ProcPtrType)(des_cblock);
-int des_is_weak_key (
- des_cblock key)
-{
- static des_is_weak_key_ProcPtrType des_is_weak_key_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_is_weak_key_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_is_weak_key_ProcPtr, "\pdes_is_weak_key", des_is_weak_key_ProcInfo);
- if((Ptr) des_is_weak_key_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_is_weak_key_ProcPtr(key);
-}
-
-
-/**** des_set_sequence_number ****/
-/* void des_set_sequence_number(des_cblock new_sequence_number); */
-
-enum {
- des_set_sequence_number_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef void (*des_set_sequence_number_ProcPtrType)(des_cblock);
-void des_set_sequence_number (
- des_cblock new_sequence_number)
-{
- static des_set_sequence_number_ProcPtrType des_set_sequence_number_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_set_sequence_number_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_set_sequence_number_ProcPtr, "\pdes_set_sequence_number", des_set_sequence_number_ProcInfo);
- if((Ptr) des_set_sequence_number_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_set_sequence_number_ProcPtr(new_sequence_number);
-}
-
-
-/**** des_fixup_key_parity ****/
-/* void des_fixup_key_parity(register des_cblock key); */
-
-enum {
- des_fixup_key_parity_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef void (*des_fixup_key_parity_ProcPtrType)(register des_cblock);
-void des_fixup_key_parity (
- register des_cblock key)
-{
- static des_fixup_key_parity_ProcPtrType des_fixup_key_parity_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_fixup_key_parity_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_fixup_key_parity_ProcPtr, "\pdes_fixup_key_parity", des_fixup_key_parity_ProcInfo);
- if((Ptr) des_fixup_key_parity_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_fixup_key_parity_ProcPtr(key);
-}
-
-
-/**** des_cbc_encrypt ****/
-/* int des_cbc_encrypt(des_cblock *in, des_cblock *out, long length, des_key_schedule schedule, des_cblock ivec, int encrypt); */
-
-enum {
- des_cbc_encrypt_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(long)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(struct des_ks_struct *)))
- | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(unsigned char *)))
- | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(int)))
-};
-
-typedef int (*des_cbc_encrypt_ProcPtrType)(des_cblock *, des_cblock *, long, des_key_schedule, des_cblock, int);
-int des_cbc_encrypt (
- des_cblock * in,
- des_cblock * out,
- long length,
- des_key_schedule schedule,
- des_cblock ivec,
- int encrypt)
-{
- static des_cbc_encrypt_ProcPtrType des_cbc_encrypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_cbc_encrypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_cbc_encrypt_ProcPtr, "\pdes_cbc_encrypt", des_cbc_encrypt_ProcInfo);
- if((Ptr) des_cbc_encrypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_cbc_encrypt_ProcPtr(in, out, length, schedule, ivec, encrypt);
-}
-
-
-/**** des_quad_cksum ****/
-/* unsigned long des_quad_cksum(unsigned char *in, unsigned long *out, long length, int out_count, des_cblock *c_seed); */
-
-enum {
- des_quad_cksum_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(unsigned long)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(long)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(des_cblock *)))
-};
-
-typedef unsigned long (*des_quad_cksum_ProcPtrType)(unsigned char *, unsigned long *, long, int, des_cblock *);
-unsigned long des_quad_cksum (
- unsigned char * in,
- unsigned long * out,
- long length,
- int out_count,
- des_cblock * c_seed)
-{
- static des_quad_cksum_ProcPtrType des_quad_cksum_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_quad_cksum_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_quad_cksum_ProcPtr, "\pdes_quad_cksum", des_quad_cksum_ProcInfo);
- if((Ptr) des_quad_cksum_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_quad_cksum_ProcPtr(in, out, length, out_count, c_seed);
-}
-
-
-/**** des_read_password ****/
-/* int des_read_password(des_cblock *k, char *prompt, int verify); */
-
-enum {
- des_read_password_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(int)))
-};
-
-typedef int (*des_read_password_ProcPtrType)(des_cblock *, char *, int);
-int des_read_password (
- des_cblock * k,
- char * prompt,
- int verify)
-{
- static des_read_password_ProcPtrType des_read_password_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_read_password_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_read_password_ProcPtr, "\pdes_read_password", des_read_password_ProcInfo);
- if((Ptr) des_read_password_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_read_password_ProcPtr(k, prompt, verify);
-}
-
-
-/**** des_ecb_encrypt ****/
-/* int des_ecb_encrypt(des_cblock *in, des_cblock *out, des_key_schedule schedule, int encrypt); */
-
-enum {
- des_ecb_encrypt_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct des_ks_struct *)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int)))
-};
-
-typedef int (*des_ecb_encrypt_ProcPtrType)(des_cblock *, des_cblock *, des_key_schedule, int);
-int des_ecb_encrypt (
- des_cblock * in,
- des_cblock * out,
- des_key_schedule schedule,
- int encrypt)
-{
- static des_ecb_encrypt_ProcPtrType des_ecb_encrypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_ecb_encrypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_ecb_encrypt_ProcPtr, "\pdes_ecb_encrypt", des_ecb_encrypt_ProcInfo);
- if((Ptr) des_ecb_encrypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_ecb_encrypt_ProcPtr(in, out, schedule, encrypt);
-}
-
-
-/**** des_3ecb_encrypt ****/
-/* void des_3ecb_encrypt(des_cblock *in, des_cblock *out, des_key_schedule ks1, des_key_schedule ks2, des_key_schedule ks3, int encrypt); */
-
-enum {
- des_3ecb_encrypt_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(des_key_schedule)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(des_key_schedule)))
- | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(des_key_schedule)))
- | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(int)))
-};
-
-typedef void (*des_3ecb_encrypt_ProcPtrType)(des_cblock *, des_cblock *, des_key_schedule, des_key_schedule, des_key_schedule, int);
-void des_3ecb_encrypt (
- des_cblock * in,
- des_cblock * out,
- des_key_schedule ks1,
- des_key_schedule ks2,
- des_key_schedule ks3,
- int encrypt)
-{
- static des_3ecb_encrypt_ProcPtrType des_3ecb_encrypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_3ecb_encrypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_3ecb_encrypt_ProcPtr, "\pdes_3ecb_encrypt", des_3ecb_encrypt_ProcInfo);
- if((Ptr) des_3ecb_encrypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_3ecb_encrypt_ProcPtr(in, out, ks1, ks2, ks3, encrypt);
-}
-
-
-/**** des_key_sched ****/
-/* int des_key_sched(des_cblock k, des_key_schedule schedule); */
-
-enum {
- des_key_sched_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(struct des_ks_struct *)))
-};
-
-typedef int (*des_key_sched_ProcPtrType)(des_cblock, des_key_schedule);
-int des_key_sched (
- des_cblock k,
- des_key_schedule schedule)
-{
- static des_key_sched_ProcPtrType des_key_sched_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_key_sched_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_key_sched_ProcPtr, "\pdes_key_sched", des_key_sched_ProcInfo);
- if((Ptr) des_key_sched_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_key_sched_ProcPtr(k, schedule);
-}
-
-
-/**** des_3pcbc_encrypt ****/
-/* void des_3pcbc_encrypt(des_cblock *input, des_cblock *output, long length, des_key_schedule schedule1, des_cblock ivec1, des_key_schedule schedule2, des_cblock ivec2, des_key_schedule schedule3, des_cblock ivec3, int encrypt); */
-/*
-enum {
- des_3pcbc_encrypt_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(long)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(struct des_ks_struct *)))
- | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(unsigned char *)))
- | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(struct des_ks_struct *)))
- | STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(unsigned char *)))
- | STACK_ROUTINE_PARAMETER(8, SIZE_CODE(sizeof(struct des_ks_struct *)))
- | STACK_ROUTINE_PARAMETER(9, SIZE_CODE(sizeof(unsigned char *)))
- | STACK_ROUTINE_PARAMETER(10, SIZE_CODE(sizeof(int)))
-};
-
-typedef void (*des_3pcbc_encrypt_ProcPtrType)(des_cblock *, des_cblock *, long, des_key_schedule, des_cblock, des_key_schedule, des_cblock, des_key_schedule, des_cblock, int);
-void des_3pcbc_encrypt (
- des_cblock * input,
- des_cblock * output,
- long length,
- des_key_schedule schedule1,
- des_cblock ivec1,
- des_key_schedule schedule2,
- des_cblock ivec2,
- des_key_schedule schedule3,
- des_cblock ivec3,
- int encrypt)
-{
- static des_3pcbc_encrypt_ProcPtrType des_3pcbc_encrypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_3pcbc_encrypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_3pcbc_encrypt_ProcPtr, "\pdes_3pcbc_encrypt", des_3pcbc_encrypt_ProcInfo);
- if((Ptr) des_3pcbc_encrypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_3pcbc_encrypt_ProcPtr(input, output, length, schedule1, ivec1, schedule2, ivec2, schedule3, ivec3, encrypt);
-}
-*/
-
-/**** make_key_sched ****/
-/* int make_key_sched(des_cblock *key, des_key_schedule schedule); */
-
-enum {
- make_key_sched_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(struct des_ks_struct *)))
-};
-
-typedef int (*make_key_sched_ProcPtrType)(des_cblock *, des_key_schedule);
-int make_key_sched (
- des_cblock * key,
- des_key_schedule schedule)
-{
- static make_key_sched_ProcPtrType make_key_sched_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) make_key_sched_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &make_key_sched_ProcPtr, "\pmake_key_sched", make_key_sched_ProcInfo);
- if((Ptr) make_key_sched_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return make_key_sched_ProcPtr(key, schedule);
-}
-
-
-/**** des_crypt ****/
-/* char *des_crypt(const char *buf, const char *salt); */
-
-enum {
- des_crypt_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(char *)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const char *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char *)))
-};
-
-typedef char * (*des_crypt_ProcPtrType)(const char *, const char *);
-char * des_crypt (
- const char * buf,
- const char * salt)
-{
- static des_crypt_ProcPtrType des_crypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_crypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_crypt_ProcPtr, "\pdes_crypt", des_crypt_ProcInfo);
- if((Ptr) des_crypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return(des_crypt_ProcPtr(buf, salt));
-}
-
-
-/**** des_set_random_generator_seed ****/
-/* void des_set_random_generator_seed(des_cblock key); */
-
-enum {
- des_set_random_generator_seed_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef void (*des_set_random_generator_seed_ProcPtrType)(des_cblock);
-void des_set_random_generator_seed (
- des_cblock key)
-{
- static des_set_random_generator_seed_ProcPtrType des_set_random_generator_seed_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_set_random_generator_seed_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_set_random_generator_seed_ProcPtr, "\pdes_set_random_generator_seed", des_set_random_generator_seed_ProcInfo);
- if((Ptr) des_set_random_generator_seed_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_set_random_generator_seed_ProcPtr(key);
-}
-
-
-/**** des_new_random_key ****/
-/* int des_new_random_key(des_cblock key); */
-
-enum {
- des_new_random_key_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef int (*des_new_random_key_ProcPtrType)(des_cblock);
-int des_new_random_key (
- des_cblock key)
-{
- static des_new_random_key_ProcPtrType des_new_random_key_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_new_random_key_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_new_random_key_ProcPtr, "\pdes_new_random_key", des_new_random_key_ProcInfo);
- if((Ptr) des_new_random_key_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_new_random_key_ProcPtr(key);
-}
-
-
-/**** des_set_key ****/
-/* int des_set_key(des_cblock *key, des_key_schedule schedule); */
-
-enum {
- des_set_key_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(struct des_ks_struct *)))
-};
-
-typedef int (*des_set_key_ProcPtrType)(des_cblock *, des_key_schedule);
-int des_set_key (
- des_cblock * key,
- des_key_schedule schedule)
-{
- static des_set_key_ProcPtrType des_set_key_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_set_key_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_set_key_ProcPtr, "\pdes_set_key", des_set_key_ProcInfo);
- if((Ptr) des_set_key_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_set_key_ProcPtr(key, schedule);
-}
-
-
-/**** des_generate_random_block ****/
-/* void des_generate_random_block(des_cblock block); */
-
-enum {
- des_generate_random_block_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef void (*des_generate_random_block_ProcPtrType)(des_cblock);
-void des_generate_random_block (
- des_cblock block)
-{
- static des_generate_random_block_ProcPtrType des_generate_random_block_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_generate_random_block_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_generate_random_block_ProcPtr, "\pdes_generate_random_block", des_generate_random_block_ProcInfo);
- if((Ptr) des_generate_random_block_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_generate_random_block_ProcPtr(block);
-}
-
-
-/**** des_fcrypt ****/
-/* char *des_fcrypt(const char *buf, const char *salt, char *ret); */
-
-enum {
- des_fcrypt_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(char *)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const char *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(char *)))
-};
-
-typedef char * (*des_fcrypt_ProcPtrType)(const char *, const char *, char *);
-char * des_fcrypt (
- const char * buf,
- const char * salt,
- char * ret)
-{
- static des_fcrypt_ProcPtrType des_fcrypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_fcrypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_fcrypt_ProcPtr, "\pdes_fcrypt", des_fcrypt_ProcInfo);
- if((Ptr) des_fcrypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_fcrypt_ProcPtr(buf, salt, ret);
-}
-
-
-/**** des_read_pw_string ****/
-/* int des_read_pw_string(char *s, int max, char *prompt, int verify); */
-
-enum {
- des_read_pw_string_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(char *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(char *)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int)))
-};
-
-typedef int (*des_read_pw_string_ProcPtrType)(char *, int, char *, int);
-int des_read_pw_string (
- char * s,
- int max,
- char * prompt,
- int verify)
-{
- static des_read_pw_string_ProcPtrType des_read_pw_string_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_read_pw_string_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_read_pw_string_ProcPtr, "\pdes_read_pw_string", des_read_pw_string_ProcInfo);
- if((Ptr) des_read_pw_string_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_read_pw_string_ProcPtr(s, max, prompt, verify);
-}
-
-
-/**** des_cblock_print_file ****/
-/* void des_cblock_print_file(des_cblock *x, FILE *fp); */
-
-enum {
- des_cblock_print_file_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(FILE *)))
-};
-
-typedef void (*des_cblock_print_file_ProcPtrType)(des_cblock *, FILE *);
-void des_cblock_print_file (
- des_cblock * x,
- FILE * fp)
-{
- static des_cblock_print_file_ProcPtrType des_cblock_print_file_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_cblock_print_file_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_cblock_print_file_ProcPtr, "\pdes_cblock_print_file", des_cblock_print_file_ProcInfo);
- if((Ptr) des_cblock_print_file_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_cblock_print_file_ProcPtr(x, fp);
-}
-
-
-/**** des_pcbc_encrypt ****/
-/* int des_pcbc_encrypt(des_cblock *in, des_cblock *out, long length, des_key_schedule schedule, des_cblock ivec, int encrypt); */
-
-enum {
- des_pcbc_encrypt_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(long)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(struct des_ks_struct *)))
- | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(unsigned char *)))
- | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(int)))
-};
-
-typedef int (*des_pcbc_encrypt_ProcPtrType)(des_cblock *, des_cblock *, long, des_key_schedule, des_cblock, int);
-int des_pcbc_encrypt (
- des_cblock * in,
- des_cblock * out,
- long length,
- des_key_schedule schedule,
- des_cblock ivec,
- int encrypt)
-{
- static des_pcbc_encrypt_ProcPtrType des_pcbc_encrypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_pcbc_encrypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_pcbc_encrypt_ProcPtr, "\pdes_pcbc_encrypt", des_pcbc_encrypt_ProcInfo);
- if((Ptr) des_pcbc_encrypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_pcbc_encrypt_ProcPtr(in, out, length, schedule, ivec, encrypt);
-}
-
-
-/**** des_check_key_parity ****/
-/* int des_check_key_parity(register des_cblock key); */
-
-enum {
- des_check_key_parity_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef int (*des_check_key_parity_ProcPtrType)(register des_cblock);
-int des_check_key_parity (
- register des_cblock key)
-{
- static des_check_key_parity_ProcPtrType des_check_key_parity_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_check_key_parity_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_check_key_parity_ProcPtr, "\pdes_check_key_parity", des_check_key_parity_ProcInfo);
- if((Ptr) des_check_key_parity_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_check_key_parity_ProcPtr(key);
-}
-
-
-/**** des_3cbc_encrypt ****/
-/* void des_3cbc_encrypt(des_cblock *in, des_cblock *out, long length, des_key_schedule ks1, des_key_schedule ks2, des_key_schedule ks3, des_cblock ivec, int encrypt); */
-
-enum {
- des_3cbc_encrypt_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(des_cblock *)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(long)))
- | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(des_key_schedule)))
- | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(des_key_schedule)))
- | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(des_key_schedule)))
- | STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(des_cblock)))
- | STACK_ROUTINE_PARAMETER(8, SIZE_CODE(sizeof(int)))
-};
-
-typedef void (*des_3cbc_encrypt_ProcPtrType)(des_cblock *, des_cblock *, long, des_key_schedule, des_key_schedule, des_key_schedule, des_cblock, int);
-void des_3cbc_encrypt (
- des_cblock * in,
- des_cblock * out,
- long length,
- des_key_schedule ks1,
- des_key_schedule ks2,
- des_key_schedule ks3,
- des_cblock ivec,
- int encrypt)
-{
- static des_3cbc_encrypt_ProcPtrType des_3cbc_encrypt_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_3cbc_encrypt_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_3cbc_encrypt_ProcPtr, "\pdes_3cbc_encrypt", des_3cbc_encrypt_ProcInfo);
- if((Ptr) des_3cbc_encrypt_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_3cbc_encrypt_ProcPtr(in, out, length, ks1, ks2, ks3, ivec, encrypt);
-}
-
-
-/**** des_string_to_key ****/
-/* int des_string_to_key(char *str, des_cblock key); */
-
-enum {
- des_string_to_key_ProcInfo = kThinkCStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(int)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(char *)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef int (*des_string_to_key_ProcPtrType)(char *, des_cblock);
-int des_string_to_key (
- char * str,
- des_cblock key)
-{
- static des_string_to_key_ProcPtrType des_string_to_key_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_string_to_key_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_string_to_key_ProcPtr, "\pdes_string_to_key", des_string_to_key_ProcInfo);
- if((Ptr) des_string_to_key_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- return des_string_to_key_ProcPtr(str, key);
-}
-
-
-/**** des_init_random_number_generator ****/
-/* void des_init_random_number_generator(des_cblock key); */
-
-enum {
- des_init_random_number_generator_ProcInfo = kThinkCStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(unsigned char *)))
-};
-
-typedef void (*des_init_random_number_generator_ProcPtrType)(des_cblock);
-void des_init_random_number_generator (
- des_cblock key)
-{
- static des_init_random_number_generator_ProcPtrType des_init_random_number_generator_ProcPtr = kUnresolvedCFragSymbolAddress;
-
- // if this symbol has not been setup yet...
- if((Ptr) des_init_random_number_generator_ProcPtr == (Ptr) kUnresolvedCFragSymbolAddress)
- Find_Symbol((Ptr *) &des_init_random_number_generator_ProcPtr, "\pdes_init_random_number_generator", des_init_random_number_generator_ProcInfo);
- if((Ptr) des_init_random_number_generator_ProcPtr != (Ptr) kUnresolvedCFragSymbolAddress)
- des_init_random_number_generator_ProcPtr(key);
-}
-
-
-Boolean DESLibraryIsPresent(void)
-{
- Ptr symAddr;
- return (Find_Symbol (&symAddr, "\pdes_cbc_encrypt", des_cbc_encrypt_ProcInfo)) == noErr;
-}
+++ /dev/null
-#ifndef __DESLIB_CFMGLUE__
-#define __DESLIB_CFMGLUE__
-
-/* Prototype for checking if the library is there */
-
-Boolean DESLibraryIsPresent(void);
-
-#endif /* __DESLIB_CFMGLUE__ */
\ No newline at end of file
+++ /dev/null
-/*
- Copyright (C) 1989 by the Massachusetts Institute of Technology
-
- Export of this software from the United States of America is assumed
- to require a specific license from the United States Government.
- It is the responsibility of any person or organization contemplating
- export to obtain such a license before exporting.
-
-WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
-distribute this software and its documentation for any purpose and
-without fee is hereby granted, provided that the above copyright
-notice appear in all copies and that both that copyright notice and
-this permission notice appear in supporting documentation, and that
-the name of M.I.T. not be used in advertising or publicity pertaining
-to distribution of the software without specific, written prior
-permission. M.I.T. makes no representations about the suitability of
-this software for any purpose. It is provided "as is" without express
-or implied warranty.
-
- */
+++ /dev/null
-Changes between CodeWarrior Pro 2 and MITAthena MSL project:
-
- - ÒMSL C.CFM68K DLL.mcpÓ renamed to ÒMIT C.CFM68K DLL.prjÓ
- - This document added to the project
- - ÒMSL MWRuntimeLibCFM68KÓ removed from the project
- - Changed settings in ÒMSL C.CFM68K DLLÓ target
- - Added ÒMIT C.CFM68K DLL.debugÓ target
-
-Changes to ÒMSL C.CFM68K DLLÓ target:
-
- - Added ÒMIT RuntimeLib.68KÓ
- - Name set to ÒMIT C.CFM68K DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Added Ò{Compiler Ä}:Metrowerks Standard Library:MSL C:Ó to user paths
- ¥¥¥ Important: this path must come after Ò{Project Ä}::Ó so that we can override
- ¥¥¥ original MSL with our own sources
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT CLib.68KÓ
- - Changed output file creator to '????'
- - Changed CFM68K fragment name to ÒMIT_¥MITCLibÓ
-
-Configuration of the ÒMIT C.CFM68K DLL.debugÓ target:
-
- - Added ÒMIT RuntimeLib.68K.debugÓ
- - Started by cloning ÒMIT C.CFM68K DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT CLib.68K.debugÓ
- - Peephole optimizer turned off
- - CSE optimizer turned off
- - Optimize for size turned off
- - Generating SYM files turned on
- - Changed CFM68K fragment name to ÒMIT_¥MIT CLib.debugÓ
+++ /dev/null
-Changes between CodeWarrior Pro 2 and MITAthena MSL project:
-
- - ÒMSL C.PPC DLL.mcpÓ renamed to ÒMIT C.PPC DLL.prjÓ
- - This document added to the project
- - ÒMSL Runtime PPC.DLLÓ removed from the project
- - Changed settings in ÒMSL C.PPC DLLÓ target
- - Added ÒMIT C.PPC DLL.debugÓ target
-
-Changes to ÒMSL C.PPC DLLÓ target:
-
- - Added ÒMIT RuntimeLib.PPCÓ
- - Name set to ÒMIT C.PPC DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Added Ò{Compiler Ä}:Metrowerks Standard Library:MSL C:Ó to user paths
- ¥¥¥ Important: this path must come after Ò{Project Ä}::Ó so that we can override
- ¥¥¥ original MSL with our own sources
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT CLib.PPCÓ
- - Changed output file creator to '????'
- - Changed PPC PEF fragment name to ÒMIT_¥MITCLibÓ
-
-Configuration of the ÒMIT C.PPC DLL.debugÓ target:
-
- - Added ÒMIT RuntimeLib.PPC.debugÓ
- - Started by cloning ÒMIT C.PPC DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT CLib.PPC.debugÓ
- - Instruction scheduling turned off
- - Global optimization turned off
- - Peephole optimization turned off
- - Generating SYM files turned on
- - Changed PPC PEF fragment name to ÒMIT_¥MITCLib.debugÓ
+++ /dev/null
-Changes between CodeWarrior Pro 2 and MITAthena MSL project:
-
- - ÒMSL MWRuntimeLibCFM68K.mcpÓ renamed to ÒMIT RuntimeCFM68K DLL.prjÓ
- - This document added to the project
- - Changed settings in ÒMSL MWRuntimeLibCFM68KÓ target
- - Added ÒMIT RuntimeCFM68K DLL.debugÓ target
-
-Changes to ÒMSL MWRuntimeLibCFM68KÓ target:
-
- - Target name set to ÒMIT RuntimeCFM68K DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Set user paths to:
- Ò{Project Ä}::Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Runtime CFM68K:(Sources):Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Common Sources:Ó
- ¥¥¥ Important: the compiler-relative paths must come after Ò{Project Ä}::Ó so that
- ¥¥¥ we can override original sources with our own
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT RuntimeLib.68KÓ
- - Changed output file creator to '????'
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLibÓ
-
-Configuration of the ÒMIT RuntimeCFM68K DLL.debugÓ target:
-
- - Started by cloning ÒMIT RuntimeCFM68K DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT RuntimeLib.68K.debugÓ
- - Peephole optimizer turned off
- - CSE optimizer turned off
- - Optimize for size turned off
- - Generating SYM files turned on
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLib.debugÓ
+++ /dev/null
-Changes between CodeWarrior Pro 2 and MITAthena MSL project:
-
- - ÒMSL RuntimePPC.mcpÓ renamed to ÒMIT RuntimePPC DLL.prjÓ
- - This document added to the project
- - Changed settings in ÒMSL RuntimePPC DLLÓ target
- - Added ÒMIT RuntimePPC.debugÓ target
-
-Changes to ÒMSL RuntimePPCÓ target:
-
- - Name set to ÒMIT RuntimePPC DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Set user paths to:
- Ò{Project Ä}::Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Runtime PPC:(Sources):Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Common Sources:Ó
- ¥¥¥ Important: the compiler-relative paths must come after Ò{Project Ä}::Ó so that
- ¥¥¥ we can override original sources with our own
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT RuntimeLib.PPCÓ
- - Changed output file creator to '????'
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLibÓ
-
-Configuration of the ÒMIT RuntimePPC DLL.debugÓ target:
-
- - Started by cloning ÒMIT RuntimePPC DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT RuntimeLib.PPC.debugÓ
- - Instruction scheduling turned off
- - Global optimization turned off
- - Peephole optimization turned off
- - Generating SYM files turned on
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLib.debugÓ
+++ /dev/null
-Changes between CodeWarrior Pro 4 and MITAthena MSL project:
-
- - ÒMSL C.CFM68K DLL.mcpÓ renamed to ÒMIT C.CFM68K DLL.prjÓ
- - This document added to the project
- - ÒMSL MWRuntimeLibCFM68KÓ removed from the project
- - Changed settings in ÒMSL C.CFM68K DLLÓ target
- - Added ÒMIT C.CFM68K DLL.debugÓ target
-
-Changes to ÒMSL C.CFM68K DLLÓ target:
-
- - Added ÒMIT RuntimeLib.68KÓ
- - Name set to ÒMIT C.CFM68K DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Added Ò{Compiler Ä}:Metrowerks Standard Library:MSL C:Ó to user paths
- ¥¥¥ Important: this path must come after Ò{Project Ä}::Ó so that we can override
- ¥¥¥ original MSL with our own sources
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT CLib.68KÓ
- - Changed output file creator to '????'
- - Global optimizations turned off
- - Changed CFM68K fragment name to ÒMIT_¥MITCLibÓ
-
-Configuration of the ÒMIT C.CFM68K DLL.debugÓ target:
-
- - Added ÒMIT RuntimeLib.68K.debugÓ
- - Started by cloning ÒMIT C.CFM68K DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT CLib.68K.debugÓ
- - Global optimizations turned off
- - Generating SYM files turned on
- - Changed CFM68K fragment name to ÒMIT_¥MIT CLib.debugÓ
+++ /dev/null
-Changes between CodeWarrior Pro 4 and MITAthena MSL project:
-
- - ÒMSL C.PPC DLL.mcpÓ renamed to ÒMIT C.PPC DLL.prjÓ
- - This document added to the project
- - ÒMSL Runtime PPC.DLLÓ removed from the project
- - Changed settings in ÒMSL C.PPC DLLÓ target
- - Added ÒMIT C.PPC DLL.debugÓ target
-
-Changes to ÒMSL C.PPC DLLÓ target:
-
- - Added ÒMIT RuntimeLib.PPCÓ
- - Name set to ÒMIT C.PPC DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Added Ò{Compiler Ä}:Metrowerks Standard Library:MSL C:Ó to user paths
- ¥¥¥ Important: this path must come after Ò{Project Ä}::Ó so that we can override
- ¥¥¥ original MSL with our own sources
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT CLib.PPCÓ
- - Changed output file creator to '????'
- - Global optimizations turned off (because of reports of optimizer bugs)
- - Changed PPC PEF fragment name to ÒMIT_¥MITCLibÓ
-
-Configuration of the ÒMIT C.PPC DLL.debugÓ target:
-
- - Added ÒMIT RuntimeLib.PPC.debugÓ
- - Started by cloning ÒMIT C.PPC DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT CLib.PPC.debugÓ
- - Instruction scheduling turned off
- - Global optimization turned off
- - Peephole optimization turned off
- - Global optimizations turned off (because of reports of optimizer bugs)
- - Generating SYM files turned on
- - Changed PPC PEF fragment name to ÒMIT_¥MITCLib.debugÓ
+++ /dev/null
-Changes between CodeWarrior Pro 4 and MITAthena MSL project:
-
- - ÒMSL MWRuntimeLibCFM68K.mcpÓ renamed to ÒMIT RuntimeCFM68K DLL.prjÓ
- - This document added to the project
- - Changed settings in ÒMSL MWRuntimeLibCFM68KÓ target
- - Added ÒMIT RuntimeCFM68K DLL.debugÓ target
-
-Changes to ÒMSL MWRuntimeLibCFM68KÓ target:
-
- - Target name set to ÒMIT RuntimeCFM68K DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Set user paths to:
- Ò{Project Ä}::Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Runtime CFM68K:(Sources):Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Common Sources:Ó
- ¥¥¥ Important: the compiler-relative paths must come after Ò{Project Ä}::Ó so that
- ¥¥¥ we can override original sources with our own
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT RuntimeLib.68KÓ
- - Changed output file creator to '????'
- - Global optimizations turned off
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLibÓ
-
-Configuration of the ÒMIT RuntimeCFM68K DLL.debugÓ target:
-
- - Started by cloning ÒMIT RuntimeCFM68K DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT RuntimeLib.68K.debugÓ
- - Global optimizations turned off
- - Generating SYM files turned on
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLib.debugÓ
+++ /dev/null
-Changes between CodeWarrior Pro 4 and MITAthena MSL project:
-
- - ÒMSL RuntimePPC.mcpÓ renamed to ÒMIT RuntimePPC DLL.prjÓ
- - This document added to the project
- - Changed settings in ÒMSL RuntimePPC DLLÓ target
- - Added ÒMIT RuntimePPC.debugÓ target
-
-Changes to ÒMSL RuntimePPCÓ target:
-
- - Name set to ÒMIT RuntimePPC DLLÓ
- - Output directory changed to Ò{Project Ä}::bin:Ó
- - Set user paths to:
- Ò{Project Ä}::Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Runtime PPC:(Sources):Ó
- Ò{Compiler Ä}:MacOS Support:Libraries:Runtime:Common Sources:Ó
- ¥¥¥ Important: the compiler-relative paths must come after Ò{Project Ä}::Ó so that
- ¥¥¥ we can override original sources with our own
- - Turned on ÒActivate BrowserÓ
- - Changed output file name to ÒMIT RuntimeLib.PPCÓ
- - Changed output file creator to '????'
- - GLobal optimizations turned off (because of reports of optimizer bugs)
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLibÓ
-
-Configuration of the ÒMIT RuntimePPC DLL.debugÓ target:
-
- - Started by cloning ÒMIT RuntimePPC DLLÓ target after making the above modifications
- - Changed output file name to ÒMIT RuntimeLib.PPC.debugÓ
- - Schedule instructions turned off
- - Peephole optimization turned off
- - Generating SYM files turned on
- - Global optimizations turned off
- - Changed PPC PEF fragment name to ÒMIT_¥MITRuntimeLib.debugÓ
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * kpropd.c (authorized_principal): make the acl file contain
+ etypes, and use that in the authorization process.
+
Wed Feb 18 16:27:28 1998 Tom Yu <tlyu@mit.edu>
* Makefile.in (thisconfigdir): Remove trailing slash.
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
/*
* slave/kpropd.c
*
PROTOTYPE((krb5_context,
int,
krb5_principal *,
+ krb5_enctype *,
struct sockaddr_in));
krb5_boolean authorized_principal
PROTOTYPE((krb5_context,
- krb5_principal));
+ krb5_principal,
+ krb5_enctype));
void recv_database
PROTOTYPE((krb5_context,
int,
krb5_data confmsg;
int lock_fd;
int omask;
+ krb5_enctype etype;
fromlen = sizeof (from);
if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
/*
* Now do the authentication
*/
- kerberos_authenticate(kpropd_context, fd, &client, from);
- if (!authorized_principal(kpropd_context, client)) {
+ kerberos_authenticate(kpropd_context, fd, &client, &etype, from);
+
+ if (!authorized_principal(kpropd_context, client, etype)) {
char *name;
if (retval = krb5_unparse_name(kpropd_context, client, &name)) {
* Figure out who's calling on the other end of the connection....
*/
void
-kerberos_authenticate(context, fd, clientp, sin)
+kerberos_authenticate(context, fd, clientp, etype, sin)
krb5_context context;
int fd;
krb5_principal * clientp;
+ krb5_enctype * etype;
struct sockaddr_in sin;
{
krb5_error_code retval;
exit(1);
}
+ *etype = ticket->enc_part.enctype;
+
if (debug) {
char * name;
+ char etypebuf[100];
if (retval = krb5_unparse_name(context, *clientp, &name)) {
com_err(progname, retval, "While unparsing client name");
exit(1);
}
- printf("authenticated client: %s\n", name);
+
+ if (retval = krb5_enctype_to_string(*etype, etypebuf,
+ sizeof(etypebuf))) {
+ com_err(progname, retval, "While unparsing ticket etype");
+ exit(1);
+ }
+
+ printf("authenticated client: %s (etype == %s)\n", name, etypebuf);
free(name);
}
+
krb5_free_ticket(context, ticket);
}
krb5_boolean
-authorized_principal(context, p)
+authorized_principal(context, p, auth_etype)
krb5_context context;
krb5_principal p;
+ krb5_enctype auth_etype;
{
- char *name;
+ char *name, *ptr;
char buf[1024];
krb5_error_code retval;
FILE *acl_file;
int end;
+ krb5_enctype acl_etype;
retval = krb5_unparse_name(context, p, &name);
if (retval)
end = strlen(buf) - 1;
if (buf[end] == '\n')
buf[end] = '\0';
- if (!strcmp(name, buf)) {
+ if (!strncmp(name, buf, strlen(name))) {
+ ptr = buf+strlen(name);
+
+ /* if the next character is not whitespace or nul, then
+ the match is only partial. continue on to new lines. */
+ if (*ptr && !isspace(*ptr))
+ continue;
+
+ /* otherwise, skip trailing whitespace */
+ for (; *ptr && isspace(*ptr); ptr++) ;
+
+ /* now, look for an etype string. if there isn't one,
+ return true. if there is an invalid string, continue.
+ If there is a valid string, return true only if it
+ matches the etype passed in, otherwise continue */
+
+ if ((*ptr) &&
+ ((retval = krb5_string_to_enctype(ptr, &acl_etype)) ||
+ (acl_etype != auth_etype)))
+ continue;
+
free(name);
fclose(acl_file);
return TRUE;
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * kdb5_mkdums.c: update to new crypto api
+
1998-05-06 Theodore Ts'o <tytso@rsts-11.mit.edu>
* kdb5_mkdums.c (argv): POSIX states that getopt returns -1
krb5_keyblock master_keyblock;
krb5_principal master_princ;
krb5_db_entry master_entry;
-krb5_encrypt_block master_encblock;
krb5_pointer master_random;
krb5_context test_context;
exit(1);
}
- krb5_use_enctype(test_context, &master_encblock, master_keyblock.enctype);
-
if (!dbname)
dbname = DEFAULT_KDB_FILE; /* XXX? */
}
}
- krb5_finish_random_key(test_context, &master_encblock, &master_random);
- krb5_finish_key(test_context, &master_encblock);
-
retval = krb5_db_fini(test_context);
memset((char *)master_keyblock.contents, 0, master_keyblock.length);
if (retval && retval != KRB5_KDB_DBNOTINITED) {
pwd.length = strlen(princ_name);
pwd.data = princ_name; /* must be able to regenerate */
- if ((retval = krb5_string_to_key(context, &master_encblock,
- &key, &pwd, &salt))) {
+ if ((retval = krb5_c_string_to_key(context, master_keyblock.enctype,
+ &pwd, &salt, &key))) {
com_err(progname,retval,"while converting password to key for '%s'",
princ_name);
krb5_free_data_contents(context, &salt);
goto error;
}
- if ((retval = krb5_dbekd_encrypt_key_data(context,&master_encblock,
+ if ((retval = krb5_dbekd_encrypt_key_data(context,&master_keyblock,
&key, NULL, 1,
newentry.key_data))) {
com_err(progname, retval, "while encrypting key for '%s'",
com_err(pname, retval, "while calculated master key salt");
return(1);
}
- if ((retval = krb5_string_to_key(test_context, &master_encblock,
- &master_keyblock, &pwd, &scratch))) {
+ if ((retval = krb5_c_string_to_key(test_context,
+ master_keyblock.enctype,
+ &pwd, &scratch,
+ &master_keyblock))) {
com_err(pname, retval,
"while transforming master key from password");
return(1);
free(scratch.data);
} else {
if ((retval = krb5_db_fetch_mkey(test_context, master_princ,
- &master_encblock, manual_mkey,
+ master_keyblock.enctype, manual_mkey,
FALSE, 0, NULL, &master_keyblock))) {
com_err(pname, retval, "while reading master key");
return(1);
return(1);
}
if ((retval = krb5_db_verify_master_key(test_context, master_princ,
- &master_keyblock, &master_encblock))){
+ &master_keyblock))){
com_err(pname, retval, "while verifying master key");
(void) krb5_db_fini(test_context);
return(1);
return(1);
}
- if ((retval = krb5_process_key(test_context,
- &master_encblock, &master_keyblock))) {
- com_err(pname, retval, "while processing master key");
- (void) krb5_db_fini(test_context);
- return(1);
- }
- if ((retval = krb5_init_random_key(test_context,
- &master_encblock, &master_keyblock,
- &master_random))) {
- com_err(pname, retval, "while initializing random key generator");
- krb5_finish_key(test_context, &master_encblock);
- (void) krb5_db_fini(test_context);
- return(1);
- }
mblock.max_life = master_entry.max_life;
mblock.max_rlife = master_entry.max_renewable_life;
mblock.expiration = master_entry.expiration;
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+ int inlen, outlen, i;
+ unsigned char *instr, *outstr;
+
+ if (argc != 3) {
+ fprintf(stderr, "%s: instr outlen\n", argv[0]);
+ exit(1);
+ }
+
+ instr = (unsigned char *) argv[1];
+ inlen = strlen(instr)*8;
+ outlen = atoi(argv[2]);
+ if (outlen%8) {
+ fprintf(stderr, "outlen must be a multiple of 8\n");
+ exit(1);
+ }
+
+ if ((outstr = (unsigned char *) malloc(outlen/8)) == NULL) {
+ fprintf(stderr, "ENOMEM\n");
+ exit(1);
+ }
+
+ krb5_nfold(inlen,instr,outlen,outstr);
+
+ printf("%d-fold(",outlen);
+ for (i=0; i<(inlen/8); i++)
+ printf("%02x",instr[i]);
+ printf(") = ");
+ for (i=0; i<(outlen/8); i++)
+ printf("%02x",outstr[i]);
+ printf("\n");
+
+ exit(0);
+}
+1998-10-27 Marc Horowitz <marc@mit.edu>
+
+ * kdb5_verify.c: update to new crypto api
+
1998-05-06 Theodore Ts'o <tytso@rsts-11.mit.edu>
* kdb5_verify.c (argv): POSIX states that getopt returns -1
goto errout;
}
- if ((retval = krb5_dbekd_decrypt_key_data(context, &master_encblock,
+ if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
kdbe.key_data, &db_key, NULL))) {
com_err(progname, retval, "while decrypting key for '%s'", princ_name);
goto errout;
}
free(scratch.data);
} else {
- if ((retval = krb5_db_fetch_mkey(context, master_princ, &master_encblock,
+ if ((retval = krb5_db_fetch_mkey(context, master_princ,
+ master_keyblock.enctype,
manual_mkey, FALSE, (char *) NULL, 0,
&master_keyblock))) {
com_err(pname, retval, "while reading master key");
return(1);
}
if ((retval = krb5_db_verify_master_key(context, master_princ,
- &master_keyblock,
- &master_encblock))) {
+ &master_keyblock))) {
com_err(pname, retval, "while verifying master key");
(void) krb5_db_fini(context);
return(1);
problem where an insertion into the middle of the linked
list didn't update a previous link. [krb5-libs/615]
+1998-07-12 Sam Hartman <hartmans@fundsxpress.com>
+
+ * Makefile.in: Add dependency on -lcom_err
+
Mon Mar 2 16:19:58 1998 Ezra Peisach <epeisach@mit.edu>
* Makefile.in: Integrate in the krb5 build tree rules.
LIB=profile
LIBMAJOR=1
LIBMINOR=0
+SHLIB_EXPDEPS = $(TOPLIBD)/libcom_err$(SHLIBEXT)
+SHLIB_EXPLIBS = -lcom_err
+SHLIB_DIRS = -L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
STOBJLISTS=OBJS.ST
all-unix:: includes test_parse test_profile
AC_PROG_AWK
KRB5_BUILD_LIBOBJS
KRB5_BUILD_PROGRAM
-KRB5_BUILD_LIBRARY
+KRB5_BUILD_LIBRARY_WITH_DEPS
V5_AC_OUTPUT_MAKEFILE
+
+1998-08-16 <hartmans@fundsxpress.com>
+
+ * Makefile.in (SHLIB_EXPDEPS): Depend on lib_comerr
+
1998-07-05 <hartmans@fundsxpress.com>
* update_utmp.c (pty_update_utmp): If the ut_exit differs test
SRCS=pty_err.c $(CFILES)
+SHLIB_EXPDEPS = \
+ $(TOPLIBD)/libcom_err$(SHLIBEXT)
+SHLIB_EXPLIBS= -lcom_err
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
DEPLIBS=
dnl
ADD_DEF(-DKERBEROS)
AC_CONST
-KRB5_BUILD_LIBRARY
+KRB5_BUILD_LIBRARY_WITH_DEPS
KRB5_BUILD_LIBOBJS
V5_AC_OUTPUT_MAKEFILE
char *line_ptr;
{
char **argv;
- int argc;
+ int argc, ret;
/* flush leading whitespace */
while (line_ptr[0] == ' ' || line_ptr[0] == '\t')
return 0;
/* look it up in the request tables, execute if found */
- return really_execute_command (sci_idx, argc, &argv);
+ ret = really_execute_command (sci_idx, argc, &argv);
+
+ free(argv);
+
+ return(ret);
}
+++ /dev/null
-Tue Mar 18 12:08:50 1997 Michael Graff <explorer@flame.org>
-
- * registry.h, registry.c: add.
-
-Thu Mar 13 20:17:12 1997 Michael Graff <explorer@flame.org>
-
- * gic.c, gic.h, vardlg.c, vardlg.h: Finish up the variable dialog box
- code.
-
-Thu Mar 6 21:45:05 1997 Michael Graff <explorer@flame.org>
-
- * gic.c, gic.h: Added to start using get_init_creds.
-
- * vardlg.c, vardlg.h: on-the-fly variable dialog building functions.
-
-
+++ /dev/null
-CFLAGS = $(CCOPTS2) $(DEFS)
-
-##DOSBUILDTOP = ..\..
-
-lib-windows: libwin.lib
-
-SRCS= vardlg.c gic.c registry.c
-
-OBJS= vardlg.obj gic.obj registry.obj
-
-libwin.lib: $(OBJS)
- lib /nologo /out:$*.lib $(OBJS)
-
-all-windows:: lib-windows
-
-clean-windows::
- $(RM) *.dll *.exp *.map *.lib *.obj
-
-install-windows::
+++ /dev/null
-/*
- * Copyright (C) 1997 Cygnus Solutions.
- *
- * Author: Michael Graff
- */
-
-#include <windows.h>
-#include <windowsx.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "krb5.h"
-
-#include "vardlg.h"
-#include "gic.h"
-
-/*
- * Steps performed:
- *
- * 1) Create the dialog with all the windows we will need
- * later. This is done by calling vardlg_build() from
- * gic_prompter().
- *
- * 2) Run the dialog from within gic_prompter(). If the return
- * value of the dialog is -1 or IDCANCEL, return an error.
- * Otherwise, return success.
- *
- * 3) From within the dialog initialization code, call
- * vardlg_config(), which will:
- *
- * a) Set all the label strings in all the entry labels and
- * the banner.
- *
- * b) Set the maximum input lengths on the entry fields.
- *
- * c) Calculate the size of the text used within the banner.
- *
- * d) Calculate the longest string of text used as a label.
- *
- * e) Resize each label and each entry within the dialog
- * to "look nice."
- *
- * f) Place the OK and perhaps the Cancel buttons at the bottom
- * of the dialog.
- *
- * 4) When the OK button is clicked, copy all the values from the
- * input fields and store them in the pointers we are given.
- * Also, set the actual lengths to what we collected from the
- * entries. Finally, call EndDialog(IDOK) to end the dialog.
- */
-
-/*
- * Yes, a global. It is a PITA to not use them in windows.
- */
-gic_data *gd;
-
-
-/*
- * initialize the dialog
- */
-static BOOL
-gic_dialog_init(HWND hwnd, HWND hwndFocus, LPARAM lParam)
-{
- vardlg_config(hwnd, gd->width, gd->banner, gd->num_prompts,
- gd->prompts, (WORD)(gd->id));
-
- return FALSE;
-}
-
-/*
- * process dialog "commands"
- */
-static void
-gic_dialog_command(HWND hwnd, int cid, HWND hwndCtl, UINT codeNotify)
-{
-
- int n;
- WORD id;
-
- /*
- * We are only interested in button clicks, and then only of
- * type IDOK or IDCANCEL.
- */
- if (codeNotify != BN_CLICKED)
- return;
- if (cid != IDOK && cid != IDCANCEL)
- return;
-
- /*
- * If we are canceled, wipe all the fields and return IDCANCEL.
- */
- if (cid == IDCANCEL) {
- EndDialog(hwnd, IDCANCEL);
- return;
- }
-
- /*
- * must be IDOK...
- */
- id = (gd->id + 2);
- for (n = 0 ; n < gd->num_prompts ; n++) {
- Edit_GetText(GetDlgItem(hwnd, id), gd->prompts[n].reply->data,
- gd->prompts[n].reply->length);
- gd->prompts[n].reply->length = strlen(gd->prompts[n].reply->data);
- id += 2;
- }
-
- EndDialog(hwnd, IDOK);
-}
-
-/*
- * The dialog callback.
- */
-static BOOL CALLBACK
-gic_dialog(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- switch (message) {
- HANDLE_MSG(hwnd, WM_INITDIALOG, gic_dialog_init);
-
- HANDLE_MSG(hwnd, WM_COMMAND, gic_dialog_command);
- }
-
- return FALSE;
-}
-
-
-/*
- * All the disgusting code to use the get_init_creds() functions in a
- * broken environment
- */
-krb5_error_code KRB5_CALLCONV
-gic_prompter(krb5_context ctx, void *data, const char *banner,
- int num_prompts, krb5_prompt prompts[])
-{
- int rc;
- void *dlg;
-
- gd = data;
-
- gd->banner = banner;
- gd->num_prompts = num_prompts;
- gd->prompts = prompts;
- if (gd->width == 0)
- gd->width = 450;
-
- dlg = vardlg_build((WORD)(gd->width), gd->banner, (WORD)num_prompts, prompts, (WORD)(gd->id));
-
- rc = DialogBoxIndirect(gd->hinstance, (LPDLGTEMPLATE)dlg, gd->hwnd, gic_dialog);
-
- if (rc != IDOK)
- return 1;
-
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (C) 1997 Cygnus Solutions
- *
- * Author: Michael Graff
- */
-
-#ifndef _WINDOWS_LIB_GIC_H
-#define _WINDOWS_LIB_GIC_H
-
-#include <windows.h>
-#include <windowsx.h>
-
-#include "krb5.h"
-
-typedef struct {
- HINSTANCE hinstance; /* application instance */
- HWND hwnd; /* parent window */
- WORD id; /* starting ID */
- WORD width; /* max width of the dialog box */
- const char *banner; /* the banner */
- WORD num_prompts; /* the number of prompts we were passed */
- krb5_prompt *prompts; /* the prompts themselves */
-} gic_data;
-
-krb5_error_code KRB5_CALLCONV gic_prompter(krb5_context, void *, const char *,
- int, krb5_prompt []);
-
-#endif /* _WINDOWS_LIB_GIC_H */
+++ /dev/null
-/*
- * Copyright (c) 1997 Cygnus Solutions
- *
- * Author: Michael Graff
- */
-
-#include <windows.h>
-#include <windowsx.h>
-
-#include "registry.h"
-
-HKEY
-registry_open(HKEY hkey, char *base, REGSAM sam)
-{
- HKEY k = INVALID_HANDLE_VALUE;
- DWORD err;
-
- /*
- * if the base path is null, return the already open key in hkey
- */
- if (base == NULL)
- return hkey;
-
- err = RegOpenKeyEx(hkey, base, 0, sam, &hkey);
- if (err != ERROR_SUCCESS)
- return INVALID_HANDLE_VALUE;
-
- return hkey;
-}
-
-void
-registry_close(HKEY hkey)
-{
- CloseHandle(hkey);
-}
-
-HKEY
-registry_key_create(HKEY hkey, char *sub, REGSAM sam)
-{
- HKEY key;
- DWORD err;
- DWORD disp;
-
- err = RegCreateKeyEx(hkey, sub, 0, 0, REG_OPTION_NON_VOLATILE, sam,
- NULL, &key, &disp);
- if (err != ERROR_SUCCESS)
- return INVALID_HANDLE_VALUE;
-
- return key;
-}
-
-int
-registry_key_delete(HKEY hkey, char *sub)
-{
- DWORD err;
-
- err = RegDeleteKey(hkey, sub);
- if (err != ERROR_SUCCESS)
- return -1;
-
- return 0;
-}
-
-int
-registry_string_get(HKEY hkey, char *sub, char **val)
-{
- DWORD err;
- DWORD type;
- DWORD datasize;
-
- err = RegQueryValueEx(hkey, sub, 0, &type, 0, &datasize);
- if (err != ERROR_SUCCESS || type != REG_SZ) {
- *val = NULL;
- return -1;
- }
-
- *val = malloc(datasize);
- if (*val == NULL)
- return -1;
-
- err = RegQueryValueEx(hkey, sub, 0, &type, *val, &datasize);
- if (err != ERROR_SUCCESS) {
- free(*val);
- *val = NULL;
- return -1;
- }
-
- return 0;
-}
-
-int
-registry_dword_get(HKEY hkey, char *sub, DWORD *val)
-{
- DWORD err;
- DWORD type;
- DWORD datasize;
-
- err = RegQueryValueEx(hkey, sub, 0, &type, 0, &datasize);
- if (err != ERROR_SUCCESS || type != REG_DWORD) {
- *val = 0;
- return -1;
- }
-
- err = RegQueryValueEx(hkey, sub, 0, &type, (BYTE *)val, &datasize);
- if (err != ERROR_SUCCESS) {
- *val = 0;
- return -1;
- }
-
- return 0;
-}
-
-int
-registry_string_set(HKEY hkey, char *sub, char *x)
-{
- DWORD err;
-
- err = RegSetValueEx(hkey, sub, 0, REG_SZ, (BYTE *)x, strlen(x) + 1);
- if (err != ERROR_SUCCESS)
- return -1;
-
- return 0;
-}
-
-int
-registry_dword_set(HKEY hkey, char *sub, DWORD x)
-{
- DWORD err;
-
- err = RegSetValueEx(hkey, sub, 0, REG_DWORD, (CONST BYTE *)&x, sizeof(DWORD));
- if (err != ERROR_SUCCESS)
- return -1;
-
- return 0;
-}
-
-int
-registry_keyval_dword_set(HKEY hkey, char *base, char *sub, DWORD val)
-{
- HKEY k;
- int err;
-
- k = registry_open(hkey, base, KEY_WRITE);
- if (k == INVALID_HANDLE_VALUE)
- return -1;
-
- err = registry_dword_set(k, sub, val);
-
- registry_close(k);
-
- return err;
-}
-
-int
-registry_keyval_dword_get(HKEY hkey, char *base, char *sub, DWORD *val)
-{
- HKEY k;
- int err;
-
- k = registry_open(hkey, base, KEY_READ);
- if (k == INVALID_HANDLE_VALUE)
- return -1;
-
- err = registry_dword_get(k, sub, val);
-
- registry_close(k);
-
- return err;
-}
-
-int
-registry_keyval_string_get(HKEY hkey, char *base, char *sub, char **val)
-{
- HKEY k;
- int err;
-
- k = registry_open(hkey, base, KEY_READ);
- if (k == INVALID_HANDLE_VALUE) {
- *val = NULL;
- return -1;
- }
-
- err = registry_string_get(k, sub, val);
-
- registry_close(k);
-
- return err;
-}
-
-int
-registry_keyval_string_set(HKEY hkey, char *base, char *sub, char *val)
-{
- HKEY k;
- int err;
-
- k = registry_open(hkey, base, KEY_WRITE);
- if (k == INVALID_HANDLE_VALUE)
- return -1;
-
- err = registry_string_set(k, sub, val);
-
- registry_close(k);
-
- return err;
-}
-
-int
-registry_value_delete(HKEY hkey, char *sub)
-{
- if (RegDeleteValue(hkey, sub))
- return -1;
-
- return 0;
-}
-
-int
-registry_keyval_delete(HKEY hkey, char *base, char *sub)
-{
- HKEY k;
- int err;
-
- k = registry_open(hkey, base, KEY_WRITE);
- if (k == INVALID_HANDLE_VALUE)
- return -1;
-
- err = registry_value_delete(k, sub);
-
- registry_close(k);
-
- return err;
-}
+++ /dev/null
-/*
- * Copyright (c) 1997 Cygnus Solutions
- *
- * Author: Michael Graff
- */
-
-#ifndef LIB_WINDOWS_REGISTRY_H
-#define LIB_WINDOWS_REGISTRY_H
-
-#include <windows.h>
-#include <windowsx.h>
-
-HKEY registry_open(HKEY, char *, REGSAM);
-void registry_close(HKEY);
-HKEY registry_key_create(HKEY, char *, REGSAM);
-int registry_key_delete(HKEY, char *);
-int registry_string_get(HKEY, char *, char **);
-int registry_dword_get(HKEY, char *, DWORD *);
-int registry_string_set(HKEY, char *, char *);
-int registry_dword_set(HKEY, char *, DWORD);
-int registry_keyval_dword_set(HKEY, char *, char *, DWORD);
-int registry_keyval_dword_get(HKEY, char *, char *, DWORD *);
-int registry_keyval_string_get(HKEY, char *, char *, char **);
-int registry_keyval_string_set(HKEY, char *, char *, char *);
-int registry_value_delete(HKEY, char *);
-int registry_keyval_delete(HKEY, char *, char *);
-
-#define CYGNUS_SOLUTIONS "SOFTWARE\\Cygnus Solutions"
-
-#define KERBNET_SANS_VERSION CYGNUS_SOLUTIONS "\\Kerbnet"
-#define KERBNET_BASE KERBNET_SANS_VERSION "\\1"
-
-#define KERBNET_TELNET_BASE KERBNET_BASE "\\telnet"
-#define KERBNET_TELNET_HOST KERBNET_TELNET_BASE "\\hosts"
-
-#define KERBNET_CNS_BASE KERBNET_BASE "\\cns"
-
-#define KERBNET_HOME "KERBNET_HOME"
-
-#endif /* LIB_WINDOWS_REGISTRY_H */
+++ /dev/null
-/*
- * Dialog box building for various numbers of (label, entry) fields.
- *
- * This code is somewhat hardcoded to build boxes for the krb5_get_init_creds()
- * function.
- *
- * Copyright (C) 1997 Cygnus Solutions.
- *
- * Author: Michael Graff
- */
-
-#include <windows.h>
-#include <windowsx.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "krb5.h"
-#include "vardlg.h"
-
-/*
- * a hack, I know... No error checking below, either.
- */
-static unsigned char dlg[DLG_BUF];
-
-/*
- * Add a WORD (16-bit int) to the buffer. Return the number of characters
- * added.
- */
-static int
-ADD_WORD(unsigned char *p, WORD w)
-{
- *((WORD *)p) = w;
-
- return 2;
-}
-
-static int
-ADD_DWORD(unsigned char *p, DWORD dw)
-{
- *((DWORD *)p) = dw;
-
- return 4;
-}
-
-static int
-ADD_UNICODE_STRING(unsigned char *p, const char *s)
-{
- WORD *w;
- int i;
- int len;
-
- w = (WORD *)p;
-
- len = strlen(s) + 1; /* copy the null, too */
-
- for (i = 0 ; i < len ; i++)
- *w++ = *s++;
-
- return (len * 2);
-}
-
-#define DWORD_ALIGN(p) { while ((DWORD)p % 4) *p++ = 0x00; }
-
-static int
-ADD_DLGTEMPLATE(unsigned char *dlg, short x, short y, short cx, short cy,
- const char *caption, const char *fontname, WORD fontsize,
- WORD n)
-{
- unsigned char *p;
- DLGTEMPLATE dlt;
-
- p = dlg;
-
- dlt.style = (DS_MODALFRAME | WS_POPUP);
- if (caption != NULL)
- dlt.style |= WS_CAPTION;
- if (fontname != NULL)
- dlt.style |= DS_SETFONT;
- dlt.dwExtendedStyle = 0;
- dlt.cdit = n;
- dlt.x = x;
- dlt.y = y;
- dlt.cx = cx;
- dlt.cy = cy;
- memcpy(p, &dlt, sizeof(dlt));
- p += sizeof(dlt);
-
- p += ADD_WORD(p, 0x0000); /* menu == none */
-
- p += ADD_WORD(p, 0x0000); /* class == default? */
-
- if (caption != NULL)
- p += ADD_UNICODE_STRING(p, caption);
- else
- p += ADD_WORD(p, 0x0000);
-
- if (fontname != NULL) {
- p += ADD_WORD(p, fontsize);
- p += ADD_UNICODE_STRING(p, fontname);
- }
-
- DWORD_ALIGN(p);
-
- return (p - dlg);
-}
-
-static int
-ADD_DLGITEM(unsigned char *dlg, short x, short y, short cx, short cy,
- const char *label, WORD id, WORD type, DWORD style)
-{
- unsigned char *p;
- DLGITEMTEMPLATE dit;
-
- p = dlg;
-
- dit.style = style;
- dit.dwExtendedStyle = 0;
- dit.x = x;
- dit.y = y;
- dit.cx = cx;
- dit.cy = cy;
- dit.id = id;
- memcpy(p, &dit, sizeof(dit));
- p += sizeof(dit);
-
- p += ADD_WORD(p, 0xffff);
- p += ADD_WORD(p, type);
-
- p += ADD_UNICODE_STRING(p, label);
-
- /*
- * creation data? For now, just make this empty, like the resource
- * compiler does.
- */
- p += ADD_WORD(p, 0x0000);
-
- DWORD_ALIGN(p);
-
- return (p - dlg);
-}
-
-#define ADD_DLGITEM_defpushbutton(a, b, c, d, e, f, g) \
- ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0080, 0x50010001);
-
-#define ADD_DLGITEM_pushbutton(a, b, c, d, e, f, g) \
- ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0080, 0x50010000);
-
-#define ADD_DLGITEM_left_static(a, b, c, d, e, f, g) \
- ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020000);
-
-#define ADD_DLGITEM_centered_static(a, b, c, d, e, f, g) \
- ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020001);
-
-#define ADD_DLGITEM_right_static(a, b, c, d, e, f, g) \
- ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020002);
-
-#define ADD_DLGITEM_entry(a, b, c, d, e, f, g) \
- ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0081, 0x50810080);
-
-#define ADD_DLGITEM_hidden_entry(a, b, c, d, e, f, g) \
- ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0081, 0x508100a0);
-
-
-/*
- * "build" the dialog box. In this bit of code, we create the dialog box,
- * create the OK button, and a static label for the banner text.
- *
- * If there are items, we also create a Cancel button and one (label, entry)
- * fields for each item.
- */
-void *
-vardlg_build(WORD cx, const char *banner, WORD n, krb5_prompt prompts[],
- WORD id)
-{
- unsigned char *p;
- WORD i;
-
- p = dlg; /* global */
-
- if (cx < MIN_WIDTH)
- cx = MIN_WIDTH;
- if (cx > MAX_WIDTH)
- cx = MAX_WIDTH;
-
- /*
- * Store the dialog template
- */
- p += ADD_DLGTEMPLATE(p, 0, 0, cx, 0, "KerbNet", "MS Sans Serif", 8,
- (WORD)(n * 2 + 3));
-
- /*
- * Create a label for the banner. This will be ID (id).
- */
- p += ADD_DLGITEM_left_static(p, 0, 0, 0, 0, "", id++);
-
- /*
- * Each label field is ID (id + 1) + (item * 2), and each entry field
- * is (id + 2) + (item * 2)
- */
- for (i = 0 ; i < n ; i++) {
- p += ADD_DLGITEM_right_static(p, 0, 0, 0, 0, "", id++);
- if (prompts[i].hidden) {
- p += ADD_DLGITEM_hidden_entry(p, 0, 0, 0, 0, "", id++);
- } else {
- p += ADD_DLGITEM_entry(p, 0, 0, 0, 0, "", id++);
- }
- }
-
- /*
- * Create the OK and Cancel buttons.
- */
- p += ADD_DLGITEM_defpushbutton(p, 0, 0, 0, 0,
- "OK", IDOK);
- if (n != 0)
- p += ADD_DLGITEM_pushbutton(p, 0, 0, 0, 0,
- "Cancel", IDCANCEL);
-
- return dlg;
-}
-
-#define SPACE_Y 4 /* logical units */
-#define SPACE_X 4 /* logical units */
-#define ENTRY_PX 120 /* pixels */
-#define BUTTON_PX 70 /* pixels */
-#define BUTTON_PY 30 /* pixels */
-
-void
-vardlg_config(HWND hwnd, WORD width, const char *banner, WORD num_prompts,
- krb5_prompt *prompts, WORD id)
-{
- int n;
- WORD cid;
- HDC hdc;
- SIZE csize;
- SIZE maxsize;
- LONG cx, cy;
- LONG ccx, ccy;
- LONG space_x, space_y;
- LONG max_x, max_y;
- LONG banner_y;
- RECT rect;
- int done;
- const char *p;
-
- /*
- * First, set the banner's text.
- */
- Static_SetText(GetDlgItem(hwnd, id), banner);
-
- /*
- * Next, run through the items and set their static text.
- * Also, set the corresponding edit string and set the
- * maximum input length.
- */
- cid = (id + 1);
-
- for (n = 0 ; n < num_prompts ; n++) {
- Static_SetText(GetDlgItem(hwnd, cid), prompts[n].prompt);
- cid++;
- Edit_SetText(GetDlgItem(hwnd, cid), "");
- Edit_LimitText(GetDlgItem(hwnd, cid), prompts[n].reply->length);
- cid++;
- }
-
- /*
- * Now run through the entry fields and find the longest string.
- */
- maxsize.cx = maxsize.cy = 0;
- cid = (id + 1);
- hdc = GetDC(GetDlgItem(hwnd, cid)); /* assume one label is the same as all the others */
-
- for (n = 0 ; n < num_prompts ; n++) {
- GetTextExtentPoint32(hdc, prompts[n].prompt, strlen(prompts[n].prompt), &csize);
- if (csize.cx > maxsize.cx)
- maxsize.cx = csize.cx;
- if (csize.cy > maxsize.cy)
- maxsize.cy = csize.cy;
- }
-
-#if 0
- /*
- * convert the maximum values into pixels. Ugh.
- */
- rect.left = 0;
- rect.top = 0;
- rect.right = maxsize.cx;
- rect.bottom = maxsize.cy;
- MapDialogRect(hwnd, &rect);
-
- max_x = rect.right;
- max_y = rect.bottom;
-#else
- max_x = maxsize.cx;
- max_y = (long)(((double)maxsize.cy) * 1.5);
-#endif
-
- /*
- * convert the spacing values, too. Ugh. Ugh.
- */
- rect.left = 0;
- rect.top = 0;
- rect.right = SPACE_X;
- rect.bottom = SPACE_Y;
- MapDialogRect(hwnd, &rect);
-
- space_x = rect.right;
- space_y = rect.bottom;
-
- /*
- * Now we know the maximum length of the string for the entry labels. Guestimate
- * that the entry fields should be ENTRY_PX pixels long and resize the dialog
- * window to fit the longest string plus the entry fields (plus a little for the
- * spacing between the edges of the windows and the static and edit fields, and
- * between the static and edit fields themselves.)
- */
- cx = max_x + ENTRY_PX + (space_x * 3);
- cy = (max_y + space_y) * num_prompts;
-
- /*
- * resize the dialog box itself (take 1)
- */
- SetWindowPos(hwnd, HWND_TOPMOST,
- 0, 0,
- cx + 10, cy + 30,
- SWP_NOMOVE);
-
- /*
- * position the dialog items. First, the banner. (take 1)
- */
- SetWindowPos(GetDlgItem(hwnd, id), HWND_BOTTOM,
- space_x, space_y,
- (cx - space_x * 2), max_y,
- 0);
-
- /*
- * Now that the window for the banner is in place, convert the width into logical units
- * and find out how many lines we need to reserve room for.
- */
- done = 0;
- p = banner;
- banner_y = 0;
-
- do {
- int nFit;
- int pDx[128];
-
- hdc = GetDC(GetDlgItem(hwnd, id));
-
- GetTextExtentExPoint(hdc, p, strlen(p), cx, &nFit,
- pDx, &csize);
-
- banner_y += csize.cy;
-
- p += nFit;
-
- } while (*p != 0);
-
- banner_y += space_y;
-
- /*
- * position the banner (take 2)
- */
- SetWindowPos(GetDlgItem(hwnd, id), HWND_BOTTOM,
- space_x, space_y,
- (cx - space_x * 2), banner_y,
- 0);
-
- /*
- * Don't forget to include the banner estimate and the buttons, too. Once again,
- * assume the buttons are BUTTON_PY pixels high. The extra three space_y's are
- * for between the top of the dialog and the banner, between the banner and the
- * first label, and between the buttons and the bottom of the screen.
- */
- cy += banner_y + BUTTON_PY + (space_y * 3);
-
- /*
- * resize the dialog box itself (Again... ugh!)
- */
- SetWindowPos(hwnd, HWND_TOPMOST,
- 0, 0,
- cx + 10, cy + 30,
- SWP_NOMOVE);
-
- cid = (id + 1);
- ccy = banner_y + (space_y * 2);
- ccx = max_x + (space_x * 2); /* where the edit fields start */
-
- for (n = 0 ; n < num_prompts ; n++) {
- SetWindowPos(GetDlgItem(hwnd, cid), HWND_BOTTOM,
- space_x, ccy,
- max_x, max_y, 0);
- cid++;
- SetWindowPos(GetDlgItem(hwnd, cid), HWND_BOTTOM,
- ccx, ccy,
- ENTRY_PX, max_y - 3, 0);
- cid++;
- ccy += (max_y + space_y);
- }
-
- /*
- * Now the buttons. If there are any entries we will have both an OK and a
- * Cancel button. If we don't have any entries, we will have only an OK.
- */
- if (num_prompts == 0) {
- SetWindowPos(GetDlgItem(hwnd, IDOK), HWND_BOTTOM,
- (cx / 2), cy - space_y - BUTTON_PY,
- BUTTON_PX, BUTTON_PY, 0);
- } else {
- SetWindowPos(GetDlgItem(hwnd, IDOK), HWND_BOTTOM,
- space_x, cy - space_y - BUTTON_PY,
- BUTTON_PX, BUTTON_PY, 0);
- SetWindowPos(GetDlgItem(hwnd, IDCANCEL), HWND_BOTTOM,
- cx - space_x - BUTTON_PX, cy - space_y - BUTTON_PY,
- BUTTON_PX, BUTTON_PY, 0);
- }
-
- return;
-}
-
-/*
- * To use these functions, first create the dialog box and entries.
- * You will always get an OK button. If there are at least one item,
- * you will also get a cancel button. The OK button is IDOK, and the cancel
- * button is IDCANCEL, as usual.
- *
- * After calling bld_dlg, the banner will have ID "id", and the labels
- * will be "1 + id + i * 2" (i is the entry number, starting with zero) and
- * the entries will be "2 + id + i * 2".
- *
- * unsigned char *dlg = vardlg_build(minwidth, banner, num_prompts,
- * krb5_prompt[], id);
- *
- * Then, "run" the dialog using:
- *
- * rc = DialogBoxIndirect(hinstance, (LPDLGTEMPLATE)dlg,
- * HWND_DESKTOP, myDialogProc);
- *
- * Note that the vardlg_build function uses a static data area and so cannot
- * be used more than once before the DialogBoxIndirect() procedure is called.
- * I assume windows won't need that area after that call is complete.
- *
- * In the dialog's _initialization_ procedure, call
- *
- * vardlg_config(hwnd, banner, num_prompts, krb5_prompt[], id);
- *
- * This function will resize the various elements of the dialog and fill in the
- * labels.
- */
+++ /dev/null
-/*
- * Copyright (C) 1997 Cygnus Solutions
- *
- * Author: Michael Graff
- */
-
-#ifndef _WINDOWS_LIB_VARDLG_H
-#define _WINDOWS_LIB_VARDLG_H
-
-#include <windows.h>
-#include <windowsx.h>
-
-#define DLG_BUF 4096
-
-/*
- * The minimum and maximum dialog box widths we will allow.
- */
-#define MIN_WIDTH 350
-#define MAX_WIDTH 600
-
-/*
- * "build" the dialog box. In this bit of code, we create the dialog box,
- * create the OK button, and a static label for the banner text.
- *
- * If there are items, we also create a Cancel button and one (label, entry)
- * fields for each item.
- */
-void *vardlg_build(WORD, const char *, WORD, krb5_prompt *, WORD);
-
-void vardlg_config(HWND, WORD, const char *, WORD, krb5_prompt *, WORD);
-
-#endif /* _WINDOWS_LIB_VARDLG_H */