dh_installchangelogs: adjust to use ckc301.txt. changelog: explain -O1 usage
[ckermit.git] / ckuath.c
1 char *ckathv = "Authentication, 9.0.235, 16 Mar 2010";
2 /*
3   C K U A T H . C  --  Authentication for C-Kermit
4
5   Copyright (C) 1999, 2010,
6     Trustees of Columbia University in the City of New York.
7     All rights reserved.  See the C-Kermit COPYING.TXT file or the
8     copyright text in the ckcmai.c module for disclaimer and permissions.
9
10     Author:  Jeffrey E Altman (jaltman@secure-endpoints.com)
11                Secure Endpoints Inc., New York City
12 */
13 /*
14  * Additional copyrights included with affected code.
15  */
16
17 #ifdef HEIMDAL
18 /*
19   Turned off User to User support
20   Turned off KDESTROY support
21   Turned off KLIST support
22   Turned off krb5_prompter() support
23   Turned off ticket validation
24   Turned off ticket renewal
25   Turned off alternative cache support in k5_get_ccache()
26
27   Remaining link problems:
28
29   ckuath.o: In function `ck_krb5_initTGT':
30   ckuath.o(.text+0x50c2): undefined reference to `krb5_string_to_deltat'
31   ckuath.o(.text+0x516d): undefined reference to `krb5_string_to_deltat'
32   ckuath.o(.text+0x51ef): undefined reference to `krb5_string_to_deltat'
33 */
34 #endif /* HEIMDAL */
35
36 /*
37  * Implements Kerberos 4/5, SRP, SSL, NTLM authentication and START_TLS
38  */
39
40 #include "ckcsym.h"
41 #include "ckcdeb.h"
42
43 #ifdef CK_SECURITY
44
45 #define CKUATH_C
46 #include "ckcker.h"
47 #include "ckuusr.h"
48 #include "ckucmd.h"                             /* For struct keytab */
49 #include "ckcnet.h"
50 #include "ckctel.h"
51
52 char szUserNameRequested[UIDBUFLEN+1];    /* for incoming connections */
53 char szUserNameAuthenticated[UIDBUFLEN+1];/* for incoming connections */
54 char szHostName[UIDBUFLEN+1];
55 char szUserName[UIDBUFLEN+1];
56 static char szIP[16];
57 static int  validUser = AUTH_REJECT;    /* User starts out invalid */
58 int authentication_version = AUTHTYPE_NULL;
59 int accept_complete = 0;
60
61 #ifdef CK_AUTHENTICATION
62 #ifdef CK_SSL
63 #ifdef KRB5
64 #define TLS_VERIFY
65 #endif /* KRB5 */
66 #endif /* CK_SSL */
67
68 #ifdef CK_DES
69 #ifdef CK_SSL
70 #ifndef LIBDES
71 #define LIBDES
72 #endif /* LIBDES */
73 #endif /* CK_SSL */
74 #endif /* CK_DES */
75
76 #ifdef CRYPT_DLL
77 #ifndef LIBDES
78 #define LIBDES
79 #endif /* LIBDES */
80 #ifdef OS2
81 #ifdef NT
82 #include <windows.h>
83 #else /* NT */
84 #define INCL_DOSMODULEMGR
85 #include <os2.h>
86 #endif /* NT */
87 #endif /* OS2 */
88 #endif /* CRYPT_DLL */
89
90 #ifdef NT
91 #define KRB5_AUTOCONF__
92 #define NTLM
93 #endif /* NT */
94
95 #ifdef CK_KERBEROS
96 #define KINIT
97 #ifndef HEIMDAL
98 #define KLIST
99 #define KDESTROY
100 #endif /* HEIMDAL */
101 #define CHECKADDRS
102 #else /* CK_KERBEROS */
103 #ifdef KRB4
104 #undef KRB4
105 #endif /* KRB4 */
106 #ifdef KRB5
107 #undef KRB5
108 #endif /* KRB5 */
109 #ifdef KRB524
110 #undef KRB524
111 #endif /* KRB524 */
112 #endif /* CK_KERBEROS */
113
114 #include <stdlib.h>
115 #include <string.h>
116 #include <stdio.h>
117 #include <time.h>
118 #include <fcntl.h>
119 #include <errno.h>
120 #ifndef malloc
121 #ifndef VMS
122 #ifndef FREEBSD4
123 #ifndef OpenBSD
124 #ifdef MACOSX
125 #include <sys/malloc.h>
126 #else /* MACOSX */
127 #include <malloc.h>
128 #endif /* MACOSX */
129 #endif /* OpenBSD */
130 #endif /* FREEBSD4 */
131 #endif /* VMS */
132 #endif /* malloc */
133 #ifdef OS2
134 #include <io.h>
135 #endif /* OS2 */
136
137 #ifdef KRB5
138 #ifdef HEIMDAL
139 #ifdef printf
140 #define saveprintf printf
141 #undef printf
142 #endif /* printf */
143 #include "krb5.h"
144
145 #include "com_err.h"
146
147 #ifdef saveprintf
148 #define printf saveprintf
149 #endif /* saveprintf */
150 #else /* HEIMDAL */
151 #include "krb5.h"
152 #include "profile.h"
153 #include "com_err.h"
154 #ifdef KRB5_GET_INIT_CREDS_OPT_TKT_LIFE
155 #define KRB5_HAVE_GET_INIT_CREDS
156 #else
157 #define krb5_free_unparsed_name(con,val) krb5_xfree((char *)(val))
158 #endif
159 #ifndef KRB5_HAVE_GET_INIT_CREDS
160 #define krb5_free_data_contents(c,v) krb5_xfree((char *)(v)->data)
161 #endif
162 #endif /* HEIMDAL */
163 #ifdef HAVE_PWD_H
164 #include <pwd.h>
165 #endif
166 #endif /* KRB5 */
167
168 #ifdef KRB4
169 #define  des_cblock Block
170 #define  const_des_cblock const Block
171 #define  des_key_schedule Schedule
172 #ifdef KRB524
173 #ifdef NT
174 #define _WINDOWS
175 #endif /* NT */
176 #include "kerberosIV/krb.h"
177 #ifndef OS2
178 #ifdef KRB524_CONV
179 #include "krb524.h"
180 #endif /* KRB524_CONV */
181 _PROTOTYP(const char * krb_get_err_text_entry, (int));
182 #endif /* OS2 */
183 #else /* KRB524 */
184 #ifdef SOLARIS
185 #ifndef sun
186 /* for some reason the Makefile entries for the Solaris systems have -Usun */
187 #define sun
188 #endif /* sun */
189 #endif /* SOLARIS */
190 #include "krb.h"
191 #define krb_get_err_text_entry krb_get_err_text
192 #endif /* KRB524 */
193 #else /* KRB4 */
194 #ifdef CK_SSL
195 #define  des_cblock Block
196 #ifdef COMMENT
197 #define  const_des_cblock const Block
198 #endif /* COMMENT */
199 #define  des_key_schedule Schedule
200 #endif /* CK_SSL */
201 #endif /* KRB4 */
202
203 #include "ckuath.h"
204 #ifdef CK_KERBEROS
205 #ifndef KRB5
206 #define NOBLOCKDEF
207 #else /* KRB5 */
208 #ifdef KRB524
209 #define NOBLOCKDEF
210 #endif /* KRB524 */
211 #endif /* KRB5 */
212 #endif /* CK_KERBEROS */
213 #include "ckuat2.h"
214
215 #ifdef CK_SSL
216 #ifdef LIBDES
217 #ifdef OPENSSL_097
218 #ifdef CK_DES
219 #define OPENSSL_ENABLE_OLD_DES_SUPPORT
220 #include <openssl/des.h>
221 #endif  /* CK_DES */
222 #endif /* OPENSSL_097 */
223 #ifndef HEADER_DES_H
224 #define HEADER_DES_H
225 #endif /* HEADER_DES_H */
226 #endif /* LIBDES */
227 #include "ck_ssl.h"
228 extern int ssl_finished_messages;
229 #endif /* SSL */
230
231 #define PWD_SZ 128
232
233 #ifndef LIBDES
234 #ifdef UNIX
235 #define des_set_random_generator_seed(x) des_init_random_number_generator(x)
236 #endif /* UNIX */
237 #else /* LIBDES */
238 #define des_fixup_key_parity des_set_odd_parity
239 #endif /* LIBDES */
240
241 #ifdef OS2
242 #ifdef CK_ENCRYPTION
243 #define MAP_DES
244 #endif /* CK_ENCRYPTION */
245 #ifdef KRB4
246 #define MAP_KRB4
247 #endif /* KRB4 */
248 #ifdef SRPDLL
249 #define MAP_SRP
250 #endif /* SRPDLL */
251 #ifdef KRB5
252 #define MAP_KRB5
253 #endif /* KRB5 */
254 #ifdef CRYPT_DLL
255 #define MAP_CRYPT
256 #endif /* CRYPT_DLL */
257 #define MAP_NTLM
258 #include "ckoath.h"
259 #include "ckosyn.h"
260 #endif /* OS2 */
261
262 /*
263  * Globals
264  */
265 int auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_AUTO, AUTHTYPE_NULL};
266 int auth_how=0;
267 int auth_crypt=0;
268 int auth_fwd=0;
269
270 /* These are state completion variables */
271 static int mutual_complete = 0;
272
273 #ifdef KRB4
274 #ifdef OS2
275 static LEASH_CREDENTIALS cred;
276 #else /* OS2 */
277 static CREDENTIALS cred;
278 #endif /* OS2 */
279 static KTEXT_ST k4_auth;
280 static char     k4_name[ANAME_SZ];
281 static AUTH_DAT k4_adat  = { 0 };
282 static MSG_DAT  k4_msg_data;
283 #ifdef CK_ENCRYPTION
284 static Block    k4_session_key     = { 0 };
285 static Schedule k4_sched;
286 static Block    k4_challenge       = { 0 };
287 #ifdef MIT_CURRENT
288 static krb5_keyblock k4_krbkey;
289 #endif /* MIT_CURRENT */
290 #endif /* ENCRYPTION */
291 #define KRB4_SERVICE_NAME    "rcmd"
292
293 _PROTOTYP(static int k4_auth_send,(VOID));
294 _PROTOTYP(static int k4_auth_reply,(unsigned char *, int));
295 _PROTOTYP(static int k4_auth_is,(unsigned char *, int));
296 #endif /* KRB4 */
297
298 #ifdef KRB5
299 static krb5_data          k5_auth;
300 static krb5_auth_context  auth_context;
301 static krb5_keyblock     *k5_session_key = NULL;
302 static krb5_ticket       *k5_ticket = NULL;
303 #ifndef KRB5_SERVICE_NAME
304 #define KRB5_SERVICE_NAME    "host"
305 #ifdef MACOSX
306 #define MIT_CURRENT 1
307 #define decode_krb5_ticket  krb5_decode_ticket
308 #define krb5_read_message   ck_krb5_read_message
309 #define krb5_write_message  ck_krb5_write_message
310 #endif /* MACOSX */
311 #endif
312
313 _PROTOTYP(static int k5_auth_send,(int,int,int));
314 _PROTOTYP(static int k5_auth_reply,(int, unsigned char *, int));
315 _PROTOTYP(static int k5_auth_is,(int,unsigned char *, int));
316 _PROTOTYP(static int SendK5AuthSB,(int, void *, int));
317 #ifdef TLS_VERIFY
318 static int krb5_tls_verified = 0;
319 #endif /* TLS_VERIFY */
320 #endif /* KRB5 */
321
322 #ifdef GSSAPI_KRB5
323 #include <gssapi/gssapi.h>
324 #include <gssapi/gssapi_generic.h>
325 #include <gssapi/gssapi_krb5.h>
326
327 static gss_ctx_id_t gcontext;
328 #define GSS_BUFSIZ 4096
329 static gss_buffer_desc gss_send_tok, gss_recv_tok, *gss_token_ptr;
330 static char gss_stbuf[GSS_BUFSIZ];
331 static gss_name_t gss_target_name;
332 static struct gss_channel_bindings_struct gss_chan;
333
334 _PROTOTYP(static int gssk5_auth_send,(int,int,int));
335 _PROTOTYP(static int gssk5_auth_reply,(int, unsigned char *, int));
336 _PROTOTYP(static int gssk5_auth_is,(int,unsigned char *, int));
337 _PROTOTYP(static int SendGSSK5AuthSB,(int, void *, int));
338 #endif /* GSSAPI_KRB5 */
339
340 #ifdef CK_SRP
341 #ifdef PRE_SRP_1_7_3
342 _PROTOTYP(static int srp_reply,(int, unsigned char *, int));
343 _PROTOTYP(static int srp_is,(int, unsigned char *, int));
344 #else /* PRE_SRP_1_7_3 */
345 _PROTOTYP(static int new_srp_reply,(int, unsigned char *, int));
346 _PROTOTYP(static int new_srp_is,(int, unsigned char *, int));
347 #endif /* PRE_SRP_1_7_3 */
348 #endif /* SRP */
349
350 #ifdef CK_ENCRYPTION
351 int encrypt_flag = 1;
352 #endif
353 #ifdef FORWARD
354 int forward_flag = 0;              /* forward tickets? */
355 int forwardable_flag = 1;          /* get forwardable tickets to forward? */
356 int forwarded_tickets = 0;         /* were tickets forwarded? */
357 #endif
358
359 static unsigned char str_data[4096] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
360                                         AUTHTYPE_KERBEROS_V5, };
361 #define AUTHTMPBL 2048
362 static char strTmp[AUTHTMPBL+1];
363 static char szLocalHostName[UIDBUFLEN+1];
364 static kstream g_kstream=NULL;
365
366 #ifdef KRB5
367 krb5_context k5_context=NULL;
368 static krb5_creds * ret_cred=NULL;
369 static krb5_context telnet_context=NULL;
370 static char * telnet_krb5_realm = NULL;
371 static krb5_principal fwd_server = NULL;
372 #endif /* KRB5 */
373
374 #ifdef CK_SRP
375 #ifdef PRE_SRP_1_4_4
376 #ifndef PRE_SRP_1_4_5
377 #define PRE_SRP_1_4_5
378 #endif /* PRE_SRP_1_4_5 */
379 #endif /* PRE_SRP_1_4_5 */
380 #ifdef PRE_SRP_1_4_5
381 #ifndef PRE_SRP_1_7_3
382 #define PRE_SRP_1_7_3
383 #endif /* PRE_SRP_1_7_3 */
384 #endif /* PRE_SRP_1_4_5 */
385 #include <t_pwd.h>
386 #include <t_client.h>
387 #include <t_server.h>
388 static struct t_server * ts = NULL;
389 static struct t_client * tc = NULL;
390 #ifdef PRE_SRP_1_4_4
391 static struct t_pw * tpw = NULL;
392 static struct t_conf * tconf = NULL;
393 #endif /* PRE_SRP_1_4_4 */
394 #ifndef PRE_SRP_1_7_3
395 #ifndef STDC_HEADERS
396 #define STDC_HEADERS 1
397 #endif /* STDC_HEADERS */
398 #include <srp.h>
399 static SRP * s_srp = NULL;
400 static cstr * s_key = NULL;
401 static SRP * c_srp = NULL;
402 static cstr * c_key = NULL;
403 #endif /* PRE_SRP_1_7_3 */
404 static int srp_waitresp = 0;    /* Flag to indicate readiness for response */
405 static char srp_passwd[PWD_SZ];
406 #endif /* CK_SRP */
407
408 #ifdef CK_KERBEROS
409 #ifdef RLOGCODE
410 #define OPTS_FORWARD_CREDS           0x00000020
411 #define OPTS_FORWARDABLE_CREDS       0x00000010
412 #define KCMD_KEYUSAGE                1026
413
414 #define RLOG_BUFSIZ 5120
415 static int rlog_encrypt = 0;
416 char des_inbuf[2*RLOG_BUFSIZ];       /* needs to be > largest read size */
417 char des_outpkt[2*RLOG_BUFSIZ+4];    /* needs to be > largest write size */
418 #ifdef KRB5
419 krb5_data desinbuf,desoutbuf;
420 krb5_encrypt_block eblock;             /* eblock for encrypt/decrypt */
421 static krb5_data encivec_i[2], encivec_o[2];
422
423 enum krb5_kcmd_proto {
424   /* Old protocol: DES encryption only.  No subkeys.  No protection
425      for cleartext length.  No ivec supplied.  OOB hacks used for
426      rlogin.  Checksum may be omitted at connection startup.  */
427   KCMD_OLD_PROTOCOL = 1,
428   /* New protocol: Any encryption scheme.  Client-generated subkey
429      required.  Prepend cleartext-length to cleartext data (but don't
430      include it in count).  Starting ivec defined, chained.  In-band
431      signalling.  Checksum required.  */
432   KCMD_NEW_PROTOCOL,
433   /* Hack: Get credentials, and use the old protocol iff the session
434      key type is single-DES.  */
435   KCMD_PROTOCOL_COMPAT_HACK,
436   KCMD_UNKNOWN_PROTOCOL
437 };
438 enum krb5_kcmd_proto krb5_rlog_ver = KCMD_PROTOCOL_COMPAT_HACK;
439 #endif /* KRB5 */
440 #endif /* RLOGCODE */
441 static char storage[65536];            /* storage for the decryption */
442 static int nstored = 0;
443 static char *store_ptr = storage;
444
445 extern char * krb5_d_principal;         /* Default principal */
446 extern char * krb5_d_instance;          /* Default instance */
447 extern char * krb5_d_realm;             /* Default realm */
448 extern char * krb5_d_cc;                /* Default credentials cache */
449 extern char * krb5_d_srv;               /* Default service name */
450 extern int    krb5_d_lifetime;          /* Default lifetime */
451 extern int    krb5_d_forwardable;
452 extern int    krb5_d_proxiable;
453 extern int    krb5_d_renewable;
454 extern int    krb5_autoget;
455 extern int    krb5_checkaddrs;
456 extern int    krb5_d_getk4;
457 extern int    krb5_d_no_addresses;
458 extern char * k5_keytab;
459
460 extern int    krb5_errno;
461 extern char * krb5_errmsg;
462
463 extern char * krb4_d_principal;         /* Default principal */
464 extern char * krb4_d_realm;             /* Default realm */
465 extern char * krb4_d_srv;               /* Default service name */
466 extern int    krb4_d_lifetime;          /* Default lifetime */
467 extern int    krb4_d_preauth;
468 extern char * krb4_d_instance;
469 extern int    krb4_autoget;
470 extern int    krb4_checkaddrs;
471 extern char * k4_keytab;
472
473 extern int    krb4_errno;
474 extern char * krb4_errmsg;
475 #endif /* CK_KERBEROS */
476
477 extern char tn_msg[], hexbuf[];         /* from ckcnet.c */
478 extern CHAR pwbuf[];
479 extern int  pwflg, pwcrypt;
480 extern int deblog, debses, tn_deb;
481 extern int sstelnet, inserver;
482 #ifdef CK_LOGIN
483 extern int ckxanon;
484 #endif /* CK_LOGIN */
485 extern int tn_auth_how;
486 extern int tn_auth_enc;
487 #ifdef CK_ENCRYPTION
488 extern int cx_type;
489 #endif /* CK_ENCRYPTION */
490 extern int quiet, ttyfd, ttnproto;
491
492 int
493 ck_gssapi_is_installed()
494 {
495 #ifdef KRB5
496 #ifdef OS2
497     return(hGSSAPI != NULL);
498 #else /* OS2 */
499     return(1);
500 #endif /* OS2 */
501 #else /* KRB5 */
502     return(0);
503 #endif /* KRB5 */
504 }
505
506 int
507 ck_krb5_is_installed()
508 {
509 #ifdef KRB5
510 #ifdef OS2
511     return(hKRB5_32 != NULL);
512 #else /* OS2 */
513     return(1);
514 #endif /* OS2 */
515 #else /* KRB5 */
516     return(0);
517 #endif /* KRB5 */
518 }
519
520
521 int
522 ck_krb5_is_installed_as_server()
523 {
524 #ifdef KRB5
525 #ifdef HEIMDAL
526     krb5_error_code ret;
527     krb5_keytab kt;
528     krb5_kt_cursor cursor;
529
530     ret = krb5_kt_default(k5_context, &kt);
531     if ( ret ) {
532         krb5_kt_close(k5_context, kt);
533         return(0);
534     } else {
535         krb5_kt_end_seq_get(k5_context, kt, &cursor);
536         krb5_kt_close(k5_context, kt);
537         return(1);
538     }
539 #else /* HEIMDAL */
540 #ifndef COMMENT
541     char ktname[CKMAXPATH]="";
542
543     if ( k5_keytab ) {
544         ckstrncpy(ktname,k5_keytab,CKMAXPATH);
545     } else {
546         krb5_error_code code;
547
548         if ( k5_context == NULL)
549             if (krb5_init_context(&k5_context))
550                 return(0);
551
552         code = krb5_kt_default_name(k5_context,ktname,CKMAXPATH);
553         debug(F101,"krb5_kt_default_name","",code);
554         if ( code ) {
555             /* We can't check the existence of the file since we can't   */
556             /* determine the file name.  So we return TRUE and let       */
557             /* Krb5 be offered to the user even though it may fail later */
558             return(1);
559         }
560     }
561
562     if ( !strncmp("FILE:",ktname,5) ) {
563         if ( zchki(&ktname[5]) > 0 )
564             return(1);
565         else
566             return(0);
567     } else {
568         if (ktname[0])
569             return(1);
570         else
571             return(0);
572     }
573 #else /* COMMENT */
574     krb5_error_code             krb5rc = KRB5KRB_ERR_GENERIC;
575     krb5_context                krb5context = NULL;
576     krb5_ccache                 krb5ccdef = NULL;
577     krb5_creds                  krb5creds, *krb5credsp = NULL;
578     int                         rc = 0;
579
580     if ( !ck_krb5_is_installed() )
581         return(0);
582
583     memset((char *)&krb5creds, 0, sizeof(krb5creds));
584
585     if ((krb5rc = krb5_init_context(&krb5context)) != 0)
586         goto err;
587
588     if ((krb5rc = krb5_sname_to_principal(krb5context,
589                                           szHostName,
590                                           krb5_d_srv ?
591                                           krb5_d_srv :
592                                           KRB5_SERVICE_NAME,
593                                           KRB5_NT_SRV_HST,
594                                           &krb5creds.server)) != 0)
595       goto err;
596
597     if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
598         goto err;
599
600     if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
601                                          &krb5creds.client)) != 0)
602         goto err;
603
604     if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
605                                         &krb5creds, &krb5credsp)) != 0)
606         goto err;
607     rc = 1;
608
609   err:
610
611     if (krb5creds.client)
612       krb5_free_principal(krb5context, krb5creds.client);
613     if (krb5creds.server)
614       krb5_free_principal(krb5context, krb5creds.server);
615     if (krb5context)
616       krb5_free_context(krb5context);
617     return(rc);
618
619 #endif /* COMMENT */
620 #endif /* HEIMDAL */
621 #else /* KRB5 */
622     return(0);
623 #endif /* KRB5 */
624 }
625
626 int
627 ck_krb4_is_installed()
628 {
629 #ifdef KRB4
630 #ifdef OS2
631     return(hKRB4_32 != NULL);
632 #else /* OS2 */
633     return(1);
634 #endif /* OS2 */
635 #else /* KRB4 */
636     return(0);
637 #endif /* KRB4 */
638 }
639
640 int
641 ck_krb4_is_installed_as_server()
642 {
643     if ( !ck_krb4_is_installed() )
644         return(0);
645
646 #ifdef KRB4
647     if ( !k4_keytab ) {
648 #ifdef NT
649         char name[CKMAXPATH]="";
650         DWORD len = CKMAXPATH;
651
652         len = GetWindowsDirectory(name,len);
653         if ( len > 0 )
654             ckstrncat(name,"/srvtab",CKMAXPATH);
655         if ( name[0] )
656             makestr(&k4_keytab,name);
657 #else /* NT */
658         makestr(&k4_keytab,"/etc/srvtab");
659 #endif /* NT */
660     }
661
662     if ( !k4_keytab )
663         return(0);
664
665     if ( zchki(k4_keytab) > 0 )
666         return(1);
667 #ifdef KRB524
668     else if (ck_krb5_is_installed_as_server())
669         return(1);
670 #endif /* KRB524 */
671     else
672         return(0);
673 #endif /* KRB4 */
674 }
675
676 int
677 ck_srp_is_installed_as_server()
678 {
679 #ifdef CK_SRP
680 #ifdef SRPDLL
681     if ( hSRP == NULL )
682         return(0);
683 #endif /* SRPDLL */
684 #ifdef COMMENT
685     /* This is the new API as of 1.7.4.  However, all it does
686        is allocate a data structure.  It can never fail.
687      */
688     {
689         SRP * s_srp = SRP_new(SRP_RFC2945_server_method());
690         if ( s_srp ) {
691             SRP_free(s_srp);
692             s_srp = NULL;
693             return(1);
694         }
695         return(0);
696     }
697 #else /* COMMENT */
698     {
699         struct t_pw * tpw = NULL;
700         struct t_conf * tconf = NULL;
701         if((tconf = t_openconf(NULL)) == NULL)
702             return(0);
703         if((tpw = t_openpw(NULL)) == NULL) {
704             t_closeconf(tconf);
705             return(0);
706         }
707         t_closeconf(tconf);
708         t_closepw(tpw);
709         return(1);
710     }
711 #endif /* COMMENT */
712 #else /* SRP */
713     return(0);
714 #endif /* SRP */
715 }
716
717 int
718 ck_srp_is_installed()
719 {
720 #ifdef CK_SRP
721 #ifdef SRPDLL
722     if ( hSRP == NULL )
723         return(0);
724 #endif /* SRPDLL */
725     return(1);
726 #else /* CK_SRP */
727     return(0);
728 #endif /* CK_SRP */
729 }
730
731 int
732 ck_krypto_is_installed()
733 {
734 #ifdef CK_SRP
735 #ifdef OS2
736     if ( hLIBKRYPTO == NULL )
737         return(0);
738 #endif /* OS2 */
739     return(1);
740 #else /* CK_SRP */
741     return(0);
742 #endif /* CK_SRP */
743 }
744
745 int
746 ck_crypt_is_installed()
747 {
748 #ifdef CK_ENCRYPTION
749 #ifdef CRYPT_DLL
750     return(hCRYPT != NULL);
751 #else /* CRYPT_DLL */
752     return(1);
753 #endif /* CRYPT_DLL */
754 #else /* ENCRYPTION */
755     return(0);
756 #endif /* ENCRYPTION */
757 }
758
759 int
760 ck_ntlm_is_installed()
761 {
762 #ifdef NT
763     return(hSSPI != NULL);
764 #else /* NT */
765     return(0);
766 #endif /* NT */
767 }
768
769 int
770 ck_tn_auth_valid()
771 {
772     return(validUser);
773 }
774
775 /* C K _ K R B _ A U T H _ I N _ P R O G R E S S
776  *
777  * Is an authentication negotiation still in progress?
778  *
779  */
780
781 int
782 #ifdef CK_ANSIC
783 ck_tn_auth_in_progress(void)
784 #else
785 ck_tn_auth_in_progress()
786 #endif
787 {
788     switch (authentication_version) {
789     case AUTHTYPE_AUTO:
790         return(1);
791     case AUTHTYPE_NULL:
792         return(0);
793 #ifdef KRB4
794     case AUTHTYPE_KERBEROS_V4:
795         if (!accept_complete) {
796             debug(F100,"ck_auth_in_progress() Kerberos 4 !accept_complete",
797                    "",0);
798             return(1);
799         }
800         else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) {
801             debug(F100,"ck_auth_in_progress() Kerberos 4 !mutual_complete",
802                    "",0);
803             return(1);
804         }
805         else
806             return(0);
807 #endif /* KRB4 */
808 #ifdef KRB5
809     case AUTHTYPE_KERBEROS_V5:
810         if (!accept_complete) {
811             debug(F100,"ck_auth_in_progress() Kerberos 5 !accept_complete",
812                    "",0);
813             return(1);
814         }
815         else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) {
816             debug(F100,"ck_auth_in_progress() Kerberos 5 !mutual_complete",
817                    "",0);
818             return(1);
819         }
820         else
821             return(0);
822 #ifdef GSSAPI_K5
823     case AUTHTYPE_GSSAPI_KRB5:
824         if (!accept_complete) {
825             debug(F100,
826                   "ck_auth_in_progress() GSSAPI Kerberos 5 !accept_complete",
827                   "",
828                   0
829                   );
830             return(1);
831         }
832         else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) {
833             debug(F100,
834                   "ck_auth_in_progress() GSSAPI Kerberos 5 !mutual_complete",
835                   "",
836                   0
837                   );
838             return(1);
839         } else
840           return(0);
841         break;
842 #endif /* GSSAPI_K5 */
843 #endif /* KRB5 */
844 #ifdef CK_SRP
845     case AUTHTYPE_SRP:
846         if (!accept_complete || srp_waitresp)
847             return(1);
848         else
849             return(0);
850 #endif /* CK_SRP */
851 #ifdef NTLM
852     case AUTHTYPE_NTLM:
853         if (!accept_complete) {
854             debug(F100,"ck_auth_in_progress() NTLM !accept_complete",
855                    "",0);
856             return(1);
857         }
858         else
859             return(0);
860 #endif /* NTLM */
861     case AUTHTYPE_SSL:
862         if (!accept_complete) {
863             debug(F100,"ck_auth_in_progress() SSL !accept_complete",
864                    "",0);
865             return(1);
866         }
867         else
868             return(0);
869     default:
870         return(0);
871     }
872     return(0);
873 }
874
875
876 /*  C K _ K R B _ T N _ A U T H _ R E Q U E S T
877  *
878  *  Builds a Telnet Authentication Send Negotiation providing the
879  *  list of supported authentication methods.  To be used only
880  *  when accepting incoming connections as only the server (DO) side of the
881  *  Telnet negotiation is allowed to send an AUTH SEND.
882  *
883  *  Returns: 0 on success and -1 on failure
884  */
885
886 static unsigned char str_request[64] = { IAC, SB,
887                                              TELOPT_AUTHENTICATION,
888                                              TELQUAL_SEND };
889 #ifdef GSSAPI_K5
890 static int
891 ck_tn_auth_request_gsskrb5(int i)
892 {
893     if (ck_gssapi_is_installed() && ck_krb5_is_installed_as_server()) {
894         if ( (tn_auth_how == TN_AUTH_HOW_ANY ||
895                tn_auth_how == TN_AUTH_HOW_MUTUAL)  &&
896              (tn_auth_enc == TN_AUTH_ENC_ANY ||
897                tn_auth_enc == TN_AUTH_ENC_EXCH) ) {
898             str_request[i++] = AUTHTYPE_KERBEROS_V5;
899             str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
900             str_request[i] |= AUTH_ENCRYPT_AFTER_EXCHANGE;
901
902             if ( deblog || tn_deb || debses )
903                 ckstrncat(tn_msg,
904                 "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE ",
905                           TN_MSG_LEN);
906             i++;
907         }
908     }
909 }
910 #endif /* GSSAPI_K5 */
911
912 #ifdef KRB5
913 static int
914 ck_tn_auth_request_krb5(int i)
915 {
916     if (ck_krb5_is_installed_as_server()) {
917 #ifdef CK_SSL
918         if ( ck_ssleay_is_installed() &&
919              (tls_active_flag || ssl_active_flag) &&
920              ssl_finished_messages )
921         {
922 #ifdef USE_INI_CRED_FWD
923             if ( forward_flag &&
924                  (tn_auth_how == TN_AUTH_HOW_ANY ||
925                    tn_auth_how == TN_AUTH_HOW_MUTUAL)  &&
926                  (tn_auth_enc == TN_AUTH_ENC_ANY ||
927                    tn_auth_enc == TN_AUTH_ENC_TELOPT)
928                  )
929             {
930                 str_request[i++] = AUTHTYPE_KERBEROS_V5;
931                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
932                 str_request[i] |= AUTH_ENCRYPT_START_TLS;
933                 str_request[i] |= INI_CRED_FWD_ON;
934
935                 if ( deblog || tn_deb || debses )
936                     ckstrncat(tn_msg,
937  "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS|INI_CRED_FWD_ON ",
938                                TN_MSG_LEN);
939                 i++;
940             }
941 #endif /* USE_INI_CRED_FWD */
942             if ( (tn_auth_how == TN_AUTH_HOW_ANY ||
943                    tn_auth_how == TN_AUTH_HOW_MUTUAL)  &&
944                  (tn_auth_enc == TN_AUTH_ENC_ANY ||
945                    tn_auth_enc == TN_AUTH_ENC_TELOPT) ) {
946                 str_request[i++] = AUTHTYPE_KERBEROS_V5;
947                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
948                 str_request[i] |= AUTH_ENCRYPT_START_TLS;
949
950                 if ( deblog || tn_deb || debses )
951                     ckstrncat(tn_msg,
952                       "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS ",
953                               TN_MSG_LEN);
954                 i++;
955             }
956             if ( tn_auth_how == TN_AUTH_HOW_ANY ||
957                  tn_auth_how == TN_AUTH_HOW_ONE_WAY ) {
958                 str_request[i++] = AUTHTYPE_KERBEROS_V5;
959                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
960                 str_request[i] |= AUTH_ENCRYPT_START_TLS;
961
962                 if ( deblog || tn_deb || debses )
963                     ckstrncat(tn_msg,
964                     "KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ",
965                                TN_MSG_LEN);
966                 i++;
967             }
968         }
969 #ifdef CK_ENCRYPTION
970         else
971         {
972 #endif /* CK_ENCRYPTION */
973 #endif /* CK_SSL */
974 #ifdef CK_ENCRYPTION
975 #ifdef USE_INI_CRED_FWD
976             if ( forward_flag &&
977                  TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
978                  TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
979                  (tn_auth_how == TN_AUTH_HOW_ANY ||
980                    tn_auth_how == TN_AUTH_HOW_MUTUAL)  &&
981                  (tn_auth_enc == TN_AUTH_ENC_ANY ||
982                    tn_auth_enc == TN_AUTH_ENC_TELOPT)
983                  )
984             {
985                 str_request[i++] = AUTHTYPE_KERBEROS_V5;
986                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
987                 str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
988                 str_request[i] |= INI_CRED_FWD_ON;
989
990                 if ( deblog || tn_deb || debses )
991                     ckstrncat(tn_msg,
992   "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT|INI_CRED_FWD_ON ",
993                                TN_MSG_LEN);
994                 i++;
995             }
996 #endif /* USE_INI_CRED_FWD */
997
998             if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
999                  TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
1000                  (tn_auth_how == TN_AUTH_HOW_ANY ||
1001                    tn_auth_how == TN_AUTH_HOW_MUTUAL)  &&
1002                  (tn_auth_enc == TN_AUTH_ENC_ANY ||
1003                    tn_auth_enc == TN_AUTH_ENC_TELOPT) ) {
1004                 str_request[i++] = AUTHTYPE_KERBEROS_V5;
1005                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
1006                 str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
1007
1008                 if ( deblog || tn_deb || debses )
1009                     ckstrncat(tn_msg,
1010               "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT ",
1011                                TN_MSG_LEN);
1012                 i++;
1013             }
1014 #ifdef CK_SSL
1015         }
1016 #endif /* CK_SSL */
1017 #endif /* CK_ENCRYPTION */
1018
1019         if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1020              TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1021              (tn_auth_enc == TN_AUTH_ENC_ANY ||
1022                tn_auth_enc == TN_AUTH_ENC_NONE)
1023 #ifdef CK_SSL
1024              && !(ck_ssleay_is_installed() &&
1025                    (tls_active_flag || ssl_active_flag) &&
1026                    tls_is_anon(0))
1027 #endif /* CK_SSL */
1028              )
1029         {
1030 #ifdef CK_ENCRYPTION
1031             /* Can't perform mutual authentication without encryption */
1032             if ( tn_auth_how == TN_AUTH_HOW_ANY ||
1033                  tn_auth_how == TN_AUTH_HOW_MUTUAL ) {
1034                 str_request[i++] = AUTHTYPE_KERBEROS_V5;
1035                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
1036                 str_request[i] |= AUTH_ENCRYPT_OFF;
1037
1038                 if ( deblog || tn_deb || debses )
1039                     ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL ",
1040                                TN_MSG_LEN);
1041                 i++;
1042             }
1043 #endif /* CK_ENCRYPTION */
1044             if ( tn_auth_how == TN_AUTH_HOW_ANY ||
1045                  tn_auth_how == TN_AUTH_HOW_ONE_WAY ) {
1046                 str_request[i++] = AUTHTYPE_KERBEROS_V5;
1047                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
1048                 str_request[i] |= AUTH_ENCRYPT_OFF;
1049
1050                 if ( deblog || tn_deb || debses )
1051                     ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY ",
1052                                TN_MSG_LEN);
1053                 i++;
1054             }
1055         }
1056     }
1057     return(i);
1058 }
1059 #endif /* KRB5 */
1060 #ifdef KRB4
1061 static int
1062 ck_tn_auth_request_krb4(int i)
1063 {
1064     if (ck_krb4_is_installed_as_server()) {
1065 #ifdef CK_ENCRYPTION
1066         if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
1067              TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
1068              (tn_auth_how == TN_AUTH_HOW_ANY ||
1069                tn_auth_how == TN_AUTH_HOW_MUTUAL)  &&
1070              (tn_auth_enc == TN_AUTH_ENC_ANY ||
1071                tn_auth_enc == TN_AUTH_ENC_TELOPT) )
1072         {
1073             str_request[i++] = AUTHTYPE_KERBEROS_V4;
1074             str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
1075             str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
1076
1077             if ( deblog || tn_deb || debses )
1078               ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL|ENCRYPT ",
1079                         TN_MSG_LEN);
1080             i++;
1081         }
1082 #endif /* CK_ENCRYPTION */
1083
1084         if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1085              TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1086              (tn_auth_enc == TN_AUTH_ENC_ANY ||
1087                tn_auth_enc == TN_AUTH_ENC_NONE) )
1088         {
1089 #ifdef CK_ENCRYPTION
1090             /* Can't perform mutual authentication without encryption */
1091             if ( tn_auth_how == TN_AUTH_HOW_ANY ||
1092                  tn_auth_how == TN_AUTH_HOW_MUTUAL ) {
1093                 str_request[i++] = AUTHTYPE_KERBEROS_V4;
1094                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
1095                 str_request[i] |= AUTH_ENCRYPT_OFF;
1096
1097                 if ( deblog || tn_deb || debses )
1098                     ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL ",
1099                                TN_MSG_LEN);
1100                 i++;
1101             }
1102 #endif /* CK_ENCRYPTION */
1103             if ( tn_auth_how == TN_AUTH_HOW_ANY ||
1104                  tn_auth_how == TN_AUTH_HOW_ONE_WAY ) {
1105                 str_request[i++] = AUTHTYPE_KERBEROS_V4;
1106                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
1107                 str_request[i] |= AUTH_ENCRYPT_OFF;
1108
1109                 if ( deblog || tn_deb || debses )
1110                     ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|ONE_WAY ",
1111                                TN_MSG_LEN);
1112                 i++;
1113             }
1114         }
1115     }
1116
1117     return(i);
1118 }
1119 #endif /* KRB4 */
1120
1121 #ifdef CK_SRP
1122 static int
1123 ck_tn_auth_request_srp(int i)
1124 {
1125     if (ck_srp_is_installed_as_server()) {
1126 #ifndef PRE_SRP_1_4_5
1127         /* Dont' do this yet.  SRP when it uses the ENCRYPT_USING_TELOPT   */
1128         /* flag it must perform a checksum of the auth-type-pair but there */
1129         /* is no mechansim to do that yet.                                 */
1130 #ifdef CK_SSL
1131         if ( ck_ssleay_is_installed() &&
1132              (tls_active_flag || ssl_active_flag) &&
1133              ssl_finished_messages &&
1134                  (tn_auth_how == TN_AUTH_HOW_ANY ||
1135                    tn_auth_how == TN_AUTH_HOW_ONE_WAY)  &&
1136                  (tn_auth_enc == TN_AUTH_ENC_ANY ||
1137                    tn_auth_enc == TN_AUTH_ENC_TELOPT))
1138         {
1139             str_request[i++] = AUTHTYPE_SRP;
1140             str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
1141             str_request[i] |= AUTH_ENCRYPT_START_TLS;
1142
1143             if ( deblog || tn_deb || debses )
1144                 ckstrncat(tn_msg,
1145                            "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ",
1146                            TN_MSG_LEN);
1147             i++;
1148         }
1149 #ifdef CK_ENCRYPTION
1150         else {
1151 #endif /* CK_ENCRYPTION */
1152 #endif /* CK_SSL */
1153 #ifdef CK_ENCRYPTION
1154             if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
1155                  TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
1156                  (tn_auth_how == TN_AUTH_HOW_ANY ||
1157                    tn_auth_how == TN_AUTH_HOW_ONE_WAY)  &&
1158                  (tn_auth_enc == TN_AUTH_ENC_ANY ||
1159                    tn_auth_enc == TN_AUTH_ENC_TELOPT)
1160                  ) {
1161                 str_request[i++] = AUTHTYPE_SRP;
1162                 str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
1163                 str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
1164
1165                 if ( deblog || tn_deb || debses )
1166                     ckstrncat(tn_msg,
1167                     "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT ",
1168                                TN_MSG_LEN);
1169                 i++;
1170             }
1171 #ifdef CK_SSL
1172         }
1173 #endif /* CK_SSL */
1174 #endif /* CK_ENCRYPTION */
1175 #endif /* PRE_SRP_1_4_5 */
1176         if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1177              TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1178              (tn_auth_how == TN_AUTH_HOW_ANY ||
1179                tn_auth_how == TN_AUTH_HOW_MUTUAL)  &&
1180              (tn_auth_enc == TN_AUTH_ENC_ANY ||
1181                tn_auth_enc == TN_AUTH_ENC_NONE)
1182 #ifdef CK_SSL
1183              && !(ck_ssleay_is_installed() &&
1184                    (tls_active_flag || ssl_active_flag) &&
1185                    tls_is_anon(0))
1186 #endif /* CK_SSL */
1187              )
1188         {
1189             str_request[i++] = AUTHTYPE_SRP;
1190             str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
1191             str_request[i] |= AUTH_ENCRYPT_OFF;
1192
1193             if ( deblog || tn_deb || debses )
1194                 ckstrncat(tn_msg,"SRP CLIENT_TO_SERVER|ONE_WAY ",
1195                            TN_MSG_LEN);
1196             i++;
1197         }
1198     }
1199
1200     return(i);
1201 }
1202 #endif /* CK_SRP */
1203
1204 #ifdef CK_SSL
1205 static int
1206 ck_tn_auth_request_ssl(int i)
1207 {
1208     if (ck_ssleay_is_installed()
1209          && !tls_active_flag && !ssl_active_flag && ssl_initialized
1210          ) {
1211         if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1212              TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1213              (tn_auth_how == TN_AUTH_HOW_ANY ||
1214                tn_auth_how == TN_AUTH_HOW_ONE_WAY)  &&
1215              (tn_auth_enc == TN_AUTH_ENC_ANY ||
1216                tn_auth_enc == TN_AUTH_ENC_NONE) )
1217         {
1218             str_request[i++] = AUTHTYPE_SSL;
1219             str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
1220             str_request[i] |= AUTH_ENCRYPT_OFF;
1221             if ( deblog || tn_deb || debses )
1222                 ckstrncat(tn_msg,"SSL CLIENT_TO_SERVER|ONE_WAY ",
1223                            TN_MSG_LEN);
1224             i++;
1225         }
1226     }
1227
1228     return(i);
1229 }
1230 #endif /* CK_SSL */
1231 #ifdef NTLM
1232 static int
1233 ck_tn_auth_request_ntlm(int i)
1234 {
1235     /* Microsoft's Telnet client won't perform authentication if */
1236     /* NTLM is not first.                                        */
1237     if ( ck_ntlm_is_valid(1) ) {
1238         if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1239              TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
1240              (tn_auth_how == TN_AUTH_HOW_ANY ||
1241                tn_auth_how == TN_AUTH_HOW_ONE_WAY)  &&
1242              (tn_auth_enc == TN_AUTH_ENC_ANY ||
1243                tn_auth_enc == TN_AUTH_ENC_NONE) )
1244         {
1245             str_request[i++] = AUTHTYPE_NTLM;
1246             str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
1247             str_request[i] |= AUTH_ENCRYPT_OFF;
1248             if ( deblog || tn_deb || debses )
1249                 ckstrncat(tn_msg,"NTLM CLIENT_TO_SERVER|ONE_WAY ",
1250                            TN_MSG_LEN);
1251             i++;
1252         }
1253     }
1254
1255     return(i);
1256 }
1257 #endif /* NTLM */
1258 int
1259 #ifdef CK_ANSIC
1260 ck_tn_auth_request(void)
1261 #else
1262 ck_tn_auth_request()
1263 #endif
1264 {
1265     int i = 4, rc = -1;
1266
1267 #ifdef CK_SSL
1268     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1269         return(0);
1270     }
1271 #endif /* CK_SSL */
1272
1273     if ( deblog || tn_deb || debses )
1274         strcpy(tn_msg,"TELNET SENT SB AUTHENTICATION SEND ");
1275
1276     /* Create a list of acceptable Authentication types to send to */
1277     /* the client and let it choose find one that we support       */
1278
1279     /* For those authentication methods that support Encryption or */
1280     /* Credentials Forwarding we must send all of the appropriate  */
1281     /* combinations based upon the state of                        */
1282     /* TELOPT_x_MODE(TELOPT_ENCRYPTION) and forward_flag.          */
1283
1284     if ( auth_type_user[0] == AUTHTYPE_AUTO ) {
1285 #ifdef GSSAPI_K5
1286         i = ck_tn_auth_request_gsskrb5(i);
1287 #endif /* GSSAPI_K5 */
1288 #ifdef KRB5
1289         i = ck_tn_auth_request_krb5(i);
1290 #endif /* KRB5 */
1291 #ifdef KRB4
1292         i = ck_tn_auth_request_krb4(i);
1293 #endif /* KRB4 */
1294 #ifdef CK_SRP
1295         i = ck_tn_auth_request_srp(i);
1296 #endif /* SRP */
1297 #ifdef CK_SSL
1298         i = ck_tn_auth_request_ssl(i);
1299 #endif /* CK_SSL */
1300 #ifdef NTLM
1301         i = ck_tn_auth_request_ntlm(i);
1302 #endif /* NTLM */
1303     } else {
1304         int j;
1305         for ( j=0;
1306               j<AUTHTYPLSTSZ && auth_type_user[j] != AUTHTYPE_NULL;
1307               j++) {
1308 #ifdef NTLM
1309             if (auth_type_user[j] == AUTHTYPE_NTLM)
1310                 i = ck_tn_auth_request_ntlm(i);
1311 #endif /* NTLM */
1312 #ifdef CK_SSL
1313             if ( auth_type_user[j] == AUTHTYPE_SSL )
1314                 i = ck_tn_auth_request_ssl(i);
1315 #endif /* CK_SSL */
1316 #ifdef CK_SRP
1317             if ( auth_type_user[j] == AUTHTYPE_SRP )
1318                 i = ck_tn_auth_request_srp(i);
1319 #endif /* SRP */
1320 #ifdef GSSAPI_K5
1321             if ( auth_type_user[j] == AUTHTYPE_GSSAPI_KRB5 )
1322                 i = ck_tn_auth_request_gsskrb5(i);
1323 #endif /* GSSAPI_K5 */
1324 #ifdef KRB5
1325             if ( auth_type_user[j] == AUTHTYPE_KERBEROS_V5 )
1326                 i = ck_tn_auth_request_krb5(i);
1327 #endif /* KRB5 */
1328 #ifdef KRB4
1329             if ( auth_type_user[j] == AUTHTYPE_KERBEROS_V4 )
1330                 i = ck_tn_auth_request_krb4(i);
1331 #endif /* KRB4 */
1332         }
1333     }
1334
1335     str_request[i++] = IAC;
1336     str_request[i++] = SE;
1337     if ( deblog || tn_deb || debses ) {
1338         ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
1339         debug(F100,tn_msg,"",0);
1340         if (tn_deb || debses) tn_debug(tn_msg);
1341     }
1342
1343     /* Send data */
1344 #ifdef OS2
1345     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1346 #endif
1347     rc = ttol((CHAR *)str_request, i);
1348 #ifdef OS2
1349     ReleaseTelnetMutex();
1350 #endif
1351     if ( rc == i )
1352         return(0);
1353     else
1354         return(-1);
1355 }
1356
1357 #ifdef CK_ENCRYPTION
1358 VOID
1359 ck_tn_enc_start()
1360 {
1361     if (!TELOPT_ME(TELOPT_ENCRYPTION) && !TELOPT_U(TELOPT_ENCRYPTION))
1362         return;
1363     if (!TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop &&
1364          (!encrypt_is_decrypting() || !encrypt_is_encrypting())) {
1365         debug(F110,"ck_tn_enc_start","nothing to do",0);
1366         return;
1367     }
1368     TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
1369     if (TELOPT_ME(TELOPT_ENCRYPTION) && !encrypt_is_encrypting()) {
1370         debug(F110,"ck_tn_enc_start","encrypt_request_start",0);
1371         encrypt_request_start();
1372     }
1373     if (TELOPT_U(TELOPT_ENCRYPTION) && !encrypt_is_decrypting()) {
1374         debug(F110,"ck_tn_enc_start","encrypt_send_request_start",0);
1375         encrypt_send_request_start();
1376     }
1377     tn_wait("encrypt start");
1378     tn_push();
1379 }
1380
1381 VOID
1382 ck_tn_enc_stop()
1383 {
1384     if (!TELOPT_ME(TELOPT_ENCRYPTION) && !TELOPT_U(TELOPT_ENCRYPTION))
1385         return;
1386     if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop ||
1387          !(encrypt_is_decrypting() || encrypt_is_encrypting())) {
1388         debug(F110,"ck_tn_enc_stop","nothing to do",0);
1389       return;
1390     }
1391     TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 1;
1392     if (TELOPT_U(TELOPT_ENCRYPTION) && encrypt_is_decrypting()) {
1393         debug(F110,"ck_tn_enc_stop","encrypt_send_request_end",0);
1394         encrypt_send_request_end();
1395     }
1396     if (TELOPT_ME(TELOPT_ENCRYPTION) && encrypt_is_encrypting()) {
1397         debug(F110,"ck_tn_enc_stop","encrypt_send_end",0);
1398         encrypt_send_end();
1399     }
1400     tn_wait("encrypt stop");
1401     tn_push();
1402 }
1403 #endif /* CK_ENCRYPTION */
1404
1405 /*  C K _ K R B _ T N _ S B _ A U T H
1406  *  An interface between the C-Kermit Telnet Command Parser and the Authent-
1407  *  ication option parser implemented in the Kerberos Telnet client.
1408  *
1409  *  sb   - the subnegotiation as calculated in ckcnet.c
1410  *  len  - the length of the buffer
1411  *
1412  *  Returns: 0 on success and -1 on failure
1413  */
1414
1415 int
1416 #ifdef CK_ANSIC
1417 ck_tn_sb_auth(char * sb, int len)
1418 #else /* CK_ANSIC */
1419 ck_tn_sb_auth(sb,len) char * sb; int len;
1420 #endif /* CK_ANSIC */
1421 {
1422     /* auth_parse() assumes that sb starts at pos 1 not 0 as in ckcnet.c */
1423     /* and it wants the length to exclude the IAC SE bytes               */
1424     CHAR * buf;
1425     int rc = -1;
1426
1427     buf = malloc(len-1);
1428     if ( !buf ) return(-1);
1429
1430     buf[0] = SB;
1431     memcpy( &buf[1], sb, len-2 );
1432     rc = auth_parse(buf,len-1);
1433     free(buf);
1434     debug(F111,"ck_tn_sb_auth","rc",rc);
1435     if (rc == AUTH_FAILURE) {
1436         authentication_version = AUTHTYPE_NULL;
1437 #ifndef NOLOCAL
1438 #ifdef OS2
1439         ipadl25();
1440 #endif /* OS2 */
1441 #endif /* NOLOCAL */
1442         return(-1);
1443     }
1444 #ifndef NOLOCAL
1445 #ifdef OS2
1446     ipadl25();
1447 #endif /* OS2 */
1448 #endif /* NOLOCAL */
1449     return(0);
1450 }
1451
1452 /*  C K _ K R B _ T N _ S B _ E N C R Y P T
1453  *  An interface between the C-Kermit Telnet Command Parser and the Encryption
1454  *  option parser implemented in the Kerberos Telnet client.
1455  *
1456  *  sb   - the subnegotiation as calculated in ckcnet.c
1457  *  len  - the length of the buffer
1458  *
1459  *  Returns: Always returns 0 for success since encrypt_parse is void
1460  */
1461
1462
1463 int
1464 #ifdef CK_ANSIC
1465 ck_tn_sb_encrypt(char * sb, int len)
1466 #else
1467 ck_tn_sb_encrypt(sb,len) char * sb; int len;
1468 #endif /* CK_ANSIC */
1469 {
1470     /* encrypt_parse() assumes that sb starts at pos 1 not 0 as in ckcnet.c */
1471     /* and it wants the length to exclude the IAC SE bytes                  */
1472 #ifdef CK_ENCRYPTION
1473     char * buf;
1474     int rc = -1;
1475
1476     buf = malloc(len-1);
1477     if ( !buf ) return(-1);
1478
1479     buf[0] = SB;
1480     memcpy( &buf[1], sb, len-2 );
1481     rc = encrypt_parse((CHAR *)buf,len-1);
1482
1483     if (rc < 0) {
1484         free(buf);
1485         return(-1);
1486     }
1487
1488     /* This is a hack.  It does not belong here but should really be in */
1489     /* encrypt_parse() but in K95 the encrypt_parse() routine does not  */
1490     /* have access to the telopt_states array.                          */
1491     if ( buf[1] == ENCRYPT_REQEND )
1492         TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 1;
1493     else if ( buf[1] == ENCRYPT_REQSTART )
1494         TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
1495 #ifndef NOLOCAL
1496 #ifdef OS2
1497     ipadl25();
1498 #endif /* OS2 */
1499 #endif /* NOLOCAL */
1500     free(buf);
1501 #endif /* ENCRYPTION */
1502     return(0);
1503 }
1504
1505
1506 /*  C K _ K R B _ E N C R Y P T I N G
1507  *  Returns 1 if we are encrypting and 0 if we are not
1508  */
1509
1510 int
1511 #ifdef CK_ANSIC
1512 ck_tn_encrypting(VOID)
1513 #else /* CK_ANSIC */
1514 ck_tn_encrypting()
1515 #endif /* CK_ANSIC */
1516 {
1517 #ifdef CK_ENCRYPTION
1518     if ( g_kstream == NULL )
1519         return(0);
1520     if ( g_kstream->encrypt && encrypt_is_encrypting()) {
1521         debug(F111,"ck_tn_encrypting","encrypting",
1522                g_kstream->encrypt_type);
1523         return(g_kstream->encrypt_type);
1524     }
1525 #endif /* CK_ENCRYPTION */
1526     debug(F110,"ck_tn_encrypting","not encrypting",0);
1527     return(0);
1528 }
1529
1530 /*  C K _ K R B _ D E C R Y P T I N G
1531  *  Returns 1 if we are decrypting and 0 if we are not
1532  */
1533
1534 int
1535 #ifdef CK_ANSIC
1536 ck_tn_decrypting(VOID)
1537 #else
1538 ck_tn_decrypting()
1539 #endif /* CK_ANSIC */
1540 {
1541 #ifdef CK_ENCRYPTION
1542     if ( g_kstream == NULL )
1543         return(0);
1544     if ( g_kstream->decrypt && encrypt_is_decrypting()) {
1545         debug(F111,"ck_tn_decrypting","decrypting",
1546                g_kstream->decrypt_type);
1547         return(g_kstream->decrypt_type);
1548     }
1549 #endif /* CK_ENCRYPTION */
1550     debug(F110,"ck_tn_decrypting","not decrypting",0);
1551     return(0);
1552 }
1553
1554 /*  C K _ K R B _ A U T H E N T I C A T E D
1555  *  Returns the authentication type: AUTHTYPE_NULL, AUTHTYPE_KERBEROS4,
1556  *  or AUTHTYPE_KERBEROS5, AUTHTYPE_SRP, ... (see ckctel.h)
1557  */
1558
1559 int
1560 #ifdef CK_ANSIC
1561 ck_tn_authenticated(VOID)
1562 #else
1563 ck_tn_authenticated()
1564 #endif
1565 {
1566     return(authentication_version);
1567 }
1568
1569 /*  C K _ K R B _ E N C R Y P T
1570  *  encrypts n characters in s if we are encrypting
1571  */
1572
1573 VOID
1574 #ifdef CK_ANSIC
1575 ck_tn_encrypt( char * s, int n )
1576 #else
1577 ck_tn_encrypt( s,n ) char * s; int n;
1578 #endif
1579 {
1580 #ifdef CK_ENCRYPTION
1581     struct kstream_data_block i;
1582
1583     if (g_kstream->encrypt && encrypt_is_encrypting()) {
1584 #ifdef DEBUG
1585       ckhexdump("from plaintext", s, n);
1586 #endif
1587         i.ptr = s;
1588         i.length = n;
1589         g_kstream->encrypt(&i, NULL);
1590 #ifdef DEBUG
1591         ckhexdump("to cyphertext", s, n);
1592 #endif
1593     }
1594     else debug(F101,"ck_tn_encrypt not encrypting","",n);
1595 #endif /* ENCRYPTION */
1596 }
1597
1598 /*  C K _ K R B _ D E C R Y P T
1599  *  decrypts n characters in s if we are decrypting
1600  */
1601
1602 VOID
1603 #ifdef CK_ANSIC
1604 ck_tn_decrypt( char * s, int n )
1605 #else
1606 ck_tn_decrypt( s,n ) char * s; int n;
1607 #endif
1608 {
1609 #ifdef CK_ENCRYPTION
1610     struct kstream_data_block i;
1611
1612     if (g_kstream->decrypt && encrypt_is_decrypting()) {
1613
1614 #ifdef DEBUG
1615         ckhexdump("from cyphertext", s, n);
1616 #endif
1617
1618         i.ptr = s;
1619         i.length = n;
1620         g_kstream->decrypt(&i, NULL);
1621 #ifdef DEBUG
1622         ckhexdump("to plaintext", s, n);
1623 #endif
1624     }
1625     else debug(F101,"ck_tn_decrypt not decrypting","",n);
1626 #endif /* ENCRYPTION */
1627 }
1628
1629 /*  S E N D K 5 A U T H S B
1630  *  Send a Kerberos 5 Authentication Subnegotiation to host and
1631  *  output appropriate Telnet Debug messages
1632  *
1633  *  type - Sub Negotiation type
1634  *  data - ptr to buffer containing data
1635  *  len  - len of buffer if not NUL terminated
1636  *
1637  *  returns number of characters sent or error value
1638  */
1639
1640 static int
1641 #ifdef CK_ANSIC
1642 SendK5AuthSB(int type, void *data, int len)
1643 #else
1644 SendK5AuthSB(type,data,len) int type; void *data; int len;
1645 #endif
1646 {
1647     int rc;
1648     unsigned char *p = str_data + 3;
1649     unsigned char *cd = (unsigned char *)data;
1650     extern int sstelnet;
1651
1652 #ifdef CK_SSL
1653     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1654         if (ttchk() < 0)
1655           return(0);
1656         else
1657           return(1);
1658     }
1659 #endif /* CK_SSL */
1660
1661     if ( type < 0 || type > 7 )         /* Check for invalid values */
1662         return(0);
1663
1664     if (!cd) {
1665         cd = (unsigned char *)"";
1666         len = 0;
1667     }
1668
1669     if (len == -1)                        /* Use strlen() for len */
1670         len = strlen((char *)cd);
1671
1672     /* Construct Message */
1673     *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
1674     *p++ = AUTHTYPE_KERBEROS_V5;
1675     *p = AUTH_CLIENT_TO_SERVER;
1676     *p |= auth_how;
1677 #ifdef CK_ENCRYPTION
1678     *p |= auth_crypt;
1679 #endif
1680 #ifdef USE_INI_CRED_FWD
1681     if (auth_fwd)
1682         *p |= INI_CRED_FWD_ON;
1683 #endif /* USE_INI_CRED_FWD */
1684     p++;
1685     *p++ = type;
1686     while (len-- > 0) {
1687         if ((*p++ = *cd++) == IAC)
1688             *p++ = IAC;
1689     }
1690     *p++ = IAC;
1691     *p++ = SE;
1692
1693     /* Handle Telnet Debugging Messages */
1694     if (deblog || tn_deb || debses) {
1695         int i;
1696         int deblen=p-str_data-2;
1697         char *s=NULL;
1698         int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) |
1699             auth_crypt
1700 #ifdef USE_INI_CRED_FWD
1701               | (auth_fwd?INI_CRED_FWD_ON:INI_CRED_FWD_OFF)
1702 #endif /* USE_INI_CRED_FWD */
1703                     ;
1704
1705         switch (type) {
1706         case 0:
1707             s = "AUTH";
1708             break;
1709         case 1:
1710             s = "REJECT";
1711             break;
1712         case 2:
1713             s = "ACCEPT";
1714             break;
1715         case 3:
1716             s = "RESPONSE";
1717             break;
1718         case 4:
1719             s = "FORWARD";
1720             break;
1721         case 5:
1722             s = "FORWARD_ACCEPT";
1723             break;
1724         case 6:
1725             s = "FORWARD_REJECT";
1726             break;
1727         case 7:
1728             s = "TLS_VERIFY";
1729                 break;
1730         }
1731
1732         ckmakxmsg(tn_msg,TN_MSG_LEN,
1733                   "TELNET SENT SB ",
1734                  TELOPT(TELOPT_AUTHENTICATION)," ",
1735                  str_data[3] == TELQUAL_IS ? "IS" :
1736                  str_data[3] == TELQUAL_REPLY ? "REPLY" : "???"," ",
1737                  AUTHTYPE_NAME(authentication_version)," ",
1738                  AUTHMODE_NAME(mode)," ",
1739                  s," ",NULL);
1740         tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
1741         ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
1742         debug(F100,tn_msg,"",0);
1743         if (tn_deb || debses) tn_debug(tn_msg);
1744     }
1745
1746     /* Send data */
1747 #ifdef OS2
1748     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1749 #endif
1750     rc = ttol((CHAR *)str_data, p - str_data);
1751 #ifdef OS2
1752     ReleaseTelnetMutex();
1753 #endif
1754     debug(F111,"SendK5AuthSB","ttol()",rc);
1755     return(rc);
1756 }
1757
1758 /*  S E N D K 4 A U T H S B
1759  *  Send a Kerberos 4 Authentication Subnegotiation to host and
1760  *  output appropriate Telnet Debug messages
1761  *
1762  *  type - Sub Negotiation type
1763  *  data - ptr to buffer containing data
1764  *  len  - len of buffer if not NUL terminated
1765  *
1766  *  returns number of characters sent or error value
1767  */
1768
1769 static int
1770 #ifdef CK_ANSIC
1771 SendK4AuthSB(int type, void *data, int len)
1772 #else
1773 SendK4AuthSB(type,data,len) int type; void *data; int len;
1774 #endif
1775 {
1776     int rc;
1777     unsigned char *p = str_data + 3;
1778     unsigned char *cd = (unsigned char *)data;
1779     extern int sstelnet;
1780     int mode = (auth_how & AUTH_HOW_MASK) |
1781         auth_crypt;
1782
1783     if ( type < 0 || type > 4 )         /* Check for invalid values */
1784         return(0);
1785
1786 #ifdef CK_SSL
1787     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1788         if (ttchk() < 0)
1789           return(0);
1790         else
1791           return(1);
1792     }
1793 #endif /* CK_SSL */
1794
1795     if (!cd) {
1796         cd = (unsigned char *)"";
1797         len = 0;
1798     }
1799
1800     if (len == -1)                        /* Use strlen() for len */
1801         len = strlen((char *)cd);
1802
1803
1804     /* Construct Message */
1805     *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
1806     *p++ = AUTHTYPE_KERBEROS_V4;
1807     *p = AUTH_CLIENT_TO_SERVER;
1808     *p |= mode;
1809     p++;
1810     *p++ = type;
1811     while (len-- > 0) {
1812         if ((*p++ = *cd++) == IAC)
1813             *p++ = IAC;
1814         }
1815     *p++ = IAC;
1816     *p++ = SE;
1817
1818     /* Handle Telnet Debugging Messages */
1819     if (deblog || tn_deb || debses) {
1820         int i;
1821         int deblen=p-str_data-2;
1822         char *s=NULL;
1823
1824         switch (type) {
1825         case 0:
1826             s = "AUTH";
1827             break;
1828         case 1:
1829             s = "REJECT";
1830             break;
1831         case 2:
1832             s = "ACCEPT";
1833             break;
1834         case 3:
1835             s = "CHALLENGE";
1836             break;
1837         case 4:
1838             s = "RESPONSE";
1839             break;
1840         }
1841
1842         ckmakxmsg(tn_msg,TN_MSG_LEN,"TELNET SENT SB ",
1843                  TELOPT(TELOPT_AUTHENTICATION)," ",
1844                  str_data[3] == TELQUAL_IS ? "IS" :
1845                  (str_data[3] == TELQUAL_REPLY ? "REPLY" : "???")," ",
1846                  AUTHTYPE_NAME(authentication_version)," ",
1847                  AUTHMODE_NAME(mode)," ",
1848                  s," ",NULL);
1849         tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
1850         ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
1851         debug(F100,tn_msg,"",0);
1852         if (tn_deb || debses) tn_debug(tn_msg);
1853     }
1854
1855     /* Send data */
1856 #ifdef OS2
1857     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1858 #endif
1859     rc = ttol((CHAR *)str_data, p - str_data);
1860 #ifdef OS2
1861     ReleaseTelnetMutex();
1862 #endif
1863     debug(F111,"SendK4AuthSB","ttol()",rc);
1864     return(rc);
1865 }
1866
1867 /*  S E N D S R P A U T H S B
1868  *  Send a SRP Authentication Subnegotiation to host and
1869  *  output appropriate Telnet Debug messages
1870  *
1871  *  type - Sub Negotiation type
1872  *  data - ptr to buffer containing data
1873  *  len  - len of buffer if not NUL terminated
1874  *
1875  *  returns number of characters sent or error value
1876  */
1877
1878 static int
1879 #ifdef CK_ANSIC
1880 SendSRPAuthSB(int type, void *data, int len)
1881 #else
1882 SendSRPAuthSB(type,data,len) int type; void *data; int len;
1883 #endif
1884 {
1885     int rc;
1886     unsigned char *p = str_data + 3;
1887     unsigned char *cd = (unsigned char *)data;
1888     extern int sstelnet;
1889
1890     /* Check for invalid values */
1891     if ( type != SRP_EXP && type != SRP_RESPONSE &&
1892          type != SRP_REJECT && type != SRP_ACCEPT &&
1893          type != SRP_CHALLENGE && type != SRP_PARAMS &&
1894          type != SRP_AUTH)
1895         return(0);
1896
1897     if (len == -1)                        /* Use strlen() for len */
1898         len = strlen((char *)cd);
1899
1900     /* Construct Message */
1901     *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
1902     *p++ = AUTHTYPE_SRP;
1903     *p = AUTH_CLIENT_TO_SERVER;
1904     *p |= auth_how;
1905 #ifdef CK_ENCRYPTION
1906     *p |= auth_crypt;
1907 #endif
1908     p++;
1909     *p++ = type;
1910     while (len-- > 0) {
1911         if ((*p++ = *cd++) == IAC)
1912             *p++ = IAC;
1913         }
1914     *p++ = IAC;
1915     *p++ = SE;
1916
1917     /* Handle Telnet Debugging Messages */
1918     if (deblog || tn_deb || debses) {
1919         int i;
1920         int deblen=p-str_data-2;
1921         char *s=NULL;
1922         int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) |
1923             auth_crypt;
1924
1925         switch (type) {
1926         case 0:
1927             s = "AUTH";
1928             break;
1929         case 1:
1930             s = "REJECT";
1931             break;
1932         case 2:
1933             s = "ACCEPT";
1934             break;
1935         case 3:
1936             s = "CHALLENGE";
1937             break;
1938         case 4:
1939             s = "RESPONSE";
1940             break;
1941         case 5:
1942             s = "FORWARD";
1943             break;
1944         case 6:
1945             s = "FORWARD_ACCEPT";
1946             break;
1947         case 7:
1948             s = "FORWARD_REJECT";
1949             break;
1950         case 8:
1951             s = "EXP";
1952             break;
1953         case 9:
1954             s = "PARAMS";
1955             break;
1956         }
1957
1958         ckmakxmsg(tn_msg,TN_MSG_LEN,
1959                   "TELNET SENT SB ",
1960                  TELOPT(TELOPT_AUTHENTICATION)," ",
1961                  str_data[3] == TELQUAL_REPLY ? "REPLY" :
1962                  str_data[3] == TELQUAL_IS ? "IS" : "???"," ",
1963                  AUTHTYPE_NAME(authentication_version)," ",
1964                  AUTHMODE_NAME(mode)," ",
1965                  s," ",NULL);
1966         tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
1967         ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
1968         debug(F100,tn_msg,"",0);
1969         if (tn_deb || debses) tn_debug(tn_msg);
1970     }
1971
1972     /* Send data */
1973 #ifdef OS2
1974     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1975 #endif
1976     rc = ttol((CHAR *)str_data, p - str_data);
1977 #ifdef OS2
1978     ReleaseTelnetMutex();
1979 #endif
1980     return(rc);
1981 }
1982
1983 #ifdef CK_ENCRYPTION
1984 /*
1985  * Function: Enable or disable the encryption process.
1986  *
1987  * Parameters:
1988  *      enable - TRUE to enable, FALSE to disable.
1989  */
1990 static VOID
1991 #ifdef CK_ANSIC
1992 auth_encrypt_enable(BOOL enable)
1993 #else
1994 auth_encrypt_enable(enable) BOOL enable;
1995 #endif
1996 {
1997   encrypt_flag = enable;
1998 }
1999 #endif
2000
2001 /*
2002  * Function: Abort the authentication process
2003  *
2004  * Parameters:
2005  */
2006 static VOID
2007 #ifdef CK_ANSIC
2008 auth_abort(char *errmsg, long r)
2009 #else
2010 auth_abort(errmsg,r) char *errmsg; long r;
2011 #endif
2012 {
2013     char buf[9];
2014     extern int sstelnet;
2015
2016 #ifdef CK_SSL
2017     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
2018         return;
2019     }
2020 #endif /* CK_SSL */
2021     debug(F111,"auth_abort",errmsg,r);
2022
2023     /* Construct Telnet Debugging messages */
2024     if (deblog || tn_deb || debses) {
2025         ckmakxmsg(tn_msg,TN_MSG_LEN,
2026                   "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
2027                   " IS ",AUTHTYPE_NAME(AUTHTYPE_NULL)," ",
2028                    AUTHTYPE_NAME(AUTHTYPE_NULL)," IAC SE",
2029                    NULL,NULL,NULL,NULL,NULL
2030                  );
2031         debug(F100,tn_msg,"",0);
2032         if (tn_deb || debses) tn_debug(tn_msg);
2033     }
2034
2035     /* Construct the Abort message to send to the host   */
2036     /* Basicly we change the authentication type to NULL */
2037     sprintf(buf, "%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION,
2038              sstelnet ? TELQUAL_REPLY : TELQUAL_IS, AUTHTYPE_NULL,
2039              AUTHTYPE_NULL, IAC, SE);   /* safe */
2040 #ifdef OS2
2041     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
2042 #endif
2043     ttol((CHAR *)buf, 8);
2044 #ifdef OS2
2045     ReleaseTelnetMutex();
2046 #endif
2047
2048     /* If there is an error message, and error number construct */
2049     /* an explanation to display to the user                    */
2050     if (errmsg != NULL) {
2051         ckstrncpy(strTmp, errmsg, AUTHTMPBL);
2052     } else
2053         strTmp[0] = '\0';
2054
2055
2056     if (r != AUTH_SUCCESS) {
2057         ckstrncat(strTmp, "\r\n",AUTHTMPBL);
2058 #ifdef KRB4
2059         if ( authentication_version == AUTHTYPE_KERBEROS_V4 ) {
2060             ckstrncat(strTmp, (char *)krb_get_err_text_entry(r),
2061                        AUTHTMPBL);
2062             debug(F111,"auth_abort",(char *)krb_get_err_text_entry(r),r);
2063         }
2064 #endif
2065 #ifdef KRB5
2066         if ( authentication_version == AUTHTYPE_KERBEROS_V5 ) {
2067             ckstrncat(strTmp, error_message(r),AUTHTMPBL);
2068             debug(F111,"auth_abort",error_message(r),r);
2069         }
2070 #endif
2071     }
2072     printf("Authentication failed: %s\r\n",strTmp);
2073 #ifdef CKSYSLOG
2074     if (ckxsyslog >= SYSLG_LI && ckxlogging) {
2075         cksyslog(SYSLG_LI, 0, "Telnet authentication failure",
2076                   (char *) szUserNameRequested,
2077                   strTmp);
2078     }
2079 #endif /* CKSYSLOG */
2080     authentication_version = AUTHTYPE_NULL;
2081 }
2082
2083
2084 /*
2085  * Function: Copy data to buffer, doubling IAC character if present.
2086  *
2087  */
2088 int
2089 #ifdef CK_ANSIC
2090 copy_for_net(unsigned char *to, unsigned char *from, int c)
2091 #else
2092 copy_for_net(to,from,c) unsigned char *to; unsigned char *from; int c;
2093 #endif
2094 {
2095     int n;
2096
2097     n = c;
2098     debug(F111,"copy_for_net","before",n);
2099     while (c-- > 0) {
2100         if ((*to++ = *from++) == IAC) {
2101             n++;
2102             *to++ = IAC;
2103         }
2104     }
2105     debug(F111,"copy_for_net","after",n);
2106     return n;
2107 }
2108
2109 #ifdef CK_SSL
2110 /*  S E N D S S L A U T H S B
2111  *  Send a SSL Authentication Subnegotiation to host and
2112  *  output appropriate Telnet Debug messages
2113  *
2114  *  type - Sub Negotiation type
2115  *  data - ptr to buffer containing data
2116  *  len  - len of buffer if not NUL terminated
2117  *
2118  *  returns number of characters sent or error value
2119  */
2120
2121 int
2122 #ifdef CK_ANSIC
2123 SendSSLAuthSB(int type, void *data, int len)
2124 #else
2125 SendSSLAuthSB(type,data,len) int type; void *data; int len;
2126 #endif
2127 {
2128     int rc;
2129     unsigned char *p = str_data + 3;
2130     unsigned char *cd = (unsigned char *)data;
2131     extern int sstelnet;
2132
2133     /* Check for invalid values */
2134     if ( type != SSL_START && type != SSL_ACCEPT &&
2135          type != SSL_REJECT)
2136         return(0);
2137
2138     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
2139         if (ttchk() < 0)
2140           return(0);
2141         else
2142           return(1);
2143     }
2144
2145     if (len == -1)                        /* Use strlen() for len */
2146         len = strlen((char *)cd);
2147
2148     /* Construct Message */
2149     *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
2150     *p++ = AUTHTYPE_SSL;
2151     *p = AUTH_CLIENT_TO_SERVER;
2152     *p |= auth_how;
2153 #ifdef CK_ENCRYPTION
2154     *p |= auth_crypt;
2155 #endif
2156     p++;
2157     *p++ = type;
2158     while (len-- > 0) {
2159         if ((*p++ = *cd++) == IAC)
2160             *p++ = IAC;
2161         }
2162     *p++ = IAC;
2163     *p++ = SE;
2164
2165     /* Handle Telnet Debugging Messages */
2166     if (deblog || tn_deb || debses) {
2167         int i;
2168         int deblen=p-str_data-2;
2169         char *s=NULL;
2170         int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) |
2171             (auth_crypt?AUTH_ENCRYPT_USING_TELOPT:AUTH_ENCRYPT_OFF);
2172
2173         switch (type) {
2174         case SSL_START:
2175             s = "START";
2176             break;
2177         case SSL_ACCEPT:
2178             s = "ACCEPT";
2179             break;
2180         case SSL_REJECT:
2181             s = "REJECT";
2182             break;
2183         }
2184
2185         ckmakxmsg(tn_msg,TN_MSG_LEN,
2186                   "TELNET SENT SB ",
2187                  TELOPT(TELOPT_AUTHENTICATION)," ",
2188                  str_data[3] == TELQUAL_REPLY ? "REPLY" :
2189                  str_data[3] == TELQUAL_IS ? "IS" : "???"," ",
2190                  AUTHTYPE_NAME(authentication_version)," ",
2191                  AUTHMODE_NAME(mode)," ",
2192                  s," ",NULL);
2193         tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
2194         ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
2195         debug(F100,tn_msg,"",0);
2196         if (tn_deb || debses) tn_debug(tn_msg);
2197     }
2198
2199     /* Send data */
2200 #ifdef OS2
2201     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
2202 #endif
2203     rc = ttol((CHAR *)str_data, p - str_data);
2204 #ifdef OS2
2205     ReleaseTelnetMutex();
2206 #endif
2207     return(rc);
2208 }
2209 #endif  /* CK_SSL */
2210
2211 int
2212 tn_how_ok(int how)
2213 {
2214     switch ( tn_auth_how ) {
2215     case TN_AUTH_HOW_ANY:
2216         return(1);
2217     case TN_AUTH_HOW_ONE_WAY:
2218         return((how & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY);
2219     case TN_AUTH_HOW_MUTUAL:
2220         return((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL);
2221     default:
2222         return(0);
2223     }
2224 }
2225
2226 int
2227 tn_enc_ok(int enc)
2228 {
2229     switch ( tn_auth_enc ) {
2230     case TN_AUTH_ENC_ANY:
2231         if ((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS &&
2232             (!ck_ssleay_is_installed()
2233 #ifdef CK_SSL
2234              || !ssl_finished_messages ||
2235              !(tls_active_flag || ssl_active_flag)
2236 #endif /* CK_SSL */
2237              )) {
2238 #ifdef CK_SSL
2239             if (!ssl_finished_messages)
2240                 debug(F100,"tn_enc_ok !ssl_finished_messages","",0);
2241 #endif /* CK_SSL */
2242             return(0);
2243         }
2244         return(1);
2245     case TN_AUTH_ENC_NONE:
2246         return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_OFF);
2247     case TN_AUTH_ENC_TELOPT:
2248         return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT);
2249     case TN_AUTH_ENC_EXCH:
2250         return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE);
2251     case TN_AUTH_ENC_TLS:
2252         return(((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) &&
2253                ck_ssleay_is_installed()
2254 #ifdef CK_SSL
2255                && ssl_finished_messages &&
2256                (tls_active_flag || ssl_active_flag)
2257 #endif /* CK_SSL */
2258            );
2259     default:
2260         return(0);
2261     }
2262 }
2263
2264 static int
2265 atok(int at) {
2266     int i;
2267     if ( auth_type_user[0] == AUTHTYPE_AUTO )
2268         return(1);
2269     if ( auth_type_user[0] == AUTHTYPE_NULL )
2270         return(0);
2271
2272     for ( i=0;
2273           i<AUTHTYPLSTSZ && auth_type_user[i] != AUTHTYPE_NULL;
2274           i++ ) {
2275         if ( auth_type_user[i] == at )
2276             return(1);
2277     }
2278
2279     return(0);
2280 }
2281
2282
2283 /*
2284  * Function: Parse authentication send command
2285  *
2286  * Parameters:
2287  *  parsedat - the sub-command data.
2288  *
2289  *      end_sub - index of the character in the 'parsedat' array which
2290  *              is the last byte in a sub-negotiation
2291  *
2292  * Returns: Kerberos error code.
2293  */
2294
2295 static unsigned char send_list[512];
2296 static int  send_len = 0;
2297
2298 _PROTOTYP(static int auth_send, (unsigned char *parsedat, int end_sub));
2299
2300 static int
2301 #ifdef CK_ANSIC
2302 auth_resend(int type)
2303 #else
2304 auth_resend(type) int type;
2305 #endif /* CK_ANSIC */
2306 {
2307     int i=2;
2308     while (i+1 <= send_len) {
2309         if (send_list[i] == type) {
2310             int j;
2311             send_len -= 2;
2312             for (j = i; j < send_len; j++)
2313                 send_list[j] = send_list[j+2];
2314         } else {
2315             i += 2;
2316         }
2317     }
2318     return(auth_send(send_list,send_len));
2319 }
2320
2321 static int
2322 #ifdef CK_ANSIC
2323 auth_send(unsigned char *parsedat, int end_sub)
2324 #else
2325 auth_send(parsedat,end_sub) unsigned char *parsedat; int end_sub;
2326 #endif
2327 {
2328     static unsigned char buf[4096];
2329     unsigned char *pname;
2330     int plen;
2331     int r;
2332     int i;
2333     int mode;
2334 #ifdef MIT_CURRENT
2335 #ifdef CK_ENCRYPTION
2336     krb5_data data;
2337     krb5_enc_data encdata;
2338     krb5_error_code code;
2339     krb5_keyblock random_key;
2340 #endif /* ENCRYPTION */
2341 #endif /* MIT_CURRENT */
2342 #ifdef KRB5
2343     int krb5_msg = 0;
2344 #endif /* KRB5 */
2345 #ifdef KRB4
2346     int krb4_msg = 0;
2347 #endif /* KRB4 */
2348 #ifdef GSSAPI_KRB5
2349     int gssk5_msg = 0;
2350 #endif /* GSSAPI_KRB5 */
2351     int iaccnt=0;
2352
2353 #ifdef CK_SSL
2354     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
2355         return(AUTH_SUCCESS);
2356 #endif /* CK_SSL */
2357
2358     auth_how = -1;              /* We have not found an auth method  */
2359     auth_crypt = 0;             /* We are not using encryption (yet) */
2360     send_len = end_sub > 512 ? 512 : end_sub;
2361     memcpy(send_list,parsedat,send_len);
2362
2363     /* Search the list of acceptable Authentication types sent from */
2364     /* the host and find one that we support                        */
2365
2366     /* For Kerberos authentications, try to determine if we have a  */
2367     /* valid TGT, if not skip over the authentication type because  */
2368     /* we wouldn't be able to successfully login anyway.  Perhaps   */
2369     /* there is another supported authentication which we could use */
2370
2371 #ifdef NO_FTP_AUTH
2372     /* If the userid is "ftp" or "anonymous" refuse to perform AUTH */
2373     /* for Kerberos or SRP.                                         */
2374 #endif /* NO_FTP_AUTH */
2375
2376     if ( auth_type_user[0] == AUTHTYPE_AUTO ) {
2377     for (i = 2; i+1 <= end_sub; i += 2) {
2378 #ifdef NTLM
2379         if (parsedat[i] == AUTHTYPE_NTLM &&
2380              ck_ntlm_is_valid(1) &&
2381              ntlm_auth_send() == 0) {
2382             if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
2383                  tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2384 #ifdef CK_ENCRYPTION
2385                 /* NTLM does not support Telnet Encryption */
2386                 if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
2387                     continue;
2388                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2389 #endif /* CK_ENCRYPTION */
2390                 TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2391                 TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2392                 authentication_version = AUTHTYPE_NTLM;
2393                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2394                 break;
2395             }
2396         }
2397 #endif /* NTLM */
2398 #ifdef CK_SSL
2399         if ( parsedat[i] == AUTHTYPE_SSL && ssl_initialized &&
2400 #ifdef SSLDLL
2401              ck_ssleay_is_installed() &&
2402 #endif /* SSLDLL */
2403              !tls_active_flag && !ssl_active_flag
2404 #ifndef USE_CERT_CB
2405              && tls_load_certs(ssl_ctx,ssl_con,0)
2406 #endif /* USE_CERT_CB */
2407              ) {
2408
2409             if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
2410                  tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2411 #ifdef CK_ENCRYPTION
2412                 /* SSL does not support Telnet Encryption */
2413                 if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
2414                     continue;
2415                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2416 #endif /* CK_ENCRYPTION */
2417                 TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2418                 TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2419                 authentication_version = AUTHTYPE_SSL;
2420                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2421                 break;
2422             }
2423         }
2424 #endif /* SSL */
2425 #ifdef CK_SRP
2426         if ( parsedat[i] == AUTHTYPE_SRP
2427 #ifdef SRPDLL
2428              && hSRP
2429 #endif /* SRPDLL */
2430 #ifdef NO_FTP_AUTH
2431              && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName)
2432 #endif /* NO_FTP_AUTH */
2433              ) {
2434             if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
2435                  tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2436 #ifdef PRE_SRP_1_4_5
2437                 if (parsedat[i+1] & AUTH_ENCRYPT_MASK)
2438                      /* Do not support ENCRYPT_USING_TELOPT yet. */
2439                     continue;
2440 #endif /* PRE_SRP_1_4_5 */
2441                 if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2442                      AUTH_ENCRYPT_USING_TELOPT) &&
2443                     (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
2444                      TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
2445                     continue;
2446
2447                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2448 #ifdef CK_ENCRYPTION
2449                 if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
2450                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2451                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2452                 }
2453 #endif /* CK_ENCRYPTION */
2454 #ifdef CK_SSL
2455                 if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
2456                      ck_ssleay_is_installed() &&
2457                      (tls_active_flag || ssl_active_flag) ) {
2458                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2459                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2460                 }
2461 #endif /* CK_SSL */
2462                 authentication_version = AUTHTYPE_SRP;
2463                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2464                 break;
2465             }
2466         }
2467 #endif /* SRP */
2468 #ifdef GSSAPI_KRB5
2469         if (parsedat[i] == AUTHTYPE_GSSAPI_KRB5 &&
2470             (parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2471             AUTH_ENCRYPT_AFTER_EXCHANGE &&
2472 #ifdef OS2
2473             hGSSAPI &&
2474 #endif /* OS2 */
2475 #ifdef NO_FTP_AUTH
2476              strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
2477 #endif /* NO_FTP_AUTH */
2478              ck_gssapi_is_installed() && !gssk5_msg)
2479         {
2480             if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
2481                                   parsedat[i+1] & AUTH_ENCRYPT_MASK,
2482                                   parsedat[i+1] & INI_CRED_FWD_MASK) )
2483             {
2484                 /* If we are auto-getting TGTs, try */
2485                 if ( !ck_krb5_is_tgt_valid() ) {
2486                 printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n");
2487                 }
2488                 gssk5_msg = 1;
2489             }
2490             else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
2491                       AUTH_CLIENT_TO_SERVER &&
2492                       tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2493                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2494 #ifdef CK_ENCRYPTION
2495                 if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) {
2496                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2497                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2498                 }
2499 #endif /* CK_ENCRYPTION */
2500                 auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK;
2501                 authentication_version = AUTHTYPE_GSSAPI_KRB5;
2502                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2503                 break;
2504             }
2505         }
2506 #endif /* GSSAPI_KRB5 */
2507 #ifdef KRB5
2508         if (parsedat[i] == AUTHTYPE_KERBEROS_V5 &&
2509 #ifdef OS2
2510              hKRB5_32 &&
2511 #endif /* OS2 */
2512 #ifdef NO_FTP_AUTH
2513              strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
2514 #endif /* NO_FTP_AUTH */
2515              ck_krb5_is_installed() && !krb5_msg) {
2516
2517             /* Without encryption we can't perform mutual authentication */
2518             if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
2519                  !ck_crypt_is_installed())
2520                 continue;
2521
2522             /* Skip over entries that request credential forwarding */
2523             /* if we are not forwarding.                            */
2524             if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) ||
2525                 (forward_flag &&
2526                   ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY)))
2527                 continue;
2528
2529             if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
2530                                 parsedat[i+1] & AUTH_ENCRYPT_MASK,
2531                                 parsedat[i+1] & INI_CRED_FWD_MASK) )
2532             {
2533                 /* If we are auto-getting TGTs, try */
2534                 if ( !ck_krb5_is_tgt_valid() ) {
2535                 printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n");
2536                 }
2537                 krb5_msg = 1;
2538             }
2539             else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
2540                       AUTH_CLIENT_TO_SERVER &&
2541                       tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2542                 if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2543                      AUTH_ENCRYPT_USING_TELOPT) &&
2544                      (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
2545                        TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
2546                     continue;
2547                 if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2548                      AUTH_ENCRYPT_START_TLS) &&
2549                      (!ck_ssleay_is_installed()
2550 #ifdef CK_SSL
2551                        || !(tls_active_flag || ssl_active_flag)
2552 #endif /* CK_SSL */
2553                        ))
2554                     continue;
2555
2556                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2557 #ifdef CK_ENCRYPTION
2558                 if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
2559                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2560                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2561                 }
2562 #endif /* CK_ENCRYPTION */
2563 #ifdef CK_SSL
2564                 if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
2565                      ck_ssleay_is_installed() &&
2566                      (tls_active_flag || ssl_active_flag) ) {
2567                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2568                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2569                 }
2570 #endif /* CK_SSL */
2571                 auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK;
2572                 authentication_version = AUTHTYPE_KERBEROS_V5;
2573                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2574                 if ( auth_how == AUTH_HOW_ONE_WAY ) {
2575                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2576                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2577                 }
2578                 break;
2579             }
2580         }
2581 #endif /* KRB5 */
2582 #ifdef KRB4
2583         if (parsedat[i] == AUTHTYPE_KERBEROS_V4 &&
2584 #ifdef OS2
2585              hKRB4_32 &&
2586 #endif /* OS2 */
2587 #ifdef NO_FTP_AUTH
2588              strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
2589 #endif /* NO_FTP_AUTH */
2590              ck_krb4_is_installed() && !krb4_msg) {
2591             int rc = 0;
2592
2593             /* Without encryption we can't perform mutual authentication */
2594             if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
2595                  !ck_crypt_is_installed() )
2596                 continue;
2597
2598             if ( !k4_auth_send() )
2599             {
2600                 /* If we are auto-getting TGTs, try */
2601                 if ( !ck_krb4_is_tgt_valid() ) {
2602                     printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n");
2603                 }
2604                 krb4_msg = 1;
2605             }
2606             else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
2607                       AUTH_CLIENT_TO_SERVER &&
2608                       tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2609 #ifdef CK_ENCRYPTION
2610                 if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) &&
2611                      (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
2612                        TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
2613                     continue;
2614                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2615                 if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
2616                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2617                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2618                 }
2619 #endif /* CK_ENCRYPTION */
2620                 authentication_version = AUTHTYPE_KERBEROS_V4;
2621                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2622                 if ( auth_how == AUTH_HOW_ONE_WAY ) {
2623                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2624                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2625                 }
2626                 break;
2627             }
2628         }
2629 #endif /* KRB4 */
2630     }
2631     } else {
2632         for (i = 2; i+1 <= end_sub; i += 2) {
2633 #ifdef CK_SSL
2634             if ( atok(AUTHTYPE_SSL) && parsedat[i] == AUTHTYPE_SSL &&
2635 #ifdef SSLDLL
2636                  ck_ssleay_is_installed() &&
2637 #endif /* SSLDLL */
2638                  !tls_active_flag && !ssl_active_flag && ssl_initialized
2639 #ifndef USE_CERT_CB
2640                  && tls_load_certs(ssl_ctx,ssl_con,0)
2641 #endif /* USE_CERT_CB */
2642                  )
2643             {
2644                 if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
2645                      tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2646 #ifdef CK_ENCRYPTION
2647                     /* SSL does not support Telnet Encryption */
2648                     if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
2649                         continue;
2650                     auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2651 #endif /* CK_ENCRYPTION */
2652                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2653                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2654                     authentication_version = AUTHTYPE_SSL;
2655                     auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2656                     break;
2657                 }
2658             }
2659 #endif /* SSL */
2660 #ifdef CK_SRP
2661             if ( atok(AUTHTYPE_SRP) &&
2662                  parsedat[i] == AUTHTYPE_SRP
2663 #ifdef SRPDLL
2664                  && hSRP
2665 #endif /* SRPDLL */
2666 #ifdef NO_FTP_AUTH
2667                  && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName)
2668 #endif /* NO_FTP_AUTH */
2669                  ) {
2670                 if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
2671                      tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2672 #ifdef PRE_SRP_1_4_5
2673                 if (parsedat[i+1] & AUTH_ENCRYPT_MASK)
2674                      /* Do not support ENCRYPT_USING_TELOPT yet. */
2675                     continue;
2676 #endif /* PRE_SRP_1_4_5 */
2677                 if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2678                      AUTH_ENCRYPT_USING_TELOPT) &&
2679                      (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
2680                        TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
2681                     continue;
2682                 if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2683                      AUTH_ENCRYPT_START_TLS) &&
2684                      (!ck_ssleay_is_installed()
2685 #ifdef CK_SSL
2686                        || !(tls_active_flag || ssl_active_flag)
2687 #endif /* CK_SSL */
2688                        ))
2689                     continue;
2690                     auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2691 #ifdef CK_ENCRYPTION
2692                     if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
2693                         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2694                         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2695                     }
2696 #endif /* CK_ENCRYPTION */
2697 #ifdef CK_SSL
2698                 if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
2699                      ck_ssleay_is_installed() &&
2700                      (tls_active_flag || ssl_active_flag) ) {
2701                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2702                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2703                 }
2704 #endif /* CK_SSL */
2705                     authentication_version = AUTHTYPE_SRP;
2706                     auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2707                     break;
2708                 }
2709             }
2710 #endif /* SRP */
2711 #ifdef GSSAPI_KRB5
2712         if (atok(AUTHTYPE_GSSAPI_KRB5) &&
2713             parsedat[i] == AUTHTYPE_GSSAPI_KRB5 &&
2714             (parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2715             AUTH_ENCRYPT_AFTER_EXCHANGE &&
2716 #ifdef OS2
2717             hGSSAPI &&
2718 #endif /* OS2 */
2719 #ifdef NO_FTP_AUTH
2720             strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
2721 #endif /* NO_FTP_AUTH */
2722             ck_gssapi_is_installed() && !gssk5_msg)
2723         {
2724             if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
2725                                   parsedat[i+1] & AUTH_ENCRYPT_MASK,
2726                                   parsedat[i+1] & INI_CRED_FWD_MASK) )
2727             {
2728                 /* If we are auto-getting TGTs, try */
2729                 if ( !ck_krb5_is_tgt_valid() ) {
2730                 printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n");
2731                 }
2732                 gssk5_msg = 1;
2733             }
2734             else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
2735                       AUTH_CLIENT_TO_SERVER &&
2736                       tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2737                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2738 #ifdef CK_ENCRYPTION
2739                 if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) {
2740                     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2741                     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2742                 }
2743 #endif /* CK_ENCRYPTION */
2744                 auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK;
2745                 authentication_version = AUTHTYPE_GSSAPI_KRB5;
2746                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2747                 break;
2748             }
2749         }
2750 #endif /* GSSAPI_KRB5 */
2751 #ifdef KRB5
2752             if ( atok(AUTHTYPE_KERBEROS_V5) &&
2753                  parsedat[i] == AUTHTYPE_KERBEROS_V5 &&
2754 #ifdef OS2
2755                  hKRB5_32 &&
2756 #endif /* OS2 */
2757 #ifdef NO_FTP_AUTH
2758                  strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
2759 #endif /* NO_FTP_AUTH */
2760                  ck_krb5_is_installed() && !krb5_msg) {
2761
2762                 /* Without encryption we can't perform mutual authentication */
2763                 if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
2764                      !ck_crypt_is_installed())
2765                     continue;
2766
2767                 /* Skip over entries that request credential forwarding */
2768                 /* if we are not forwarding.                            */
2769                 if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) ||
2770                      (forward_flag &&
2771                        ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY)))
2772                     continue;
2773
2774                 if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
2775                                     parsedat[i+1] & AUTH_ENCRYPT_MASK,
2776                                     parsedat[i+1] & INI_CRED_FWD_MASK) )
2777                 {
2778                     /* If we are auto-getting TGTs, try */
2779                     if ( !ck_krb5_is_tgt_valid() ) {
2780                         printf(
2781                            "Kerberos 5: Ticket Getting Ticket not valid.\r\n");
2782                     }
2783                     krb5_msg = 1;
2784                 }
2785                 else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
2786                           AUTH_CLIENT_TO_SERVER &&
2787                           tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1]))
2788                 {
2789                     if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2790                          AUTH_ENCRYPT_USING_TELOPT) &&
2791                          (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
2792                            TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
2793                         continue;
2794                     if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
2795                          AUTH_ENCRYPT_START_TLS) &&
2796                          (!ck_ssleay_is_installed()
2797 #ifdef CK_SSL
2798                            || !(tls_active_flag || ssl_active_flag)
2799 #endif /* CK_SSL */
2800                            ))
2801                         continue;
2802                     auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2803 #ifdef CK_ENCRYPTION
2804                     if (auth_crypt) {
2805                         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2806                         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2807                     }
2808 #endif /* CK_ENCRYPTION */
2809 #ifdef CK_SSL
2810                     if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
2811                          ck_ssleay_is_installed() &&
2812                          (tls_active_flag || ssl_active_flag) ) {
2813                         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2814                         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2815                     }
2816 #endif /* CK_SSL */
2817                     authentication_version = AUTHTYPE_KERBEROS_V5;
2818                     auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2819                     if ( auth_how == AUTH_HOW_ONE_WAY ) {
2820                         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2821                         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2822                     }
2823                     break;
2824                 }
2825             }
2826 #endif /* KRB5 */
2827 #ifdef KRB4
2828             if ( atok(AUTHTYPE_KERBEROS_V4) &&
2829                  parsedat[i] == AUTHTYPE_KERBEROS_V4 &&
2830 #ifdef OS2
2831                  hKRB4_32 &&
2832 #endif /* OS2 */
2833 #ifdef NO_FTP_AUTH
2834                  strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
2835 #endif /* NO_FTP_AUTH */
2836                  ck_krb4_is_installed() && !krb4_msg) {
2837                 int rc = 0;
2838
2839                 /* Without encryption we can't perform mutual authentication */
2840                 if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
2841                      !ck_crypt_is_installed())
2842                     continue;
2843
2844                 if ( !k4_auth_send() )
2845                 {
2846                     /* If we are auto-getting TGTs, try */
2847                     if ( !ck_krb4_is_tgt_valid() ) {
2848                     printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n");
2849                     }
2850                     krb4_msg = 1;
2851                 }
2852                 else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
2853                           AUTH_CLIENT_TO_SERVER &&
2854                           tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1]))
2855                 {
2856 #ifdef CK_ENCRYPTION
2857                     if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) &&
2858                         (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
2859                          TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
2860                       continue;
2861                     auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2862                     if (auth_crypt) {
2863                         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2864                         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
2865                     }
2866 #endif /* CK_ENCRYPTION */
2867                     authentication_version = AUTHTYPE_KERBEROS_V4;
2868                     auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2869                     if ( auth_how == AUTH_HOW_ONE_WAY ) {
2870                         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2871                         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2872                     }
2873                     break;
2874                 }
2875             }
2876 #endif /* KRB4 */
2877 #ifdef NTLM
2878         if ( atok(AUTHTYPE_NTLM) &&
2879              parsedat[i] == AUTHTYPE_NTLM &&
2880              ck_ntlm_is_valid(1) &&
2881              ntlm_auth_send() == 0) {
2882             if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
2883                  tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
2884 #ifdef CK_ENCRYPTION
2885                 /* NTLM does not support Telnet Encryption */
2886                 if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
2887                     continue;
2888                 auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
2889 #endif /* CK_ENCRYPTION */
2890                 TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2891                 TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2892                 authentication_version = AUTHTYPE_NTLM;
2893                 auth_how = parsedat[i+1] & AUTH_HOW_MASK;
2894                 break;
2895             }
2896         }
2897 #endif /* NTLM */
2898         }
2899     }
2900
2901     if (auth_how == -1) {               /* Did we find one? */
2902         switch ( auth_type_user[0] ) {  /* If not, abort the negotiation */
2903         case AUTHTYPE_NULL:
2904             auth_abort("User refused to accept any authentication method",0);
2905             break;
2906         case AUTHTYPE_AUTO:
2907             auth_abort("No authentication method available", 0);
2908             break;
2909         default: {
2910             char msg[80];
2911             ckmakmsg(msg,80,AUTHTYPE_NAME(auth_type_user[0]),
2912                       " could not be negotiated",NULL,NULL
2913                      );
2914             auth_abort(msg, 0);
2915         }
2916         }
2917         auth_finished(AUTH_REJECT);
2918         return AUTH_FAILURE;
2919     }
2920
2921     printf("Authenticating with %s\r\n",
2922             AUTHTYPE_NAME(authentication_version));
2923
2924     /* Send Telnet Auth Name message (if necessary) */
2925     switch ( authentication_version ) {
2926     case AUTHTYPE_SRP:
2927     case AUTHTYPE_KERBEROS_V4:
2928     case AUTHTYPE_KERBEROS_V5:
2929     case AUTHTYPE_GSSAPI_KRB5:
2930         /* if we do not have a name to login with get one now. */
2931         while ( szUserName[0] == '\0' ) {
2932             extern char * tn_pr_uid;
2933             int ok = uq_txt(NULL,
2934                      tn_pr_uid && tn_pr_uid[0] ? tn_pr_uid : "Host Userid: ",
2935                             1, NULL, szUserName, 63, NULL,DEFAULT_UQ_TIMEOUT);
2936             if ( !ok )
2937                 return AUTH_FAILURE;
2938         }
2939         plen = strlen(szUserName);
2940         pname = (unsigned char *) szUserName;
2941
2942         /* Construct Telnet Debugging Message */
2943         if (deblog || tn_deb || debses) {
2944             ckmakxmsg(tn_msg,TN_MSG_LEN,
2945                        "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
2946                        " NAME ",(char *)pname," IAC SE",NULL,
2947                        NULL,NULL,NULL,NULL,NULL,NULL
2948                      );
2949             debug(F100,tn_msg,"",0);
2950             if (tn_deb || debses) tn_debug(tn_msg);
2951         }
2952
2953         /* Construct and send Authentication Name subnegotiation */
2954         if ( plen < sizeof(buf) - 6 ) {
2955             sprintf((char *)buf, "%c%c%c%c", IAC, SB, 
2956                      TELOPT_AUTHENTICATION,
2957                      TELQUAL_NAME);
2958             memcpy(&buf[4], pname, plen);               /* safe */
2959             sprintf((char *)&buf[plen + 4], "%c%c", IAC, SE);   /* safe */
2960 #ifdef OS2
2961             RequestTelnetMutex( SEM_INDEFINITE_WAIT );
2962 #endif
2963             ttol((CHAR *)buf, plen+6);
2964 #ifdef OS2
2965             ReleaseTelnetMutex();
2966 #endif
2967         } else {
2968             sprintf((char *)buf, "%c%c%c%c%c%c", IAC, SB, 
2969                      TELOPT_AUTHENTICATION,
2970                      TELQUAL_NAME, IAC, SE);    /* safe */
2971 #ifdef OS2
2972             RequestTelnetMutex( SEM_INDEFINITE_WAIT );
2973 #endif
2974             ttol((CHAR *)buf, 6);
2975 #ifdef OS2
2976             ReleaseTelnetMutex();
2977 #endif
2978         }
2979     }
2980
2981     /* Construct Authentication Mode subnegotiation message (if necessary) */
2982     switch ( authentication_version ) {
2983     case AUTHTYPE_SRP:
2984     case AUTHTYPE_KERBEROS_V4:
2985     case AUTHTYPE_KERBEROS_V5:
2986     case AUTHTYPE_GSSAPI_KRB5:
2987     case AUTHTYPE_NTLM:
2988         mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt
2989 #ifdef USE_INI_CRED_FWD
2990                | (((authentication_version == AUTHTYPE_KERBEROS_V5) &&
2991                   auth_fwd)?INI_CRED_FWD_ON:INI_CRED_FWD_OFF)
2992 #endif /* USE_INI_CRED_FWD */
2993                ;
2994         sprintf((char *)buf, "%c%c%c%c%c%c%c",
2995                  IAC, SB, TELOPT_AUTHENTICATION,
2996                  TELQUAL_IS,
2997                  authentication_version,
2998                  mode,
2999                  KRB_AUTH);     /* safe */
3000         break;
3001     }
3002
3003     /* Send initial authentication data */
3004     switch ( authentication_version ) {
3005 #ifdef CK_SSL
3006     case AUTHTYPE_SSL:
3007         SendSSLAuthSB(SSL_START,NULL,0);
3008         break;
3009 #endif /* SSL */
3010 #ifdef CK_SRP
3011     case AUTHTYPE_SRP:
3012         sprintf(&buf[7], "%c%c", IAC, SE);      /* safe */
3013         if (deblog || tn_deb || debses) {
3014             ckmakxmsg(tn_msg,TN_MSG_LEN,
3015                       "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
3016                       " IS ",AUTHTYPE_NAME(authentication_version),
3017                       " AUTH ",AUTHMODE_NAME(mode)," IAC SE",
3018                       NULL,NULL,NULL,NULL,NULL
3019                      );
3020             debug(F100,tn_msg,"",0);
3021             if (tn_deb || debses) tn_debug(tn_msg);
3022         }
3023 #ifdef OS2
3024         RequestTelnetMutex( SEM_INDEFINITE_WAIT );
3025 #endif
3026         ttol((CHAR *)buf, 9);
3027 #ifdef OS2
3028         ReleaseTelnetMutex();
3029 #endif
3030         break;
3031 #endif /* SRP */
3032 #ifdef NTLM
3033     case AUTHTYPE_NTLM: {
3034         int length = 0;
3035
3036         for ( i=0 ; i<NTLMSecBuf[0].cbBuffer ; i++ ) {
3037             if ( ((char *)NTLMSecBuf[0].pvBuffer)[i] == IAC )
3038                 iaccnt++;
3039         }
3040
3041         if ( ( 2*sizeof(ULONG) + NTLMSecBuf[0].cbBuffer + iaccnt + 10)  <
3042              sizeof(buf) ) {
3043             length = copy_for_net(&buf[7],(char *)&NTLMSecBuf[0],
3044                                    2*sizeof(ULONG));
3045             length += copy_for_net(&buf[7+length], NTLMSecBuf[0].pvBuffer,
3046                                   NTLMSecBuf[0].cbBuffer);
3047         }
3048         sprintf(&buf[7+length], "%c%c", IAC, SE);
3049
3050         if (deblog || tn_deb || debses) {
3051             int i;
3052             ckmakxmsg(tn_msg,TN_MSG_LEN,
3053                       "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
3054                       " IS ",AUTHTYPE_NAME(authentication_version)," ",
3055                       AUTHMODE_NAME(mode)," NTLM_AUTH ",
3056                        NULL,NULL,NULL,NULL,NULL
3057                       );
3058             tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],length);
3059             ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
3060             debug(F100,tn_msg,"",0);
3061             if (tn_deb || debses) tn_debug(tn_msg);
3062         }
3063 #ifdef OS2
3064         RequestTelnetMutex( SEM_INDEFINITE_WAIT );
3065 #endif
3066         ttol((CHAR *)buf, length+9);
3067 #ifdef OS2
3068         ReleaseTelnetMutex();
3069 #endif
3070         break;
3071     }
3072 #endif /* NTLM */
3073 #ifdef KRB4
3074     case AUTHTYPE_KERBEROS_V4:
3075         for ( i=0 ; i<k4_auth.length ; i++ ) {
3076             if ( k4_auth.dat[i] == IAC )
3077                 iaccnt++;
3078         }
3079
3080         if ( k4_auth.length + iaccnt + 10 < sizeof(buf) )
3081           k4_auth.length = copy_for_net(&buf[7], k4_auth.dat, k4_auth.length);
3082         else
3083             k4_auth.length = 0;
3084         sprintf(&buf[k4_auth.length+7], "%c%c", IAC, SE);
3085
3086         if (deblog || tn_deb || debses) {
3087             int i;
3088             ckmakxmsg(tn_msg,TN_MSG_LEN,
3089                       "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
3090                       AUTHTYPE_NAME(authentication_version)," ",
3091                       AUTHMODE_NAME(mode)," AUTH ",
3092                       NULL,NULL,NULL,NULL,NULL
3093                      );
3094             tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],k4_auth.length);
3095             ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
3096             debug(F100,tn_msg,"",0);
3097             if (tn_deb || debses) tn_debug(tn_msg);
3098         }
3099 #ifdef OS2
3100         RequestTelnetMutex( SEM_INDEFINITE_WAIT );
3101 #endif
3102         ttol((CHAR *)buf, k4_auth.length+9);
3103 #ifdef OS2
3104         ReleaseTelnetMutex();
3105 #endif
3106
3107 #ifndef REMOVE_FOR_EXPORT
3108 #ifdef CK_ENCRYPTION
3109         /*
3110          * If we are doing mutual authentication, get set up to send
3111          * the challenge, and verify it when the response comes back.
3112          */
3113         if ((auth_how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
3114             register int i;
3115             int rc = 0;
3116
3117 #ifdef MIT_CURRENT
3118             data.data = cred.session;
3119             data.length = 8; /* sizeof(cred.session) */;
3120
3121             if (code = krb5_c_random_seed(k5_context, &data)) {
3122                 com_err("libtelnet", code,
3123                          "while seeding random number generator");
3124                 return(0);
3125             }
3126
3127             if (code = krb5_c_make_random_key(k5_context,
3128                                                ENCTYPE_DES_CBC_RAW,
3129                                                &random_key)) {
3130                 com_err("libtelnet", code,
3131                          "while creating random session key");
3132                 return(0);
3133             }
3134
3135             /* the krb4 code uses ecb mode, but on a single block
3136             with a zero ivec, ecb and cbc are the same */
3137             k4_krbkey.enctype = ENCTYPE_DES_CBC_RAW;
3138             k4_krbkey.length = 8;
3139             k4_krbkey.contents = cred.session;
3140
3141             encdata.ciphertext.data = random_key.contents;
3142             encdata.ciphertext.length = random_key.length;
3143             encdata.enctype = ENCTYPE_UNKNOWN;
3144
3145             data.data = k4_session_key;
3146             data.length = 8;
3147
3148             code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
3149                                    &encdata, &data);
3150
3151             krb5_free_keyblock_contents(k5_context, &random_key);
3152
3153             if (code) {
3154                 com_err("libtelnet", code, "while encrypting random key");
3155                 return(0);
3156             }
3157
3158             encdata.ciphertext.data = k4_session_key;
3159             encdata.ciphertext.length = 8;
3160             encdata.enctype = ENCTYPE_UNKNOWN;
3161
3162             data.data = k4_challenge;
3163             data.length = 8;
3164
3165             code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
3166                                    &encdata, &data);
3167 #else /* MIT_CURRENT */
3168             memset(k4_sched,0,sizeof(Schedule));
3169             ckhexdump("auth_send",cred.session,8);
3170             rc = des_key_sched(cred.session, k4_sched);
3171             if ( rc == -1 ) {
3172                 printf("?Invalid DES key specified in credentials\r\n");
3173                 debug(F110,"auth_send",
3174                       "invalid DES Key specified in credentials",0);
3175             } else if ( rc == -2 ) {
3176                 printf("?Weak DES key specified in credentials\r\n");
3177                 debug(F110,"auth_send",
3178                       "weak DES Key specified in credentials",0);
3179             } else if ( rc != 0 ) {
3180                 printf("?DES Key Schedule not set by credentials\r\n");
3181                 debug(F110,"auth_send",
3182                       "DES Key Schedule not set by credentials",0);
3183             }
3184             ckhexdump("auth_send schedule",k4_sched,8*16);
3185
3186             des_set_random_generator_seed(cred.session);
3187
3188             do {
3189                 des_new_random_key(k4_session_key);
3190                 des_fixup_key_parity(k4_session_key);
3191             } while ( ck_des_is_weak_key(k4_session_key) );
3192
3193             ckhexdump("auth_send des_new_random_key(k4_session_key)",
3194                      k4_session_key,8);
3195
3196             /* Decrypt the session key so that we can send it to the */
3197             /* host as a challenge                                   */
3198 #ifdef NT
3199             des_ecb_encrypt(k4_session_key, k4_session_key, k4_sched, 0);
3200 #else /* NT */
3201             des_ecb_encrypt(&k4_session_key, &k4_session_key, k4_sched, 0);
3202 #endif /* NT */
3203             ckhexdump(
3204                 "auth_send des_ecb_encrypt(k4_session_key,k4_session_key,0)",
3205                 k4_session_key,8
3206                     );
3207             /* Prepare the result of the challenge */
3208             /* Decrypt the session_key, add 1, and then encrypt it */
3209             /* The result stored in k4_challenge should match the  */
3210             /* KRB4_RESPONSE value from the host.                  */
3211 #ifdef NT
3212             des_ecb_encrypt(k4_session_key, k4_challenge, k4_sched, 0);
3213 #else /* NT */
3214             des_ecb_encrypt(&k4_session_key, &k4_challenge, k4_sched, 0);
3215 #endif /* NT */
3216
3217             ckhexdump("auth_send des_ecb_encrypt(k4_session_key,k4_challenge,0)",
3218                      k4_challenge,8);
3219 #endif /* MIT_CURRENT */
3220             /*
3221             * Increment the challenge by 1, and encrypt it for
3222             * later comparison.
3223             */
3224             for (i = 7; i >= 0; --i) {
3225                 register int x;
3226                 x = (unsigned int)k4_challenge[i] + 1;
3227                 k4_challenge[i] = x;    /* ignore overflow */
3228                 if (x < 256)            /* if no overflow, all done */
3229                     break;
3230             }
3231             ckhexdump("auth_send k4_challenge+1",k4_challenge,8);
3232 #ifdef MIT_CURRENT
3233             data.data = k4_challenge;
3234             data.length = 8;
3235
3236             encdata.ciphertext.data = k4_challenge;
3237             encdata.ciphertext.length = 8;
3238             encdata.enctype = ENCTYPE_UNKNOWN;
3239
3240             if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &data,
3241                                        &encdata)) {
3242                 com_err("libtelnet", code, "while encrypting random key");
3243                 return(0);
3244             }
3245 #else /* MIT_CURRENT */
3246 #ifdef NT
3247             des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1);
3248 #else /* NT */
3249             des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1);
3250 #endif /* NT */
3251             ckhexdump("auth_send des_ecb_encrypt(k4_session_key,k4_challenge,1)",
3252                      k4_challenge,8);
3253 #endif /* MIT_CURRENT */
3254         }
3255 #endif  /* ENCRYPTION */
3256 #endif /* REMOVE_FOR_EXPORT */
3257         break;
3258 #endif /* KRB4 */
3259 #ifdef GSSAPI_KRB5
3260     case AUTHTYPE_GSSAPI_KRB5:
3261         for ( i=0 ; i<gss_send_tok.length ; i++ ) {
3262             if ( ((char *)gss_send_tok.value)[i] == IAC )
3263                 iaccnt++;
3264         }
3265
3266         if ( gss_send_tok.length + iaccnt + 10 < sizeof(buf) )
3267             gss_send_tok.length = copy_for_net(&buf[7], gss_send_tok.value,
3268                                                gss_send_tok.length);
3269         else
3270             gss_send_tok.length = 0;
3271         sprintf(&buf[gss_send_tok.length+7], "%c%c", IAC, SE);       /* safe */
3272         if (deblog || tn_deb || debses) {
3273             int i;
3274             ckmakxmsg(tn_msg,TN_MSG_LEN,
3275                       "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
3276                       AUTHTYPE_NAME(authentication_version)," ",
3277                       AUTHMODE_NAME(mode)," AUTH ",
3278                       NULL,NULL,NULL,NULL,NULL
3279                      );
3280             tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],gss_send_tok.length);
3281             ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
3282             debug(F100,tn_msg,"",0);
3283             if (tn_deb || debses) tn_debug(tn_msg);
3284         }
3285 #ifdef OS2
3286         RequestTelnetMutex( SEM_INDEFINITE_WAIT );
3287 #endif
3288         ttol((CHAR *)buf, gss_send_tok.length+9);
3289 #ifdef OS2
3290         ReleaseTelnetMutex();
3291 #endif
3292         break;
3293 #endif /* GSSAPI_KRB5 */
3294 #ifdef KRB5
3295     case AUTHTYPE_KERBEROS_V5:
3296         debug(F111,"auth_send KRB5","k5_auth.length",k5_auth.length);
3297         for ( i=0 ; i<k5_auth.length ; i++ ) {
3298             if ( (char *)k5_auth.data[i] == IAC )
3299                 iaccnt++;
3300         }
3301         if ( k5_auth.length + iaccnt + 10 < sizeof(buf) ) {
3302             k5_auth.length = copy_for_net(&buf[7],
3303                                           (CHAR *)k5_auth.data,
3304                                           k5_auth.length);
3305         } else {
3306           debug(F100,"auth_send() KRB5 auth data too large for buffer","",0);
3307           k5_auth.length = 0;
3308         }
3309
3310         sprintf((char *)&buf[k5_auth.length+7], "%c%c", IAC, SE); /* safe */
3311         if (deblog || tn_deb || debses) {
3312             int i;
3313             ckmakxmsg(tn_msg,TN_MSG_LEN,
3314                       "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
3315                       AUTHTYPE_NAME(authentication_version)," ",
3316                       AUTHMODE_NAME(mode)," AUTH ",
3317                       NULL,NULL,NULL,NULL,NULL
3318                      );
3319             tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&buf[7],k5_auth.length);
3320             ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
3321             debug(F100,tn_msg,"",0);
3322             if (tn_deb || debses) tn_debug(tn_msg);
3323         }
3324 #ifdef OS2
3325         RequestTelnetMutex( SEM_INDEFINITE_WAIT );
3326 #endif
3327         ttol((CHAR *)buf, k5_auth.length+9);
3328 #ifdef OS2
3329         ReleaseTelnetMutex();
3330 #endif
3331 #ifdef HEIMDAL
3332         krb5_data_free(&k5_auth);
3333 #else /* HEIMDAL */
3334         krb5_free_data_contents(k5_context,&k5_auth);
3335         memset(&k5_auth,0,sizeof(krb5_data));
3336 #endif /* HEIMDAL */
3337         break;
3338 #endif /* KRB5 */
3339     }
3340     return AUTH_SUCCESS;
3341 }
3342
3343 /*
3344  * Function: Parse authentication REPLY command
3345  *
3346  * Parameters:
3347  *  parsedat - the sub-command data.
3348  *
3349  *      end_sub - index of the character in the 'parsedat' array which
3350  *              is the last byte in a sub-negotiation
3351  *
3352  * Returns: Kerberos error code.
3353  */
3354 static int
3355 #ifdef CK_ANSIC
3356 auth_reply(unsigned char *parsedat, int end_sub)
3357 #else
3358 auth_reply(parsedat,end_sub) unsigned char *parsedat; int end_sub;
3359 #endif
3360 {
3361     int n = AUTH_FAILURE;
3362
3363     if ( parsedat[2] != authentication_version ) {
3364         printf("Authentication version mismatch (%s [%d] != %s [%d])\r\n",
3365                 AUTHTYPE_NAME(parsedat[2]),parsedat[2],
3366                 AUTHTYPE_NAME(authentication_version),authentication_version);
3367         auth_finished(AUTH_REJECT);
3368         return(AUTH_FAILURE);
3369     }
3370     if ( parsedat[3] != (auth_how|auth_crypt|auth_fwd) ) {
3371         printf("Authentication mode mismatch (%s != %s)\r\n",
3372                 AUTHMODE_NAME(parsedat[3]),
3373                 AUTHMODE_NAME(auth_how|auth_crypt|auth_fwd));
3374         auth_finished(AUTH_REJECT);
3375         return(AUTH_FAILURE);
3376     }
3377
3378 #ifdef KRB4
3379     if (authentication_version == AUTHTYPE_KERBEROS_V4)
3380         n = k4_auth_reply(parsedat, end_sub);
3381 #endif
3382 #ifdef KRB5
3383     if (authentication_version == AUTHTYPE_KERBEROS_V5)
3384         n = k5_auth_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
3385 #endif
3386 #ifdef CK_SRP
3387     if (authentication_version == AUTHTYPE_SRP) {
3388 #ifndef PRE_SRP_1_7_3
3389         n = new_srp_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
3390 #else /* PRE_SRP_1_7_3 */
3391         n = srp_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
3392 #endif /* PRE_SRP_1_7_3 */
3393     }
3394 #endif /* SRP */
3395 #ifdef CK_SSL
3396     if (authentication_version == AUTHTYPE_SSL)
3397         n = ssl_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
3398 #endif /* SSL */
3399 #ifdef NTLM
3400     if (authentication_version == AUTHTYPE_NTLM)
3401         n = ntlm_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
3402 #endif /* NTLM */
3403     return n;
3404 }
3405
3406
3407 /*
3408  * Function: Parse authentication IS command
3409  *
3410  * Parameters:
3411  *  parsedat - the sub-command data.
3412  *
3413  *      end_sub - index of the character in the 'parsedat' array which
3414  *              is the last byte in a sub-negotiation
3415  *
3416  * Returns: Kerberos error code.
3417  */
3418 static int
3419 #ifdef CK_ANSIC
3420 auth_is(unsigned char *parsedat, int end_sub)
3421 #else
3422 auth_is(parsedat,end_sub) unsigned char *parsedat; int end_sub;
3423 #endif
3424 {
3425     int n = AUTH_FAILURE;
3426
3427     if ( parsedat[2] == AUTHTYPE_NULL ) {
3428         auth_finished(AUTH_REJECT);
3429         return(AUTH_FAILURE);
3430     }
3431
3432     /*
3433      *  If CLIENT_CHOOSE_ONCE is selected the server will not allow the
3434      *  client to switch to an alternate authentication method if the one
3435      *  it originally selected fails.  (ie, if the host's SRP parameters
3436      *  are invalid.)  However, I think this is a bit of a security risk
3437      *  since allowing that functionality means that it is impossible to
3438      *  detect if an attack is being carried out on
3439      */
3440 #define CLIENT_CHOOSE_ONCE
3441 #ifdef CLIENT_CHOOSE_ONCE
3442     if ( authentication_version == AUTHTYPE_AUTO )
3443 #endif /* CLIENT_CHOOSE_ONCE */
3444     {
3445         /* this block of code needs to check the initial parameters */
3446         /* to ensure that those returned match one of the sets that */
3447         /* were sent to the client in the first place.              */
3448
3449         int i=0;
3450         for ( i=4; str_request[i] != IAC ; i+=2) {
3451             if (str_request[i] == parsedat[2] &&
3452                  str_request[i+1] == parsedat[3])
3453                 break;
3454         }
3455
3456         if ( str_request[i] == IAC ) {
3457             printf("Invalid authentication type pair (%s,%s)\r\n",
3458                     AUTHTYPE_NAME(parsedat[2]),
3459                     AUTHMODE_NAME(parsedat[3]));
3460             auth_finished(AUTH_REJECT);
3461             return(AUTH_FAILURE);
3462         }
3463
3464         if (authentication_version != parsedat[2]) {
3465             authentication_version = parsedat[2];
3466             auth_how = (parsedat[3] & AUTH_HOW_MASK);
3467             auth_crypt = (parsedat[3] & AUTH_ENCRYPT_MASK);
3468             auth_fwd = (parsedat[3] & INI_CRED_FWD_MASK);
3469             debug(F111,"auth_is","authentication_version",
3470                   authentication_version);
3471             debug(F111,"auth_is","auth_how",auth_how);
3472             debug(F111,"auth_is","auth_crypt",auth_crypt);
3473             debug(F111,"auth_is","auth_fwd",auth_fwd);
3474         }
3475     }
3476
3477 #ifdef CLIENT_CHOOSE_ONCE
3478     if ( parsedat[2] != authentication_version ) {
3479         printf("Authentication version mismatch (%s [%d] != %s [%d])\r\n",
3480                 AUTHTYPE_NAME(parsedat[2]),parsedat[2],
3481                 AUTHTYPE_NAME(authentication_version),authentication_version);
3482         auth_finished(AUTH_REJECT);
3483         return(AUTH_FAILURE);
3484     }
3485     if ( parsedat[3] != (auth_how|auth_crypt|auth_fwd) ) {
3486         printf("Authentication mode mismatch (%s != %s)\r\n",
3487                 AUTHMODE_NAME(parsedat[3]),
3488                 AUTHMODE_NAME(auth_how|auth_crypt|auth_fwd));
3489         auth_finished(AUTH_REJECT);
3490         return(AUTH_FAILURE);
3491     }
3492 #endif /* CLIENT_CHOOSE_ONCE */
3493
3494     switch (authentication_version) {
3495 #ifdef KRB4
3496     case AUTHTYPE_KERBEROS_V4:
3497         n = k4_auth_is(parsedat, end_sub);
3498         break;
3499 #endif
3500 #ifdef KRB5
3501     case AUTHTYPE_KERBEROS_V5:
3502         n = k5_auth_is(parsedat[3],parsedat, end_sub);
3503         break;
3504 #endif
3505 #ifdef CK_SRP
3506     case AUTHTYPE_SRP:
3507 #ifndef PRE_SRP_1_7_3
3508         n = new_srp_is(parsedat[3], parsedat, end_sub);
3509 #else /* PRE_SRP_1_7_3 */
3510         n = srp_is(parsedat[3], parsedat, end_sub);
3511 #endif /* PRE_SRP_1_7_3 */
3512         break;
3513 #endif /* SRP */
3514 #ifdef CK_SSL
3515     case AUTHTYPE_SSL:
3516         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
3517         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
3518         n = ssl_is(parsedat, end_sub);
3519         break;
3520 #endif /* SSL */
3521 #ifdef NTLM
3522     case AUTHTYPE_NTLM:
3523         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
3524         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
3525         n = ntlm_is(parsedat, end_sub);
3526         break;
3527 #endif /* NTLM */
3528     case AUTHTYPE_NULL:
3529     default:
3530         n = AUTH_FAILURE;
3531     }
3532     debug(F111,"auth_is","n",n);
3533     return n;
3534 }
3535
3536 /*
3537  * Function: Parse authentication NAME command
3538  *
3539  * Parameters:
3540  *  parsedat - the sub-command data.
3541  *
3542  *      end_sub - index of the character in the 'parsedat' array which
3543  *              is the last byte in a sub-negotiation
3544  *
3545  * Returns: Kerberos error code.
3546  */
3547 static int
3548 #ifdef CK_ANSIC
3549 auth_name(unsigned char *parsedat, int end_sub)
3550 #else
3551 auth_name(parsedat,end_sub) unsigned char *parsedat; int end_sub;
3552 #endif
3553 {
3554     int len = (end_sub-2) > 63 ? 63 : (end_sub-2);
3555     if ( len > 0 && (len + 1) < sizeof(szUserNameRequested)) {
3556         memcpy(szUserNameRequested,&parsedat[2],len);           /* safe */
3557         szUserNameRequested[len] = '\0';
3558     } else
3559       szUserNameRequested[0] = '\0';
3560     debug(F111,"auth_name szUserNameRequested",szUserNameRequested,len);
3561     return(AUTH_SUCCESS);
3562 }
3563
3564 /*
3565  * Function: Parse the athorization sub-options and reply.
3566  *
3567  * Parameters:
3568  *      parsedat - sub-option string to parse.
3569  *
3570  *      end_sub - last charcter position in parsedat.
3571  */
3572 int
3573 auth_parse(unsigned char *parsedat, int end_sub)
3574 {
3575     int rc = AUTH_FAILURE;
3576     switch (parsedat[1]) {
3577     case TELQUAL_SEND:
3578         rc = auth_send(parsedat, end_sub);
3579         break;
3580     case TELQUAL_REPLY:
3581         rc= auth_reply(parsedat, end_sub);
3582         break;
3583     case TELQUAL_IS:
3584         rc = auth_is(parsedat, end_sub);
3585         break;
3586     case TELQUAL_NAME:
3587         rc = auth_name(parsedat, end_sub);
3588         break;
3589     }
3590     debug(F111,"auth_parse","rc",rc);
3591     return(rc);
3592 }
3593
3594
3595 /*
3596  * Function: Initialization routine called kstream encryption system.
3597  *
3598  * Parameters:
3599  *  data - user data.
3600  */
3601 int
3602 #ifdef CK_ANSIC
3603 auth_init(kstream ks)
3604 #else
3605 auth_init(ks) kstream_ptr ks;
3606 #endif
3607 {
3608 #ifdef FORWARD
3609     forwarded_tickets = 0;  /* were tickets forwarded? */
3610 #endif /* FORWARD */
3611 #ifdef CK_ENCRYPTION
3612     encrypt_init(ks,cx_type);
3613 #endif
3614     return 0;
3615 }
3616
3617
3618 /*
3619  * Function: Destroy routine called kstream encryption system.
3620  *
3621  * Parameters:
3622  *  data - user data.
3623  */
3624 VOID
3625 #ifdef CK_ANSIC
3626 auth_destroy(void)
3627 #else
3628 auth_destroy()
3629 #endif
3630 {
3631 }
3632
3633
3634 /*
3635  * Function: Callback to encrypt a block of characters
3636  *
3637  * Parameters:
3638  *  out - return as pointer to converted buffer.
3639  *
3640  *  in - the buffer to convert
3641  *
3642  * Returns: number of characters converted.
3643  */
3644 int
3645 #ifdef CK_ANSIC
3646 auth_encrypt(struct kstream_data_block *out,
3647              struct kstream_data_block *in)
3648 #else
3649 auth_encrypt(out,in)
3650     struct kstream_data_block *out; struct kstream_data_block *in;
3651 #endif
3652 {
3653     out->ptr = in->ptr;
3654
3655     out->length = in->length;
3656
3657     return(out->length);
3658 }
3659
3660
3661 /*
3662  * Function: Callback to decrypt a block of characters
3663  *
3664  * Parameters:
3665  *  out - return as pointer to converted buffer.
3666  *
3667  *  in - the buffer to convert
3668  *
3669  * Returns: number of characters converted.
3670  */
3671 int
3672 #ifdef CK_ANSIC
3673 auth_decrypt(struct kstream_data_block *out,
3674              struct kstream_data_block *in)
3675 #else
3676 auth_decrypt(out,in)
3677     struct kstream_data_block *out; struct kstream_data_block *in;
3678 #endif
3679 {
3680     out->ptr = in->ptr;
3681
3682     out->length = in->length;
3683
3684     return(out->length);
3685 }
3686
3687 #ifdef KRB4
3688 #ifdef NT
3689 void
3690 ck_krb4_debug(int x)
3691 {
3692     set_krb_debug(x);
3693     set_krb_ap_req_debug(x);
3694 }
3695 #endif /* NT */
3696 int
3697 ck_krb4_autoget_TGT(char * realm)
3698 {
3699     extern struct krb_op_data krb_op;
3700     extern struct krb4_init_data krb4_init;
3701     char passwd[PWD_SZ];
3702     char prompt[256];
3703     char * saverealm=NULL;
3704     int  rc = -1;
3705     extern char * k4prprompt;
3706     extern char * k4pwprompt;
3707
3708     ini_kerb();         /* Place defaults in above structs */
3709     passwd[0] = '\0';
3710
3711     if ( krb4_init.principal == NULL ||
3712          krb4_init.principal[0] == '\0') {
3713         int ok = uq_txt(NULL, 
3714                  k4prprompt && k4prprompt[0] ?
3715                  k4prprompt :
3716                  "Kerberos 4 Principal: ",
3717                  2, NULL, passwd,PWD_SZ-1, NULL, DEFAULT_UQ_TIMEOUT);
3718         if ( ok && passwd[0] )
3719             makestr(&krb4_init.principal,passwd);
3720         else
3721             return(0);
3722     }
3723
3724     /* Save realm in init structure so it can be restored */
3725     if ( realm ) {
3726         saverealm = krb4_init.realm;
3727         krb4_init.realm = realm;
3728     }
3729
3730     if ( passwd[0] || !(pwbuf[0] && pwflg) ) {
3731         int ok;
3732         if ( k4pwprompt && k4pwprompt[0] &&
3733              (strlen(k4pwprompt) + strlen(krb4_init.principal) +
3734                strlen(krb4_init.realm) - 4) < sizeof(prompt)) {
3735             sprintf(prompt,k4pwprompt,krb4_init.principal,krb4_init.realm);
3736         } else
3737             ckmakxmsg(prompt,sizeof(prompt),
3738                   "Kerberos 4 Password for ",krb4_init.principal,"@",
3739                   krb4_init.realm,": ",
3740                   NULL,NULL,NULL,NULL,NULL,NULL,NULL);
3741         ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL,
3742                     DEFAULT_UQ_TIMEOUT);
3743         if ( !ok )
3744             passwd[0] = '\0';
3745     } else {
3746         ckstrncpy(passwd,pwbuf,sizeof(passwd));
3747 #ifdef OS2
3748         if ( pwcrypt )
3749             ck_encrypt((char *)passwd);
3750 #endif /* OS2 */
3751     }
3752
3753     if ( passwd[0] ) {
3754         makestr(&krb4_init.password,passwd);
3755         rc = ck_krb4_initTGT(&krb_op, &krb4_init);
3756         free(krb4_init.password);
3757         krb4_init.password = NULL;
3758     }
3759
3760     krb4_init.password = NULL;
3761     memset(passwd,0,PWD_SZ);
3762
3763     /* restore realm to init structure if needed */
3764     if ( saverealm )
3765         krb4_init.realm = saverealm;
3766     return(rc == 0);
3767 }
3768
3769 char *
3770 ck_krb4_realmofhost(char *host)
3771 {
3772     return (char *)krb_realmofhost(host);
3773 }
3774
3775 /*
3776  *
3777  * K4_auth_send - gets authentication bits we need to send to KDC.
3778  *
3779  * Result is left in auth
3780  *
3781  * Returns: 0 on failure, 1 on success
3782  */
3783 static int
3784 #ifdef CK_ANSIC
3785 k4_auth_send(void)
3786 #else
3787 k4_auth_send()
3788 #endif
3789 {
3790     int r=0;                                    /* Return value */
3791     char instance[INST_SZ+1]="";
3792     char *realm=NULL;
3793     char tgt[4*REALM_SZ+1];
3794
3795     memset(instance, 0, sizeof(instance));
3796
3797 #ifdef COMMENT
3798     /* we only need to call krb_get_phost if the hostname */
3799     /* is not fully qualified.  But we have already done  */
3800     /* this in netopen() call.  This will save a round of */
3801     /* DNS queries.                                       */
3802     debug(F110,"k4_auth_send","krb_get_phost",0);
3803     if (realm = (char *)krb_get_phost(szHostName)) {
3804         ckstrncpy(instance, realm, INST_SZ);
3805     }
3806 #else /* COMMENT */
3807     {
3808         char *p;
3809         ckstrncpy(instance, szHostName, INST_SZ);
3810         for ( p=instance; *p && *p != '.' ; p++ );
3811         *p = '\0';
3812     }
3813 #endif /* COMMENT */
3814
3815     debug(F110,"k4_auth_send","krb_get_realmofhost",0);
3816     realm = (char *)krb_realmofhost(szHostName);
3817
3818     if (!realm) {
3819         strcpy(strTmp, "Can't find realm for host \"");
3820         ckstrncat(strTmp, szHostName,AUTHTMPBL);
3821         ckstrncat(strTmp, "\"",AUTHTMPBL);
3822         printf("?Kerberos 4 error: %s\r\n",strTmp);
3823         krb4_errno = r;
3824         makestr(&krb4_errmsg,strTmp);
3825         return(0);
3826     }
3827
3828     ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm);
3829     r = ck_krb4_tkt_isvalid(tgt);
3830
3831     if ( r <= 0 && krb4_autoget )
3832         ck_krb4_autoget_TGT(realm);
3833
3834     debug(F110,"k4_auth_send","krb_mk_req",0);
3835     r = krb_mk_req(&k4_auth, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
3836                     instance, realm, 0);
3837
3838     if (r == 0) {
3839         debug(F110,"k4_auth_send","krb_get_cred",0);
3840         r = krb_get_cred(krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
3841                           instance, realm, &cred);
3842         if (r)
3843             debug(F111,"k4_auth_send","krb_get_cred() failed",r);
3844     }
3845     else
3846         debug(F111,"k4_auth_send","krb_mk_req() failed",r);
3847
3848     if (r) {
3849         strcpy(strTmp, "Can't get \"");
3850         ckstrncat(strTmp,
3851                   krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,AUTHTMPBL);
3852         if (instance[0] != 0) {
3853             ckstrncat(strTmp, ".",AUTHTMPBL);
3854             ckstrncat(strTmp, instance,AUTHTMPBL);
3855         }
3856         ckstrncat(strTmp, "@",AUTHTMPBL);
3857         ckstrncat(strTmp, realm,AUTHTMPBL);
3858         ckstrncat(strTmp, "\" ticket\r\n  ",AUTHTMPBL);
3859         ckstrncat(strTmp, (char *)krb_get_err_text_entry(r),AUTHTMPBL);
3860         debug(F111,"k4_auth_send",(char *)krb_get_err_text_entry(r),r);
3861         printf("?Kerberos 4 error: %s\r\n",strTmp);
3862         krb4_errno = r;
3863         makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno));
3864         return(0);
3865     }
3866
3867 #ifdef OS2
3868     if ( !szUserName[0] || !stricmp(szUserName,cred.pname) ) {
3869         ckstrncpy(szUserName, cred.pname, UIDBUFLEN);
3870     }
3871 #endif /* OS2 */
3872     krb4_errno = r;
3873     makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno));
3874     debug(F110,"k4_auth_send",krb4_errmsg,0);
3875     return(1);
3876 }
3877
3878 /*
3879  * Function: K4 parse authentication reply command
3880  *
3881  * Parameters:
3882  *  parsedat - the sub-command data.
3883  *
3884  *  end_sub - index of the character in the 'parsedat' array which
3885  *              is the last byte in a sub-negotiation
3886  *
3887  * Returns: Kerberos error code.
3888  */
3889 static int
3890 #ifdef CK_ANSIC
3891 k4_auth_reply(unsigned char *parsedat, int end_sub)
3892 #else
3893 k4_auth_reply(parsedat,end_sub) unsigned char *parsedat; int end_sub;
3894 #endif
3895 {
3896 #ifdef CK_ENCRYPTION
3897     Session_Key skey;
3898 #ifdef MIT_CURRENT
3899     krb5_data kdata;
3900     krb5_enc_data encdata;
3901     krb5_error_code code;
3902 #endif /* MIT_CURRENT */
3903 #endif
3904     time_t t;
3905     int x;
3906     int i;
3907
3908     if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) {
3909         auth_finished(AUTH_REJECT);
3910         return AUTH_FAILURE;
3911     }
3912
3913     if (parsedat[4] == KRB_REJECT) {
3914         strTmp[0] = 0;
3915
3916         for (i = 5; i <= end_sub; i++) {
3917             if (parsedat[i] == IAC)
3918                 break;
3919             strTmp[i-5] = parsedat[i];
3920             strTmp[i-4] = 0;
3921         }
3922
3923         if (!strTmp[0])
3924             strcpy(strTmp, "Authentication rejected by remote machine!");
3925         printf("Kerberos V4 authentication failed!\r\n%s\r\n",strTmp);
3926         krb4_errno = -1;
3927         makestr(&krb4_errmsg,strTmp);
3928         auth_finished(AUTH_REJECT);
3929         return AUTH_FAILURE;
3930     }
3931
3932     if (parsedat[4] == KRB_ACCEPT) {
3933         int net_len;
3934         if ((parsedat[3] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) {
3935             ckmakmsg(strTmp,sizeof(strTmp),"Kerberos V4 accepts you as ",
3936                       szUserName,NULL,NULL);
3937             printf("%s\r\n",strTmp);
3938             accept_complete = 1;
3939             krb4_errno = 0;
3940             makestr(&krb4_errmsg,strTmp);
3941             auth_finished(AUTH_USER);
3942             return AUTH_SUCCESS;
3943         }
3944
3945         if ((parsedat[3] & AUTH_HOW_MASK) != AUTH_HOW_MUTUAL) {
3946             printf("Kerberos V4 authentication failed!\r\n");
3947             ckstrncpy(strTmp,
3948         "Kerberos V4 accepted you, but didn't provide mutual authentication",
3949                        sizeof(strTmp));
3950             printf("%s\r\n",strTmp);
3951             krb4_errno = -1;
3952             makestr(&krb4_errmsg,strTmp);
3953             auth_finished(AUTH_REJECT);
3954             return AUTH_FAILURE;
3955         }
3956
3957 #ifndef REMOVE_FOR_EXPORT
3958 #ifdef CK_ENCRYPTION
3959         SendK4AuthSB(KRB4_CHALLENGE,k4_session_key,sizeof(k4_session_key));
3960
3961         /* We have sent the decrypted session key to the host as a challenge */
3962         /* now encrypt it to restore it to its original valid DES key value */
3963 #ifdef MIT_CURRENT
3964         kdata.data = k4_session_key;
3965         kdata.length = 8;
3966
3967         encdata.ciphertext.data = k4_session_key;
3968         encdata.ciphertext.length = 8;
3969         encdata.enctype = ENCTYPE_UNKNOWN;
3970
3971         if (code = krb5_c_encrypt(k5_context, &k4_krbkey,
3972                                    0, 0, &kdata, &encdata)) {
3973             com_err("k4_auth_reply", code,
3974                      "while encrypting session_key");
3975             auth_finished(AUTH_REJECT);
3976             return AUTH_FAILURE;
3977         }
3978 #else /* MIT_CURRENT */
3979 #ifdef NT
3980         des_ecb_encrypt(k4_session_key, k4_session_key, k4_sched, 1);
3981 #else /* NT */
3982         des_ecb_encrypt(&k4_session_key, &k4_session_key, k4_sched, 1);
3983 #endif /* NT */
3984         ckhexdump(
3985             "k4_auth_reply des_ecb_encrypt(k4_session_key,k4_session_key,1)",
3986              k4_session_key,
3987              8
3988                 );
3989 #endif /* MIT_CURRENT */
3990
3991 #ifdef CK_SSL
3992         if (!(ssl_active_flag || tls_active_flag))
3993 #endif /* CK_SSL */
3994         {
3995         /* And then use it to configure the encryption state machine. */
3996             skey.type = SK_DES;
3997             skey.length = 8;
3998             skey.data = k4_session_key;
3999             encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
4000         }
4001 #endif /* ENCRYPTION */
4002 #endif /* REMOVE_FOR_EXPORT */
4003         accept_complete = 1;
4004         ckmakmsg(strTmp,sizeof(strTmp),
4005                  "Kerberos V4 accepts you as ",szUserName,NULL,NULL);
4006         printf("%s\r\n",strTmp);
4007         krb4_errno = 0;
4008         makestr(&krb4_errmsg,strTmp);
4009         auth_finished(AUTH_USER);
4010         return AUTH_SUCCESS;
4011     }
4012
4013     if (parsedat[4] == KRB4_RESPONSE) {
4014         if (end_sub < 12) {
4015             auth_finished(AUTH_REJECT);
4016             return AUTH_FAILURE;
4017         }
4018
4019         ckhexdump("KRB4_RESPONSE &parsedat[5]",&parsedat[5],8);
4020 #ifdef CK_ENCRYPTION
4021         ckhexdump("KRB4_RESPONSE k4_challenge",k4_challenge,8);
4022
4023         /* The datablock returned from the host should match the value */
4024         /* we stored in k4_challenge.                                  */
4025         if (memcmp(&parsedat[5], k4_challenge, sizeof(k4_challenge)) != 0) {
4026             printf("Kerberos V4 authentication failed!\r\n%s\r\n",
4027             "Remote machine is being impersonated!");
4028             krb4_errno = -1;
4029             makestr(&krb4_errmsg,"Remote machine is being impersonated!");
4030             auth_finished(AUTH_REJECT);
4031             return AUTH_FAILURE;
4032         }
4033 #else /* ENCRYPTION */
4034         makestr(&krb4_errmsg,"Kermit built without support for encryption.");
4035         return AUTH_FAILURE;
4036 #endif /* ENCRYPTION */
4037         mutual_complete = 1;
4038         ckstrncpy(strTmp,"Remote machine has been mutually authenticated",
4039                    sizeof(strTmp));
4040         printf("%s\r\n",strTmp);
4041         krb4_errno = 0;
4042         makestr(&krb4_errmsg,strTmp);
4043         auth_finished(AUTH_USER);
4044         return AUTH_SUCCESS;
4045     }
4046     auth_finished(AUTH_REJECT);
4047     return AUTH_FAILURE;
4048 }
4049
4050 /*
4051  * Function: K4 parse authentication IS command
4052  *
4053  * Parameters:
4054  *  parsedat - the sub-command data.
4055  *
4056  *  end_sub - index of the character in the 'parsedat' array which
4057  *            is the last byte in a sub-negotiation
4058  *
4059  * Returns: Kerberos error code.
4060  */
4061
4062 static int
4063 #ifdef CK_ANSIC
4064 k4_auth_is(unsigned char *parsedat, int end_sub)
4065 #else
4066 k4_auth_is(parsedat,end_sub) unsigned char *parsedat; int end_sub;
4067 #endif
4068 {
4069 #ifdef CK_ENCRYPTION
4070     Session_Key skey;
4071 #ifdef MIT_CURRENT
4072     Block datablock, tmpkey;
4073     krb5_data kdata;
4074     krb5_enc_data encdata;
4075     krb5_error_code code;
4076 #else /* MIT_CURRENT */
4077     Block datablock;
4078 #endif /* MIT_CURRENT */
4079 #endif  /* ENCRYPTION */
4080     char realm[REALM_SZ+1];
4081     char instance[INST_SZ];
4082     int r = 0;
4083     char * data = &parsedat[5];
4084     int    cnt = end_sub - 5;
4085     extern char myipaddr[];
4086     struct hostent *host;
4087     struct in_addr inaddr;
4088     int i;
4089
4090     if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) {
4091         debug(F110,"k4_auth_is","Not kerberos v4",0);
4092         auth_finished(AUTH_REJECT);
4093         return AUTH_FAILURE;
4094     }
4095
4096     switch (parsedat[4]) {
4097     case KRB_AUTH:
4098         debug(F110,"k4_auth_is","KRB_AUTH",0);
4099         ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ+1);
4100         if (realm[0] == '\0') {
4101             SendK4AuthSB(KRB_REJECT, (void *)"No local V4 Realm.", -1);
4102             printf("\r\n? Kerberos 4 - No Local Realm\r\n");
4103             debug(F110,"k4_auth_is","No local realm",0);
4104             krb4_errno = -1;
4105             makestr(&krb4_errmsg,"No local realm");
4106             auth_finished(AUTH_REJECT);
4107             return AUTH_FAILURE;
4108         }
4109         debug(F110,"k4_auth_is",realm,0);
4110         if ( cnt < sizeof(k4_auth.dat) ) {
4111             k4_auth.length = cnt;
4112             memcpy((void *)k4_auth.dat, (void *)data, k4_auth.length);
4113         } else
4114             k4_auth.length = 0;
4115         ckhexdump("k4_auth.dat",k4_auth.dat, k4_auth.length);
4116
4117         /* Get Instance */
4118         inaddr.s_addr = inet_addr(myipaddr);
4119         host = gethostbyaddr((unsigned char *)&inaddr,4,PF_INET);
4120         if ( host ) {
4121 #ifdef HADDRLIST
4122             host = ck_copyhostent(host);
4123 #endif /* HADDRLIST */
4124             ckstrncpy(instance,host->h_name,INST_SZ);
4125             for ( i=0;i<INST_SZ;i++ ) {
4126                 if ( instance[i] == '.' )
4127                     instance[i] = '\0';
4128                 else
4129                     instance[i] = tolower(instance[i]);
4130             }
4131         } else {
4132             instance[0] = '*';
4133             instance[1] = 0;
4134         }
4135
4136         if (r = krb_rd_req(&k4_auth,
4137                             krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
4138                             instance, 0, &k4_adat, k4_keytab)) {
4139
4140             ckhexdump("k4_adat", &k4_adat, sizeof(AUTH_DAT));
4141             krb_kntoln(&k4_adat, k4_name);
4142             ckmakmsg(strTmp,sizeof(strTmp),
4143                      "Kerberos failed him as ", k4_name,NULL,NULL);
4144             printf("%s\r\n",strTmp);
4145             krb4_errno = r;
4146             makestr(&krb4_errmsg,strTmp);
4147             SendK4AuthSB(KRB_REJECT, (void *)krb_get_err_text_entry(r), -1);
4148             auth_finished(AUTH_REJECT);
4149             return AUTH_FAILURE;
4150         }
4151
4152 #ifdef CK_ENCRYPTION
4153         memcpy((void *)k4_session_key, (void *)k4_adat.session,
4154                 sizeof(Block));                 /* safe */
4155         ckhexdump("k4_auth_is k4_session_key",k4_session_key,sizeof(Block));
4156 #endif /* ENCRYPTION */
4157         krb_kntoln(&k4_adat, k4_name);
4158
4159         ckstrncpy(szUserNameAuthenticated,k4_name,UIDBUFLEN);
4160         if (szUserNameRequested && !kuserok(&k4_adat, k4_name)) {
4161             SendK4AuthSB(KRB_ACCEPT, (void *)0, 0);
4162             if ( !strcmp(k4_name,szUserNameRequested) )
4163                 auth_finished(AUTH_VALID);
4164             else
4165                 auth_finished(AUTH_USER);
4166             accept_complete = 1;
4167         }
4168         else {
4169             SendK4AuthSB(KRB_REJECT,
4170                   (void *)"user is not authorized", -1);
4171             auth_finished(AUTH_REJECT);
4172             krb4_errno = r;
4173             makestr(&krb4_errmsg,"user is not authorized");
4174             return(AUTH_FAILURE);
4175         }
4176         break;
4177
4178     case KRB4_CHALLENGE:
4179         debug(F110,"k4_auth_is","KRB_CHALLENGE",0);
4180 #ifndef CK_ENCRYPTION
4181         SendK4AuthSB(KRB4_RESPONSE, (void *)0, 0);
4182 #else   /* ENCRYPTION */
4183         if (!VALIDKEY(k4_session_key)) {
4184             /*
4185             * We don't have a valid session key, so just
4186             * send back a response with an empty session
4187             * key.
4188             */
4189             SendK4AuthSB(KRB4_RESPONSE, (void *)0, 0);
4190             mutual_complete = 1;
4191             break;
4192         }
4193
4194         /*
4195         * Initialize the random number generator since it's
4196         * used later on by the encryption routine.
4197         */
4198 #ifdef MIT_CURRENT
4199         kdata.data = k4_session_key;
4200         kdata.length = 8;
4201
4202         if (code = krb5_c_random_seed(k5_context, &kdata)) {
4203             com_err("k4_auth_is", code,
4204                      "while seeding random number generator");
4205             auth_finished(AUTH_REJECT);
4206             return AUTH_FAILURE;
4207         }
4208
4209         memcpy((void *)datablock, (void *)data, sizeof(Block)); /* safe */
4210         /*
4211         * Take the received encrypted challenge, and encrypt
4212         * it again to get a unique session_key for the
4213         * ENCRYPT option.
4214         */
4215         k4_krbkey.enctype = ENCTYPE_DES_CBC_RAW;
4216         k4_krbkey.length = 8;
4217         k4_krbkey.contents = k4_session_key;
4218
4219         kdata.data = datablock;
4220         kdata.length = 8;
4221
4222         encdata.ciphertext.data = tmpkey;
4223         encdata.ciphertext.length = 8;
4224         encdata.enctype = ENCTYPE_UNKNOWN;
4225
4226         if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0,
4227                                    &kdata, &encdata)) {
4228             com_err("k4_auth_is", code, "while encrypting random key");
4229             auth_finished(AUTH_REJECT);
4230             return AUTH_FAILURE;
4231         }
4232
4233 #ifdef CK_SSL
4234         if (!(ssl_active_flag || tls_active_flag))
4235 #endif /* CK_SSL */
4236         {
4237             skey.type = SK_DES;
4238             skey.length = 8;
4239             skey.data = tmpkey;
4240             encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
4241         }
4242         /*
4243         * Now decrypt the received encrypted challenge,
4244         * increment by one, re-encrypt it and send it back.
4245         */
4246         encdata.ciphertext.data = datablock;
4247         encdata.ciphertext.length = 8;
4248         encdata.enctype = ENCTYPE_UNKNOWN;
4249
4250         kdata.data = k4_challenge;
4251         kdata.length = 8;
4252
4253         if (code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
4254                                    &encdata, &kdata)) {
4255             com_err("k4_auth_is", code, "while decrypting challenge");
4256             auth_finished(AUTH_REJECT);
4257             return AUTH_FAILURE;
4258         }
4259 #else /* MIT_CURRENT */
4260         des_set_random_generator_seed(k4_session_key);
4261         r = des_key_sched(k4_session_key, k4_sched);
4262         if ( r == -1 ) {
4263             printf("?Invalid DES key specified in credentials\r\n");
4264             debug(F110,"auth_is CHALLENGE",
4265                    "invalid DES Key specified in credentials",0);
4266         } else if ( r == -2 ) {
4267             printf("?Weak DES key specified in credentials\r\n");
4268             debug(F110,"auth_is CHALLENGE",
4269                    "weak DES Key specified in credentials",0);
4270         } else if ( r != 0 ) {
4271             printf("?DES Key Schedule not set by credentials\r\n");
4272             debug(F110,"auth_is CHALLENGE",
4273                    "DES Key Schedule not set by credentials",0);
4274         }
4275         ckhexdump("auth_is schedule",k4_sched,8*16);
4276
4277         memcpy((void *)datablock, (void *)data, sizeof(Block)); /* safe */
4278         ckhexdump("auth_is challege",datablock,sizeof(Block));
4279
4280         /*
4281         * Take the received encrypted challenge, and encrypt
4282         * it again to get a unique k4_session_key for the
4283         * ENCRYPT option.
4284         */
4285 #ifdef NT
4286         des_ecb_encrypt(datablock, k4_session_key, k4_sched, 1);
4287 #else /* NT */
4288         des_ecb_encrypt(&datablock, &k4_session_key, k4_sched, 1);
4289 #endif /* NT */
4290         ckhexdump("auth_is des_ecb_encrypt(datablock,k4_session_key,1)",
4291                  k4_session_key,8);
4292
4293 #ifdef CK_SSL
4294         if (!(ssl_active_flag || tls_active_flag))
4295 #endif /* CK_SSL */
4296         {
4297             skey.type = SK_DES;
4298             skey.length = 8;
4299             skey.data = k4_session_key;
4300             encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
4301         }
4302         /*
4303         * Now decrypt the received encrypted challenge,
4304         * increment by one, re-encrypt it and send it back.
4305         */
4306 #ifdef NT
4307         des_ecb_encrypt(datablock, k4_challenge, k4_sched, 0);
4308 #else /* NT */
4309         des_ecb_encrypt(&datablock, &k4_challenge, k4_sched, 0);
4310 #endif /* NT */
4311         ckhexdump("auth_is des_ecb_encrypt(datablock,k4_challenge,0)",
4312                  k4_session_key,8);
4313 #endif /* MIT_CURRENT */
4314         for (r = 7; r >= 0; r--) {
4315             register int t;
4316             t = (unsigned int)k4_challenge[r] + 1;
4317             k4_challenge[r] = t;        /* ignore overflow */
4318             if (t < 256)                /* if no overflow, all done */
4319                 break;
4320         }
4321         ckhexdump("auth_is k4_challenge+1",k4_challenge,8);
4322
4323 #ifdef MIT_CURRENT
4324         kdata.data = k4_challenge;
4325         kdata.length = 8;
4326
4327         encdata.ciphertext.data = k4_challenge;
4328         encdata.ciphertext.length = 8;
4329         encdata.enctype = ENCTYPE_UNKNOWN;
4330
4331         if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0,
4332                                    &kdata, &encdata)) {
4333             com_err("k4_auth_is", code, "while decrypting challenge");
4334             auth_finished(AUTH_REJECT);
4335             return AUTH_FAILURE;
4336         }
4337 #else /* MIT_CURRENT */
4338 #ifdef NT
4339         des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1);
4340 #else /* NT */
4341         des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1);
4342 #endif /* NT */
4343         ckhexdump("auth_is des_ecb_encrypt(k4_challenge_key,k4_challenge,1)",
4344                  k4_challenge,8);
4345
4346 #endif /* MIT_CURRENT */
4347         SendK4AuthSB(KRB4_RESPONSE,(void *)k4_challenge,sizeof(k4_challenge));
4348 #endif  /* ENCRYPTION */
4349         mutual_complete = 1;
4350         break;
4351
4352     default:
4353         if (1)
4354             printf("Unknown Kerberos option %d\r\n", data[-1]);
4355         SendK4AuthSB(KRB_REJECT, 0, 0);
4356         return(AUTH_FAILURE);
4357     }
4358     krb4_errno = r;
4359     makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno));
4360     return(AUTH_SUCCESS);
4361 }
4362 #endif /* KRB4 */
4363
4364 #ifdef KRB5
4365 int
4366 ck_krb5_autoget_TGT(char * realm)
4367 {
4368     extern struct krb_op_data krb_op;
4369     extern struct krb5_init_data krb5_init;
4370     char passwd[PWD_SZ];
4371     char prompt[64];
4372     char * saverealm=NULL;
4373     int  rc = -1;
4374     extern char * k5prprompt;
4375     extern char * k5pwprompt;
4376
4377     ini_kerb();         /* Place defaults in above structs */
4378     passwd[0] = '\0';
4379
4380     if ( krb5_init.principal == NULL ||
4381          krb5_init.principal[0] == '\0') {
4382         int ok = uq_txt(NULL,k5prprompt && k5prprompt[0] ? k5prprompt :
4383                   "Kerberos 5 Principal: ",2,NULL,passwd,PWD_SZ-1,NULL,
4384                         DEFAULT_UQ_TIMEOUT);
4385         if ( ok && passwd[0] )
4386             makestr(&krb5_init.principal,passwd);
4387         else
4388             return(0);
4389     }
4390
4391     /* Save realm in init structure so it can be restored */
4392     if ( realm ) {
4393         saverealm = krb5_init.realm;
4394         krb5_init.realm = realm;
4395     }
4396
4397     if ( passwd[0] || !(pwbuf[0] && pwflg) ) {
4398         int ok;
4399         if ( k5pwprompt && k5pwprompt[0] &&
4400              (strlen(k5pwprompt) + strlen(krb5_init.principal) +
4401               strlen(krb5_init.realm) - 4) < sizeof(prompt)) {
4402             sprintf(prompt,k5pwprompt,krb5_init.principal,krb5_init.realm);
4403         } else
4404         ckmakxmsg(prompt,sizeof(prompt),
4405                   k5pwprompt && k5pwprompt[0] ? k5pwprompt :
4406                   "Kerberos 5 Password for ",
4407                   krb5_init.principal,"@",krb5_init.realm,": ",
4408                   NULL,NULL,NULL,NULL,NULL,NULL,NULL
4409                  );
4410         ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL,
4411                     DEFAULT_UQ_TIMEOUT);
4412         if ( !ok )
4413             passwd[0] = '\0';
4414     } else {
4415         ckstrncpy(passwd,(char *)pwbuf,sizeof(passwd));
4416 #ifdef OS2
4417         if ( pwcrypt )
4418             ck_encrypt((char *)passwd);
4419 #endif /* OS2 */
4420     }
4421
4422     if ( passwd[0] ) {
4423         extern struct krb4_init_data krb4_init;
4424         char * savek4realm=NULL;
4425
4426         makestr(&krb5_init.password,passwd);
4427
4428         if ( krb5_d_getk4 ) {
4429             krb5_init.getk4 = 1;
4430             makestr(&krb4_init.principal,krb5_init.principal);
4431             makestr(&krb4_init.password,passwd);
4432             if ( realm ) {
4433                 savek4realm = krb4_init.realm;
4434                 krb4_init.realm = realm;
4435             }
4436             rc = ck_krb5_initTGT(&krb_op, &krb5_init,&krb4_init);
4437
4438             if ( savek4realm )
4439                 krb4_init.realm = savek4realm;
4440             free(krb4_init.password);
4441             krb4_init.password = NULL;
4442         } else {
4443             rc = ck_krb5_initTGT(&krb_op, &krb5_init,NULL);
4444         }
4445
4446         free(krb5_init.password);
4447         krb5_init.password = NULL;
4448
4449         memset(passwd,0,PWD_SZ);
4450     }
4451
4452     /* restore realm to init structure if needed */
4453     if ( saverealm )
4454         krb5_init.realm = saverealm;
4455     return(rc == 0);
4456 }
4457
4458 static krb5_error_code
4459 #ifdef CK_ANSIC
4460 k5_get_ccache( krb5_context k5_context, krb5_ccache * p_ccache,
4461                char * cc_name )
4462 #else  /* CK_ANSIC */
4463 k5_get_ccache(k5_context, p_ccache, cc_name)
4464     krb5_context k5_context;
4465     krb5_ccache * p_ccache;
4466     char * cc_name;
4467 #endif /* CK_ANSIC */
4468 {
4469     krb5_error_code r=0;
4470     char cc_tmp[CKMAXPATH+1];
4471     const char * def_name = NULL;
4472
4473 #ifndef HEIMDAL
4474     if ( cc_name ) {
4475         if ( strncmp("FILE:",cc_name,5) &&
4476              strncmp("MEMORY:",cc_name,7) &&
4477              strncmp("API:",cc_name,4) &&
4478              strncmp("STDIO:",cc_name,6) &&
4479              strncmp("MSLSA:",cc_name,6))
4480 #ifdef NT
4481             ckmakmsg(cc_tmp,CKMAXPATH,"API:",cc_name,NULL,NULL);
4482 #else /* NT */
4483             ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",cc_name,NULL,NULL);
4484 #endif /* NT */
4485         else {
4486             ckstrncpy(cc_tmp,cc_name,CKMAXPATH);
4487         }
4488         r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache);
4489         if (r != 0) {
4490             com_err("k5_get_ccache resolving ccache",r,
4491                      cc_tmp);
4492         } else {
4493             /* Make sure GSSAPI sees the same cache we are using */
4494             char buf[128];
4495             ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL);
4496             putenv(buf);
4497         }
4498     } else if ( krb5_d_cc ) {
4499         if ( strncmp("FILE:",krb5_d_cc,5) &&
4500              strncmp("MEMORY:",krb5_d_cc,7) &&
4501              strncmp("API:",krb5_d_cc,4) &&
4502              strncmp("STDIO:",krb5_d_cc,6) &&
4503              strncmp("MSLSA:", krb5_d_cc,6))
4504 #ifdef NT
4505             ckmakmsg(cc_tmp,CKMAXPATH,"API:",krb5_d_cc,NULL,NULL);
4506 #else /* NT */
4507             ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",krb5_d_cc,NULL,NULL);
4508 #endif /* NT */
4509         else {
4510             ckstrncpy(cc_tmp,krb5_d_cc,CKMAXPATH);
4511         }
4512         r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache);
4513         if (r != 0) {
4514             com_err("k5_get_ccache resolving ccache",r,
4515                      krb5_d_cc);
4516         } else {
4517             /* Make sure GSSAPI sees the same cache we are using */
4518             char buf[128];
4519             ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL);
4520             putenv(buf);
4521         }
4522     } else
4523 #endif /* HEIMDAL */
4524     {
4525         if ((r = krb5_cc_default(k5_context, p_ccache))) {
4526             com_err("k5_get_ccache",r,"while getting default ccache");
4527         }
4528     }
4529     /* do not set krb5_errno/krb5_errmsg here since the value returned */
4530     /* is being passed internally within the krb5 functions.           */
4531     return(r);
4532 }
4533
4534
4535 char *
4536 ck_krb5_realmofhost(char *host)
4537 {
4538     char ** realmlist=NULL;
4539     krb5_context private_context=NULL;
4540     static char * realm = NULL;
4541
4542     if ( !host )
4543         return NULL;
4544
4545     if ( realm ) {
4546         free(realm);
4547         realm = NULL;
4548     }
4549
4550     /* create private_context */
4551     if (krb5_init_context(&private_context)) {
4552         debug(F110,"ck_krb5_realmofhost()","unable to init_context",0);
4553         return(NULL);
4554     }
4555
4556     krb5_get_host_realm(private_context,host,&realmlist);
4557     if (realmlist && realmlist[0]) {
4558         makestr(&realm,realmlist[0]);
4559         krb5_free_host_realm(private_context,realmlist);
4560         realmlist = NULL;
4561     }
4562
4563     if ( private_context ) {
4564         krb5_free_context(private_context);
4565         private_context = NULL;
4566     }
4567
4568     if (ckstrchr(realm,'.') == NULL) {
4569         int n = 0;
4570         char * p = host;
4571         while ( (p = ckstrchr(p,'.')) != NULL ) {
4572             n++;
4573             p++;
4574         }
4575         if (n == 1) {
4576             makestr(&realm,host);
4577             ckupper(realm);
4578         } else {
4579             free(realm);
4580             realm = NULL;
4581         }
4582     }
4583     return(realm);
4584 }
4585
4586 /*
4587  *
4588  * K5_auth_send - gets authentication bits we need to send to KDC.
4589  *
4590  * Code lifted from telnet sample code in the appl directory.
4591  *
4592  * Result is left in k5_auth
4593  *
4594  * Returns: 0 on failure, 1 on success
4595  *
4596  */
4597
4598 static int
4599 #ifdef CK_ANSIC
4600 k5_auth_send(int how, int encrypt, int forward)
4601 #else
4602 k5_auth_send(how,encrypt,forward) int how; int encrypt; int forward;
4603 #endif
4604 {
4605     krb5_error_code r=0;
4606     krb5_ccache ccache=NULL;
4607 #ifndef HEIMDAL
4608     krb5_creds creds;
4609 #endif /* HEIMDAL */
4610     krb5_creds * new_creds=NULL;
4611 #ifdef CK_ENCRYPTION
4612     krb5_keyblock *newkey = 0;
4613 #endif /* CK_ENCRYPTION */
4614     krb5_flags ap_opts, auth_flags;
4615     char type_check[32];
4616     krb5_data checksum;
4617     int len=0;
4618     char * realm = NULL;
4619     char tgt[256];
4620
4621     realm = ck_krb5_realmofhost(szHostName);
4622     if (!realm) {
4623         ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL);
4624         ckstrncat(strTmp, szHostName,AUTHTMPBL);
4625         ckstrncat(strTmp, "\"",AUTHTMPBL);
4626         printf("?Kerberos 5 error: %s\r\n",strTmp);
4627         krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN;
4628         makestr(&krb5_errmsg,strTmp);
4629         return(0);
4630     }
4631
4632     ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
4633     debug(F110,"k5_auth_send TGT",tgt,0);
4634     if ( krb5_autoget &&
4635          !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
4636           (ck_krb5_is_tgt_valid() > 0)) )
4637         ck_krb5_autoget_TGT(realm);
4638
4639     r = k5_get_ccache(k5_context,&ccache,NULL);
4640     if ( r ) {
4641         com_err(NULL, r, "while authorizing (0).");
4642         krb5_errno = r;
4643         makestr(&krb5_errmsg,error_message(krb5_errno));
4644         return(0);
4645     }
4646
4647 #ifndef HEIMDAL
4648     memset((char *)&creds, 0, sizeof(creds));
4649     if (r = krb5_sname_to_principal(k5_context, szHostName,
4650                                 krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
4651                                 KRB5_NT_SRV_HST, &creds.server)) {
4652         com_err(NULL, r, "while authorizing (1).");
4653         krb5_errno = r;
4654         makestr(&krb5_errmsg,error_message(krb5_errno));
4655         return(0);
4656     }
4657
4658     if (forward_flag) {
4659         if (fwd_server) {
4660             krb5_free_principal(k5_context,fwd_server);
4661             fwd_server = NULL;
4662         }
4663         krb5_copy_principal(k5_context,creds.server,&fwd_server);
4664     }
4665
4666     r = krb5_cc_get_principal(k5_context, ccache, &creds.client);
4667     if (r) {
4668         com_err(NULL, r, "while authorizing (2).");
4669         krb5_free_cred_contents(k5_context, &creds);
4670         krb5_errno = r;
4671         makestr(&krb5_errmsg,error_message(krb5_errno));
4672         return(0);
4673     }
4674
4675     if (szUserName[0] == '\0') {                /* Get user name now */
4676         len  = krb5_princ_component(k5_context, creds.client, 0)->length;
4677         if ( len < sizeof(szUserName) ) {
4678             memcpy(szUserName,
4679                     krb5_princ_component(k5_context, creds.client, 0)->data,
4680                     len);                       /* safe */
4681         } else
4682             len = 0;
4683         szUserName[len] = '\0';
4684     } else {
4685         char * name = NULL;
4686         len  = krb5_princ_component(k5_context, creds.client, 0)->length;
4687         if ( len == strlen(szUserName) ) {
4688             name = krb5_princ_component(k5_context, creds.client, 0)->data;
4689 #ifdef OS2
4690             if ( !strnicmp(szUserName,name,len) )
4691                 memcpy(szUserName,name,len);    /* safe */
4692 #endif /* OS2 */
4693         }
4694     }
4695     if ( tn_auth_krb5_des_bug ) {   /* !ALLOW_KRB_3DES_ENCRYPT */
4696         /* Not sure if this is necessary anymore.  What impact does it have
4697          * on Win2000 TGTs that use DES_CBC_MD5 or RC4_HMAC?
4698          *
4699          * This prevents using 3DES Service Tickets.
4700          */
4701         creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
4702     }
4703
4704     if (r = krb5_get_credentials(k5_context, 0,
4705                                   ccache, &creds, &new_creds)) {
4706         com_err(NULL, r, "while authorizing (3).");
4707         krb5_free_cred_contents(k5_context, &creds);
4708         krb5_errno = r;
4709         makestr(&krb5_errmsg,error_message(krb5_errno));
4710         return(0);
4711     }
4712 #endif /* HEIMDAL */
4713
4714     if (auth_context) {
4715         krb5_auth_con_free(k5_context, auth_context);
4716         auth_context = 0;
4717     }
4718     if (r = krb5_auth_con_init(k5_context, &auth_context)) {
4719         com_err(NULL, r, "while initializing auth context");
4720         krb5_errno = r;
4721         makestr(&krb5_errmsg,error_message(krb5_errno));
4722         return(0);
4723     }
4724
4725     /* UPDATE for START_TLS.  AUTH_ENCRYPT_START_TLS and inclusion of */
4726     /* client and then server finished messages.                      */
4727
4728     type_check[0] = AUTHTYPE_KERBEROS_V5;
4729     type_check[1] = AUTH_CLIENT_TO_SERVER |
4730         (how ? AUTH_HOW_MUTUAL : AUTH_HOW_ONE_WAY) |
4731         (encrypt) |
4732         (forward ? INI_CRED_FWD_ON : INI_CRED_FWD_OFF);
4733 #ifdef CK_SSL
4734     if (encrypt == AUTH_ENCRYPT_START_TLS) {
4735         ssl_get_client_finished(&type_check[2],12);
4736         ssl_get_server_finished(&type_check[14],12);
4737     }
4738 #endif /* CK_SSL */
4739
4740 #ifndef HEIMDAL
4741     checksum.magic = KV5M_DATA;
4742 #endif /* HEIMDAL */
4743     checksum.length =
4744 #ifdef CK_SSL
4745         (encrypt == AUTH_ENCRYPT_START_TLS) ? 26 :
4746 #endif /* CK_SSL */
4747         2;
4748     checksum.data = (char *)&type_check;
4749
4750     ap_opts = 0;
4751     if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
4752         ap_opts |= AP_OPTS_MUTUAL_REQUIRED;
4753
4754 #ifdef HEIMDAL
4755     r = krb5_auth_setkeytype(k5_context, auth_context, KEYTYPE_DES);
4756     if (r)
4757         com_err(NULL, r, "while setting auth keytype");
4758     r = krb5_auth_con_setaddrs_from_fd(k5_context,auth_context, &ttyfd);
4759     if (r)
4760         com_err(NULL, r, "while setting auth addrs");
4761     r = krb5_mk_req(k5_context, &auth_context, ap_opts,
4762                     krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
4763                     szHostName, &checksum, ccache, &k5_auth);
4764     if (r)
4765         com_err(NULL, r, "while making request");
4766 #else /* HEIMDAL */
4767     auth_flags = KRB5_AUTH_CONTEXT_RET_TIME;
4768 #ifdef CK_ENCRYPTION
4769     ap_opts |= AP_OPTS_USE_SUBKEY;
4770 #endif /* CK_ENCRYPTION */
4771 #ifdef TLS_VERIFY
4772     if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
4773         auth_flags |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
4774         if (!krb5_d_no_addresses)
4775             r = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
4776                                  KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
4777     }
4778 #endif /* CK_SSL */
4779     krb5_auth_con_setflags(k5_context, auth_context, auth_flags);
4780     r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts,
4781                               &checksum, new_creds, &k5_auth);
4782 #endif /* HEIMDAL */
4783
4784 #ifdef CK_ENCRYPTION
4785     if (!r) {
4786         r = krb5_auth_con_getlocalsubkey(k5_context, auth_context, &newkey);
4787         if (r)
4788             r = krb5_auth_con_getkey(k5_context, auth_context, &newkey);
4789
4790         if (k5_session_key) {
4791             krb5_free_keyblock(k5_context, k5_session_key);
4792             k5_session_key = 0;
4793         }
4794     }
4795     if (newkey) {
4796         /*
4797         * keep the key in our private storage, but don't use it
4798         * yet---see kerberos5_reply() below
4799         */
4800 #ifdef HEIMDAL
4801         if ((newkey->keytype == ETYPE_DES_CBC_CRC) ||
4802              (newkey->keytype == ETYPE_DES_CBC_MD5) ||
4803              (newkey->keytype == ETYPE_DES_CBC_MD4))
4804         {
4805             debug(F111,"k5_auth_send()","newkey->keytype",newkey->keytype);
4806             krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
4807         }
4808 #else /* HEIMDAL */
4809         /* look for all possible DES keys first - just for compatibility */
4810         /* other key types are much less likely to be available          */
4811         if ((newkey->enctype == ENCTYPE_DES_CBC_CRC) ||
4812              (newkey->enctype == ENCTYPE_DES_CBC_MD5) ||
4813              (newkey->enctype == ENCTYPE_DES_CBC_MD4))
4814         {
4815             debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype);
4816             krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
4817         }
4818         else if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
4819                  (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
4820         {
4821             /* use the session key in credentials instead */
4822             debug(F111,"k5_auth_send()","new_creds->keyblock.enctype",
4823                    new_creds->keyblock.enctype);
4824             krb5_copy_keyblock(k5_context,
4825                                 &new_creds->keyblock, &k5_session_key);
4826         }
4827         else if (newkey->enctype != 0)
4828         {
4829             debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype);
4830             krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
4831         }
4832         else if (new_creds->keyblock.enctype != 0)
4833         {
4834             /* use the session key in credentials instead */
4835             debug(F111,"k5_auth_send()","new_creds->keyblock.enctype",
4836                    new_creds->keyblock.enctype);
4837             krb5_copy_keyblock(k5_context,
4838                                 &new_creds->keyblock, &k5_session_key);
4839         }
4840         else {
4841             debug(F110,"k5_auth_send()","NO KEY in newkey",0);
4842         }
4843 #endif /* HEIMDAL */
4844         krb5_free_keyblock(k5_context, newkey);
4845     }
4846 #endif /* CK_ENCRYPTION */
4847 #ifndef HEIMDAL
4848     krb5_free_cred_contents(k5_context, &creds);
4849     krb5_free_creds(k5_context, new_creds);
4850 #endif /* HEIMDAL */
4851     krb5_cc_close(k5_context,ccache);
4852
4853     if (r) {
4854         com_err(NULL, r, "while authorizing (4).");
4855         krb5_errno = r;
4856         makestr(&krb5_errmsg,error_message(krb5_errno));
4857         return(0);
4858     }
4859     krb5_errno = 0;
4860     makestr(&krb5_errmsg,"OK");
4861     return(1);
4862 }
4863
4864 /*
4865  * K5_auth_reply -- checks the reply for mutual authentication.
4866  */
4867 static int
4868 #ifdef CK_ANSIC
4869 k5_auth_reply(int how, unsigned char *data, int cnt)
4870 #else
4871 k5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt;
4872 #endif
4873 {
4874 #ifdef CK_ENCRYPTION
4875     Session_Key skey;
4876 #endif /* CK_ENCRYPTION */
4877
4878     data += 4;                                  /* Point to status byte */
4879     cnt -=5;
4880
4881     switch (*data++) {
4882     case KRB_REJECT:
4883         if (cnt > 0) {
4884             char *s;
4885             int len;
4886             ckstrncpy(strTmp,"Kerberos V5 refuses authentication because\r\n",
4887                       sizeof(strTmp));
4888             len = strlen(strTmp);
4889             if ( len + cnt < sizeof(strTmp) ) {
4890                 s = strTmp + strlen(strTmp);
4891                 memcpy(s, data, cnt);           /* safe */
4892                 s[cnt] = 0;
4893             }
4894         } else
4895             ckstrncpy(strTmp,"Kerberos V5 refuses authentication",
4896                       sizeof(strTmp));
4897         krb5_errno = -1;
4898         makestr(&krb5_errmsg,strTmp);
4899         printf("Kerberos authentication failed!\r\n%s\r\n",strTmp);
4900         auth_finished(AUTH_REJECT);
4901         return AUTH_FAILURE;
4902
4903     case KRB_ACCEPT:
4904         if (!mutual_complete) {
4905             if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !mutual_complete) {
4906                 ckstrncpy(strTmp,
4907                           "Kerberos V5 accepted you, but didn't provide"
4908                           " mutual authentication",sizeof(strTmp));
4909                 printf("Kerberos authentication failed!\r\n%s\r\n",strTmp);
4910                 krb5_errno = -1;
4911                 makestr(&krb5_errmsg,strTmp);
4912                 auth_finished(AUTH_REJECT);
4913                 return AUTH_FAILURE;
4914             }
4915
4916 #ifdef CK_ENCRYPTION
4917             if (k5_session_key) {
4918                 if ( tn_auth_krb5_des_bug ) {   /* !ALLOW_KRB_3DES_ENCRYPT */
4919                     skey.type = SK_DES;
4920                     skey.length = 8;
4921 #ifdef HEIMDAL
4922                     skey.data = k5_session_key->keyvalue.data;
4923 #else /* HEIMDAL */
4924                     skey.data = k5_session_key->contents;
4925 #endif /* HEIMDAL */
4926                 } else {
4927 #ifdef HEIMDAL
4928                     switch ( k5_session_key->keytype ) {
4929                     case ETYPE_DES_CBC_CRC:
4930                     case ETYPE_DES_CBC_MD5:
4931                     case ETYPE_DES_CBC_MD4:
4932                         skey.type = SK_DES;
4933                         skey.length = 8;
4934                         break;
4935                     default:
4936                         skey.type = SK_GENERIC;
4937                         skey.length = k5_session_key->length;
4938                         encrypt_dont_support(ENCTYPE_DES_CFB64);
4939                         encrypt_dont_support(ENCTYPE_DES_OFB64);
4940                     }
4941                     skey.data = k5_session_key->keyvalue.data;
4942 #else /* HEIMDAL */
4943                     switch ( k5_session_key->enctype ) {
4944                     case ENCTYPE_DES_CBC_CRC:
4945                     case ENCTYPE_DES_CBC_MD5:
4946                     case ENCTYPE_DES_CBC_MD4:
4947                         skey.type = SK_DES;
4948                         skey.length = 8;
4949                     default:
4950                         skey.type = SK_GENERIC;
4951                         skey.length = k5_session_key->length;
4952                         encrypt_dont_support(ENCTYPE_DES_CFB64);
4953                         encrypt_dont_support(ENCTYPE_DES_OFB64);
4954                     }
4955                     skey.data = k5_session_key->contents;
4956 #endif /* HEIMDAL */
4957                 }
4958                 encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
4959             }
4960 #endif /* CK_ENCRYPTION */
4961         }
4962         if ( cnt > 0 ) {
4963             char *s;
4964             int len;
4965             ckstrncpy(strTmp,"Kerberos V5 accepts you as ",sizeof(strTmp));
4966             len = strlen(strTmp);
4967             if ( len + cnt < sizeof(strTmp) ) {
4968                 s = strTmp + strlen(strTmp);
4969                 memcpy(s,data,cnt);
4970                 s[cnt] = 0;
4971             }
4972         }
4973         accept_complete = 1;
4974         printf("%s\r\n",strTmp);
4975
4976 #ifdef FORWARD
4977         if (forward_flag
4978 #ifdef COMMENT
4979              /* Marc Horowitz <marc@mit.edu> has successfully argued
4980                 that it is indeed safe to send Forwarded credentials
4981                 to an untrusted host.
4982               */
4983              && (auth_how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL
4984 #endif /* COMMENT */
4985              )
4986             kerberos5_forward();
4987 #endif /* FORWARD */
4988         krb5_errno = 0;
4989         makestr(&krb5_errmsg,strTmp);
4990         auth_finished(AUTH_USER);
4991         return AUTH_SUCCESS;
4992
4993     case KRB5_RESPONSE:
4994 #ifdef TLS_VERIFY
4995         if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS &&
4996             !krb5_tls_verified) {
4997             printf(
4998     "Man in the middle attack detected.  Session terminated.\r\n");
4999 #ifndef BETATEST
5000             netclos();
5001 #endif /* BETATEST */
5002             krb5_errno = -1;
5003             makestr(&krb5_errmsg,"TLS not verified");
5004             auth_finished(AUTH_REJECT);
5005             return AUTH_FAILURE;
5006         }
5007         if((ssl_active_flag || tls_active_flag) &&
5008             (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
5009             printf("TLS session parameters verified by Kerberos 5\r\n");
5010         }
5011 #endif /* TLS_VERIFY */
5012         if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
5013             /* the rest of the reply should contain a krb_ap_rep */
5014             krb5_ap_rep_enc_part *reply;
5015             krb5_data inbuf;
5016             krb5_error_code r;
5017
5018             inbuf.length = cnt;
5019             inbuf.data = (char *)data;
5020
5021             if (r = krb5_rd_rep(k5_context, auth_context, &inbuf, &reply)) {
5022                 com_err(NULL, r, "while authorizing. (5)");
5023                 krb5_errno = r;
5024                 makestr(&krb5_errmsg,error_message(krb5_errno));
5025                 auth_finished(AUTH_REJECT);
5026                 return AUTH_FAILURE;
5027             }
5028             krb5_free_ap_rep_enc_part(k5_context, reply);
5029
5030 #ifdef CK_ENCRYPTION
5031             if (encrypt_flag && k5_session_key) {
5032                 if ( tn_auth_krb5_des_bug ) {   /* !ALLOW_KRB_3DES_ENCRYPT */
5033                     skey.type = SK_DES;
5034                     skey.length = 8;
5035 #ifdef HEIMDAL
5036                     skey.data = k5_session_key->keyvalue.data;
5037 #else /* HEIMDAL */
5038                     skey.data = k5_session_key->contents;
5039 #endif /* HEIMDAL */
5040                 } else {
5041 #ifdef HEIMDAL
5042                     switch ( k5_session_key->keytype ) {
5043                     case ETYPE_DES_CBC_CRC:
5044                     case ETYPE_DES_CBC_MD5:
5045                     case ETYPE_DES_CBC_MD4:
5046                         skey.type = SK_DES;
5047                         skey.length = 8;
5048                     default:
5049                         skey.type = SK_GENERIC;
5050                         skey.length = k5_session_key->length;
5051                     }
5052                     skey.data = k5_session_key->keyvalue.data;
5053 #else /* HEIMDAL */
5054                     switch ( k5_session_key->enctype ) {
5055                     case ENCTYPE_DES_CBC_CRC:
5056                     case ENCTYPE_DES_CBC_MD5:
5057                     case ENCTYPE_DES_CBC_MD4:
5058                         skey.type = SK_DES;
5059                         skey.length = 8;
5060                         break;
5061                     default:
5062                         skey.type = SK_GENERIC;
5063                         skey.length = k5_session_key->length;
5064                     }
5065                     skey.data = k5_session_key->contents;
5066 #endif /* HEIMDAL */
5067                 }
5068                 encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
5069             }
5070 #endif /* ENCRYPTION */
5071             mutual_complete = 1;
5072         }
5073         ckstrncpy(strTmp,"Remote machine has been mutually authenticated",
5074                   sizeof(strTmp));
5075         krb5_errno = 0;
5076         makestr(&krb5_errmsg,strTmp);
5077         printf("%s\r\n",strTmp);
5078         auth_finished(AUTH_USER);
5079         return AUTH_SUCCESS;
5080
5081 #ifdef FORWARD
5082     case KRB5_FORWARD_ACCEPT:
5083         forwarded_tickets = 1;
5084         ckstrncpy(strTmp,"Remote machine has accepted forwarded credentials",
5085                   sizeof(strTmp));
5086         krb5_errno = 0;
5087         makestr(&krb5_errmsg,strTmp);
5088         printf("%s\r\n",strTmp);
5089         return AUTH_SUCCESS;
5090
5091     case KRB5_FORWARD_REJECT:
5092         forwarded_tickets = 0;
5093         if (cnt > 0) {
5094             char *s;
5095             int len;
5096             len = ckstrncpy(strTmp,
5097                       "Kerberos V5 refuses forwarded credentials because ",
5098                        sizeof(strTmp));
5099             if ( len + cnt < sizeof(strTmp) ) {
5100                 s = strTmp + strlen(strTmp);
5101                 memcpy(s, data, cnt);
5102                 s[cnt] = 0;
5103             }
5104         } else
5105             ckstrncpy(strTmp, "Kerberos V5 refuses forwarded credentials",
5106                       sizeof(strTmp));
5107
5108         printf("%s\r\n",strTmp);
5109         krb5_errno = -1;
5110         makestr(&krb5_errmsg,strTmp);
5111         return AUTH_SUCCESS;
5112 #endif  /* FORWARD */
5113
5114 #ifdef TLS_VERIFY
5115     case KRB5_TLS_VERIFY:
5116         if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
5117             krb5_data reply, msg;
5118             char tls_verify[24];
5119             krb5_replay_data repdata;
5120             krb5_error_code r;
5121
5122             ssl_get_server_finished(&tls_verify[0],12);
5123             ssl_get_client_finished(&tls_verify[12],12);
5124
5125             reply.data = (char *)data;
5126             reply.length = cnt;
5127
5128                         krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
5129                                                                    KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
5130
5131             if (r = krb5_rd_safe(k5_context,auth_context,&reply,&msg,&repdata))
5132               {
5133                 com_err("", r, "decoding tls verifier");
5134                 krb5_errno = r;
5135                 makestr(&krb5_errmsg,"TLS verify failure");
5136                 auth_finished(AUTH_REJECT);
5137                 return(AUTH_FAILURE);
5138             }
5139             if ( msg.length == 24 && !memcmp(msg.data,tls_verify,24) )
5140                  krb5_tls_verified = 1;
5141             krb5_free_data_contents(k5_context,&msg);
5142             if (krb5_tls_verified)
5143                 return(AUTH_SUCCESS);
5144         }
5145         printf("Man in the middle attack detected.  Session terminated.\r\n");
5146         netclos();
5147         krb5_errno = -1;
5148         makestr(&krb5_errmsg,"TLS verify failure");
5149         auth_finished(AUTH_REJECT);
5150         return(AUTH_FAILURE);
5151 #endif /* CK_SSL */
5152
5153     default:
5154         krb5_errno = -1;
5155         makestr(&krb5_errmsg,"Unknown reply type");
5156         auth_finished(AUTH_REJECT);
5157         return AUTH_FAILURE;                        /* Unknown reply type */
5158     }
5159 }
5160
5161 #ifdef FORWARD
5162 /* Decode, decrypt and store the forwarded creds in the local ccache. */
5163 /* Needed for KRB5_FORWARD                                            */
5164 static krb5_error_code
5165 rd_and_store_for_creds(context, auth_context, inbuf, client)
5166     krb5_context context;
5167     krb5_auth_context auth_context;
5168     krb5_data *inbuf;
5169     krb5_const_principal client;
5170 {
5171     krb5_creds ** creds=NULL;
5172     krb5_error_code retval;
5173     krb5_ccache ccache=NULL;
5174
5175 #ifdef HEIMDAL
5176     /*
5177     Heimdal Telnetd creates the cache file at this point and sets
5178     the KRB5CCNAME environment variable.
5179
5180     struct passwd *pwd;
5181     char ccname[1024];
5182
5183     pwd = getpwnam(szUserNameRequested);
5184     if (pwd == NULL)
5185         break;
5186     snprintf(ccname, sizeof(ccname)-1, "FILE:/tmp/krb5cc_%u",pwd->pw_uid);
5187     retval = krb5_cc_resolve(context,ccname,&ccache);
5188
5189     chown(ccname + 5, pwd->pw_uid, -1);
5190     */
5191 #endif /* HEIMDAL */
5192
5193     if (retval = k5_get_ccache(context,&ccache,NULL))
5194         return(retval);
5195
5196 #ifdef HEIMDAL
5197     if ((retval = krb5_cc_initialize(context, ccache, client)))
5198         return(retval);
5199
5200     if ((retval = krb5_rd_cred(context, auth_context, ccache, inbuf)))
5201         return(retval);
5202 #else /* HEIMDAL */
5203     if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)))
5204         return(retval);
5205
5206     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
5207         goto cleanup;
5208
5209     if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
5210         goto cleanup;
5211
5212     if ((retval = krb5_cc_close(context, ccache)))
5213         goto cleanup;
5214
5215   cleanup:
5216     krb5_free_tgt_creds(context, creds);
5217 #endif /* HEIMDAL */
5218     return retval;
5219 }
5220 #endif /* FORWARD */
5221
5222 /*
5223  *
5224  * K5_auth_is.
5225  *
5226  */
5227
5228 static int
5229 #ifdef CK_ANSIC
5230 k5_auth_is(int how, unsigned char *data, int cnt)
5231 #else
5232 k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt;
5233 #endif
5234 {
5235     int r = 0;
5236     krb5_principal server;
5237     krb5_keyblock *newkey = NULL;
5238     krb5_data outbuf;
5239     char errbuf[128]="";
5240     char *getenv();
5241 #ifndef HEIMDAL
5242     krb5_authenticator *authenticator;
5243     krb5_keytab keytabid = 0;
5244 #endif /* HEIMDAL */
5245     krb5_data inbuf;
5246 #ifdef CK_ENCRYPTION
5247     Session_Key skey;
5248 #endif /* CK_ENCRYPTION */
5249     char princ[256]="";
5250     int len;
5251
5252     data += 4;                                  /* Point to status byte */
5253     cnt -= 4;
5254
5255     ckhexdump("k5_auth_is data",data,cnt);
5256     debug(F111,"k5_auth_is","how",how);
5257
5258     if (cnt-- < 1) {
5259         auth_finished(AUTH_REJECT);
5260         return AUTH_FAILURE;
5261     }
5262     switch (*data++) {
5263     case KRB_AUTH:
5264         k5_auth.data = (char *)data;
5265         k5_auth.length = cnt;
5266
5267         debug(F110,"k5_auth_is","KRB_AUTH",0);
5268         debug(F111,"k5_auth_is","auth_context",auth_context);
5269
5270         if (!r && !auth_context) {
5271             r = krb5_auth_con_init(k5_context, &auth_context);
5272             debug(F111,"k5_auth_is","krb5_auth_con_init",r);
5273         }
5274
5275 #ifdef HEIMDAL
5276         if (!r)
5277             r = krb5_auth_con_setaddrs_from_fd(k5_context,
5278                                                auth_context,
5279                                                &ttyfd);
5280         if (!r)
5281             r = krb5_sock_to_principal(k5_context,
5282                                        0,
5283                                        "host",
5284                                        KRB5_NT_SRV_HST,
5285                                        &server);
5286         if (!r)
5287 #else /* HEIMDAL */
5288         if (!r) {
5289             krb5_rcache rcache = NULL;
5290
5291             r = krb5_auth_con_getrcache(k5_context, auth_context,
5292                                          &rcache);
5293             debug(F111,"k5_auth_is","krb5_auth_con_getrcache",r);
5294
5295             if (!r && !rcache) {
5296                 /* Do not resolve server's principal name, we will check */
5297                 /* for validity after the krb5_rd_req() call.            */
5298                 r = krb5_sname_to_principal(k5_context, 0, 0,
5299                                              KRB5_NT_SRV_HST, &server);
5300                 debug(F111,"k5_auth_is","krb5_sname_to_principal",r);
5301
5302                 if (!r) {
5303                     r = krb5_get_server_rcache(k5_context,
5304                         krb5_princ_component(k5_context, server, 0),
5305                                                 &rcache);
5306                     debug(F111,"k5_auth_is","krb5_get_server_rcache",r);
5307                     krb5_free_principal(k5_context, server);
5308                 }
5309             }
5310             if (!r) {
5311                 r = krb5_auth_con_setrcache(k5_context,
5312                                              auth_context, rcache);
5313                 debug(F111,"k5_auth_is","krb5_auth_con_setrcache",r);
5314             }
5315         }
5316         if (!r && k5_keytab) {
5317             r = krb5_kt_resolve(k5_context,
5318                                  k5_keytab, &keytabid);
5319             debug(F111,"k5_auth_is","krb5_kt_resolve",r);
5320         }
5321 #endif /* HEIMDAL */
5322         if (!r) {
5323             r = krb5_rd_req(k5_context, &auth_context, &k5_auth,
5324 #ifdef HEIMDAL
5325                              server, NULL, NULL,
5326 #else /* HEIMDAL */
5327                              NULL, keytabid, NULL,
5328 #endif /* HEIMDAL */
5329                              &k5_ticket);
5330             debug(F111,"k5_auth_is","krb5_rd_req",r);
5331         }
5332         if (r) {
5333             (void) ckstrncpy(errbuf, "krb5_rd_req failed: ",sizeof(errbuf));
5334             (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
5335             goto errout;
5336         }
5337 #ifdef HEIMDAL
5338         krb5_free_principal(k5_context, server);
5339
5340         {
5341             char type_check[26];
5342
5343             /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */
5344             /* client and then server finished messages. */
5345
5346             type_check[0] = AUTHTYPE_KERBEROS_V5;
5347             type_check[1] = how;        /* not broken into parts */
5348 #ifdef CK_SSL
5349             if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
5350                 ssl_get_client_finished(&type_check[2],12);
5351                 ssl_get_server_finished(&type_check[14],12);
5352                 ckhexdump("k5_auth_is type_check",type_check,26);
5353             }
5354 #endif /* CK_SSL */
5355
5356             r = krb5_verify_authenticator_checksum(k5_context,
5357                                                     auth_context,
5358                                                     type_check,
5359 #ifdef CK_SSL
5360                 ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 :
5361 #endif /* CK_SSL */
5362                                                     2);
5363         }
5364 #else /* HEIMDAL */
5365         len = krb5_princ_component(k5_context,k5_ticket->server,0)->length;
5366         if (len < 256)
5367         {
5368             memcpy(princ,
5369                    krb5_princ_component(k5_context,k5_ticket->server,0)->data,
5370                    len);
5371             princ[len] = '\0';
5372         }
5373         if ( strcmp((krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME), princ) )
5374         {
5375             debug(F110,"k5_auth_is incorrect service name",princ,0);
5376             ckstrncpy(errbuf,"incorrect service name: ",sizeof(errbuf));
5377             ckstrncat(errbuf,krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
5378                      sizeof(errbuf));
5379             ckstrncat(errbuf," != ",sizeof(errbuf));
5380             ckstrncat(errbuf,princ,sizeof(errbuf));
5381             goto errout;
5382         }
5383
5384         r = krb5_auth_con_getauthenticator(k5_context,
5385                                             auth_context,
5386                                             &authenticator);
5387         debug(F111,"k5_auth_is","krb5_auth_con_getauthenticator",r);
5388         if (r) {
5389             (void) ckstrncpy(errbuf,
5390                              "krb5_auth_con_getauthenticator failed: ",
5391                              sizeof(errbuf)
5392                              );
5393             (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
5394             goto errout;
5395         }
5396
5397         if (authenticator->checksum) {
5398             char type_check[26];
5399             krb5_checksum *cksum = authenticator->checksum;
5400             krb5_keyblock *key;
5401
5402             /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */
5403             /* client and then server finished messages. */
5404
5405             type_check[0] = AUTHTYPE_KERBEROS_V5;
5406             type_check[1] = how;        /* not broken into parts */
5407 #ifdef CK_SSL
5408             if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
5409                 ssl_get_client_finished(&type_check[2],12);
5410                 ssl_get_server_finished(&type_check[14],12);
5411                 ckhexdump("k5_auth_is type_check",type_check,26);
5412             }
5413 #endif /* CK_SSL */
5414
5415             r = krb5_auth_con_getkey(k5_context, auth_context,
5416                                       &key);
5417             debug(F111,"k5_auth_is","krb5_auth_con_getkey",r);
5418             if (r) {
5419                 (void) ckstrncpy(errbuf, "krb5_auth_con_getkey failed: ",
5420                                   sizeof(errbuf));
5421                 (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
5422                 goto errout;
5423             }
5424
5425             r = krb5_verify_checksum(k5_context,
5426                                       cksum->checksum_type,
5427                                       cksum,
5428                                       &type_check,
5429                   ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 :
5430                                       2,
5431                                       key->contents,
5432                                       key->length
5433                                       );
5434             debug(F111,"k5_auth_is","krb5_verify_checksum",r);
5435             if (r) {
5436                 (void) ckstrncpy(errbuf,
5437                                  "checksum verification failed: ",
5438                                  sizeof(errbuf)
5439                                  );
5440                 (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
5441                 goto errout;
5442             }
5443             krb5_free_keyblock(k5_context, key);
5444         } else {
5445             if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) {
5446                 (void) strcpy(errbuf,
5447                                "authenticator is missing required checksum");
5448                 goto errout;
5449             }
5450         }
5451
5452         krb5_free_authenticator(k5_context, authenticator);
5453 #endif /* HEIMDAL */
5454
5455 #ifdef TLS_VERIFY
5456         if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
5457             krb5_data in, msg;
5458             char tls_verify[24];
5459             krb5_replay_data repdata;
5460
5461             ssl_get_server_finished(&tls_verify[0],12);
5462             ssl_get_client_finished(&tls_verify[12],12);
5463
5464             in.data = tls_verify;
5465             in.length = 24;
5466
5467             krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
5468                                                                    KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
5469             if (r = krb5_mk_safe(k5_context,auth_context,&in,&msg,&repdata)) {
5470                 com_err("", r, "encoding tls verifier");
5471                 (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
5472                 goto errout;
5473             }
5474             SendK5AuthSB(KRB5_TLS_VERIFY, msg.data, msg.length);
5475             krb5_free_data_contents(k5_context,&msg);
5476         }
5477 #endif /* CK_SSL */
5478         if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
5479             /* do ap_rep stuff here */
5480             if ((r = krb5_mk_rep(k5_context,
5481 #ifdef HEIMDAL
5482                                   &auth_context,
5483 #else /* HEIMDAL */
5484                                   auth_context,
5485 #endif /* HEIMDAL */
5486                                   &outbuf))) {
5487                 debug(F111,"k5_auth_is","krb5_mk_rep",r);
5488                 (void) ckstrncpy(errbuf, "Make reply failed: ",sizeof(errbuf));
5489                 (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
5490                 goto errout;
5491             }
5492             debug(F111,"k5_auth_is","krb5_mk_rep",r);
5493
5494             SendK5AuthSB(KRB5_RESPONSE, outbuf.data, outbuf.length);
5495             mutual_complete = 1;
5496         }
5497
5498 #ifdef HEIMDAL
5499         {
5500             char * name = NULL;
5501             if (krb5_unparse_name(k5_context, k5_ticket->client,
5502                                    &name))
5503             {
5504                 szUserNameAuthenticated[0] = '\0';
5505             } else {
5506                 ckstrncpy(szUserNameAuthenticated,UIDBUFLEN,name);
5507                 free(name);
5508             }
5509         }
5510 #else /* HEIMDAL */
5511         if ( krb5_aname_to_localname(k5_context,
5512                                       k5_ticket->enc_part2->client,
5513                                       UIDBUFLEN,szUserNameAuthenticated) )
5514             szUserNameAuthenticated[0] = '\0';
5515 #endif /* HEIMDAL */
5516
5517         SendK5AuthSB(KRB_ACCEPT, szUserNameAuthenticated,
5518                       szUserNameAuthenticated[0] ? -1 : 0);
5519         accept_complete = 1;
5520         ckmakmsg(strTmp,sizeof(strTmp),
5521                  "Kerberos5 identifies him as ``",
5522                  szUserNameAuthenticated,"''",NULL);
5523         printf("%s\r\n",strTmp);
5524
5525         if (szUserNameRequested[0] &&
5526             krb5_kuserok(k5_context,
5527 #ifdef HEIMDAL
5528                           k5_ticket->client,
5529 #else /* HEIMDAL */
5530                           k5_ticket->enc_part2->client,
5531 #endif /* HEIMDAL */
5532                           szUserNameRequested))
5533             auth_finished(AUTH_VALID);
5534         else
5535             auth_finished(AUTH_USER);
5536
5537         krb5_auth_con_getremotesubkey(k5_context, auth_context,
5538                                        &newkey);
5539         if (k5_session_key) {
5540             krb5_free_keyblock(k5_context, k5_session_key);
5541             k5_session_key = 0;
5542         }
5543         if (newkey) {
5544             krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
5545             krb5_free_keyblock(k5_context, newkey);
5546         } else {
5547             krb5_copy_keyblock(k5_context,
5548 #ifdef HEIMDAL
5549                                 &k5_ticket->ticket.key,
5550 #else /* HEIMDAL */
5551                                 k5_ticket->enc_part2->session,
5552 #endif /* HEIMDAL */
5553                                 &k5_session_key);
5554         }
5555
5556 #ifdef CK_ENCRYPTION
5557 #ifdef HEIMDAL
5558         skey.type = k5_session_key->keyvalue.length == 8 ? SK_DES : SK_GENERIC;
5559         skey.length = k5_session_key->keyvalue.length;
5560         skey.data = k5_session_key->keyvalue.data;
5561 #else /* HEIMDAL */
5562         skey.type = k5_session_key->length == 8 ? SK_DES : SK_GENERIC;
5563         skey.length = k5_session_key->length;
5564         skey.data = k5_session_key->contents;
5565 #endif /* HEIMDAL */
5566         encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
5567 #endif /* CK_ENCRYPTION */
5568         debug(F100,"k5_auth_is AUTH_SUCCESS","",0);
5569         krb5_errno = r;
5570         if ( krb5_errno )
5571             makestr(&krb5_errmsg,error_message(krb5_errno));
5572         else
5573             makestr(&krb5_errmsg,strTmp);
5574         return AUTH_SUCCESS;
5575
5576 #ifdef FORWARD
5577     case KRB5_FORWARD:
5578         if ( !forward_flag ) {
5579             SendK5AuthSB(KRB5_FORWARD_REJECT,
5580                           "forwarded credentials are being refused.",
5581                           -1);
5582             return(AUTH_SUCCESS);
5583         }
5584
5585         inbuf.length = cnt;
5586         inbuf.data = (char *)data;
5587         if (
5588 #ifndef HEIMDAL
5589             (!krb5_d_no_addresses &&
5590             (r = krb5_auth_con_genaddrs(k5_context,auth_context,g_kstream->fd,
5591                               KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))) ||
5592 #endif /* HEIMDAL */
5593             (r = rd_and_store_for_creds(k5_context, auth_context,&inbuf,
5594 #ifdef HEIMDAL
5595                                          k5_ticket->client
5596 #else /* HEIMDAL */
5597                                          k5_ticket->enc_part2->client
5598 #endif /* HEIMDAL */
5599                                          ))) {
5600             (void) ckstrncpy(errbuf, "Read forwarded creds failed: ",
5601                               sizeof(errbuf));
5602             (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
5603             SendK5AuthSB(KRB5_FORWARD_REJECT, errbuf, -1);
5604             printf("Could not read forwarded credentials\r\n");
5605             krb5_errno = r;
5606             makestr(&krb5_errmsg,error_message(krb5_errno));
5607         }
5608         else {
5609             SendK5AuthSB(KRB5_FORWARD_ACCEPT, 0, 0);
5610             ckstrncpy(strTmp,"Forwarded credentials obtained",sizeof(strTmp));
5611             printf("%s\r\n",strTmp);
5612             krb5_errno = 0;
5613             makestr(&krb5_errmsg,strTmp);
5614         }
5615         /* A failure to accept forwarded credentials is not an */
5616         /* authentication failure.                             */
5617         return AUTH_SUCCESS;
5618 #endif  /* FORWARD */
5619     default:
5620         printf("Unknown Kerberos option %d\r\n", data[-1]);
5621         SendK5AuthSB(KRB_REJECT, 0, 0);
5622         break;
5623     }
5624     auth_finished(AUTH_REJECT);
5625     return AUTH_FAILURE;
5626
5627   errout:
5628     SendK5AuthSB(KRB_REJECT, errbuf, -1);
5629     krb5_errno = r;
5630     makestr(&krb5_errmsg,errbuf);
5631     printf("%s\r\n", errbuf);
5632     if (auth_context) {
5633         krb5_auth_con_free(k5_context, auth_context);
5634         auth_context = 0;
5635     }
5636     auth_finished(AUTH_REJECT);
5637     return AUTH_FAILURE;
5638 }
5639
5640 #ifdef FORWARD
5641 int
5642 #ifdef CK_ANSIC
5643 kerberos5_forward(void)
5644 #else
5645 kerberos5_forward()
5646 #endif
5647 {
5648     krb5_error_code r;
5649     krb5_ccache ccache=NULL;
5650     krb5_principal client = 0;
5651     krb5_principal server = 0;
5652     krb5_data forw_creds;
5653 #ifdef HEIMDAL
5654     krb5_creds      creds;
5655 #endif /* HEIMDAL */
5656
5657     forw_creds.data = 0;
5658
5659     r = k5_get_ccache(k5_context,&ccache,NULL);
5660     if ( r ) {
5661         com_err(NULL, r, "Kerberos V5: could not get default ccache");
5662         krb5_errno = r;
5663         makestr(&krb5_errmsg,error_message(krb5_errno));
5664         return(AUTH_FAILURE);
5665     }
5666
5667     if ((r = krb5_cc_get_principal(k5_context, ccache, &client))) {
5668         com_err(NULL, r, "Kerberos V5: could not get default principal");
5669         goto cleanup;
5670     }
5671
5672 #ifdef HEIMDAL
5673     memset(&creds, 0, sizeof(creds));
5674     creds.client = client;
5675
5676     if (r = krb5_build_principal(k5_context,
5677                              &creds.server,
5678                              strlen(client->realm),
5679                               client->realm,
5680                               "krbtgt",
5681                               client->realm,
5682                                   NULL)) {
5683         com_err(NULL, r, "Kerberos V5: could not get principal");
5684         goto cleanup;
5685     }
5686
5687     creds.times.endtime = 0;
5688
5689     if (r = krb5_get_forwarded_creds(k5_context,
5690                                       auth_context,
5691                                       ccache,
5692                                       0,
5693                                       szHostName,
5694                                       &creds,
5695                                       &forw_creds)) {
5696         com_err(NULL, r, "Kerberos V5: error getting forwarded creds");
5697         goto cleanup;
5698     }
5699 #else /* HEIMDAL */
5700     /* we should not need to make this call since we are storing the */
5701     /* server's principal in fwd_server from our call to             */
5702     /* krb5_sname_to_principal() in k5_auth_send()                   */
5703     if (fwd_server == NULL) {
5704         if ((r = krb5_sname_to_principal(k5_context, szHostName,
5705                                  krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
5706                                           KRB5_NT_SRV_HST, &server))) {
5707             com_err(NULL, r, "Kerberos V5: could not make server principal");
5708             goto cleanup;
5709         }
5710     }
5711
5712     if (!krb5_d_no_addresses &&
5713         (r = krb5_auth_con_genaddrs(k5_context, auth_context, g_kstream->fd,
5714                              KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR)))
5715     {
5716         com_err(NULL, r, "Kerberos V5: could not gen local full address");
5717         goto cleanup;
5718     }
5719
5720     if (r = krb5_fwd_tgt_creds(k5_context, auth_context, 0, client,
5721                                 fwd_server ? fwd_server : server,
5722                                 ccache, forwardable_flag, &forw_creds)) {
5723         com_err(NULL, r, "Kerberos V5: error getting forwardable credentials");
5724         goto cleanup;
5725     }
5726 #endif /* HEIMDAL */
5727
5728     /* Send forwarded credentials */
5729     if (!SendK5AuthSB(KRB5_FORWARD, forw_creds.data, forw_creds.length)) {
5730         printf("Kerberos V5 forwarding error!\r\n%s\r\n",
5731                     "Not enough room for authentication data");
5732     }
5733
5734 cleanup:
5735     if (client)
5736         krb5_free_principal(k5_context, client);
5737     if (server)
5738         krb5_free_principal(k5_context, server);
5739 #ifdef HEIMDAL
5740     krb5_data_free(&forw_creds);
5741 #else /* HEIMDAL */
5742     krb5_free_data_contents(k5_context,&forw_creds);
5743 #endif /* HEIMDAL */
5744     krb5_cc_close(k5_context, ccache);
5745
5746     krb5_errno = r;
5747     makestr(&krb5_errmsg,krb5_errno?error_message(krb5_errno):"OK");
5748     return(r?AUTH_FAILURE:AUTH_SUCCESS);
5749 }
5750 #endif /* FORWARD */
5751 #else /* KRB5 */
5752 int
5753 ck_krb5_autoget_TGT(char * dummy)
5754 {
5755     return(0);
5756 }
5757 #ifdef CK_KERBEROS
5758 int
5759 #ifdef CK_ANSIC
5760 ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init,
5761                  struct krb4_init_data * k4_init)
5762 #else
5763 ck_krb5_initTGT(op,init,k4_init)
5764     krb_op_data * op; struct krb5_init_data * init;
5765     struct krb4_init_data * k4_init;
5766 #endif /* CK_ANSIC*/
5767 {
5768     return(-1);
5769 }
5770
5771 int
5772 #ifdef CK_ANSIC
5773 ck_krb5_destroy(struct krb_op_data * op)
5774 #else
5775 ck_krb5_destroy(op) struct krb_op_data * op;
5776 #endif
5777 {
5778     return(-1);
5779 }
5780
5781 int
5782 #ifdef CK_ANSIC
5783 ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc)
5784 #else
5785 ck_krb5_list_creds(op,lc)
5786     struct krb_op_data * op; struct krb5_list_cred_data * lc;
5787 #endif
5788 {
5789     return(-1);
5790 }
5791 #else /* CK_KERBEROS */
5792 int
5793 #ifdef CK_ANSIC
5794 ck_krb5_initTGT(void * op, void * init, void * k4_init )
5795 #else
5796 ck_krb5_initTGT(op,init,k4_init)
5797     void * op; void * init; void * k4_init;
5798 #endif /* CK_ANSIC*/
5799 {
5800     return(-1);
5801 }
5802
5803 int
5804 #ifdef CK_ANSIC
5805 ck_krb5_destroy(void * op)
5806 #else
5807 ck_krb5_destroy(op) void * op;
5808 #endif
5809 {
5810     return(-1);
5811 }
5812
5813 int
5814 #ifdef CK_ANSIC
5815 ck_krb5_list_creds(void * op, void * lc)
5816 #else
5817 ck_krb5_list_creds(op,lc)
5818     void * op; void * lc;
5819 #endif
5820 {
5821     return(-1);
5822 }
5823 #endif /* CK_KERBEROS */
5824 #endif /* KRB5 */
5825
5826 #ifdef GSSAPI_KRB5
5827 /*
5828  *
5829  * gssk5_auth_send - gets authentication bits we need to send to KDC.
5830  *
5831  * Result is left in k5_auth
5832  *
5833  * Returns: 0 on failure, 1 on success
5834  *
5835  */
5836
5837 static int
5838 #ifdef CK_ANSIC
5839 gssk5_auth_send(int how, int encrypt, int forward)
5840 #else
5841 gssk5_auth_send(how,encrypt,forward) int how; int encrypt; int forward;
5842 #endif
5843 {
5844     OM_uint32 maj_stat, min_stat;
5845 #ifdef KRB5
5846     char * realm = NULL;
5847     char tgt[256];
5848 #endif /* KRB5 */
5849
5850     gss_chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32  */
5851     gss_chan.initiator_address.length = 4;
5852     gss_chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
5853     gss_chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
5854     gss_chan.acceptor_address.length = 4;
5855     gss_chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
5856     gss_chan.application_data.length = 0;
5857     gss_chan.application_data.value = 0;
5858
5859 #ifdef KRB5
5860     realm = ck_krb5_realmofhost(ftp_host);
5861     if (realm) {
5862         ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
5863         debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
5864         if ( krb5_autoget &&
5865              !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
5866                 (ck_krb5_is_tgt_valid() > 0)) )
5867             ck_krb5_autoget_TGT(realm);
5868     }
5869 #endif /* KRB5 */
5870
5871     /* Blob from gss-client */
5872     /* host@hostname */
5873     /* the V5 GSSAPI binding canonicalizes this for us... */
5874     ckmakmsg(gss_stbuf,GSS_BUFSIZ,
5875              krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
5876              "@",
5877              szHostName,
5878               NULL
5879               );
5880     fprintf(stderr, "Authenticating to <%s>...\n", gss_stbuf);
5881     gss_send_tok.value = gss_stbuf;
5882     gss_send_tok.length = strlen(gss_stbuf);
5883     maj_stat = gss_import_name(&min_stat, &gss_send_tok,
5884                                 gss_nt_service_name,
5885                                 &gss_target_name
5886                                 );
5887     if (maj_stat != GSS_S_COMPLETE) {
5888         user_gss_error(maj_stat, min_stat, "parsing name");
5889         secure_error("name parsed <%s>\n", gss_stbuf);
5890         return(0);
5891     }
5892     token_ptr = GSS_C_NO_BUFFER;
5893     gcontext = GSS_C_NO_CONTEXT; /* structure copy */
5894
5895     fprintf(stderr, "calling gss_init_sec_context\n");
5896     maj_stat =
5897         gss_init_sec_context(&min_stat,
5898                               GSS_C_NO_CREDENTIAL,
5899                               &gcontext,
5900                               gss_target_name,
5901                               gss_mech_krb5,
5902                               GSS_C_MUTUAL_FLAG |
5903                               GSS_C_REPLAY_FLAG |
5904                               ((forward && forward_flag) ?
5905                                 GSS_C_DELEG_FLAG : 0),
5906                               0,
5907                               (krb5_d_no_addresses ? /* channel bindings */
5908                                 GSS_C_NO_CHANNEL_BINDINGS :
5909                                 &gss_chan),
5910                               gss_token_ptr,
5911                               NULL,     /* ignore mech type */
5912                               &gss_send_tok,
5913                               NULL,     /* ignore ret_flags */
5914                               NULL
5915                               );        /* ignore time_rec */
5916
5917
5918         if (maj_stat != GSS_S_COMPLETE &&
5919              maj_stat != GSS_S_CONTINUE_NEEDED) {
5920             user_gss_error(maj_stat,
5921                             min_stat,
5922                             "initializing context"
5923                             );
5924             gss_release_name(&min_stat, &gss_target_name);
5925             return(0);
5926         }
5927         return(1);
5928 }
5929
5930 /*
5931  * gssk5_auth_reply -- checks the reply for mutual authentication.
5932  */
5933 static int
5934 #ifdef CK_ANSIC
5935 gssk5_auth_reply(int how, unsigned char *data, int cnt)
5936 #else
5937 gssk5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt;
5938 #endif
5939 {
5940     data += 4;                                  /* Point to status byte */
5941     cnt -=5;
5942
5943     switch (*data++) {
5944     case GSS_REJECT:
5945         if (cnt > 0) {
5946             char *s;
5947             int len;
5948             ckstrncpy(strTmp,"GSSAPI refuses authentication because\r\n",
5949                       sizeof(strTmp));
5950             len = strlen(strTmp);
5951             if ( len + cnt < sizeof(strTmp) ) {
5952                 s = strTmp + strlen(strTmp);
5953                 memcpy(s, data, cnt);           /* safe */
5954                 s[cnt] = 0;
5955             }
5956         } else
5957             ckstrncpy(strTmp,"GSSAPI refuses authentication",
5958                       sizeof(strTmp));
5959         printf("GSSAPI authentication failed!\r\n%s\r\n",strTmp);
5960         auth_finished(AUTH_REJECT);
5961         return AUTH_FAILURE;
5962
5963     case GSS_ACCEPT:
5964         if ( cnt > 0 ) {
5965             char *s;
5966             int len;
5967             ckstrncpy(strTmp,"GSSAPI accepts you as ",sizeof(strTmp));
5968             len = strlen(strTmp);
5969             if ( len + cnt < sizeof(strTmp) ) {
5970                 s = strTmp + strlen(strTmp);
5971                 memcpy(s,data,cnt);
5972                 s[cnt] = 0;
5973             }
5974         }
5975         accept_complete = 1;
5976         printf("%s\r\n",strTmp);
5977         auth_finished(AUTH_USER);
5978         return AUTH_SUCCESS;
5979
5980     case GSS_RESPONSE:
5981         gss_token_ptr = &gss_recv_tok;
5982         gss_recv_tok.value = data;
5983         gss_recv_tok.length = cnt;
5984
5985         maj_stat =
5986             gss_init_sec_context(&min_stat,
5987                                   GSS_C_NO_CREDENTIAL,
5988                                   &gcontext,
5989                                   gss_target_name,
5990                                   gss_krb5_mech,
5991                                   GSS_C_MUTUAL_FLAG |
5992                                   GSS_C_REPLAY_FLAG |
5993                                   (forward_flag ?
5994                                     GSS_C_DELEG_FLAG : 0),
5995                                   0,
5996                                   (krb5_d_no_addresses ? /* channel bindings */
5997                                     GSS_C_NO_CHANNEL_BINDINGS :
5998                                     &gss_chan),
5999                                   gss_token_ptr,
6000                                   NULL, /* ignore mech type */
6001                                   &gss_send_tok,
6002                                   NULL, /* ignore ret_flags */
6003                                   NULL
6004                                   );    /* ignore time_rec */
6005
6006         if ( maj_stat == GSS_S_COMPLETE )
6007         {
6008
6009         } else if ( maj_stat == CSS_S_CONTINUE_NEEDED ) {
6010         } else {
6011         }
6012
6013         ckstrncpy(strTmp,"Remote machine has been mutually authenticated",
6014                   sizeof(strTmp));
6015         printf("%s\r\n",strTmp);
6016         auth_finished(AUTH_USER);
6017         return AUTH_SUCCESS;
6018
6019     default:
6020         auth_finished(AUTH_REJECT);
6021         return AUTH_FAILURE;                        /* Unknown reply type */
6022     }
6023 }
6024
6025 /*
6026  *
6027  * gssk5_auth_is.
6028  *
6029  */
6030
6031 static int
6032 #ifdef CK_ANSIC
6033 k5_auth_is(int how, unsigned char *data, int cnt)
6034 #else
6035 k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt;
6036 #endif
6037 {
6038     int replied = 0;
6039     gss_cred_id_t server_creds, deleg_creds;
6040     gss_name_t client;
6041     int ret_flags;
6042     gss_buffer_desc name_buf;
6043     gss_name_t server_name;
6044     OM_uint32 acquire_maj,
6045       acquire_min,
6046       accept_maj,
6047       accept_min,
6048       stat_maj,
6049       stat_min;
6050     gss_OID mechid;
6051     gss_buffer_desc tok, out_tok;
6052     char gbuf[GSS_BUFSIZ];
6053     u_char gout_buf[GSS_BUFSIZ];
6054     char localname[MAXHOSTNAMELEN];
6055     char service_name[MAXHOSTNAMELEN+10];
6056     char **service;
6057     struct hostent *hp;
6058
6059     data += 4;                                  /* Point to status byte */
6060     cnt -= 4;
6061
6062     ckhexdump("gssk5_auth_is data",data,cnt);
6063     debug(F111,"gssk5_auth_is","how",how);
6064
6065     if (cnt-- < 1) {
6066         auth_finished(AUTH_REJECT);
6067         return AUTH_FAILURE;
6068     }
6069     switch (*data++) {
6070     case GSS_AUTH:
6071         gss_chan.initiator_addrtype = GSS_C_AF_INET;
6072         gss_chan.initiator_address.length = 4;
6073         gss_chan.initiator_address.value = &his_addr.sin_addr.s_addr;
6074         gss_chan.acceptor_addrtype = GSS_C_AF_INET;
6075         gss_chan.acceptor_address.length = 4;
6076         gss_chan.acceptor_address.value = &ctrl_addr.sin_addr.s_addr;
6077         gss_chan.application_data.length = 0;
6078         gss_chan.application_data.value = 0;
6079
6080         tok.value = data;
6081         tok.length = cnt;
6082
6083         if (gethostname(localname, MAXHOSTNAMELEN)) {
6084             auth_finished(AUTH_REJECT);
6085             return AUTH_FAILURE;
6086         }
6087         if (!(hp = gethostbyname(localname))) {
6088             auth_finished(AUTH_REJECT);
6089             return AUTH_FAILURE;
6090         }
6091 #ifdef HADDRLIST
6092         hp = ck_copyhostent(hp);
6093 #endif /* HADDRLIST */
6094         strncpy(localname, hp->h_name, sizeof(localname) - 1);
6095         localname[sizeof(localname) - 1] = '\0';
6096
6097         sprintf(service_name, "%s@%s", *service, localname);
6098         name_buf.value = service_name;
6099         name_buf.length = strlen(name_buf.value) + 1;
6100         stat_maj = gss_import_name(&stat_min, &name_buf,
6101                                     gss_nt_service_name,
6102                                     &server_name);
6103         if (stat_maj != GSS_S_COMPLETE) {
6104             auth_finished(AUTH_REJECT);
6105             return AUTH_FAILURE;
6106         }
6107
6108         acquire_maj = gss_acquire_cred(&acquire_min, server_name, 0,
6109                                         GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
6110                                         &server_creds, NULL, NULL);
6111         (void) gss_release_name(&stat_min, &server_name);
6112
6113         if (acquire_maj != GSS_S_COMPLETE) {
6114             reply_gss_error(535, accept_maj, accept_min,
6115                                  "accepting context");
6116             syslog(LOG_ERR, "failed accepting context");
6117             (void) gss_release_cred(&stat_min, &server_creds);
6118             if (ret_flags & GSS_C_DELEG_FLAG)
6119                 (void) gss_release_cred(&stat_min,
6120                                          &deleg_creds);
6121             return 0;
6122         }
6123
6124         gcontext = GSS_C_NO_CONTEXT;
6125         accept_maj = gss_accept_sec_context(&accept_min,
6126                                             &gcontext, /* context_handle */
6127                                             /* verifier_cred_handle */
6128                                             server_creds,
6129                                             &tok, /* input_token */
6130                                             (krb5_d_no_addresses ?
6131                                              /* channel bindings */
6132                                                GSS_C_NO_CHANNEL_BINDINGS :
6133                                                &gss_chan),
6134                                              &client, /* src_name */
6135                                             &mechid, /* mech_type */
6136                                             &out_tok, /* output_token */
6137                                             &ret_flags,
6138                                             NULL,       /* ignore time_rec */
6139                                             /* forwarded credentials */
6140                                             &deleg_creds
6141                                             );
6142
6143         if (accept_maj!=GSS_S_COMPLETE && accept_maj!=GSS_S_CONTINUE_NEEDED) {
6144             reply_gss_error(535, accept_maj, accept_min,
6145                              "accepting context");
6146             syslog(LOG_ERR, "failed accepting context");
6147             (void) gss_release_cred(&stat_min, &server_creds);
6148             if (ret_flags & GSS_C_DELEG_FLAG)
6149                 (void) gss_release_cred(&stat_min,
6150                                          &deleg_creds);
6151             return 0;
6152         }
6153
6154         if (out_tok.length) {
6155             if (kerror = radix_encode(out_tok.value,gbuf,&out_tok.length, 0)) {
6156                 secure_error("Couldn't encode ADAT reply (%s)",
6157                              radix_error(kerror));
6158                 syslog(LOG_ERR, "couldn't encode ADAT reply");
6159                 (void) gss_release_cred(&stat_min, &server_creds);
6160                 if (ret_flags & GSS_C_DELEG_FLAG)
6161                         (void) gss_release_cred(&stat_min,
6162                                                 &deleg_creds);
6163                 return(0);
6164             }
6165             if (stat_maj == GSS_S_COMPLETE) {
6166                 reply(235, "ADAT=%s", gbuf);
6167                 replied = 1;
6168             } else {
6169                 /* If the server accepts the security data, and
6170                    requires additional data, it should respond
6171                    with reply code 335. */
6172                 reply(335, "ADAT=%s", gbuf);
6173             }
6174             (void) gss_release_buffer(&stat_min, &out_tok);
6175         }
6176
6177         if (stat_maj == GSS_S_COMPLETE) {
6178             /* GSSAPI authentication succeeded */
6179             stat_maj = gss_display_name(&stat_min, client,
6180                                          &client_name, &mechid);
6181             if (stat_maj != GSS_S_COMPLETE) {
6182                 /* "If the server rejects the security data (if
6183                    a checksum fails, for instance), it should
6184                    respond with reply code 535." */
6185                 reply_gss_error(535, stat_maj, stat_min,
6186                                 "extracting GSSAPI identity name");
6187                 syslog(LOG_ERR, "gssapi error extracting identity");
6188                 (void) gss_release_cred(&stat_min, &server_creds);
6189                 if (ret_flags & GSS_C_DELEG_FLAG)
6190                         (void) gss_release_cred(&stat_min,
6191                                                 &deleg_creds);
6192                 return 0;
6193             }
6194             auth_type = temp_auth_type;
6195             temp_auth_type = NULL;
6196
6197             (void) gss_release_cred(&stat_min, &server_creds);
6198             if (ret_flags & GSS_C_DELEG_FLAG) {
6199                 if (want_creds)
6200                     ftpd_gss_convert_creds(client_name.value,
6201                                             deleg_creds);
6202                 (void) gss_release_cred(&stat_min, &deleg_creds);
6203             }
6204
6205             /* If the server accepts the security data, but does
6206                not require any additional data (i.e., the security
6207                data exchange has completed successfully), it must
6208                respond with reply code 235. */
6209             if (!replied)
6210             {
6211                 if (ret_flags & GSS_C_DELEG_FLAG && !have_creds)
6212                   reply(235,
6213  "GSSAPI Authentication succeeded, but could not accept forwarded credentials"
6214                         );
6215                 else
6216                   reply(235, "GSSAPI Authentication succeeded");
6217             }
6218             return(1);
6219         } else if (stat_maj == GSS_S_CONTINUE_NEEDED) {
6220             /* If the server accepts the security data, and
6221             requires additional data, it should respond with
6222             reply code 335. */
6223             reply(335, "more data needed");
6224             (void) gss_release_cred(&stat_min, &server_creds);
6225             if (ret_flags & GSS_C_DELEG_FLAG)
6226                 (void) gss_release_cred(&stat_min, &deleg_creds);
6227             return(0);
6228         } else {
6229             /* "If the server rejects the security data (if
6230             a checksum fails, for instance), it should
6231             respond with reply code 535." */
6232             reply_gss_error(535, stat_maj, stat_min,
6233                              "GSSAPI failed processing ADAT");
6234             syslog(LOG_ERR, "GSSAPI failed processing ADAT");
6235             (void) gss_release_cred(&stat_min, &server_creds);
6236             if (ret_flags & GSS_C_DELEG_FLAG)
6237                 (void) gss_release_cred(&stat_min, &deleg_creds);
6238             return(0);
6239         }
6240
6241         debug(F100,"gssk5_auth_is AUTH_SUCCESS","",0);
6242         krb5_errno = r;
6243         if ( krb5_errno )
6244             makestr(&krb5_errmsg,error_message(krb5_errno));
6245         else
6246             makestr(&krb5_errmsg,strTmp);
6247         return AUTH_SUCCESS;
6248
6249     default:
6250         printf("Unknown Kerberos option %d\r\n", data[-1]);
6251         SendGSSK5AuthSB(GSS_REJECT, 0, 0);
6252         break;
6253     }
6254     auth_finished(AUTH_REJECT);
6255     return AUTH_FAILURE;
6256 }
6257 #endif /* GSSAPI_KRB5 */
6258
6259 #ifdef CK_SRP
6260 /*
6261  * Copyright (c) 1997 Stanford University
6262  *
6263  * The use of this software for revenue-generating purposes may require a
6264  * license from the owners of the underlying intellectual property.
6265  * Specifically, the SRP-3 protocol may not be used for revenue-generating
6266  * purposes without a license.
6267  *
6268  * NOTE: Columbia University has a license.
6269  *
6270  * Within that constraint, permission to use, copy, modify, and distribute
6271  * this software and its documentation for any purpose is hereby granted
6272  * without fee, provided that the above copyright notices and this permission
6273  * notice appear in all copies of the software and related documentation.
6274  *
6275  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
6276  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
6277  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
6278  *
6279  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
6280  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
6281  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
6282  * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
6283  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
6284  */
6285
6286 static void
6287 srp_encode_length(data, num)
6288     unsigned char * data;
6289     int num;
6290 {
6291     *data = (num >> 8) & 0xff;
6292     *++data = num & 0xff;
6293 }
6294
6295 static int
6296 srp_decode_length(data)
6297     unsigned char * data;
6298 {
6299     return (((int) *data & 0xff) << 8) | (*(data + 1) & 0xff);
6300 }
6301
6302 #ifdef PRE_SRP_1_7_3
6303 static int
6304 #ifdef CK_ANSIC
6305 srp_reply(int how, unsigned char *data, int cnt)
6306 #else
6307 srp_reply(how,data,cnt) int how; unsigned char *data; int cnt;
6308 #endif
6309 {
6310     struct t_num n;
6311     struct t_num g;
6312     struct t_num s;
6313     struct t_num B;
6314     struct t_num * A;
6315     char type_check[26];
6316     int pflag;
6317
6318 #ifdef CK_ENCRYPTION
6319     Session_Key skey;
6320 #endif /* ENCRYPTION */
6321
6322     char * str=NULL;
6323
6324     data += 4;                          /* Point to status byte */
6325     cnt  -= 4;
6326
6327     if(cnt-- < 1) {
6328         auth_finished(AUTH_REJECT);
6329         return AUTH_FAILURE;
6330     }
6331
6332     switch(*data++) {
6333     case SRP_REJECT:
6334         ckmakmsg(strTmp,sizeof(strTmp),
6335                   "SRP refuses authentication for '",szUserName,
6336                   "'\r\n",NULL);
6337         if (cnt > 0) {
6338             int len = strlen(strTmp);
6339             if ( len + cnt < sizeof(strTmp) ) {
6340                 str = strTmp + strlen(strTmp);
6341                 memcpy(str,data,cnt);
6342                 str[cnt] = 0;
6343             }
6344         }
6345         printf("SRP authentication failed!\r\n%s\r\n",strTmp);
6346         if (tc != NULL) {
6347             t_clientclose(tc);
6348             tc = NULL;
6349         }
6350         auth_finished(AUTH_REJECT);
6351         return AUTH_FAILURE;
6352
6353     case SRP_ACCEPT:
6354         if(cnt < RESPONSE_LEN || !srp_waitresp ||
6355             tc == NULL
6356             ) {
6357             printf("SRP Protocol error\r\n");
6358             return(auth_resend(AUTHTYPE_SRP));
6359         }
6360         srp_waitresp = 0;
6361
6362         if(t_clientverify(tc, data) == 0) {
6363             printf("SRP accepts you as %s\r\n",szUserName);
6364 #ifdef CK_SSL
6365             if((ssl_active_flag || tls_active_flag) &&
6366                 (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
6367                 printf("TLS session parameters verified by SRP\r\n");
6368             } else
6369 #endif /* CK_SSL */
6370
6371 #ifdef CK_ENCRYPTION
6372             {
6373                 skey.type = SK_GENERIC;
6374                 skey.length = SESSION_KEY_LEN;
6375                 skey.data = tc->session_key;
6376                 encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
6377             }
6378 #endif /* ENCRYPTION */
6379             t_clientclose(tc);
6380             tc = NULL;
6381             accept_complete = 1;
6382             auth_finished(AUTH_VALID);
6383             return AUTH_SUCCESS;
6384         } else {
6385             printf("SRP server authentication failed!\r\n");
6386             t_clientclose(tc);
6387             tc = NULL;
6388             return(auth_resend(AUTHTYPE_SRP));
6389         }
6390         break;
6391
6392     case SRP_PARAMS:
6393         if(!szUserName) {
6394             printf("No username available\r\n");
6395             return(auth_resend(AUTHTYPE_SRP));
6396         }
6397
6398         n.len = srp_decode_length(data);
6399         data += 2;
6400         cnt -= 2;
6401         if(n.len > cnt) {
6402             printf("n too long\r\n");
6403             return(auth_resend(AUTHTYPE_SRP));
6404         }
6405         n.data = data;
6406         data += n.len;
6407         cnt -= n.len;
6408
6409         g.len = srp_decode_length(data);
6410         data += 2;
6411         cnt -= 2;
6412         if(g.len > cnt) {
6413             printf("g too long\r\n");
6414             return(auth_resend(AUTHTYPE_SRP));
6415         }
6416         g.data = data;
6417         data += g.len;
6418         cnt -= g.len;
6419
6420         s.len = srp_decode_length(data);
6421         data += 2;
6422         cnt -= 2;
6423         if(s.len > cnt) {
6424             printf("salt too long\r\n");
6425             return(auth_resend(AUTHTYPE_SRP));
6426         }
6427         s.data = data;
6428         data += s.len;
6429         cnt -= s.len;
6430
6431         /* If the parameters provided by the server cannot be
6432          * validated the following function will fail.
6433          */
6434         tc = t_clientopen(szUserName, &n, &g, &s);
6435         if (tc == NULL) {
6436             printf("SRP parameter initialization error\r\n");
6437             return(auth_resend(AUTHTYPE_SRP));
6438         }
6439         A = t_clientgenexp(tc);
6440         if(A == NULL) {
6441             printf("SRP protocol error\r\n");
6442             return(auth_resend(AUTHTYPE_SRP));
6443         }
6444         SendSRPAuthSB(SRP_EXP, A->data, A->len);
6445
6446         if ( pwbuf[0] && pwflg ) {
6447             printf("SRP using %d-bit modulus for '%s'\r\n",
6448                    8 * n.len,
6449                    szUserName
6450                    );
6451             ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd));
6452 #ifdef OS2
6453             if ( pwcrypt )
6454                 ck_encrypt((char *)srp_passwd);
6455 #endif /* OS2 */
6456         } else {
6457             extern char * srppwprompt;
6458             char preface[128];
6459             int ok;
6460
6461             if (srppwprompt && srppwprompt[0] &&
6462                 (strlen(srppwprompt) + strlen(szUserName) - 2) <
6463                 sizeof(preface)) {
6464                 sprintf(preface,srppwprompt,szUserName);
6465             } else {
6466                 ckmakxmsg( preface,sizeof(preface),
6467                           "SRP using ",ckitoa(8*n.len),"-bit modulus for '",
6468                           szUserName, "'", NULL, NULL, NULL, NULL, NULL,
6469                           NULL, NULL);
6470             }
6471             ok = uq_txt( preface,"Password: ",2,NULL,
6472                          srp_passwd,sizeof(srp_passwd)-1,NULL,
6473                          DEFAULT_UQ_TIMEOUT);
6474             if ( !ok )
6475                 srp_passwd[0] = '\0';
6476         }
6477
6478         t_clientpasswd(tc, srp_passwd);
6479         memset(srp_passwd, 0, sizeof(srp_passwd));
6480         return AUTH_SUCCESS;
6481
6482     case SRP_CHALLENGE:
6483         if(tc == NULL) {
6484             printf("SRP protocol error\r\n");
6485             return(auth_resend(AUTHTYPE_SRP));
6486         }
6487
6488 #ifndef PRE_SRP_1_4_5
6489         /*
6490          * The original SRP AUTH implementation did not protect against
6491          * tampering of the auth-type-pairs.  Therefore, when the
6492          * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
6493          * into the SRP hash computation.  When AUTH_ENCRYPT_START_TLS
6494          * is set we also insert the SSL/TLS client and server finished
6495          * messages to ensure that there is no man in the middle attack
6496          * underway on the SSL/TLS connection.
6497          */
6498         if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) {
6499             type_check[0] = AUTHTYPE_SRP;
6500             type_check[1] = how;
6501 #ifdef CK_SSL
6502             if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
6503                 ssl_get_client_finished(&type_check[2],12);
6504                 ssl_get_server_finished(&type_check[14],12);
6505                 t_clientaddexdata(tc,type_check,26);
6506             } else
6507 #endif /* CK_SSL */
6508                 t_clientaddexdata(tc,type_check,2);
6509         }
6510 #endif /* PRE_SRP_1_4_5 */
6511
6512         B.data = data;
6513         B.len = cnt;
6514         t_clientgetkey(tc, &B);
6515
6516         SendSRPAuthSB(SRP_RESPONSE, t_clientresponse(tc), RESPONSE_LEN);
6517         srp_waitresp = 1;
6518         return AUTH_SUCCESS;
6519
6520     default:
6521         return(auth_resend(AUTHTYPE_SRP));
6522     }
6523     return AUTH_FAILURE;
6524 }
6525
6526 static int
6527 #ifdef CK_ANSIC
6528 srp_is(int how, unsigned char *data, int cnt)
6529 #else
6530 srp_is(how,data,cnt) int how; unsigned char *data; int cnt;
6531 #endif
6532 {
6533     char * pbuf = NULL;
6534     char * ptr;
6535 #ifdef CK_ENCRYPTION
6536     Session_Key skey;
6537 #endif
6538     struct t_num A;
6539     struct t_pw * tpw = NULL;
6540     struct t_conf * tconf = NULL;
6541     struct passwd * pass;
6542     static struct t_num * B = NULL;     /* Holder for B */
6543 #ifdef CK_SSL
6544     char type_check[26];
6545 #else
6546     char type_check[2];
6547 #endif /* CK_SSL */
6548
6549     if ((cnt -= 4) < 1) {
6550         auth_finished(AUTH_REJECT);
6551         return AUTH_FAILURE;
6552     }
6553
6554     data += 4;
6555     cnt  -= 1;
6556     switch(*data++) {
6557     case SRP_AUTH:
6558         /* Send parameters back to client */
6559         if(ts != NULL) {
6560             t_serverclose(ts);
6561             ts = NULL;
6562         }
6563         if(!szUserNameRequested[0]) {
6564             if (1)
6565                 printf("No username available\r\n");
6566             SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1);
6567             auth_finished(AUTH_REJECT);
6568             return(AUTH_FAILURE);
6569         }
6570 #ifdef IKSD
6571 #ifdef CK_LOGIN
6572         if (inserver && ckxanon &&
6573              !strcmp(szUserNameRequested,"anonymous")) {
6574             SendSRPAuthSB(SRP_REJECT, (void *)
6575             "anonymous login cannot be performed with Secure Remote Password",
6576             -1);
6577             auth_finished(AUTH_REJECT);
6578             return(AUTH_FAILURE);
6579         }
6580 #endif /* CK_LOGIN */
6581 #endif /* IKSD */
6582 #ifndef PRE_SRP_1_4_4
6583         if(tpw == NULL) {
6584             if((tpw = t_openpw(NULL)) == NULL) {
6585                 if (1)
6586                     printf("Unable to open password file\r\n");
6587                 SendSRPAuthSB(SRP_REJECT, (void *) "No password file", -1);
6588                 return(AUTH_FAILURE);
6589             }
6590         }
6591         if(tconf == NULL) {
6592             if((tconf = t_openconf(NULL)) == NULL) {
6593                 if (1)
6594                   printf("Unable to open configuration file\r\n");
6595                 SendSRPAuthSB(SRP_REJECT, (void *)"No configuration file", -1);
6596                 return(AUTH_FAILURE);
6597             }
6598         }
6599         ts = t_serveropenfromfiles(szUserNameRequested, tpw, tconf);
6600         t_closepw(tpw);
6601         tpw = NULL;
6602         t_closeconf(tconf);
6603         tconf = NULL;
6604 #else /* PRE_SRP_1_4_4 */
6605 #ifdef COMMENT
6606         /* the code in this block should no longer be necessary on OS/2
6607            or Windows because I have added functionality to libsrp.lib
6608            to find the srp files.   4/22/2000
6609         */
6610
6611         /* On Windows and OS/2 there is no well defined place for the */
6612         /* ETC directory.  So we look for either an SRP_ETC or ETC    */
6613         /* environment variable in that order.  If we find one we     */
6614         /* attempt to open the files manually.                        */
6615         /* We will reuse the strTmp[] for the file names. */
6616         ptr = getenv("SRP_ETC");
6617         if ( !ptr )
6618             ptr = getenv("ETC");
6619 #ifdef NT
6620         if ( !ptr ) {
6621             DWORD len;
6622             len = AUTHTMPBL;
6623
6624             len = GetWindowsDirectory(strTmp,len);
6625             if ( len > 0 && len < AUTHTMPBL) {
6626                 if ( !isWin95() ) {
6627                     if ( len == 1 )
6628                       ckstrncat(strTmp,"SYSTEM32/DRIVERS/ETC",sizeof(strTmp));
6629                     else
6630                       ckstrncat(strTmp,"/SYSTEM32/DRIVERS/ETC",sizeof(strTmp));
6631                 }
6632             }
6633             ptr = strTmp;
6634         }
6635 #endif /* NT */
6636         if ( ptr ) {
6637             int len = strlen(ptr);
6638             int i;
6639             if (ptr != strTmp)
6640                 strcpy(strTmp,ptr);
6641             for ( i=0;i<len;i++ ) {
6642                 if ( strTmp[i] == '\\' )
6643                     strTmp[i] = '/';
6644             }
6645             if ( strTmp[len-1] != '/' )
6646                 ckstrncat(strTmp,"/tpasswd",sizeof(strTmp));
6647             else
6648                 ckstrncat(strTmp,"tpasswd",sizeof(strTmp));
6649             tpw = t_openpwbyname(strTmp);
6650
6651             ckstrncat(strTmp,".conf",sizeof(strTmp));
6652             tconf = t_openconfbyname(strTmp);
6653         }
6654
6655         if ( tpw && tconf )
6656             ts = t_serveropenfromfiles(szUserNameRequested, tpw, tconf);
6657         else
6658             ts = t_serveropen(szUserNameRequested);
6659         if ( tpw ) {
6660             t_closepw(tpw);
6661             tpw = NULL;
6662         }
6663         if ( tconf ) {
6664             t_closeconf(tconf);
6665             tconf = NULL;
6666         }
6667 #else /* COMMENT */
6668         ts = t_serveropen(szUserNameRequested);
6669 #endif /* COMMENT */
6670 #endif /* PRE_SRP_1_4_4 */
6671
6672         if( ts == NULL ) {
6673             printf("User %s not found\r\n", szUserNameRequested);
6674             SendSRPAuthSB(SRP_REJECT, (void *) "Password not set", -1);
6675             return(AUTH_FAILURE);
6676         }
6677
6678         pbuf = (char *)malloc(ts->n.len + ts->g.len + ts->s.len + 7);
6679         ptr = pbuf;
6680
6681         srp_encode_length(ptr, ts->n.len);
6682         ptr += 2;
6683         memcpy(ptr, ts->n.data, ts->n.len);     /* safe */
6684         ptr += ts->n.len;
6685
6686         srp_encode_length(ptr, ts->g.len);
6687         ptr += 2;
6688         memcpy(ptr, ts->g.data, ts->g.len);     /* safe */
6689         ptr += ts->g.len;
6690
6691         srp_encode_length(ptr, ts->s.len);
6692         ptr += 2;
6693         memcpy(ptr, ts->s.data, ts->s.len);     /* safe */
6694         ptr += ts->s.len;
6695
6696         SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf);
6697         free(pbuf); pbuf = NULL;
6698
6699         B = t_servergenexp(ts);
6700         ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN);
6701         return AUTH_SUCCESS;
6702
6703     case SRP_EXP:
6704         /* Client is sending A to us, compute challenge & expected response. */
6705         if (ts == NULL || B == NULL) {
6706             printf("Protocol error: SRP_EXP unexpected\r\n");
6707             SendSRPAuthSB(SRP_REJECT,
6708                           (void *) "Protocol error: unexpected EXP",
6709                           -1
6710                           );
6711             return(AUTH_FAILURE);
6712         }
6713
6714         /* Wait until now to send B, since it contains the key to "u" */
6715         SendSRPAuthSB(SRP_CHALLENGE, B->data, B->len);
6716         B = NULL;
6717
6718 #ifndef PRE_SRP_1_4_5
6719         /*
6720          * The original SRP AUTH implementation did not protect against
6721          * tampering of the auth-type-pairs.  Therefore, when the
6722          * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
6723          * into the SRP hash computation.  When AUTH_ENCRYPT_START_TLS
6724          * is set we also insert the SSL/TLS client and server finished
6725          * messages to ensure that there is no man in the middle attack
6726          * underway on the SSL/TLS connection.
6727          */
6728         if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) {
6729             type_check[0] = AUTHTYPE_SRP;
6730             type_check[1] = how;
6731 #ifdef CK_SSL
6732             if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
6733                 ssl_get_client_finished(&type_check[2],12);
6734                 ssl_get_server_finished(&type_check[14],12);
6735             }
6736 #endif /* CK_SSL */
6737             t_serveraddexdata(ts,type_check,
6738 #ifdef CK_SSL
6739                   ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 :
6740 #endif /* CK_SSL */
6741                                2);
6742         }
6743 #endif /* PRE_SRP_1_4_5 */
6744
6745         A.data = data;
6746         A.len = cnt;
6747         ptr = t_servergetkey(ts, &A);
6748
6749         if(ptr == NULL) {
6750             if (1)
6751               printf("Security alert: Trivial session key attempted\r\n");
6752             SendSRPAuthSB(SRP_REJECT,
6753                           (void *) "Trivial session key detected",
6754                           -1
6755                           );
6756             return(AUTH_FAILURE);
6757         }
6758         srp_waitresp = 1;
6759         return AUTH_SUCCESS;
6760
6761     case SRP_RESPONSE:
6762         /* Got the response; see if it's correct */
6763         if (!srp_waitresp ||
6764              ts == NULL
6765              ) {
6766             if (1)
6767               printf("Protocol error: SRP_RESPONSE unexpected\r\n");
6768             SendSRPAuthSB(SRP_REJECT,
6769                           (void *) "Protocol error: unexpected RESPONSE",
6770                           -1
6771                           );
6772             return(AUTH_FAILURE);
6773         }
6774         srp_waitresp = 0;       /* we got a response */
6775
6776         if (cnt < RESPONSE_LEN) {
6777             if (1)
6778               printf("Protocol error: malformed response\r\n");
6779             SendSRPAuthSB(SRP_REJECT,
6780                           (void *) "Protocol error: malformed response",
6781                           -1
6782                           );
6783             return(AUTH_FAILURE);
6784         }
6785
6786         if (t_serververify(ts, data) == 0) {
6787             SendSRPAuthSB(SRP_ACCEPT, t_serverresponse(ts), RESPONSE_LEN);
6788             accept_complete = 1;
6789 #ifdef CK_ENCRYPTION
6790 #ifdef CK_SSL
6791             if (!(ssl_active_flag || tls_active_flag))
6792 #endif /* CK_SSL */
6793             {
6794                 ckhexdump("SRP_RESPONSE ts",ts,sizeof(ts));
6795                 ckhexdump("SRP_RESPONSE session_key",
6796                          ts->session_key,
6797                          SESSION_KEY_LEN
6798                          );
6799                 skey.type = SK_GENERIC;
6800                 skey.length = SESSION_KEY_LEN;
6801                 skey.data = ts->session_key;
6802                 encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
6803             }
6804 #endif /* CK_ENCRYPTION */
6805             auth_finished(AUTH_VALID);
6806         }
6807         else {
6808             SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1);
6809             auth_finished(AUTH_REJECT);
6810             return(AUTH_FAILURE);
6811         }
6812         return AUTH_SUCCESS;
6813
6814     default:
6815         printf("Unknown SRP option %d\r\n", data[-1]);
6816         SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1);
6817         return(AUTH_FAILURE);
6818     }
6819 }
6820 #else /* PRE_SRP_1_7_3 */
6821 static int
6822 #ifdef CK_ANSIC
6823 new_srp_reply(int how, unsigned char *data, int cnt)
6824 #else
6825 new_srp_reply(how,data,cnt) int how; unsigned char *data; int cnt;
6826 #endif
6827 {
6828     data += 4;                          /* Point to status byte */
6829     cnt  -= 4;
6830
6831     if(cnt-- < 1) {                     /* Matches with data++ */
6832         auth_finished(AUTH_REJECT);
6833         return AUTH_FAILURE;
6834     }
6835
6836     switch(*data++) {
6837     case SRP_PARAMS: {
6838         struct t_num n;
6839         struct t_num g;
6840         struct t_num s;
6841         cstr * A;
6842
6843         if(!szUserName) {
6844             printf("No username available\r\n");
6845             return(auth_resend(AUTHTYPE_SRP));
6846         }
6847
6848         n.len = srp_decode_length(data);
6849         data += 2;
6850         cnt -= 2;
6851         if(n.len > cnt) {
6852             printf("n too long\r\n");
6853             return(auth_resend(AUTHTYPE_SRP));
6854         }
6855         n.data = data;
6856         data += n.len;
6857         cnt -= n.len;
6858
6859         g.len = srp_decode_length(data);
6860         data += 2;
6861         cnt -= 2;
6862         if(g.len > cnt) {
6863             printf("g too long\r\n");
6864             return(auth_resend(AUTHTYPE_SRP));
6865         }
6866         g.data = data;
6867         data += g.len;
6868         cnt -= g.len;
6869
6870         s.len = srp_decode_length(data);
6871         data += 2;
6872         cnt -= 2;
6873         if(s.len != cnt) {
6874             printf("invalid salt\r\n");
6875             return(auth_resend(AUTHTYPE_SRP));
6876         }
6877         s.data = data;
6878         data += s.len;
6879         cnt -= s.len;
6880
6881         /* If the parameters provided by the server cannot be
6882          * validated the following function will fail.
6883          */
6884         c_srp = SRP_new(SRP_RFC2945_client_method());
6885         if (c_srp == NULL ||
6886             SRP_set_username(c_srp, szUserName) != SRP_SUCCESS ||
6887             SRP_set_params(c_srp,n.data,n.len,g.data,g.len,s.data,s.len) !=
6888             SRP_SUCCESS) {
6889             printf("SRP Parameter initialization error\r\n");
6890             return(auth_resend(AUTHTYPE_SRP));
6891         }
6892
6893         A = cstr_new();
6894         if(SRP_gen_pub(c_srp, &A) != SRP_SUCCESS) {
6895             printf("SRP Error generating key exchange\r\n");
6896             return(auth_resend(AUTHTYPE_SRP));
6897         }
6898
6899         SendSRPAuthSB(SRP_EXP, A->data, A->length);
6900         cstr_free(A);
6901
6902         if ( pwbuf[0] && pwflg ) {
6903             printf("SRP using %d-bit modulus for '%s'\r\n",
6904                    8 * n.len,
6905                    szUserName
6906                    );
6907             ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd));
6908 #ifdef OS2
6909             if ( pwcrypt )
6910                 ck_encrypt((char *)srp_passwd);
6911 #endif /* OS2 */
6912         } else {
6913             extern char * srppwprompt;
6914             char preface[128];
6915             int ok;
6916
6917             if (srppwprompt && srppwprompt[0] &&
6918                 (strlen(srppwprompt) + strlen(szUserName) - 2) <
6919                 sizeof(preface)) {
6920                 sprintf(preface,srppwprompt,szUserName);
6921             } else {
6922                 ckmakxmsg( preface,sizeof(preface),
6923                           "SRP using ",ckitoa(8*n.len),"-bit modulus for '",
6924                           szUserName, "'", NULL, NULL, NULL, NULL, NULL,
6925                           NULL, NULL);
6926             }
6927             ok = uq_txt(preface,"Password: ",2,NULL,
6928                         srp_passwd,sizeof(srp_passwd)-1,NULL,
6929                         DEFAULT_UQ_TIMEOUT);
6930             if ( !ok )
6931                 srp_passwd[0] = '\0';
6932         }
6933
6934         if(SRP_set_auth_password(c_srp, srp_passwd) != SRP_SUCCESS) {
6935             memset(srp_passwd, 0, sizeof(srp_passwd));
6936             printf("SRP Error setting client password\r\n");
6937             return(auth_resend(AUTHTYPE_SRP));
6938         }
6939         memset(srp_passwd, 0, sizeof(srp_passwd));
6940         return AUTH_SUCCESS;
6941     }
6942     case SRP_CHALLENGE: {
6943         char type_check[26];
6944         cstr * resp = NULL;
6945
6946         if(c_srp == NULL) {
6947             printf("SRP protocol error\r\n");
6948             return(auth_resend(AUTHTYPE_SRP));
6949         }
6950
6951         /*
6952          * The original SRP AUTH implementation did not protect against
6953          * tampering of the auth-type-pairs.  Therefore, when the
6954          * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
6955          * into the SRP hash computation.  When AUTH_ENCRYPT_START_TLS
6956          * is set we also insert the SSL/TLS client and server finished
6957          * messages to ensure that there is no man in the middle attack
6958          * underway on the SSL/TLS connection.
6959          */
6960         if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) {
6961             type_check[0] = AUTHTYPE_SRP;
6962             type_check[1] = how;
6963 #ifdef CK_SSL
6964             if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
6965                 ssl_get_client_finished(&type_check[2],12);
6966                 ssl_get_server_finished(&type_check[14],12);
6967                 SRP_add_ex_data(c_srp, type_check, 26);
6968             } else
6969 #endif /* CK_SSL */
6970                 SRP_add_ex_data(c_srp, type_check, 2);
6971         }
6972
6973         if(SRP_compute_key(c_srp, &c_key, data, cnt) != SRP_SUCCESS) {
6974             printf("SRP ERROR: unable to compute client key\r\n");
6975             return(auth_resend(AUTHTYPE_SRP));
6976         }
6977
6978         resp = cstr_new();
6979         if(SRP_respond(c_srp, &resp) != SRP_SUCCESS) {
6980             printf("SRP ERROR: unable to compute client response\r\n");
6981             return(auth_resend(AUTHTYPE_SRP));
6982         }
6983         SendSRPAuthSB(SRP_RESPONSE, resp->data, resp->length);
6984         cstr_free(resp);
6985         srp_waitresp = 1;
6986         return AUTH_SUCCESS;
6987     }
6988     case SRP_ACCEPT: {
6989 #ifdef CK_ENCRYPTION
6990         Session_Key skey;
6991 #endif /* ENCRYPTION */
6992
6993         if(cnt < RESPONSE_LEN || !srp_waitresp || c_srp == NULL) {
6994             printf("SRP Protocol error\r\n");
6995             return(auth_resend(AUTHTYPE_SRP));
6996         }
6997         srp_waitresp = 0;
6998
6999         if(SRP_verify(c_srp, data, cnt) == SRP_SUCCESS) {
7000             printf("SRP accepts you as %s\r\n",szUserName);
7001
7002 #ifdef CK_SSL
7003             if((ssl_active_flag || tls_active_flag) &&
7004                 (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
7005                 printf("TLS session parameters verified by SRP\r\n");
7006             } else
7007 #endif /* CK_SSL */
7008 #ifdef CK_ENCRYPTION
7009             {
7010                 skey.type = SK_GENERIC;
7011                 skey.length = c_key->length;
7012                 skey.data = c_key->data;
7013                 encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
7014                 cstr_clear_free(c_key);
7015                 c_key = NULL;
7016             }
7017 #endif /* CK_ENCRYPTION */
7018             accept_complete = 1;
7019             auth_finished(AUTH_VALID);
7020             SRP_free(c_srp);
7021             c_srp = NULL;
7022             return AUTH_SUCCESS;
7023         }
7024         else {
7025             printf("[ Error: SRP server authentication failed ]\r\n");
7026             return(auth_resend(AUTHTYPE_SRP));
7027         }
7028     }
7029     case SRP_REJECT: {
7030         char * str=NULL;
7031
7032         ckmakmsg(strTmp,sizeof(strTmp),
7033                   "SRP refuses authentication for '",szUserName,
7034                   "'\r\n",NULL);
7035         if (cnt > 0) {
7036             int len = strlen(strTmp);
7037             if ( len + cnt < sizeof(strTmp) ) {
7038                 str = strTmp + strlen(strTmp);
7039                 memcpy(str,data,cnt);
7040                 str[cnt] = 0;
7041             }
7042         }
7043         printf("SRP authentication failed!\r\n%s\r\n",strTmp);
7044         auth_finished(AUTH_REJECT);
7045         return AUTH_FAILURE;
7046     }
7047     default:
7048         printf("Unknown SRP option %d\r\n", data[-1]);
7049         return(auth_resend(AUTHTYPE_SRP));
7050     }
7051     /* NEVER REACHED */
7052 }
7053
7054 static int
7055 #ifdef CK_ANSIC
7056 new_srp_is(int how, unsigned char *data, int cnt)
7057 #else
7058 new_srp_is(how,data,cnt) int how; unsigned char *data; int cnt;
7059 #endif
7060 {
7061     char * pbuf = NULL;
7062     char * ptr;
7063 #ifdef CK_ENCRYPTION
7064     Session_Key skey;
7065 #endif
7066     static cstr * B = NULL;             /* Holder for B */
7067     struct t_passwd * pass;
7068     cstr * resp;
7069     char type_check[26];
7070
7071     if ((cnt -= 4) < 1) {
7072         auth_finished(AUTH_REJECT);
7073         return AUTH_FAILURE;
7074     }
7075
7076     data += 4;
7077     cnt  -= 1;
7078     switch(*data++) {
7079     case SRP_AUTH:
7080         /* Send parameters back to client */
7081         if(s_srp != NULL) {
7082             SRP_free(s_srp);
7083             s_srp = NULL;
7084         }
7085         if (B != NULL) {
7086             cstr_free(B);
7087             B = NULL;
7088         }
7089         if(!szUserNameRequested[0]) {
7090             if (1)
7091                 printf("No username available\r\n");
7092             SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1);
7093             auth_finished(AUTH_REJECT);
7094             return(AUTH_FAILURE);
7095         }
7096 #ifdef IKSD
7097 #ifdef CK_LOGIN
7098         if (inserver && ckxanon &&
7099              !strcmp(szUserNameRequested,"anonymous")) {
7100             SendSRPAuthSB(SRP_REJECT, (void *)
7101             "anonymous login cannot be performed with Secure Remote Password",
7102             -1);
7103             auth_finished(AUTH_REJECT);
7104             return(AUTH_FAILURE);
7105         }
7106 #endif /* CK_LOGIN */
7107 #endif /* IKSD */
7108         s_srp = SRP_new(SRP_RFC2945_server_method());
7109         if(s_srp == NULL) {
7110             printf("Error initializing SRP server\r\n");
7111             SendSRPAuthSB(SRP_REJECT,
7112                           (void *) "SRP server init failed",
7113                           -1
7114                           );
7115             return(AUTH_FAILURE);
7116         }
7117         pass = gettpnam(szUserNameRequested);
7118         if(pass == NULL) {
7119             printf("User %s not found\r\n", szUserNameRequested);
7120             SendSRPAuthSB(SRP_REJECT, (void *) "Password not set", -1);
7121             return(AUTH_FAILURE);
7122         }
7123         if(SRP_set_username(s_srp, szUserNameRequested) != SRP_SUCCESS ||
7124            SRP_set_params(s_srp, pass->tc.modulus.data,
7125                           pass->tc.modulus.len,
7126                           pass->tc.generator.data,
7127                           pass->tc.generator.len,
7128                           pass->tp.salt.data,
7129                           pass->tp.salt.len) != SRP_SUCCESS ||
7130            SRP_set_authenticator(s_srp,
7131                                  pass->tp.password.data,
7132                                  pass->tp.password.len) != SRP_SUCCESS) {
7133             printf("Error initializing SRP parameters\r\n");
7134             SendSRPAuthSB(SRP_REJECT,(void *)"SRP parameter init failed", -1);
7135             return(AUTH_FAILURE);
7136         }
7137
7138         pbuf = (char *)malloc(pass->tc.modulus.len + pass->tc.generator.len +
7139                                pass->tp.salt.len + 7);
7140         ptr = pbuf;
7141
7142         srp_encode_length(ptr, pass->tc.modulus.len);
7143         ptr += 2;
7144         memcpy(ptr, pass->tc.modulus.data, pass->tc.modulus.len);
7145         ptr += pass->tc.modulus.len;
7146
7147         srp_encode_length(ptr, pass->tc.generator.len);
7148         ptr += 2;
7149         memcpy(ptr, pass->tc.generator.data, pass->tc.generator.len);
7150         ptr += pass->tc.generator.len;
7151
7152         srp_encode_length(ptr, pass->tp.salt.len);
7153         ptr += 2;
7154         memcpy(ptr, pass->tp.salt.data, pass->tp.salt.len);
7155         ptr += pass->tp.salt.len;
7156
7157         SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf);
7158         free(pbuf);
7159         pbuf = NULL;
7160
7161         if(SRP_gen_pub(s_srp, &B) != SRP_SUCCESS) {
7162             printf("Error generating SRP public value\r\n");
7163             SendSRPAuthSB(SRP_REJECT, (void *) "SRP_gen_pub failed", -1);
7164             return(AUTH_FAILURE);
7165         }
7166         ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN);
7167         return AUTH_SUCCESS;
7168
7169     case SRP_EXP:
7170       /* Client is sending A to us, compute challenge and expected response. */
7171         if (s_srp == NULL || B == NULL) {
7172             printf("Protocol error: SRP_EXP unexpected\r\n");
7173             SendSRPAuthSB(SRP_REJECT,
7174                         (void *)"Protocol error: unexpected EXP", -1);
7175             return(AUTH_FAILURE);
7176         }
7177         /* Wait until now to send B, since it contains the key to "u" */
7178         SendSRPAuthSB(SRP_CHALLENGE, B->data, B->length);
7179         cstr_free(B);
7180         B = NULL;
7181
7182         /*
7183          * The original SRP AUTH implementation did not protect against
7184          * tampering of the auth-type-pairs.  Therefore, when the
7185          * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
7186          * into the SRP hash computation.  When AUTH_ENCRYPT_START_TLS
7187          * is set we also insert the SSL/TLS client and server finished
7188          * messages to ensure that there is no man in the middle attack
7189          * underway on the SSL/TLS connection.
7190          */
7191         if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) {
7192             type_check[0] = AUTHTYPE_SRP;
7193             type_check[1] = how;
7194 #ifdef CK_SSL
7195             if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
7196                 ssl_get_client_finished(&type_check[2],12);
7197                 ssl_get_server_finished(&type_check[14],12);
7198                 SRP_add_ex_data(s_srp, type_check, 26);
7199             } else
7200 #endif /* CK_SSL */
7201                 SRP_add_ex_data(s_srp, type_check, 2);
7202         }
7203
7204         if(SRP_compute_key(s_srp, &s_key, data, cnt) != SRP_SUCCESS) {
7205             printf("Security alert: Trivial session key attempted\r\n");
7206             SendSRPAuthSB(SRP_REJECT,
7207                           (void *) "Trivial session key detected", -1);
7208             return(AUTH_FAILURE);
7209         }
7210         srp_waitresp = 1;
7211         return AUTH_SUCCESS;
7212
7213     case SRP_RESPONSE:
7214         /* Got the response; see if it's correct */
7215         if (!srp_waitresp || s_srp == NULL) {
7216             if (1)
7217               printf("Protocol error: SRP_RESPONSE unexpected\r\n");
7218             SendSRPAuthSB(SRP_REJECT,
7219                           (void *) "Protocol error: unexpected RESPONSE",
7220                           -1
7221                           );
7222             return(AUTH_FAILURE);
7223         }
7224         srp_waitresp = 0;       /* we got a response */
7225
7226         if (cnt < RESPONSE_LEN) {
7227             if (1)
7228               printf("Protocol error: malformed response\r\n");
7229             SendSRPAuthSB(SRP_REJECT,
7230                           (void *) "Protocol error: malformed response",
7231                           -1
7232                           );
7233             return(AUTH_FAILURE);
7234         }
7235
7236         if(SRP_verify(s_srp, data, cnt) == SRP_SUCCESS) {
7237             resp = cstr_new();
7238             if(SRP_respond(s_srp, &resp) != SRP_SUCCESS) {
7239                 printf("Error computing response\r\n");
7240                 SendSRPAuthSB(SRP_REJECT,
7241                               (void *) "Error computing response", -1);
7242                 return(AUTH_FAILURE);
7243             }
7244             SendSRPAuthSB(SRP_ACCEPT, resp->data, resp->length);
7245             accept_complete = 1;
7246             cstr_free(resp);
7247
7248 #ifdef CK_ENCRYPTION
7249 #ifdef CK_SSL
7250             if (!(ssl_active_flag || tls_active_flag))
7251 #endif /* CK_SSL */
7252             {
7253                 skey.type = SK_GENERIC;
7254                 skey.length = s_key->length;
7255                 skey.data = s_key->data;
7256                 encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
7257                 cstr_clear_free(s_key);
7258                 s_key = NULL;
7259             }
7260 #endif /* CK_ENCRYPTION */
7261             auth_finished(AUTH_VALID);
7262         }
7263         else {
7264             SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1);
7265             auth_finished(AUTH_REJECT);
7266             return(AUTH_FAILURE);
7267         }
7268         return AUTH_SUCCESS;
7269
7270     default:
7271         printf("Unknown SRP option %d\r\n", data[-1]);
7272         SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1);
7273         return(AUTH_FAILURE);
7274     }
7275 }
7276 #endif /* PRE_SRP_1_7_3 */
7277 #endif /* SRP */
7278
7279 #ifdef KRB5
7280 #ifdef KINIT
7281 /*
7282  * clients/kinit/kinit.c
7283  *
7284  * Copyright 1990 by the Massachusetts Institute of Technology.
7285  * All Rights Reserved.
7286  *
7287  * Export of this software from the United States of America may
7288  *   require a specific license from the United States Government.
7289  *   It is the responsibility of any person or organization contemplating
7290  *   export to obtain such a license before exporting.
7291  *
7292  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
7293  * distribute this software and its documentation for any purpose and
7294  * without fee is hereby granted, provided that the above copyright
7295  * notice appear in all copies and that both that copyright notice and
7296  * this permission notice appear in supporting documentation, and that
7297  * the name of M.I.T. not be used in advertising or publicity pertaining
7298  * to distribution of the software without specific, written prior
7299  * permission.  M.I.T. makes no representations about the suitability of
7300  * this software for any purpose.  It is provided "as is" without express
7301  * or implied warranty.
7302  *
7303  *
7304  * Initialize a credentials cache.
7305  */
7306
7307 #define KRB5_DEFAULT_OPTIONS 0
7308 #define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
7309
7310 static krb5_data tgtname = {
7311 #ifndef HEIMDAL
7312     0,
7313 #endif /* HEIMDAL */
7314     KRB5_TGS_NAME_SIZE,
7315     KRB5_TGS_NAME
7316 };
7317
7318 /* Internal prototypes */
7319 _PROTOTYP(static krb5_error_code krb5_validate_tgt,
7320         (krb5_context, krb5_ccache,krb5_principal, krb5_data *));
7321 _PROTOTYP(static krb5_error_code krb5_renew_tgt,
7322         (krb5_context, krb5_ccache,
7323                         krb5_principal, krb5_data *));
7324 _PROTOTYP(static krb5_error_code krb5_tgt_gen,
7325         (krb5_context, krb5_ccache,
7326                         krb5_principal, krb5_data *, int opt));
7327
7328 #ifdef KRB5_HAVE_GET_INIT_CREDS
7329 static krb5_error_code KRB5_CALLCONV
7330 ck_krb5_prompter( krb5_context context,
7331                   void *data,
7332                   const char *name,
7333                   const char *banner,
7334                   int num_prompts,
7335                   krb5_prompt prompts[])
7336 {
7337     krb5_error_code     errcode = 0;
7338     int                 i;
7339 #ifdef KUI
7340     struct txtbox * tb = NULL;
7341 #else /* KUI */
7342     char * prompt = NULL;
7343 #endif /* KUI */
7344     int    len = 0, blen=0, nlen=0;
7345
7346     debug(F110,"ck_krb5_prompter name",name,0);
7347     debug(F110,"ck_krb5_prompter banner",banner,0);
7348     debug(F101,"ck_krb5_prompter num_prompts","",num_prompts);
7349
7350     if (name)
7351         nlen = strlen(name)+2;
7352
7353     if (banner)
7354         blen = strlen(banner)+2;
7355
7356 #ifdef KUI
7357     tb = (struct txtbox *) malloc(sizeof(struct txtbox) * num_prompts);
7358     if ( tb != NULL ) {
7359         int ok;
7360         memset(tb,0,sizeof(struct txtbox) * num_prompts);
7361         for ( i=0; i < num_prompts; i++ ) {
7362             tb[i].t_buf = prompts[i].reply->data;
7363             tb[i].t_len = prompts[i].reply->length;
7364             tb[i].t_lbl = prompts[i].prompt;
7365             tb[i].t_dflt = NULL;
7366             tb[i].t_echo = (prompts[i].hidden ? 2 : 1);
7367         }   
7368
7369         ok = uq_mtxt((char *)banner,NULL,num_prompts,tb);
7370         if ( ok ) {
7371             for ( i=0; i < num_prompts; i++ )
7372                 prompts[i].reply->length = strlen(prompts[i].reply->data);
7373         } else
7374             errcode = -2;
7375     }
7376 #else /* KUI */
7377     for (i = 0; i < num_prompts; i++) {
7378         debug(F111,"ck_krb5_prompter prompt",prompts[i].prompt,i);
7379
7380         if ( prompt && len < (nlen + blen + strlen(prompts[i].prompt)+2) ) {
7381             free(prompt);
7382             prompt = NULL;
7383         }
7384         if ( !prompt )
7385             prompt = (char *)malloc(nlen + blen + strlen(prompts[i].prompt)+2);
7386         if ( !prompt ) {
7387             errcode = KRB5_RC_MALLOC;
7388             goto cleanup;
7389         }
7390         len = nlen + blen + strlen(prompts[i].prompt)+2;
7391         ckmakxmsg(prompt,len,
7392                  (char *) (name?name:""),
7393                  name?"\r\n":"",
7394                  (char *) (banner?banner:""),
7395                  banner?"\r\n":"",
7396                  (char *)prompts[i].prompt,
7397                  ": ",NULL,NULL,NULL,NULL,NULL,NULL);
7398
7399         memset(prompts[i].reply->data, 0, prompts[i].reply->length);
7400         if (prompts[i].hidden) {
7401             readpass(prompt, prompts[i].reply->data,
7402                       prompts[i].reply->length);
7403         } else {
7404             readtext(prompt, prompts[i].reply->data,
7405                       prompts[i].reply->length);
7406         }
7407         prompts[i].reply->length = strlen(prompts[i].reply->data);
7408     }
7409 #endif /* KUI */
7410
7411   cleanup:
7412 #ifdef KUI
7413     if ( tb )
7414         free(tb);
7415 #else /* KUI */
7416     if ( prompt )
7417         free(prompt);
7418 #endif /* KUI */
7419     if (errcode) {
7420         for (i = 0; i < num_prompts; i++) {
7421             memset(prompts[i].reply->data, 0, prompts[i].reply->length);
7422         }
7423     }
7424     return errcode;
7425 }
7426
7427 /*
7428  *      I'm not really sure what to do with this.  The NRL DLLs use a
7429  *      different interface for the krb5_prompter callback.  It has
7430  *      one less parameter.   This is going to be ugly.
7431  */
7432 static krb5_error_code KRB5_CALLCONV
7433 ck_NRL_krb5_prompter( krb5_context context,
7434                       const char *name,
7435                       const char *banner,
7436                       int num_prompts,
7437                       krb5_prompt prompts[])
7438 {
7439     return(ck_krb5_prompter(context,NULL,name,banner,num_prompts,prompts));
7440 }
7441 #endif /* KRB5_HAVE_GET_INIT_CREDS */
7442
7443 #ifdef KRB524_CONV
7444 long
7445 try_convert524(krb5_context ctx, krb5_principal me, krb5_ccache cc)
7446 {
7447     char * progname = "convert524";
7448     krb5_error_code code = 0;
7449     int icode = 0;
7450     krb5_principal kpcserver = 0;
7451     krb5_creds *v5creds = 0;
7452     krb5_creds increds;
7453 #ifdef OS2
7454     LEASH_CREDENTIALS v4creds;
7455 #else /* OS2 */
7456     CREDENTIALS v4creds;
7457 #endif /* OS2 */
7458
7459     memset((char *) &increds, 0, sizeof(increds));
7460     /*
7461       From this point on, we can goto cleanup because increds is
7462       initialized.
7463     */
7464
7465     if ((code = krb5_build_principal(ctx,
7466                                      &kpcserver,
7467                                      krb5_princ_realm(ctx, me)->length,
7468                                      krb5_princ_realm(ctx, me)->data,
7469                                      "krbtgt",
7470                                      krb5_princ_realm(ctx, me)->data,
7471                                      NULL))) {
7472         com_err(progname, code,
7473                 "while creating service principal name");
7474         goto cleanup;
7475     }
7476
7477     memset((char*) &increds, 0, sizeof(increds));
7478     increds.client = me;
7479     increds.server = kpcserver;
7480     /* Prevent duplicate free calls.  */
7481     kpcserver = 0;
7482
7483     increds.times.endtime = 0;
7484     increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
7485     if ((code = krb5_get_credentials(ctx, 0,
7486                                      cc,
7487                                      &increds,
7488                                      &v5creds))) {
7489         com_err(progname, code,
7490                 "getting V5 credentials");
7491         goto cleanup;
7492     }
7493     if ((icode = krb524_convert_creds_kdc(ctx,
7494                                           v5creds,
7495                                           &v4creds))) {
7496         com_err(progname, icode,
7497                 "converting to V4 credentials");
7498         goto cleanup;
7499     }
7500     /* this is stolen from the v4 kinit */
7501     /* initialize ticket cache */
7502     if ((icode = krb_in_tkt(v4creds.pname, v4creds.pinst, v4creds.realm)
7503          != KSUCCESS)) {
7504         com_err(progname, icode,
7505                 "trying to create the V4 ticket file");
7506         goto cleanup;
7507     }
7508     /* stash ticket, session key, etc. for future use */
7509     if ((icode = krb_save_credentials(v4creds.service,
7510                                       v4creds.instance,
7511                                       v4creds.realm,
7512                                       v4creds.session,
7513                                       v4creds.lifetime,
7514                                       v4creds.kvno,
7515                                       &(v4creds.ticket_st),
7516                                       v4creds.issue_date))) {
7517         com_err(progname, icode,
7518                 "trying to save the V4 ticket");
7519         goto cleanup;
7520     }
7521
7522  cleanup:
7523     memset(&v4creds, 0, sizeof(v4creds));
7524     if (v5creds)
7525         krb5_free_creds(ctx, v5creds);
7526     increds.client = 0;
7527     krb5_free_cred_contents(ctx, &increds);
7528     if (kpcserver)
7529         krb5_free_principal(ctx, kpcserver);
7530     return !(code || icode);
7531 }
7532 #endif /* KRB524_CONV */
7533
7534 #define NO_KEYTAB
7535
7536 int
7537 #ifdef CK_ANSIC
7538 ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init,
7539                  struct krb4_init_data * k4_init)
7540 #else
7541 ck_krb5_initTGT(op,init,k4_init)
7542     krb_op_data * op; struct krb5_init_data * init;
7543     struct krb4_init_data * k4_init;
7544 #endif /* CK_ANSIC*/
7545 {
7546     krb5_context kcontext;
7547     krb5_ccache ccache = NULL;
7548     krb5_deltat lifetime = KRB5_DEFAULT_LIFE;   /* -l option */
7549     krb5_timestamp starttime = 0;
7550     krb5_deltat rlife = 0;
7551     int options = KRB5_DEFAULT_OPTIONS;
7552     int option;
7553     int errflg = 0;
7554     krb5_error_code code;
7555     krb5_principal me=NULL;
7556     krb5_principal server=NULL;
7557     krb5_creds my_creds;
7558     krb5_timestamp now;
7559 #ifndef HEIMDAL
7560     krb5_address **addrs = (krb5_address **)0;
7561 #endif /* HEIMDAL */
7562     int addr_count=0;
7563     int i,j;
7564 #ifndef NO_KEYTAB
7565     int use_keytab = 0;                 /* -k option */
7566     krb5_keytab keytab = NULL;
7567 #endif /* NO_KEYTAB */
7568     struct passwd *pw = 0;
7569     int pwsize;
7570     char *client_name=NULL, principal[256]="", realm[256]="", numstr[40]="";
7571     char *password=NULL, passwd[80]="";
7572 #ifdef KRB5_HAVE_GET_INIT_CREDS
7573     krb5_get_init_creds_opt opts;
7574 #endif
7575     char * name;
7576     int len;
7577
7578     if ( !ck_krb5_is_installed() )
7579         return(-1);
7580
7581 #ifdef COMMENT
7582     printf("Kerberos V initialization\r\n");
7583 #endif /* COMMENT */
7584
7585     code = krb5_init_context(&kcontext);
7586     if (code) {
7587         com_err("krb5_kinit",code,"while init_context");
7588         krb5_errno = code;
7589         makestr(&krb5_errmsg,error_message(krb5_errno));
7590         return(-1);
7591     }
7592
7593     debug(F110,"krb5_init","krb5_init_context",0);
7594
7595     if ((code = krb5_timeofday(kcontext, &now))) {
7596         com_err("krb5_kinit",code,"while getting time of day");
7597         goto exit_k5_init;
7598     }
7599
7600 #ifdef KRB5_HAVE_GET_INIT_CREDS
7601     memset(&opts, 0, sizeof(opts));
7602     krb5_get_init_creds_opt_init(&opts);
7603     debug(F110,"krb5_init","krb5_get_init_creds_opt_init",0);
7604 #endif
7605
7606     if ( init->renewable ) {
7607         options |= KDC_OPT_RENEWABLE;
7608         ckmakmsg(numstr,sizeof(numstr),ckitoa(init->renewable),"m",NULL,NULL);
7609 #ifdef HEIMDAL
7610         code = -1;
7611 #else /* HEIMDAL */
7612         code = krb5_string_to_deltat(numstr, &rlife);
7613 #endif /* HEIMDAL */
7614         if (code != 0 || rlife == 0) {
7615             printf("Bad renewable time value %s\r\n", numstr);
7616             errflg++;
7617         }
7618 #ifdef KRB5_HAVE_GET_INIT_CREDS
7619         krb5_get_init_creds_opt_set_renew_life(&opts, rlife);
7620 #endif
7621     }
7622     if ( init->renew ) {
7623         /* renew the ticket */
7624         options |= KDC_OPT_RENEW;
7625     }
7626
7627     if ( init->validate ) {
7628         /* validate the ticket */
7629         options |= KDC_OPT_VALIDATE;
7630     }
7631     if ( init->proxiable ) {
7632         options |= KDC_OPT_PROXIABLE;
7633 #ifdef KRB5_HAVE_GET_INIT_CREDS
7634         krb5_get_init_creds_opt_set_proxiable(&opts, 1);
7635 #endif
7636     }
7637     if ( init->forwardable ) {
7638         options |= KDC_OPT_FORWARDABLE;
7639 #ifdef KRB5_HAVE_GET_INIT_CREDS
7640         krb5_get_init_creds_opt_set_forwardable(&opts, 1);
7641 #endif
7642     }
7643 #ifndef NO_KEYTAB
7644     if (  ) {
7645         use_keytab = 1;
7646     }
7647     if (  ) {
7648         if (keytab == NULL && keytab_name != NULL) {
7649             code = krb5_kt_resolve(kcontext, keytab_name, &keytab);
7650             if (code != 0) {
7651                 debug(F111,"krb5_init resolving keytab",
7652                          keytab_name,code);
7653                 errflg++;
7654             }
7655         }
7656     }
7657 #endif /* NO_KEYTAB */
7658     if ( init->lifetime ) {
7659         ckmakmsg(numstr,sizeof(numstr),ckitoa(init->lifetime),"m",NULL,NULL);
7660 #ifdef HEIMDAL
7661         code = -1;
7662 #else /* HEIMDAL */
7663         code = krb5_string_to_deltat(numstr, &lifetime);
7664 #endif /* HEIMDAL */
7665         if (code != 0 || lifetime == 0) {
7666             printf("Bad lifetime value %s\r\n", numstr);
7667             errflg++;
7668         }
7669 #ifdef KRB5_HAVE_GET_INIT_CREDS
7670         krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime);
7671 #endif
7672     }
7673     if ( init->postdate ) {
7674         /* Convert cmdate() to a time_t value */
7675         struct tm * time_tm;
7676         struct tm * cmdate2tm(char *,int);
7677         time_tm = cmdate2tm(init->postdate,0);
7678         if ( time_tm )
7679             starttime = (krb5_timestamp) mktime(time_tm);
7680
7681         if (code != 0 || starttime == 0 || starttime == -1) {
7682             krb5_deltat ktmp;
7683 #ifdef HEIMDAL
7684             code = -1;
7685 #else /* HEIMDAL */
7686             code = krb5_string_to_deltat(init->postdate, &ktmp);
7687 #endif /* HEIMDAL */
7688             if (code == 0 && ktmp != 0) {
7689                 starttime = now + ktmp;
7690                 options |= KDC_OPT_POSTDATED;
7691             } else {
7692                 printf("Bad postdate start time value %s\r\n",
7693                         init->postdate);
7694                 errflg++;
7695             }
7696         } else {
7697             options |= KDC_OPT_POSTDATED;
7698         }
7699     }
7700
7701     debug(F110,"krb5_init searching for ccache",op->cache,0);
7702
7703     code = k5_get_ccache(kcontext,&ccache,op->cache);
7704     if (code != 0) {
7705         com_err("krb5_kinit",code,"while getting default ccache");
7706         goto exit_k5_init;
7707     }
7708
7709     /* This is our realm unless it is changed */
7710     ckstrncpy(realm,init->realm ? init->realm : krb5_d_realm, 256);
7711
7712 #ifdef BETATEST
7713     /* This code is going to take the realm and attempt to correct */
7714     /* the case.                                                   */
7715     {
7716         profile_t profile;
7717
7718         code = krb5_get_profile(kcontext, &profile);
7719         if ( !code ) {
7720             const char  *names[4];
7721             char ** realms;
7722             int found = 0;
7723
7724             names[0] = "realms";
7725             names[1] = NULL;
7726
7727             code = profile_get_subsection_names(profile,names,&realms);
7728             if ( code == 0 ) {
7729                 int i=0;
7730                 while ( realms[i] ) {
7731                     if (ckstrcmp(realm,realms[i],-1,0) == 0) {
7732                         strcpy(realm,realms[i]);
7733                         found = 1;
7734                         break;
7735                     }
7736                     i++;
7737                 }
7738             }
7739
7740 #ifdef CK_DNS_SRV
7741             if ( !found ) {
7742                 char * dns_realm = NULL;
7743
7744                 /* We did not find the realm in the profile so let's try DNS */
7745                 locate_txt_rr("_kerberos",realm,&dns_realm);
7746                 if ( dns_realm &&
7747                      ckstrcmp(realm,dns_realm,-1,0) == 0 &&
7748                      ckstrcmp(realm,dns_realm,-1,1) != 0
7749                      ) {
7750                     ckstrncpy(realm,dns_realm,256);
7751                     free(dns_realm);
7752                 }
7753             }
7754 #endif /* CK_DNS_SRV */
7755         }
7756
7757         if (init->realm &&
7758              ckstrcmp(realm,init->realm,-1,0) == 0 &&
7759              ckstrcmp(realm,init->realm,-1,1) != 0)
7760             strcpy(init->realm,realm);
7761         if (ckstrcmp(realm,krb5_d_realm,-1,0) == 0 &&
7762              ckstrcmp(realm,krb5_d_realm,-1,1) != 0)
7763             strcpy(krb5_d_realm,realm);
7764     }
7765 #endif /* BETATEST */
7766
7767     if (init->principal == NULL) {       /* No principal name specified */
7768 #ifndef NO_KEYTAB
7769         if (use_keytab) {
7770             /* Use the default host/service name */
7771             code = krb5_sname_to_principal(kcontext, NULL, NULL,
7772                                             KRB5_NT_SRV_HST, &me);
7773             if (code == 0 &&
7774                 krb5_princ_realm(kcontext, me)->length < sizeof(realm))
7775             {
7776                 /* Save the realm */
7777                 memcpy(realm,krb5_princ_realm(kcontext, me)->data,
7778                         krb5_princ_realm(kcontext, me)->length); /* safe */
7779                 realm[krb5_princ_realm(kcontext, me)->length]='\0';
7780             } else {
7781                 com_err("krb5_kinit",
7782                         code,
7783                         "when creating default server principal name");
7784                 goto exit_k5_init;
7785             }
7786         } else
7787 #endif /* NO_KEYTAB */
7788         {
7789             int len;
7790             char * name;
7791
7792             /* Get default principal from cache if one exists */
7793             code = krb5_cc_get_principal(kcontext, ccache, &me);
7794 #ifdef HEIMDAL
7795             name = me->realm;
7796             len = strlen(name);
7797 #else /* HEIMDAL */
7798             len = krb5_princ_realm(kcontext, me)->length;
7799             name = krb5_princ_realm(kcontext, me)->data;
7800 #endif /* HEIMDAL */
7801             if (code == 0 && len < sizeof(realm))
7802             {
7803                 /* Save the realm */
7804                 memcpy(realm,name,len); /* safe */
7805                 realm[len]='\0';
7806             } else {
7807 #ifdef HAVE_PWD_H
7808                 /* Else search passwd file for client */
7809
7810                 pw = getpwuid((int) getuid());
7811                 if (pw) {
7812                     char princ_realm[256];
7813                     if ( (strlen(pw->pw_name) + strlen(realm) + 1) > 255 )
7814                         goto exit_k5_init;
7815
7816                     ckstrncpy(principal,pw->pw_name,256);
7817                     ckstrncpy(princ_realm,pw->pw_name,256);
7818                     ckstrncat(princ_realm,"@",256);
7819                     ckstrncat(princ_realm,realm,256);
7820
7821                     if ((code = krb5_parse_name(kcontext,princ_realm,&me))) {
7822                         krb5_errno = code;
7823                         com_err("krb5_kinit",code,"when parsing name",
7824                                   princ_realm);
7825                         goto exit_k5_init;
7826                     }
7827                 } else {
7828                     printf(
7829                         "Unable to identify user from password file\r\n");
7830                     goto exit_k5_init;
7831                 }
7832 #else /* HAVE_PWD_H */
7833                 printf("Unable to identify user\r\n");
7834                 goto exit_k5_init;
7835 #endif /* HAVE_PWD_H */
7836             }
7837         }
7838
7839 #ifdef HEIMDAL
7840         len = me->name.name_string.len;
7841         name = *me->name.name_string.val;
7842 #else /* HEIMDAL */
7843         len = krb5_princ_name(kcontext, me)->length;
7844         name = krb5_princ_name(kcontext, me)->data;
7845 #endif /* HEIMDAL */
7846         if ( len < sizeof(principal) ) {
7847             memcpy(principal,name,len);     /* safe */
7848             principal[len]='\0';
7849         }
7850     } /* Use specified name */
7851     else {
7852         char princ_realm[256];
7853         if ( (strlen(init->principal) +
7854               (init->instance ? strlen(init->instance)+1 : 0) +
7855               strlen(realm)
7856               + 2) > 255 )
7857              goto exit_k5_init;
7858
7859         ckstrncpy(principal,init->principal,256);
7860         ckstrncpy(princ_realm,init->principal,256);
7861         if (init->instance) {
7862             ckstrncat(princ_realm,"/",256);
7863             ckstrncat(princ_realm,init->instance,256);
7864         }
7865         if (realm[0]) {
7866           ckstrncat(princ_realm,"@",256);
7867           ckstrncat(princ_realm,realm,256);
7868         }
7869         if ((code = krb5_parse_name (kcontext, princ_realm, &me))) {
7870             com_err("krb5_kinit",code,"when parsing name",princ_realm);
7871             goto exit_k5_init;
7872         }
7873     }
7874
7875     if ((code = krb5_unparse_name(kcontext, me, &client_name))) {
7876         com_err("krb5_kinit",code,"when unparsing name");
7877         goto exit_k5_init;
7878     }
7879     debug(F110,"krb5_init client_name",client_name,0);
7880
7881
7882     memset((char *)&my_creds, 0, sizeof(my_creds));
7883     my_creds.client = me;
7884
7885     if (init->service == NULL) {
7886         if ((code =
7887              krb5_build_principal_ext(kcontext,
7888                                       &server,
7889                                       strlen(realm),realm,
7890                                       tgtname.length, tgtname.data,
7891                                       strlen(realm),realm,
7892                                       0))) {
7893             com_err("krb5_kinit",code,"while building server name");
7894             goto exit_k5_init;
7895         }
7896     } else {
7897         if (code = krb5_parse_name(kcontext, init->service, &server)) {
7898             com_err("krb5_kinit",code,"while parsing service name",
7899                     init->service);
7900             goto exit_k5_init;
7901         }
7902     }
7903
7904     my_creds.server = server;
7905
7906     if (options & KDC_OPT_POSTDATED) {
7907         my_creds.times.starttime = starttime;
7908         my_creds.times.endtime = starttime + lifetime;
7909     } else {
7910         my_creds.times.starttime = 0;   /* start timer when request
7911                                            gets to KDC */
7912         my_creds.times.endtime = now + lifetime;
7913     }
7914     if (options & KDC_OPT_RENEWABLE) {
7915         my_creds.times.renew_till = now + rlife;
7916     } else
7917         my_creds.times.renew_till = 0;
7918
7919     if (options & KDC_OPT_VALIDATE) {
7920         krb5_data outbuf;
7921
7922 #ifdef KRB5_HAVE_GET_INIT_CREDS
7923         code = krb5_get_validated_creds(kcontext,
7924                                         &my_creds, me, ccache, init->service);
7925         if ( code == -1 )
7926 #endif
7927         {
7928 #ifdef HEIMDAL
7929             printf("?validate not implemented\r\n");
7930             code = -1;
7931             goto exit_k5_init;
7932 #else /* HEIMDAL */
7933             code = krb5_validate_tgt(kcontext, ccache, server, &outbuf);
7934 #endif /* HEIMDAL */
7935         }
7936         if (code) {
7937             com_err("krb5_kinit",code,"validating tgt");
7938             goto exit_k5_init;
7939         }
7940         /* should be done... */
7941         goto exit_k5_init;
7942     }
7943
7944     if (options & KDC_OPT_RENEW) {
7945         krb5_data outbuf;
7946
7947 #ifdef KRB5_HAVE_GET_INIT_CREDS
7948         code = krb5_get_renewed_creds(kcontext,
7949                                       &my_creds, me, ccache, init->service);
7950         if ( code == -1 )
7951 #endif
7952         {
7953 #ifdef HEIMDAL
7954             printf("?renew not implemented\r\n");
7955             code = -1;
7956             goto exit_k5_init;
7957 #else /* HEIMDAL */
7958             code = krb5_renew_tgt(kcontext, ccache, server, &outbuf);
7959 #endif /* HEIMDAL */
7960         }
7961         if (code) {
7962             com_err("krb5_kinit",code,"while renewing tgt");
7963             goto exit_k5_init;
7964         }
7965         /* should be done... */
7966         goto store_cred;
7967     }
7968
7969 #ifndef HEIMDAL
7970     if ( init->addrs && !init->no_addresses ) {
7971         /* construct an array of krb5_address structs to pass to get_in_tkt */
7972         /* include both the local ip addresses as well as any other that    */
7973         /* are specified.                                                   */
7974         unsigned long ipaddr;
7975
7976         for ( addr_count=0;addr_count<KRB5_NUM_OF_ADDRS;addr_count++ )
7977             if ( init->addrs[addr_count] == NULL )
7978                 break;
7979
7980         if (addr_count > 0) {
7981             krb5_address ** local_addrs=NULL;
7982             krb5_os_localaddr(kcontext, &local_addrs);
7983             i = 0;
7984             while ( local_addrs[i] )
7985                 i++;
7986             addr_count += i;
7987
7988             addrs = (krb5_address **)
7989               malloc((addr_count+1) * sizeof(krb5_address *));
7990             if ( !addrs ) {
7991                 krb5_free_addresses(kcontext, local_addrs);
7992                 goto exit_k5_init;
7993             }
7994             memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
7995             i = 0;
7996             while ( local_addrs[i] ) {
7997                 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
7998                 if (addrs[i] == NULL) {
7999                     krb5_free_addresses(kcontext, local_addrs);
8000                     goto exit_k5_init;
8001                 }
8002
8003                 addrs[i]->magic = local_addrs[i]->magic;
8004                 addrs[i]->addrtype = local_addrs[i]->addrtype;
8005                 addrs[i]->length = local_addrs[i]->length;
8006                 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
8007                 if (!addrs[i]->contents) {
8008                     krb5_free_addresses(kcontext, local_addrs);
8009                     goto exit_k5_init;
8010                 }
8011
8012                 memcpy(addrs[i]->contents,local_addrs[i]->contents,
8013                         local_addrs[i]->length);        /* safe */
8014                 i++;
8015             }
8016             krb5_free_addresses(kcontext, local_addrs);
8017
8018             for ( j=0;i<addr_count;i++,j++ ) {
8019                 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
8020                 if (addrs[i] == NULL)
8021                     goto exit_k5_init;
8022
8023                 addrs[i]->magic = KV5M_ADDRESS;
8024                 addrs[i]->addrtype = AF_INET;
8025                 addrs[i]->length = 4;
8026                 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
8027                 if (!addrs[i]->contents)
8028                     goto exit_k5_init;
8029
8030                 ipaddr = inet_addr(init->addrs[j]);
8031                 memcpy(addrs[i]->contents,&ipaddr,4);   /* safe */
8032             }
8033 #ifdef KRB5_HAVE_GET_INIT_CREDS
8034             krb5_get_init_creds_opt_set_address_list(&opts,addrs);
8035 #endif
8036         }
8037      }
8038 #endif /* !HEIMDAL */
8039 #ifdef KRB5_HAVE_GET_INIT_CREDS
8040     if ( init->no_addresses )
8041         krb5_get_init_creds_opt_set_address_list(&opts,NULL);
8042 #endif
8043
8044 #ifndef NO_KEYTAB
8045     if (!use_keytab)
8046 #endif
8047     {
8048         if ( init->password ) {
8049             pwsize = strlen(init->password);
8050             if ( pwsize )
8051                 password = init->password;
8052         } else if (init->getk4 && k4_init) {
8053             /* When we are requesting that K4 tickets be automatically */
8054             /* acquired when K5 tickets are acquired, we must get the  */
8055             /* password up front.                                      */
8056             char prmpt[256];
8057             extern char * k5prprompt;
8058             extern char * k5pwprompt;
8059             int ok = 0;
8060
8061             if ( k5pwprompt && k5pwprompt[0] &&
8062                  (strlen(k5pwprompt) + strlen(principal) +
8063                   strlen(realm) - 4) < sizeof(prmpt)) {
8064                 sprintf(prmpt,k5pwprompt,principal,realm);
8065             } else
8066                 ckmakxmsg(prmpt,sizeof(prmpt),
8067                            k5pwprompt && k5pwprompt[0] ? k5pwprompt :
8068                            "Kerberos 5 Password for ",
8069                            principal,"@",realm,": ",
8070                            NULL,NULL,NULL,NULL,NULL,NULL,NULL
8071                            );
8072             ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT);
8073             if ( ok )
8074                 password = passwd;
8075
8076             if ( k4_init->password == NULL )
8077                 makestr(&k4_init->password,passwd);
8078         }
8079 #ifdef KRB5_HAVE_GET_INIT_CREDS
8080         debug(F100,"krb5_init calling krb5_get_init_creds_password()","",0);
8081 #ifdef OS2
8082         if ( is_NRL_KRB5() )
8083             code = krb5_get_init_creds_password(kcontext, &my_creds, me,
8084                                                  password,
8085                                                  (void *)ck_NRL_krb5_prompter,
8086                                                  NULL,
8087                                                  starttime, init->service,
8088                                                  &opts);
8089         else
8090 #endif /* OS2 */
8091             code = krb5_get_init_creds_password(kcontext, &my_creds, me,
8092                                                  password,
8093                                                  ck_krb5_prompter,
8094                                                  NULL,
8095                                                  starttime, init->service,
8096                                                  &opts);
8097         debug(F111,"krb5_init","krb5_get_init_creds_password()",code);
8098
8099         if ( code == -1 )
8100         {
8101             if (!password) {
8102                 char prmpt[256];
8103                 int ok;
8104
8105                 ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ",
8106                           client_name,": ",NULL);
8107                 ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,
8108                             DEFAULT_UQ_TIMEOUT);
8109                 if ( ok )
8110                     password = passwd;
8111                 else {
8112                     code = -2;
8113                     goto exit_k5_init;
8114                 }
8115             }
8116
8117             if ( !password ) 
8118                 password = "";
8119             code = krb5_get_in_tkt_with_password(kcontext, options,
8120 #ifdef HEIMDAL
8121                                                   NULL,
8122 #else /* HEIMDAL */
8123                                             init->no_addresses ? NULL :addrs,
8124 #endif /* HEIMDAL */
8125                                                   NULL, NULL,
8126                                                   password,
8127                                                   NULL, &my_creds, NULL);
8128             if ( code )
8129                 debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code);
8130         }
8131 #else /* KRB5_HAVE_GET_INIT_CREDS */
8132         if (!password) {
8133             char prmpt[256];
8134             int ok;
8135
8136             ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ",
8137                       client_name,": ",NULL);
8138             ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT);
8139             if ( ok )
8140                 password = passwd;
8141             else {
8142                 code = -2;
8143                 goto exit_k5_init;
8144             }
8145         }
8146         if ( !password ) 
8147             password = "";
8148         code = krb5_get_in_tkt_with_password(kcontext, options,
8149 #ifdef HEIMDAL
8150                                               NULL,
8151 #else /* HEIMDAL */
8152                                             init->no_addresses ? NULL :addrs,
8153 #endif /* HEIMDAL */
8154                                               NULL, NULL,
8155                                               password,
8156                                               NULL, &my_creds, NULL);
8157         if ( code )
8158             debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code);
8159 #endif /* KRB5_HAVE_GET_INIT_CREDS */
8160
8161         if ( init->password && pwsize > 0 )
8162             memset(init->password, 0, pwsize);
8163         memset(passwd,0,80);
8164     }
8165 #ifndef NO_KEYTAB
8166     else {
8167 #ifdef KRB5_HAVE_GET_INIT_CREDS
8168         code = krb5_get_init_creds_keytab(kcontext, &my_creds, me, keytab,
8169                                            starttime, init->service,
8170                                            &opts);
8171 #ifdef OS2
8172         if ( code == -1)
8173             code = krb5_get_in_tkt_with_keytab(kcontext, options,
8174                                            init->no_addresses ? NULL :addrs,
8175                                                 NULL, NULL, keytab, NULL,
8176                                                 &my_creds, 0);
8177 #endif /* OS2 */
8178 #else /* KRB5_HAVE_GET_INIT_CREDS */
8179         code = krb5_get_in_tkt_with_keytab(kcontext, options,
8180 #ifdef HEIMDAL
8181                                                   NULL,
8182 #else /* HEIMDAL */
8183                                             init->no_addresses ? NULL :addrs,
8184 #endif /* HEIMDAL */
8185                                             NULL, NULL, keytab, NULL,
8186                                             &my_creds, 0);
8187 #endif /* KRB5_HAVE_GET_INIT_CREDS */
8188     }
8189 #endif
8190
8191     if (code) {
8192         switch (code) {
8193         case KRB5KRB_AP_ERR_BAD_INTEGRITY:
8194             printf("Password incorrect\r\n");
8195             goto exit_k5_init;
8196         case KRB5KRB_AP_ERR_V4_REPLY:
8197             if (init->getk4 && k4_init) {
8198                 printf("Kerberos 5 Tickets not support by server.  ");
8199                 printf("A version 4 Ticket will be requested.\r\n");
8200             }
8201             goto exit_k5_init;
8202         default:
8203             goto exit_k5_init;
8204         }
8205     }
8206
8207   store_cred:
8208     debug(F100,"krb5_init calling krb5_cc_initialize()","",0);
8209
8210     code = krb5_cc_initialize (kcontext, ccache, me);
8211     if ( code == KRB5_CC_BADNAME ) {
8212         /* This is a really ugly hack that should not have to be here.
8213          * krb5_cc_initialize should not fail with an error if the
8214          * cache already exists.  The reason the problem is occuring
8215          * is that the krb5 library is no longer calling cc_destroy()
8216          * when cc_initialize() is called and the CCAPI implementation
8217          * on Windows has not yet been corrected to handle it.  To
8218          * ensure that K95 will continue to work with both we will call
8219          * cc_destroy() if the cc_initialize() call fails with a BADNAME
8220          * error.  If the cc_destroy() is successful, we will try again.
8221          */
8222
8223         debug(F100,"krb5_init calling krb5_cc_destroy()","",0);
8224         code = krb5_cc_destroy (kcontext, ccache);
8225         if ( !code ) {
8226             debug(F100,"krb5_init calling k5_get_ccache()","",0);
8227             code = k5_get_ccache(kcontext,&ccache,op->cache);
8228             debug(F100,"krb5_init calling krb5_cc_initialize()","",0);
8229             code = krb5_cc_initialize (kcontext, ccache, me);
8230         } else
8231             code = KRB5_CC_BADNAME;
8232     }
8233     if (code) {
8234         com_err("krb5_kinit",code,"when initializing cache",op->cache);
8235         goto exit_k5_init;
8236     }
8237
8238     debug(F100,"krb5_init calling krb5_cc_store_cred()","",0);
8239     code = krb5_cc_store_cred(kcontext, ccache, &my_creds);
8240     if (code) {
8241         com_err("krb5_kinit",code,"while storing credentials");
8242         goto exit_k5_init;
8243     }
8244
8245     if ( init->getk4 && 
8246 #ifdef KRB524_CONV
8247          !try_convert524(kcontext,me,ccache) && 
8248 #endif /* KRB524_CONV */
8249          k4_init ) {
8250         int k4rc = ck_krb4_initTGT(op,k4_init);
8251         if (k4rc < 0)
8252             code = -3;
8253     }
8254
8255 exit_k5_init:
8256     debug(F100,"krb5_init exit_k5_init","",0);
8257
8258 #ifndef HEIMDAL
8259     /* Free krb5_address structures if we created them */
8260     if ( addrs ) {
8261         for ( i=0;i<addr_count;i++ ) {
8262             if ( addrs[i] ) {
8263                 if ( addrs[i]->contents )
8264                     free(addrs[i]->contents);
8265                 free(addrs[i]);
8266             }
8267         }
8268     }
8269 #endif /* HEIMDAL */
8270
8271
8272     krb5_errno = code;
8273     makestr(&krb5_errmsg,krb5_errno ? error_message(krb5_errno) : "OK");
8274
8275     if (client_name)
8276         krb5_free_unparsed_name(kcontext, client_name);
8277
8278     /* my_creds is pointing at server */
8279     debug(F100,"krb5_init calling krb5_free_principal()","",0);
8280     krb5_free_principal(kcontext, server);
8281     debug(F100,"krb5_init calling krb5_cc_close()","",0);
8282     krb5_cc_close(kcontext,ccache);
8283     debug(F100,"krb5_init calling krb5_free_context()","",0);
8284     krb5_free_context(kcontext);
8285
8286     if (code != -2)
8287         printf("Result from realm %s: %s\r\n",realm,
8288                 code==-3?"Unable to retrieve Kerberos IV credentials":
8289                 code?error_message(code):"OK");
8290     return(code?-1:0);
8291 }
8292
8293 #ifndef HEIMDAL
8294 #define VALIDATE 0
8295 #define RENEW 1
8296
8297 /* stripped down version of krb5_mk_req */
8298 static krb5_error_code
8299 #ifdef CK_ANSIC
8300 krb5_validate_tgt( krb5_context context,
8301                    krb5_ccache ccache,
8302                    krb5_principal     server, /* tgtname */
8303                    krb5_data *outbuf )
8304 #else
8305 krb5_validate_tgt(context, ccache, server, outbuf)
8306      krb5_context context;
8307      krb5_ccache ccache;
8308      krb5_principal     server; /* tgtname */
8309      krb5_data *outbuf;
8310 #endif
8311 {
8312     return krb5_tgt_gen(context, ccache, server, outbuf, VALIDATE);
8313 }
8314
8315 /* stripped down version of krb5_mk_req */
8316 static krb5_error_code
8317 #ifdef CK_ANSIC
8318 krb5_renew_tgt(krb5_context context,
8319                 krb5_ccache ccache,
8320                 krb5_principal    server, /* tgtname */
8321                 krb5_data *outbuf)
8322 #else
8323 krb5_renew_tgt(context, ccache, server, outbuf)
8324      krb5_context context;
8325      krb5_ccache ccache;
8326      krb5_principal       server; /* tgtname */
8327      krb5_data *outbuf;
8328 #endif
8329 {
8330     return krb5_tgt_gen(context, ccache, server, outbuf, RENEW);
8331 }
8332
8333
8334 /* stripped down version of krb5_mk_req */
8335 static krb5_error_code
8336 #ifdef CK_ANSIC
8337 krb5_tgt_gen(krb5_context context,
8338               krb5_ccache ccache,
8339               krb5_principal      server, /* tgtname */
8340               krb5_data *outbuf,
8341               int opt)
8342 #else
8343 krb5_tgt_gen(context, ccache, server, outbuf, opt)
8344      krb5_context context;
8345      krb5_ccache ccache;
8346      krb5_principal       server; /* tgtname */
8347      krb5_data *outbuf;
8348      int opt;
8349 #endif
8350 {
8351     krb5_error_code       retval;
8352     krb5_creds          * credsp;
8353     krb5_creds            creds;
8354
8355     /* obtain ticket & session key */
8356     memset((char *)&creds, 0, sizeof(creds));
8357     if ((retval = krb5_copy_principal(context, server, &creds.server)))
8358         goto cleanup;
8359
8360     if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)))
8361         goto cleanup_creds;
8362
8363     if (opt == VALIDATE) {
8364         if ((retval = krb5_get_credentials_validate(context, 0,
8365                                                     ccache, &creds, &credsp)))
8366           goto cleanup_creds;
8367     } else {
8368         if ((retval = krb5_get_credentials_renew(context, 0,
8369                                                  ccache, &creds, &credsp)))
8370           goto cleanup_creds;
8371     }
8372
8373     /* we don't actually need to do the mk_req, just get the creds. */
8374 cleanup_creds:
8375     krb5_free_cred_contents(context, &creds);
8376
8377 cleanup:
8378
8379     return retval;
8380 }
8381 #endif /* HEIMDAL */
8382 #endif /* KINIT */
8383 #ifdef KDESTROY
8384 int
8385 #ifdef CK_ANSIC
8386 ck_krb5_destroy(struct krb_op_data * op)
8387 #else
8388 ck_krb5_destroy(op) struct krb_op_data * op;
8389 #endif
8390 {
8391     krb5_context kcontext;
8392     krb5_error_code retval;
8393     int c;
8394     krb5_ccache ccache = NULL;
8395     char *cache_name = NULL;
8396     int code;
8397     int errflg=0;
8398     int quiet = 0;
8399
8400     if ( !ck_krb5_is_installed() )
8401         return(-1);
8402
8403     code = krb5_init_context(&kcontext);
8404     if (code) {
8405         debug(F101,"ck_krb5_destroy while initializing krb5","",code);
8406         krb5_errno = code;
8407         makestr(&krb5_errmsg,error_message(krb5_errno));
8408         return(-1);
8409     }
8410
8411     code = k5_get_ccache(kcontext,&ccache,op->cache);
8412     if (code != 0) {
8413         debug(F101,"ck_krb5_destroy while getting ccache",
8414                "",code);
8415         krb5_free_context(kcontext);
8416         krb5_errno = code;
8417         makestr(&krb5_errmsg,error_message(krb5_errno));
8418         return(-1);
8419     }
8420
8421     code = krb5_cc_destroy (kcontext, ccache);
8422     if (code != 0) {
8423         debug(F101,"ck_krb5_destroy while destroying cache","",code);
8424         if ( code == KRB5_FCC_NOFILE )
8425             printf("No ticket cache to destroy.\r\n");
8426         else
8427             printf("Ticket cache NOT destroyed!\r\n");
8428         krb5_cc_close(kcontext,ccache);
8429         krb5_free_context(kcontext);
8430         krb5_errno = code;
8431         makestr(&krb5_errmsg,error_message(krb5_errno));
8432         return(-1);
8433     }
8434
8435     printf("Tickets destroyed.\r\n");
8436     /* Do not call krb5_cc_close() because cache has been destroyed */
8437     krb5_free_context(kcontext);
8438     krb5_errno = 0;
8439     makestr(&krb5_errmsg,"OK");
8440     return (0);
8441 }
8442 #else /* KDESTROY */
8443 #ifdef KRB5
8444 int
8445 #ifdef CK_ANSIC
8446 ck_krb5_destroy(struct krb_op_data * op)
8447 #else
8448 ck_krb5_destroy(op) struct krb_op_data * op;
8449 #endif
8450 {
8451     printf("?Not implemented.\r\n");
8452     return(-1);
8453 }
8454 #endif /* KRB5 */
8455 #endif /* KDESTROY */
8456 #ifndef KLIST
8457 #ifdef KRB5
8458 int
8459 #ifdef CK_ANSIC
8460 ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc)
8461 #else
8462 ck_krb5_list_creds(op,lc)
8463     struct krb_op_data * op; struct krb5_list_cred_data * lc;
8464 #endif
8465 {
8466     printf("?Not implemented.\r\n");
8467     return(-1);
8468 }
8469 #endif /* KRB5 */
8470 #else /* KLIST */
8471 static int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;
8472 static int show_etype = 0, show_addr = 0;
8473 static char *defname;
8474 static char *progname;
8475 static krb5_int32 now;
8476 static int timestamp_width;
8477
8478 _PROTOTYP(static char * etype_string, (krb5_enctype ));
8479 _PROTOTYP(static void show_credential,(krb5_context,krb5_creds *));
8480 _PROTOTYP(static int do_ccache, (krb5_context,char *));
8481 _PROTOTYP(static int do_keytab, (krb5_context,char *));
8482 _PROTOTYP(static void printtime, (time_t));
8483 _PROTOTYP(static void fillit, (int, int));
8484
8485 #define DEFAULT 0
8486 #define CCACHE 1
8487 #define KEYTAB 2
8488
8489 int
8490 #ifdef CK_ANSIC
8491 ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc)
8492 #else
8493 ck_krb5_list_creds(op,lc)
8494     struct krb_op_data * op; struct krb5_list_cred_data * lc;
8495 #endif
8496 {
8497     krb5_context kcontext;
8498     krb5_error_code retval;
8499     int code;
8500     char *name = op->cache;
8501     int mode;
8502
8503     if ( !ck_krb5_is_installed() )
8504         return(-1);
8505
8506     code = krb5_init_context(&kcontext);
8507     if (code) {
8508         debug(F101,"ck_krb5_list_creds while initializing krb5","",code);
8509         krb5_errno = code;
8510         makestr(&krb5_errmsg,error_message(krb5_errno));
8511         return(-1);
8512     }
8513
8514     name = op->cache;
8515     mode = DEFAULT;
8516     show_flags = 0;
8517     show_time = 0;
8518     status_only = 0;
8519     show_keys = 0;
8520     show_etype = 0;
8521     show_addr = 0;
8522
8523     show_flags = lc->flags;
8524     show_etype = lc->encryption;
8525     show_addr  = lc->addr;
8526     show_time = 1;
8527     show_keys = 1;
8528     mode = CCACHE;
8529
8530     if ((code = krb5_timeofday(kcontext, &now))) {
8531         if (!status_only)
8532             debug(F101,"ck_krb5_list_creds while getting time of day.",
8533                    "",code);
8534         krb5_free_context(kcontext);
8535         krb5_errno = code;
8536         makestr(&krb5_errmsg,error_message(krb5_errno));
8537         return(-1);
8538     }
8539     else {
8540         char tmp[BUFSIZ];
8541
8542         if (!krb5_timestamp_to_sfstring(now, tmp, 20, (char *) NULL) ||
8543             !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), (char *) NULL))
8544             timestamp_width = (int) strlen(tmp);
8545         else
8546             timestamp_width = 15;
8547     }
8548
8549     if (mode == DEFAULT || mode == CCACHE)
8550          retval = do_ccache(kcontext,name);
8551     else
8552          retval = do_keytab(kcontext,name);
8553     krb5_free_context(kcontext);
8554     return(retval);
8555 }
8556
8557 static int
8558 #ifdef CK_ANSIC
8559 do_keytab(krb5_context kcontext, char * name)
8560 #else
8561 do_keytab(kcontext,name) krb5_context kcontext; char * name;
8562 #endif
8563 {
8564     krb5_keytab kt;
8565     krb5_keytab_entry entry;
8566     krb5_kt_cursor cursor;
8567     char buf[BUFSIZ]; /* hopefully large enough for any type */
8568     char *pname;
8569     int code = 0;
8570
8571     if (name == NULL) {
8572         if ((code = krb5_kt_default(kcontext, &kt))) {
8573             debug(F101,"ck_krb5_list_creds while getting default keytab",
8574                    "",code);
8575             krb5_errno = code;
8576             makestr(&krb5_errmsg,error_message(krb5_errno));
8577             return(-1);
8578         }
8579     } else {
8580         if ((code = krb5_kt_resolve(kcontext, name, &kt))) {
8581             debug(F111,"ck_krb5_list_creds while resolving keytab",
8582                      name,code);
8583             krb5_errno = code;
8584             makestr(&krb5_errmsg,error_message(krb5_errno));
8585             return(-1);
8586         }
8587     }
8588
8589     if ((code = krb5_kt_get_name(kcontext, kt, buf, BUFSIZ))) {
8590         debug(F101,"ck_krb5_list_creds while getting keytab name",
8591                "",code);
8592         krb5_errno = code;
8593         makestr(&krb5_errmsg,error_message(krb5_errno));
8594         return(-1);
8595     }
8596
8597      printf("Keytab name: %s\r\n", buf);
8598
8599      if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) {
8600          debug(F101,"ck_krb5_list_creds while starting keytab scan",
8601                 "",code);
8602          krb5_errno = code;
8603          makestr(&krb5_errmsg,error_message(krb5_errno));
8604          return(-1);
8605      }
8606
8607      if (show_time) {
8608           printf("KVNO Timestamp");
8609           fillit(timestamp_width - sizeof("Timestamp") + 2, (int) ' ');
8610           printf("Principal\r\n");
8611           printf("---- ");
8612           fillit(timestamp_width, (int) '-');
8613           printf(" ");
8614           fillit(78 - timestamp_width - sizeof("KVNO"), (int) '-');
8615           printf("\r\n");
8616      } else {
8617           printf("KVNO Principal\r\n");
8618           printf(
8619 "---- --------------------------------------------------------------------\
8620 ------\r\n");
8621      }
8622
8623     while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
8624         if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) {
8625             debug(F101,"ck_krb5_list_creds while unparsing principal name",
8626                    "",code);
8627             krb5_errno = code;
8628             makestr(&krb5_errmsg,error_message(krb5_errno));
8629             return(-1);
8630         }
8631         printf("%4d ", entry.vno);
8632         if (show_time) {
8633             printtime(entry.timestamp);
8634             printf(" ");
8635         }
8636         printf("%s", pname);
8637         if (show_etype)
8638             printf(" (%s) " ,
8639 #ifdef HEIMDAL
8640                     etype_string(entry.key.keytype)
8641 #else /* HEIMDAL */
8642                     etype_string(entry.key.enctype)
8643 #endif /* HEIMDAL */
8644                     );
8645         if (show_keys) {
8646             printf(" (0x");
8647             {
8648                 int i;
8649                 for (i = 0; i < entry.key.length; i++)
8650                     printf("%02x",
8651 #ifdef HEIMDAL
8652                             entry.key.keyvalue[i]
8653 #else /* HEIMDAL */
8654                             entry.key.contents[i]
8655 #endif /* HEIMDAL */
8656                             );
8657             }
8658             printf(")");
8659         }
8660         printf("\r\n");
8661         krb5_free_unparsed_name(kcontext,pname);
8662     }
8663     if (code && code != KRB5_KT_END) {
8664         debug(F101,"ck_krb5_list_creds while scanning keytab",
8665                "",code);
8666         krb5_errno = code;
8667         makestr(&krb5_errmsg,error_message(krb5_errno));
8668         return(-1);
8669     }
8670     if ((code = krb5_kt_end_seq_get(kcontext, kt, &cursor))) {
8671         debug(F101,"ck_krb5_list_creds while ending keytab scan",
8672                "",code);
8673         krb5_errno = code;
8674         makestr(&krb5_errmsg,error_message(krb5_errno));
8675         return(-1);
8676     }
8677     krb5_errno = 0;
8678     makestr(&krb5_errmsg,"OK");
8679     return(0);
8680 }
8681
8682 static int
8683 #ifdef CK_ANSIC
8684 do_ccache(krb5_context kcontext, char * cc_name)
8685 #else
8686 do_ccache(kcontext,name) krb5_context kcontext; char * cc_name;
8687 #endif
8688 {
8689     krb5_ccache cache = NULL;
8690     krb5_cc_cursor cur;
8691     krb5_creds creds;
8692     krb5_principal princ=NULL;
8693     krb5_flags flags=0;
8694     krb5_error_code code = 0;
8695     int exit_status = 0;
8696
8697     if (status_only)
8698         /* exit_status is set back to 0 if a valid tgt is found */
8699         exit_status = 1;
8700
8701     code = k5_get_ccache(kcontext,&cache,cc_name);
8702     if (code != 0) {
8703         debug(F111,"do_ccache while getting ccache",
8704                error_message(code),code);
8705         krb5_errno = code;
8706         makestr(&krb5_errmsg,error_message(krb5_errno));
8707         return(-1);
8708     }
8709
8710     flags = 0;                          /* turns off OPENCLOSE mode */
8711     if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
8712         if (code == ENOENT) {
8713             debug(F111,"ck_krb5_list_creds (ticket cache)",
8714                    krb5_cc_get_name(kcontext, cache),code);
8715         } else {
8716             debug(F111,
8717                  "ck_krb5_list_creds while setting cache flags (ticket cache)",
8718                   krb5_cc_get_name(kcontext, cache),code);
8719         }
8720         printf("No ticket File.\r\n");
8721         krb5_errno = code;
8722         makestr(&krb5_errmsg,error_message(krb5_errno));
8723         krb5_cc_close(kcontext,cache);
8724         return(-1);
8725     }
8726     if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
8727         debug(F101,"ck_krb5_list_creds while retrieving principal name",
8728                "",code);
8729         krb5_errno = code;
8730         makestr(&krb5_errmsg,error_message(krb5_errno));
8731         krb5_cc_close(kcontext,cache);
8732         return(-1);
8733     }
8734     if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
8735         debug(F101,"ck_krb5_list_creds while unparsing principal name",
8736                "",code);
8737         krb5_errno = code;
8738         makestr(&krb5_errmsg,error_message(krb5_errno));
8739         krb5_cc_close(kcontext,cache);
8740         return(-1);
8741     }
8742     if (!status_only) {
8743         printf("Ticket cache:      %s:%s\r\nDefault principal: %s\r\n\r\n",
8744                 krb5_cc_get_type(kcontext, cache),
8745                 krb5_cc_get_name(kcontext, cache), defname);
8746         printf("Valid starting");
8747         fillit(timestamp_width - sizeof("Valid starting") + 3,
8748                (int) ' ');
8749         printf("Expires");
8750         fillit(timestamp_width - sizeof("Expires") + 3,
8751                (int) ' ');
8752         printf("Service principal\r\n");
8753     }
8754     if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
8755         debug(F101,"ck_krb5_list_creds while starting to retrieve tickets",
8756                "",code);
8757         krb5_errno = code;
8758         makestr(&krb5_errmsg,error_message(krb5_errno));
8759         krb5_cc_close(kcontext,cache);
8760         return(-1);
8761     }
8762     while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
8763         if (status_only) {
8764             if (exit_status && creds.server->length == 2 &&
8765                 strcmp(creds.server->realm.data, princ->realm.data) == 0 &&
8766                 strcmp((char *)creds.server->data[0].data, "krbtgt") == 0 &&
8767                 strcmp((char *)creds.server->data[1].data,
8768                        princ->realm.data) == 0 &&
8769                 creds.times.endtime > now)
8770                 exit_status = 0;
8771         } else {
8772             show_credential(kcontext, &creds);
8773         }
8774         krb5_free_cred_contents(kcontext, &creds);
8775     }
8776     printf("\r\n");
8777     if (code == KRB5_CC_END || code == KRB5_CC_NOTFOUND) {
8778         if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
8779             debug(F101,"ck_krb5_list_creds while finishing ticket retrieval",
8780                    "",code);
8781             krb5_errno = code;
8782             makestr(&krb5_errmsg,error_message(krb5_errno));
8783             krb5_cc_close(kcontext,cache);
8784             return(-1);
8785         }
8786         flags = KRB5_TC_OPENCLOSE;      /* turns on OPENCLOSE mode */
8787         if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
8788             debug(F101,"ck_krb5_list_creds while closing ccache",
8789                    "",code);
8790             krb5_errno = code;
8791             makestr(&krb5_errmsg,error_message(krb5_errno));
8792             krb5_cc_close(kcontext,cache);
8793             return(-1);
8794         }
8795         krb5_errno = 0;
8796         makestr(&krb5_errmsg,"OK");
8797         krb5_cc_close(kcontext,cache);
8798         return(0);
8799     } else {
8800         debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code);
8801         krb5_errno = code;
8802         makestr(&krb5_errmsg,error_message(krb5_errno));
8803         krb5_cc_close(kcontext,cache);
8804         return(-1);
8805     }
8806     krb5_errno = 0;
8807     makestr(&krb5_errmsg,"OK");
8808     krb5_cc_close(kcontext,cache);
8809     return(0);
8810 }
8811
8812 static char *
8813 #ifdef CK_ANSIC
8814 #ifdef HEIMDAL
8815 etype_string(krb5_keytype enctype)
8816 #else /* HEIMDAL */
8817 etype_string(krb5_enctype enctype)
8818 #endif /* HEIMDAL */
8819 #else
8820 #ifdef HEIMDAL
8821 etype_string(enctype) krb5_keytype enctype;
8822 #else /* HEIMDAL */
8823 etype_string(enctype) krb5_enctype enctype;
8824 #endif /* HEIMDAL */
8825 #endif
8826 {
8827     static char buf[12];
8828
8829     switch (enctype) {
8830     case ENCTYPE_NULL:
8831         return "NULL";
8832     case ENCTYPE_DES_CBC_CRC:
8833         return "DES-CBC-CRC";
8834     case ENCTYPE_DES_CBC_MD4:
8835         return "DES-CBC-MD4";
8836     case ENCTYPE_DES_CBC_MD5:
8837         return "DES-CBC-MD5";
8838     case ENCTYPE_DES_CBC_RAW:
8839         return "DES-CBC-RAW";
8840     case ENCTYPE_DES3_CBC_SHA:
8841         return "DES3-CBC-SHA";
8842     case ENCTYPE_DES3_CBC_RAW:
8843         return "DES3-CBC-RAW";
8844     case ENCTYPE_DES_HMAC_SHA1:
8845         return "DES-HMAC-SHA1";
8846     case ENCTYPE_DES3_CBC_SHA1:
8847         return "DES3-CBC-SHA1";
8848     case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
8849         return "AES128_CTS-HMAC-SHA1_96";
8850     case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
8851         return "AES256_CTS-HMAC-SHA1_96";
8852     case ENCTYPE_ARCFOUR_HMAC:
8853         return "RC4-HMAC-NT";
8854     case ENCTYPE_ARCFOUR_HMAC_EXP:
8855         return "RC4-HMAC-NT-EXP";
8856     case ENCTYPE_UNKNOWN:
8857         return "UNKNOWN";
8858     case ENCTYPE_LOCAL_DES3_HMAC_SHA1:
8859         return "LOCAL-DES3-HMAC-SHA1";
8860     case ENCTYPE_LOCAL_RC4_MD4:
8861         return "LOCAL-RC4-MD4";
8862     default:
8863         ckmakmsg(buf, sizeof(buf),"etype ", ckitoa(enctype),NULL,NULL);
8864         return buf;
8865         break;
8866     }
8867 }
8868
8869 static char *
8870 #ifdef CK_ANSIC
8871 flags_string(register krb5_creds *cred)
8872 #else
8873 flags_string(cred) register krb5_creds *cred;
8874 #endif
8875 {
8876     static char buf[32];
8877     int i = 0;
8878
8879     if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
8880         buf[i++] = 'F';
8881     if (cred->ticket_flags & TKT_FLG_FORWARDED)
8882         buf[i++] = 'f';
8883     if (cred->ticket_flags & TKT_FLG_PROXIABLE)
8884         buf[i++] = 'P';
8885     if (cred->ticket_flags & TKT_FLG_PROXY)
8886         buf[i++] = 'p';
8887     if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
8888         buf[i++] = 'D';
8889     if (cred->ticket_flags & TKT_FLG_POSTDATED)
8890         buf[i++] = 'd';
8891     if (cred->ticket_flags & TKT_FLG_INVALID)
8892         buf[i++] = 'i';
8893     if (cred->ticket_flags & TKT_FLG_RENEWABLE)
8894         buf[i++] = 'R';
8895     if (cred->ticket_flags & TKT_FLG_INITIAL)
8896         buf[i++] = 'I';
8897     if (cred->ticket_flags & TKT_FLG_HW_AUTH)
8898         buf[i++] = 'H';
8899     if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
8900         buf[i++] = 'A';
8901     buf[i] = '\0';
8902     return(buf);
8903 }
8904
8905 static char   *
8906 #ifdef CK_ANSIC
8907 short_date(long   *dp)
8908 #else
8909 short_date(dp) long   *dp;
8910 #endif
8911 {
8912     register char *cp;
8913 #ifndef ctime
8914     extern char *ctime();
8915 #endif /* ctime */
8916     cp = ctime(dp) + 4;
8917     cp[15] = '\0';
8918     return (cp);
8919 }
8920
8921
8922 static VOID
8923 #ifdef CK_ANSIC
8924 printtime(time_t tv)
8925 #else
8926 printtime(tv) time_t tv;
8927 #endif
8928 {
8929     char timestring[BUFSIZ];
8930     char format[12];
8931     char fill;
8932
8933     fill = ' ';
8934     sprintf(format,"%%-%ds",timestamp_width);   /* safe */
8935     if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv,
8936                                      timestring,
8937                                      timestamp_width+1,
8938                                      &fill)) {
8939         printf(format,timestring);
8940     }
8941     else {
8942         printf(format,short_date(&tv));
8943     }
8944
8945 }
8946
8947 static void
8948 #ifdef CK_ANSIC
8949 one_addr(krb5_address *a)
8950 #else
8951 one_addr(a) krb5_address *a;
8952 #endif
8953 {
8954     struct hostent *h;
8955     extern tcp_rdns;
8956
8957     if ((a->addrtype == ADDRTYPE_INET) &&
8958         (a->length == 4)) {
8959         if (tcp_rdns != SET_OFF) {
8960             h = gethostbyaddr(a->contents, 4, AF_INET);
8961             if (h) {
8962 #ifdef HADDRLIST
8963                 h = ck_copyhostent(h);
8964 #endif /* HADDRLIST */
8965                 printf("%s (%d.%d.%d.%d)", h->h_name,
8966                         a->contents[0], a->contents[1],
8967                         a->contents[2], a->contents[3]);
8968             }
8969         }
8970         if (tcp_rdns == SET_OFF || !h) {
8971             printf("%d.%d.%d.%d", a->contents[0], a->contents[1],
8972                    a->contents[2], a->contents[3]);
8973         }
8974     } else {
8975         printf("unknown addr type %d", a->addrtype);
8976     }
8977 }
8978
8979 static VOID
8980 #ifdef CK_ANSIC
8981 show_credential(krb5_context kcontext, register krb5_creds * cred)
8982 #else
8983 show_credential(kcontext, cred)
8984     krb5_context          kcontext;
8985     register krb5_creds * cred;
8986 #endif
8987 {
8988     krb5_error_code retval=0;
8989     krb5_ticket *tkt=NULL;
8990     char *name=NULL, *sname=NULL, *flags=NULL;
8991     int extra_field = 0;
8992
8993     retval = krb5_unparse_name(kcontext, cred->client, &name);
8994     if (retval) {
8995         debug(F101,"ck_krb5_list_creds while unparsing client name","",retval);
8996         krb5_errno = retval;
8997         makestr(&krb5_errmsg,error_message(krb5_errno));
8998         return;
8999     }
9000     retval = krb5_unparse_name(kcontext, cred->server, &sname);
9001     if (retval) {
9002         debug(F101,"ck_krb5_list_creds while unparsing server name","",retval);
9003         free(name);
9004         krb5_errno = retval;
9005         makestr(&krb5_errmsg,error_message(krb5_errno));
9006         return;
9007     }
9008     if (!cred->times.starttime)
9009         cred->times.starttime = cred->times.authtime;
9010
9011     printtime(cred->times.starttime);
9012     printf("  ");
9013
9014     if ( time(0) < cred->times.endtime )
9015         printtime(cred->times.endtime);
9016     else
9017         printf("** expired ** ");
9018
9019     printf("  %s\r\n", sname);
9020
9021     if (strcmp(name, defname)) {
9022         printf("   for client %s", name);
9023         extra_field++;
9024     }
9025
9026     if (cred->times.renew_till) {
9027         if (!extra_field)
9028             printf("   ");
9029         else
9030             printf(", ");
9031         printf("renew until ");
9032         printtime(cred->times.renew_till);
9033         extra_field += 2;
9034     }
9035
9036     if (extra_field > 3) {
9037         printf("\r\n");
9038         extra_field = 0;
9039     }
9040
9041     if (show_flags) {
9042         flags = flags_string(cred);
9043         if (flags && *flags) {
9044             if (!extra_field)
9045                 printf("   ");
9046             else
9047                 printf(", ");
9048             printf("Flags: %s", flags);
9049             extra_field++;
9050         }
9051     }
9052
9053     if (extra_field > 2) {
9054         printf("\r\n");
9055         extra_field = 0;
9056     }
9057
9058     if (show_etype) {
9059         retval = decode_krb5_ticket(&cred->ticket, &tkt);
9060         if (!extra_field)
9061             printf("   ");
9062         else
9063             printf(", ");
9064 #ifdef HEIMDAL
9065         printf("Etype (skey, tkt): %s, %s ",
9066                etype_string(cred->session.keytype),
9067                etype_string(tkt->enc_part.keytype));
9068 #else /* HEIMDAL */
9069         printf("Etype (skey, tkt): %s, %s ",
9070                etype_string(cred->keyblock.enctype),
9071                etype_string(tkt->enc_part.enctype));
9072 #endif /* HEIMDAL */
9073         krb5_free_ticket(kcontext, tkt);
9074         extra_field++;
9075     }
9076
9077     /* if any additional info was printed, extra_field is non-zero */
9078     if (extra_field)
9079         printf("\r\n");
9080
9081     if ( show_addr ) {
9082         if (!cred->addresses || !cred->addresses[0]) {
9083             printf("\tAddresses: (none)\r\n");
9084         } else {
9085             int i;
9086             for (i=0; cred->addresses[i]; i++) {
9087                 if (i)
9088                     printf("              ");
9089                 else
9090                     printf("   Addresses: ");
9091                 one_addr(cred->addresses[i]);
9092                 printf("\r\n");
9093             }
9094         }
9095     }
9096
9097     krb5_free_unparsed_name(kcontext,name);
9098     krb5_free_unparsed_name(kcontext,sname);
9099
9100     krb5_errno = 0;
9101     makestr(&krb5_errmsg,"OK");
9102 }
9103
9104 static VOID
9105 #ifdef CK_ANSIC
9106 fillit(int num, int c)
9107 #else
9108 fillit(num, c) int num; int c;
9109 #endif
9110 {
9111     int i;
9112
9113     for (i=0; i<num; i++)
9114         printf("%c",c);
9115 }
9116 #endif /* KLIST */
9117 #endif /* KRB5 */
9118
9119 #ifdef KRB4
9120 #define KDEBUG 1
9121 int k4debug = 0;                /* Kerberos 4 runtime debugging */
9122
9123 #ifdef KINIT
9124 #define KRB_DEFAULT_LIFE 120 /* 10 hours in 5 minute intervals */
9125
9126 #ifdef SNK4
9127 /* SNK4 is a hardware authentication system used to pre-authenticate    */
9128 /* a ticket getting ticket.  We do not support this code at the present */
9129 /* time in Kermit.                                                      */
9130 void
9131 get_input(s, size, stream)
9132 char *s;
9133 int size;
9134 FILE *stream;
9135 {
9136     char *p;
9137
9138     if (fgets(s, size, stream) == NULL)
9139         exit(1);
9140     if ( (p = strchr(s, '\n')) != NULL)
9141         *p = '\0';
9142 }
9143 #endif /* SNK4 */
9144
9145 #ifdef COMMENT
9146 static char
9147 #ifdef CK_ANSIC
9148 hex_scan_nybble(char c)
9149 #else
9150 hex_scan_nybble(c) char c;
9151 #endif
9152 {
9153     if (c >= '0' && c <= '9')
9154         return c - '0';
9155     if (c >= 'A' && c <= 'F')
9156         return c - 'A' + 10;
9157     if (c >= 'a' && c <= 'f')
9158         return c - 'a' + 10;
9159     return -1;
9160 }
9161
9162 /* returns: NULL for ok, pointer to error string for bad input */
9163 static char*
9164 #ifdef CK_ANSIC
9165 hex_scan_four_bytes(char *out, char *in)
9166 #else
9167 hex_scan_four_bytes(out, in) char *out; char *in;
9168 #endif
9169 {
9170     int i;
9171     int c;
9172     char c1;
9173     for (i=0; i<8; i++) {
9174         if(!in[i])
9175             return "not enough input";
9176         c = hex_scan_nybble(in[i]);
9177         if(c<0)
9178             return "invalid digit";
9179         c1 = c;
9180         i++;
9181         if(!in[i])
9182             return "not enough input";
9183         c = hex_scan_nybble(in[i]);
9184         if(c<0)
9185             return "invalid digit";
9186         *out++ = (c1 << 4) + c;
9187     }
9188     switch(in[i]) {
9189     case 0:
9190     case '\r':
9191     case '\n':
9192         return NULL;
9193     default:
9194         return "extra characters at end of input";
9195     }
9196 }
9197 #endif /* COMMENT */
9198
9199 /* ck_krb4_initTGT() returns 0 on success */
9200 int
9201 #ifdef CK_ANSIC
9202 ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init)
9203 #else
9204 ck_krb4_initTGT(op,init)
9205     struct krb_op_data * op, struct krb4_init_data * init
9206 #endif
9207 {
9208     char    aname[ANAME_SZ+1];
9209     char    inst[INST_SZ+1];
9210     char    realm[REALM_SZ+1];
9211     char    *password=NULL;
9212     char    passwd[80]="";
9213     char    *username = NULL;
9214     char    *usernameptr=NULL;
9215     int     iflag,      /* Instance */
9216             rflag,      /* Realm */
9217             vflag,      /* Verbose */
9218             lflag,      /* Lifetime */
9219             pflag,      /* Preauth */
9220             lifetime=KRB_DEFAULT_LIFE,   /* Life Time */
9221             k_errno;
9222     register char *cp;
9223     register i;
9224
9225     if ( !ck_krb4_is_installed() )
9226         return(-1);
9227
9228     *inst = *realm = '\0';
9229     iflag = rflag = vflag = lflag = pflag = 0;
9230
9231     vflag = init->verbose;
9232     pflag = init->preauth;
9233
9234     if ( init->lifetime ) {
9235         lifetime = init->lifetime<5?1:init->lifetime/5;
9236         if ( lifetime > 255 ) lifetime = 255;
9237     }
9238     else
9239         lifetime = KRB_DEFAULT_LIFE;
9240
9241     username = init->principal;
9242
9243     if (username && username[0] &&
9244         (k_errno = kname_parse(aname, inst, realm, username))
9245         != AUTH_SUCCESS) {
9246         krb4_errno = k_errno;
9247         makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9248         printf("%s\r\n", krb_get_err_text_entry(k_errno));
9249         iflag = rflag = 1;
9250         username = NULL;
9251     }
9252
9253     if ( init->realm ) {
9254         ckstrncpy(realm,init->realm,REALM_SZ);
9255     }
9256
9257     if ( init->instance ) {
9258         ckstrncpy(inst,init->instance, INST_SZ);
9259     }
9260
9261 #ifdef COMMENT
9262     if ( vflag )
9263         printf("Kerberos IV initialization\r\n");
9264 #endif /* COMMENT */
9265
9266     if (!username || !username[0]) {
9267         debug(F100,"ck_krb4_initTGT no username specified","",0);
9268         printf("?Invalid principal specified.\r\n");
9269         krb4_errno = -1;
9270         makestr(&krb4_errmsg,"No principal specified");
9271         return(-1);
9272     }
9273     if (!*realm) {
9274         ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ);
9275     }
9276
9277     if ( init->password )
9278         password = init->password;
9279     else {
9280         char prmpt[80];
9281         int ok;
9282
9283         ckmakxmsg(prmpt,sizeof(prmpt),
9284                   "Kerberos 4 Password for ",username,"@",realm,": ",
9285                    NULL,NULL,NULL,NULL,NULL,NULL,NULL);
9286         ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT);
9287         if ( ok )
9288             password = passwd;
9289     }
9290
9291     if (pflag) {
9292         k_errno = krb_get_pw_in_tkt_preauth( aname, inst, realm,
9293                                              "krbtgt", realm,
9294                                              lifetime,
9295                                              password);
9296         if (k_errno == -1) {    /* preauth method not available */
9297             k_errno = krb_get_pw_in_tkt(aname,
9298                                          inst, realm,
9299                                          "krbtgt", realm,
9300                                          lifetime,
9301                                          password);
9302         }
9303     } else {
9304         k_errno = krb_get_pw_in_tkt(aname,
9305                                      inst, realm,
9306                                      "krbtgt", realm,
9307                                      lifetime,
9308                                      password);
9309     }
9310
9311     memset(passwd,0,sizeof(passwd));
9312     if (k_errno) {
9313         printf("%s for principal %s%s%s@%s\r\n",
9314                 krb_get_err_text_entry(k_errno), aname,
9315                 inst[0]?".":"", inst, realm);
9316         krb4_errno = k_errno;
9317         makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9318         return(-1);
9319     } else if (vflag) {
9320         printf("Result from realm %s: ", realm);
9321         printf("%s\r\n", krb_get_err_text_entry(k_errno));
9322     }
9323     krb4_errno = k_errno;
9324     makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9325     return(0);
9326 }
9327 #endif /* KINIT */
9328 #ifdef KDESTROY
9329 int
9330 #ifdef CK_ANSIC
9331 ck_krb4_destroy(struct krb_op_data * op)
9332 #else
9333 ck_krb4_destroy(op) struct krb_op_data * op;
9334 #endif
9335 {
9336     int k_errno=0;
9337
9338     if ( !ck_krb4_is_installed() )
9339         return(-1);
9340
9341     k_errno = dest_tkt();
9342
9343     krb4_errno = k_errno;
9344     makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9345
9346     if (k_errno == 0)
9347         printf("Tickets destroyed.\r\n");
9348     else if (k_errno == RET_TKFIL)
9349         printf("No tickets to destroy.\r\n");
9350     else {
9351         printf("Tickets MAY NOT be destroyed.\r\n");
9352         return(-1);
9353     }
9354     return(0);
9355 }
9356 #endif /* KDESTROY */
9357 #ifdef KLIST
9358 _PROTOTYP(static int display_tktfile,(char *, int, int, int));
9359
9360 int
9361 #ifdef CK_ANSIC
9362 ck_krb4_list_creds(struct krb_op_data * op)
9363 #else
9364 ck_krb4_list_creds(op) struct krb_op_data * op;
9365 #endif
9366 {
9367     int     long_form = 1;
9368     int     tgt_test = 0;
9369     int     do_srvtab = 0;
9370     int     show_kvnos = 0;
9371     char   *tkt_file = NULL;
9372
9373     if ( !ck_krb4_is_installed() )
9374         return(-1);
9375
9376     if ( op->cache )
9377         tkt_file = op->cache;
9378
9379     if ( k4debug ) {
9380         show_kvnos = 1;
9381     }
9382
9383     if (do_srvtab)
9384         return(display_srvtab(tkt_file));
9385     else
9386         return(display_tktfile(tkt_file, tgt_test, long_form, show_kvnos));
9387 }
9388
9389 #ifndef KRB5
9390 static int timestamp_width=0;
9391
9392 static char   *
9393 #ifdef CK_ANSIC
9394 short_date(long   *dp)
9395 #else
9396 short_date(dp) long   *dp;
9397 #endif
9398 {
9399     register char *cp;
9400     extern char *ctime();
9401     cp = ctime(dp) + 4;
9402     cp[15] = '\0';
9403     return (cp);
9404 }
9405
9406
9407 static VOID
9408 #ifdef CK_ANSIC
9409 printtime(time_t tv)
9410 #else
9411 printtime(tv) time_t tv;
9412 #endif
9413 {
9414     char timestring[BUFSIZ];
9415     char format[12];
9416     char fill;
9417
9418     fill = ' ';
9419     sprintf(format,"%%-%ds",timestamp_width);   /* safe */
9420     printf(format,short_date(&tv));
9421 }
9422 #endif /* KRB5 */
9423
9424 static int
9425 #ifdef CK_ANSIC
9426 display_tktfile(char *file, int tgt_test, int long_form, int show_kvnos)
9427 #else
9428 display_tktfile(file,tgt_test,long_form,show_kvnos)
9429     char *file; int tgt_test; int long_form; int show_kvnos;
9430 #endif
9431 {
9432     char    pname[ANAME_SZ];
9433     char    pinst[INST_SZ];
9434     char    prealm[REALM_SZ];
9435     char    buf1[20], buf2[20];
9436     int     k_errno;
9437 #ifdef OS2
9438     LEASH_CREDENTIALS creds;
9439 #else /* OS2 */
9440     CREDENTIALS creds;
9441 #endif /* OS2 */
9442     int     header = 1;
9443
9444     file = tkt_string();
9445
9446     if (long_form) {
9447         printf("Ticket cache:      %s\r\n", file);
9448     }
9449
9450     /*
9451      * Since krb_get_tf_realm will return a ticket_file error,
9452      * we will call tf_init and tf_close first to filter out
9453      * things like no ticket file.  Otherwise, the error that
9454      * the user would see would be
9455      * klist: can't find realm of ticket file: No ticket file (tf_util)
9456      * instead of
9457      * klist: No ticket file (tf_util)
9458      */
9459
9460     /* Open ticket file */
9461     if (k_errno = tf_init(file, R_TKT_FIL)) {
9462         if (!tgt_test)
9463             printf("%s\r\n", krb_get_err_text_entry (k_errno));
9464         krb4_errno = k_errno;
9465         makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9466         return(-1);
9467     }
9468
9469
9470     /* Close ticket file */
9471     (void) tf_close();
9472
9473     /*
9474      * We must find the realm of the ticket file here before calling
9475      * tf_init because since the realm of the ticket file is not
9476      * really stored in the principal section of the file, the
9477      * routine we use must itself call tf_init and tf_close.
9478      */
9479     if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
9480         if (!tgt_test)
9481             printf("can't find realm of ticket file: %s\r\n",
9482                     krb_get_err_text_entry (k_errno));
9483         krb4_errno = k_errno;
9484         makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9485         return(-1);
9486     }
9487
9488     /* Open ticket file */
9489     if (k_errno = tf_init(file, R_TKT_FIL)) {
9490         if (!tgt_test)
9491             printf("%s\r\n", krb_get_err_text_entry (k_errno));
9492         krb4_errno = k_errno;
9493         makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9494         return(-1);
9495     }
9496     /* Get principal name and instance */
9497     if ((k_errno = tf_get_pname(pname)) ||
9498          (k_errno = tf_get_pinst(pinst))) {
9499         (void) tf_close();
9500         if (!tgt_test)
9501             printf("%s\r\n", krb_get_err_text_entry (k_errno));
9502         krb4_errno = k_errno;
9503         makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9504         return(-1);
9505     }
9506
9507     /*
9508      * You may think that this is the obvious place to get the
9509      * realm of the ticket file, but it can't be done here as the
9510      * routine to do this must open the ticket file.  This is why
9511      * it was done before tf_init.
9512      */
9513
9514     if (!tgt_test && long_form)
9515         printf("Default principal: %s%s%s%s%s\r\n\r\n", pname,
9516                (pinst[0] ? "." : ""), pinst,
9517                (prealm[0] ? "@" : ""), prealm);
9518
9519     while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
9520         if (!tgt_test && long_form && header) {
9521             printf("%-17s  %-17s  %s\r\n",
9522                    "Valid starting", "Expires", "Service principal");
9523             header = 0;
9524         }
9525         if (tgt_test) {
9526             creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60;
9527             if (!strcmp(creds.service, "krbtgt") &&
9528                 !strcmp(creds.instance, prealm)) {
9529                 krb4_errno = k_errno;
9530                 makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9531
9532                 (void) tf_close();
9533                 if (time(0) < creds.issue_date) {
9534                     return(0);          /* tgt hasn't expired */
9535                 } else {
9536                     return(-1);         /* has expired */
9537                 }
9538             }
9539             continue;                   /* not a tgt */
9540         }
9541         if (long_form) {
9542             timestamp_width = 17;       /* for k5 display function */
9543                                         /* if available            */
9544             printtime(creds.issue_date);
9545             printf("  ");
9546             creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60;
9547             if ( time(0) < creds.issue_date )
9548                 printtime(creds.issue_date);
9549             else
9550                 printf("*** expired ***  ");
9551             printf("  ");
9552         }
9553         if (show_kvnos)
9554           printf("%s%s%s%s%s (%d)\r\n",
9555                  creds.service, (creds.instance[0] ? "." : ""), creds.instance,
9556                  (creds.realm[0] ? "@" : ""), creds.realm, creds.kvno);
9557         else
9558           printf("%s%s%s%s%s\r\n",
9559                  creds.service, (creds.instance[0] ? "." : ""), creds.instance,
9560                  (creds.realm[0] ? "@" : ""), creds.realm);
9561
9562 #ifdef OS2
9563         if ( creds.address[0] )
9564             printf("   Address: %s\r\n",creds.address);
9565 #endif /* OS2 */
9566     }
9567
9568     (void) tf_close();
9569
9570     if (tgt_test) {
9571         return(-1);
9572     }/* no tgt found */
9573     if (header && long_form && k_errno == EOF) {
9574         printf("No tickets in file.\r\n");
9575     }
9576     krb4_errno = k_errno;
9577     makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
9578     return(0);
9579 }
9580
9581 #ifdef COMMENT
9582 /* Just so we remember what the command line interface looked like */
9583 usage()
9584 {
9585     printf(
9586         "Usage: [ -s | -t ] [ -file filename ] [ -srvtab ] [ -version ]\r\n");
9587     return(-1);
9588 }
9589 #endif /* COMMENT */
9590
9591 /* adapted from getst() in librkb */
9592 /*
9593  * ok_getst() takes a file descriptor, a string and a count.  It reads
9594  * from the file until either it has read "count" characters, or until
9595  * it reads a null byte.  When finished, what has been read exists in
9596  * the given string "s".  If "count" characters were actually read, the
9597  * last is changed to a null, so the returned string is always null-
9598  * terminated.  ok_getst() returns the number of characters read, including
9599  * the null terminator.
9600  *
9601  * If there is a read error, it returns -1 (like the read(2) system call)
9602  */
9603
9604 static int
9605 #ifdef CK_ANSIC
9606 ok_getst(int fd, register char *s, int n)
9607 #else
9608 ok_getst(fd, s, n) int fd; register char *s; int n;
9609 #endif
9610 {
9611     register int count = n;
9612     int err;
9613     while ((err = read(fd, s, 1)) > 0 && --count)
9614         if (*s++ == '\0')
9615             return (n - count);
9616     if (err < 0)
9617         return(-1);
9618     *s = '\0';
9619     return (n - count);
9620 }
9621
9622 int
9623 #ifdef CK_ANSIC
9624 display_srvtab(char *file)
9625 #else
9626 display_srvtab(file) char *file;
9627 #endif
9628 {
9629     int stab;
9630     char serv[SNAME_SZ];
9631     char inst[INST_SZ];
9632     char rlm[REALM_SZ];
9633     unsigned char key[8];
9634     unsigned char vno;
9635     int count;
9636
9637     printf("Server key file:   %s\r\n", file);
9638 #ifdef NT
9639 #ifndef O_RDONLY
9640 #define O_RDONLY _O_RDONLY
9641 #endif /* O_RDONLY */
9642 #endif /* NT */
9643
9644     if ((stab = open(file, O_RDONLY, 0400)) < 0) {
9645         perror(file);
9646         return(-1);
9647     }
9648     printf("%-15s %-15s %-10s %s\r\n","Service","Instance","Realm",
9649            "Key Version");
9650     printf("------------------------------------------------------\r\n");
9651
9652     /* argh. getst doesn't return error codes, it silently fails */
9653     while (((count = ok_getst(stab, serv, SNAME_SZ)) > 0)
9654            && ((count = ok_getst(stab, inst, INST_SZ)) > 0)
9655            && ((count = ok_getst(stab, rlm, REALM_SZ)) > 0)) {
9656         if (((count = read(stab,(char *) &vno,1)) != 1) ||
9657              ((count = read(stab,(char *) key,8)) != 8)) {
9658             if (count < 0)
9659                 perror("reading from key file");
9660             else
9661                 printf("key file truncated\r\n");
9662             return(-1);
9663         }
9664         printf("%-15s %-15s %-15s %d\r\n",serv,inst,rlm,vno);
9665     }
9666     if (count < 0)
9667         perror(file);
9668     (void) close(stab);
9669     return(0);
9670 }
9671 #endif /* KLIST */
9672 #else /* KRB4 */
9673 int
9674 ck_krb4_autoget_TGT(char * dummy)
9675 {
9676     return(-1);
9677 }
9678 #ifdef CK_KERBEROS
9679 int
9680 #ifdef CK_ANSIC
9681 ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init)
9682 #else
9683 ck_krb4_initTGT(op,init)
9684     struct krb_op_data * op, struct krb4_init_data * init
9685 #endif
9686 {
9687     return(-1);
9688 }
9689
9690 #ifdef CK_ANSIC
9691 ck_krb4_destroy(struct krb_op_data * op)
9692 #else
9693 ck_krb4_destroy(op) struct krb_op_data * op;
9694 #endif
9695 {
9696     return(-1);
9697 }
9698 int
9699 #ifdef CK_ANSIC
9700 ck_krb4_list_creds(struct krb_op_data * op)
9701 #else
9702 ck_krb4_list_creds(op) struct krb_op_data * op;
9703 #endif
9704 {
9705     return(-1);
9706 }
9707 #else /* CK_KERBEROS */
9708 int ck_krb4_initTGT(void * a, void *b)
9709 {
9710     return(-1);
9711 }
9712 int ck_krb4_destroy(void *a)
9713 {
9714     return(-1);
9715 }
9716 int ck_krb4_list_creds(void *a)
9717 {
9718     return(-1);
9719 }
9720 #endif /* CK_KERBEROS */
9721 #endif /* KRB4 */
9722
9723 /* The following functions are used to implement the Kermit Script Language */
9724 /* functions                                                                */
9725
9726 struct tkt_list_item {
9727     char * name;
9728     struct tkt_list_item * next;
9729 };
9730
9731 static struct tkt_list_item * k4_tkt_list = NULL;
9732
9733 int
9734 #ifdef CK_ANSIC
9735 ck_krb4_get_tkts(VOID)
9736 #else
9737 ck_krb4_get_tkts()
9738 #endif
9739 {
9740 #ifdef KRB4
9741     char   *file=NULL;
9742     char    pname[ANAME_SZ];
9743     char    pinst[INST_SZ];
9744     char    prealm[REALM_SZ];
9745     char    buf1[20], buf2[20];
9746     int     k_errno;
9747 #ifdef OS2
9748     LEASH_CREDENTIALS creds;
9749 #else /* OS2 */
9750     CREDENTIALS creds;
9751 #endif /* OS2 */
9752     int     tkt_count=0;
9753     struct  tkt_list_item ** list = &k4_tkt_list;
9754
9755     while ( k4_tkt_list ) {
9756         struct tkt_list_item * next;
9757         next = k4_tkt_list->next;
9758         free(k4_tkt_list->name);
9759         free(k4_tkt_list);
9760         k4_tkt_list = next;
9761     }
9762
9763     if ( !ck_krb4_is_installed() )
9764         return(-1);
9765
9766     file = tkt_string();
9767
9768     /*
9769      * Since krb_get_tf_realm will return a ticket_file error,
9770      * we will call tf_init and tf_close first to filter out
9771      * things like no ticket file.  Otherwise, the error that
9772      * the user would see would be
9773      * klist: can't find realm of ticket file: No ticket file (tf_util)
9774      * instead of
9775      * klist: No ticket file (tf_util)
9776      */
9777
9778     /* Open ticket file */
9779     if (k_errno = tf_init(file, R_TKT_FIL)) {
9780         return(-1);
9781     }
9782
9783     /* Close ticket file */
9784     (void) tf_close();
9785
9786     /*
9787      * We must find the realm of the ticket file here before calling
9788      * tf_init because since the realm of the ticket file is not
9789      * really stored in the principal section of the file, the
9790      * routine we use must itself call tf_init and tf_close.
9791      */
9792     if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
9793         return(-1);
9794     }
9795
9796     /* Open ticket file */
9797     if (k_errno = tf_init(file, R_TKT_FIL)) {
9798         return(-1);
9799     }
9800     /* Get principal name and instance */
9801     if ((k_errno = tf_get_pname(pname)) ||
9802          (k_errno = tf_get_pinst(pinst))) {
9803         return(-1);
9804     }
9805
9806     /*
9807      * You may think that this is the obvious place to get the
9808      * realm of the ticket file, but it can't be done here as the
9809      * routine to do this must open the ticket file.  This is why
9810      * it was done before tf_init.
9811      */
9812
9813     while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
9814         char tkt_buf[256];
9815         ckmakxmsg(tkt_buf,sizeof(tkt_buf),
9816                  creds.service, (creds.instance[0] ? "." : ""), creds.instance,
9817                  (creds.realm[0] ? "@" : ""), creds.realm,
9818                  NULL,NULL,NULL,NULL,NULL,NULL,NULL);
9819         *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item));
9820         (*list)->name = strdup(tkt_buf);
9821         (*list)->next = NULL;
9822         list = &((*list)->next);
9823         tkt_count++;
9824     }
9825
9826     tf_close();
9827     return(tkt_count);
9828 #else /* KRB4 */
9829     return(0);
9830 #endif /* KRB4 */
9831 }
9832
9833 char *
9834 #ifdef CK_ANSIC
9835 ck_krb4_get_next_tkt(VOID)
9836 #else
9837 ck_krb4_get_next_tkt()
9838 #endif
9839 {
9840 #ifdef KRB4
9841     static char * s=NULL;
9842     struct tkt_list_item * next=NULL;
9843
9844     if ( s ) {
9845         free(s);
9846         s = NULL;
9847     }
9848
9849     if ( k4_tkt_list == NULL )
9850         return(NULL);
9851
9852     next = k4_tkt_list->next;
9853     s = k4_tkt_list->name;
9854     free(k4_tkt_list);
9855     k4_tkt_list = next;
9856     return(s);
9857 #else /* KRB4 */
9858     return(NULL);
9859 #endif /* KRB4 */
9860 }
9861
9862 int
9863 #ifdef CK_ANSIC
9864 ck_krb4_tkt_isvalid(char * tktname)
9865 #else
9866 ck_krb4_tkt_isvalid(tktname) char * tktname;
9867 #endif
9868 {
9869 #ifdef KRB4
9870     char   *file=NULL;
9871     char    pname[ANAME_SZ];
9872     char    pinst[INST_SZ];
9873     char    prealm[REALM_SZ];
9874     char    buf1[20], buf2[20];
9875     int     k_errno;
9876     time_t  issue_t, expire_t, now_t;
9877 #ifdef OS2
9878     LEASH_CREDENTIALS creds;
9879 #else /* OS2 */
9880     CREDENTIALS creds;
9881 #endif /* OS2 */
9882
9883     if ( !ck_krb4_is_installed() )
9884         return(-1);
9885
9886     debug(F110,"ck_krb4_tkt_isvalid","tkt_string",0);
9887     file = tkt_string();
9888
9889     /*
9890      * Since krb_get_tf_realm will return a ticket_file error,
9891      * we will call tf_init and tf_close first to filter out
9892      * things like no ticket file.  Otherwise, the error that
9893      * the user would see would be
9894      * klist: can't find realm of ticket file: No ticket file (tf_util)
9895      * instead of
9896      * klist: No ticket file (tf_util)
9897      */
9898
9899     /* Open ticket file */
9900     debug(F110,"ck_krb4_tkt_isvalid","tf_init",0);
9901     if (k_errno = tf_init(file, R_TKT_FIL)) {
9902         return(-1);
9903     }
9904
9905     /* Close ticket file */
9906     debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
9907     (void) tf_close();
9908
9909     /*
9910      * We must find the realm of the ticket file here before calling
9911      * tf_init because since the realm of the ticket file is not
9912      * really stored in the principal section of the file, the
9913      * routine we use must itself call tf_init and tf_close.
9914      */
9915     debug(F110,"ck_krb4_tkt_isvalid","krb_get_tf_realm",0);
9916     if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
9917         return(-1);
9918     }
9919
9920     /* Open ticket file */
9921     debug(F110,"ck_krb4_tkt_isvalid","tf_init",0);
9922     if (k_errno = tf_init(file, R_TKT_FIL)) {
9923         return(-1);
9924     }
9925     /* Get principal name and instance */
9926     debug(F110,"ck_krb4_tkt_isvalid","tf_get_name/tf_get_pinst",0);
9927     if ((k_errno = tf_get_pname(pname)) ||
9928          (k_errno = tf_get_pinst(pinst))) {
9929
9930         /* Close ticket file */
9931         debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
9932         (void) tf_close();
9933
9934         return(-1);
9935     }
9936
9937     /*
9938      * You may think that this is the obvious place to get the
9939      * realm of the ticket file, but it can't be done here as the
9940      * routine to do this must open the ticket file.  This is why
9941      * it was done before tf_init.
9942      */
9943
9944     debug(F110,"ck_krb4_tkt_isvalid","tf_get_cred",0);
9945     while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
9946         char tkt_buf[256];
9947         ckmakxmsg(tkt_buf,sizeof(tkt_buf),
9948                  creds.service, (creds.instance[0] ? "." : ""), creds.instance,
9949                  (creds.realm[0] ? "@" : ""), creds.realm,
9950                  NULL,NULL,NULL,NULL,NULL,NULL,NULL);
9951         if ( !strcmp(tktname,tkt_buf) ) {
9952
9953             /* we found the ticket we are looking for */
9954             issue_t = creds.issue_date;
9955             expire_t = creds.issue_date
9956                 + ((unsigned char) creds.lifetime) * 5 * 60;
9957             now_t = time(0);
9958
9959             /* We add a 5 minutes fudge factor to compensate for potential */
9960             /* clock skew errors between the KDC and K95's host OS         */
9961
9962             if ( now_t >= (issue_t-300) && now_t < expire_t) {
9963 #ifdef OS2
9964 #ifdef CHECKADDRS
9965                 if ( krb4_checkaddrs ) {
9966                     extern char myipaddr[20];       /* From ckcnet.c */
9967                     if ( !myipaddr[0] ) {
9968                         int i;
9969                         char buf[60];
9970                         for ( i=0;i<64;i++ ) {
9971                             if ( getlocalipaddrs(buf,60,i) < 0 )
9972                                 break;
9973
9974                             if ( !strcmp(buf,creds.address) ) {
9975                                 /* Close ticket file */
9976                                 debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
9977                                 (void) tf_close();
9978                                 return(1); /* They're the same */
9979                             }
9980                         }
9981
9982                         /* Close ticket file */
9983                         debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
9984                         (void) tf_close();
9985                         return(0);                  /* They're different */
9986                     } else if ( strcmp(myipaddr,creds.address) ) {
9987                         /* Close ticket file */
9988                         debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
9989                         (void) tf_close();
9990                         return(0);                  /* They're different */
9991                     }
9992                     else {
9993                         /* Close ticket file */
9994                         debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
9995                         (void) tf_close();
9996                         return(1);                  /* They're the same */
9997                     }
9998                 } else {
9999                     /* Close ticket file */
10000                     debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
10001                     (void) tf_close();
10002                     return(1);                  /* They're the same */
10003                 }
10004 #else /* CHECKADDRS */
10005                 /* Close ticket file */
10006                 debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
10007                 (void) tf_close();
10008                 return(1);      /* valid but no ip address check */
10009 #endif /* CHECKADDRS */
10010 #else /* OS2 */
10011                 /* Close ticket file */
10012                 debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
10013                 (void) tf_close();
10014                 return(1);      /* Valid but no ip address check */
10015 #endif /* OS2 */
10016             }
10017             else {
10018                 /* Close ticket file */
10019                 debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
10020                 (void) tf_close();
10021                 return(0);      /* expired or otherwise invalid */
10022             }
10023         }
10024     }
10025     /* Close ticket file */
10026     debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
10027     (void) tf_close();
10028     return(0);                  /* could not find the desired ticket */
10029 #else /* KRB4 */
10030     return(-1);
10031 #endif /* KRB4 */
10032 }
10033
10034 int
10035 #ifdef CK_ANSIC
10036 ck_krb4_is_tgt_valid(VOID)
10037 #else
10038 ck_krb4_is_tgt_valid()
10039 #endif
10040 {
10041 #ifdef KRB4
10042     char tgt[256];
10043     char * s;
10044     int rc = 0;
10045
10046     s = krb4_d_realm ? krb4_d_realm : ck_krb4_getrealm();
10047     ckmakmsg(tgt,sizeof(tgt),"krbtgt.",s,"@",s);
10048     rc = ck_krb4_tkt_isvalid(tgt);
10049     debug(F111,"ck_krb4_is_tgt_valid",tgt,rc);
10050     return(rc > 0);
10051 #else /* KRB4 */
10052     return(0);
10053 #endif /* KRB4 */
10054 }
10055
10056 int
10057 #ifdef CK_ANSIC
10058 ck_krb4_tkt_time(char * tktname)
10059 #else
10060 ck_krb4_tkt_time(tktname) char * tktname;
10061 #endif
10062 {
10063 #ifdef KRB4
10064     char   *file=NULL;
10065     char    pname[ANAME_SZ];
10066     char    pinst[INST_SZ];
10067     char    prealm[REALM_SZ];
10068     char    buf1[20], buf2[20];
10069     int     k_errno;
10070 #ifdef OS2
10071     LEASH_CREDENTIALS creds;
10072 #else /* OS2 */
10073     CREDENTIALS creds;
10074 #endif /* OS2 */
10075
10076     if ( !ck_krb4_is_installed() )
10077         return(-1);
10078
10079     file = tkt_string();
10080
10081     /*
10082      * Since krb_get_tf_realm will return a ticket_file error,
10083      * we will call tf_init and tf_close first to filter out
10084      * things like no ticket file.  Otherwise, the error that
10085      * the user would see would be
10086      * klist: can't find realm of ticket file: No ticket file (tf_util)
10087      * instead of
10088      * klist: No ticket file (tf_util)
10089      */
10090
10091     /* Open ticket file */
10092     if (k_errno = tf_init(file, R_TKT_FIL)) {
10093         return(-1);
10094     }
10095
10096     /* Close ticket file */
10097     (void) tf_close();
10098
10099     /*
10100      * We must find the realm of the ticket file here before calling
10101      * tf_init because since the realm of the ticket file is not
10102      * really stored in the principal section of the file, the
10103      * routine we use must itself call tf_init and tf_close.
10104      */
10105     if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
10106         return(-1);
10107     }
10108
10109     /* Open ticket file */
10110     if (k_errno = tf_init(file, R_TKT_FIL)) {
10111         return(-1);
10112     }
10113     /* Get principal name and instance */
10114     if ((k_errno = tf_get_pname(pname)) ||
10115          (k_errno = tf_get_pinst(pinst))) {
10116         tf_close();
10117         return(-1);
10118     }
10119
10120     /*
10121      * You may think that this is the obvious place to get the
10122      * realm of the ticket file, but it can't be done here as the
10123      * routine to do this must open the ticket file.  This is why
10124      * it was done before tf_init.
10125      */
10126
10127     while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
10128         char tkt_buf[256];
10129         ckmakxmsg(tkt_buf,sizeof(tkt_buf),
10130                  creds.service, (creds.instance[0] ? "." : ""),
10131                  creds.instance,
10132                  (creds.realm[0] ? "@" : ""), creds.realm,
10133                  NULL,NULL,NULL,NULL,NULL,NULL,NULL);
10134         if ( !strcmp(tktname,tkt_buf) ) {
10135             /* we found the ticket we are looking for */
10136             int n = (creds.issue_date
10137                       + (((unsigned char) creds.lifetime) * 5 * 60))
10138                 - time(0);
10139             tf_close();
10140             return(n <= 0 ? 0 : n);
10141         }
10142     }
10143     tf_close();
10144     return(0);                  /* could not find the desired ticket */
10145 #else /* KRB4 */
10146     return(-1);
10147 #endif /* KRB4 */
10148 }
10149
10150 char *
10151 #ifdef CK_ANSIC
10152 ck_krb4_getrealm(void)
10153 #else
10154 ck_krb4_getrealm()
10155 #endif
10156 {
10157 #ifdef KRB4
10158     char   *file=NULL;
10159     int     k_errno;
10160     static char realm[256]="";
10161     realm[0]='\0';
10162
10163     if ( !ck_krb4_is_installed() )
10164         return(realm);
10165
10166     /* Try to get realm from ticket file */
10167     /* If failure get the local realm    */
10168
10169     /*
10170     * Since krb_get_tf_realm will return a ticket_file error,
10171     * we will call tf_init and tf_close first to filter out
10172     * things like no ticket file.
10173     */
10174
10175     /* Open ticket file */
10176     file = tkt_string();
10177     if (file == NULL || !file[0])
10178         return(realm);
10179
10180     if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) {
10181         /* Close ticket file */
10182         (void) tf_close();
10183
10184         k_errno = krb_get_tf_realm(file, realm);
10185     }
10186     if (k_errno != KSUCCESS) {
10187         k_errno = krb_get_lrealm(realm, 1);
10188     }
10189     return(realm);
10190 #else /* KRB4 */
10191     return("");
10192 #endif /* KRB4 */
10193 }
10194
10195 char *
10196 #ifdef CK_ANSIC
10197 ck_krb4_getprincipal(void)
10198 #else
10199 ck_krb4_getprincipal()
10200 #endif
10201 {
10202 #ifdef KRB4
10203     char   *file=NULL;
10204     int     k_errno;
10205     static char principal[256]="";
10206     char        instance[256]="";
10207     char        realm[256]="";
10208     principal[0]='\0';
10209
10210     if ( !ck_krb4_is_installed() )
10211         return(principal);
10212
10213     /* Try to get realm from ticket file */
10214     /* If failure get the local realm    */
10215
10216     /*
10217     * Since krb_get_tf_realm will return a ticket_file error,
10218     * we will call tf_init and tf_close first to filter out
10219     * things like no ticket file.
10220     */
10221
10222     /* Open ticket file */
10223     file = tkt_string();
10224     if (file == NULL || !file[0])
10225         return(principal);
10226
10227     if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) {
10228         /* Close ticket file */
10229         (void) tf_close();
10230
10231         k_errno = krb_get_tf_fullname(file, principal, instance, realm);
10232     }
10233     return(principal);
10234 #else /* KRB4 */
10235     return("");
10236 #endif /* KRB4 */
10237 }
10238
10239 static struct tkt_list_item * k5_tkt_list = NULL;
10240
10241 int
10242 #ifdef CK_ANSIC
10243 ck_krb5_get_tkts(char * cc_name)
10244 #else
10245 ck_krb5_get_tkts(cc_name) char * cc_name;
10246 #endif
10247 {
10248 #ifdef KRB5
10249 #ifndef HEIMDAL
10250     krb5_context kcontext;
10251     krb5_error_code retval;
10252     krb5_ccache cache = NULL;
10253     krb5_cc_cursor cur;
10254     krb5_creds creds;
10255     krb5_principal princ=NULL;
10256     krb5_flags flags=0;
10257     krb5_error_code code=0;
10258     int exit_status = 0;
10259
10260     int     tkt_count=0;
10261     struct  tkt_list_item ** list = &k5_tkt_list;
10262
10263     while ( k5_tkt_list ) {
10264         struct tkt_list_item * next;
10265         next = k5_tkt_list->next;
10266         free(k5_tkt_list->name);
10267         free(k5_tkt_list);
10268         k5_tkt_list = next;
10269     }
10270
10271     if ( !ck_krb5_is_installed() )
10272         return(-1);
10273
10274     retval = krb5_init_context(&kcontext);
10275     if (retval) {
10276         debug(F101,"ck_krb5_get_tkts while initializing krb5","",retval);
10277         return(-1);
10278     }
10279
10280     code = k5_get_ccache(kcontext,&cache,cc_name);
10281     if (code != 0) {
10282         debug(F111,"ck_krb5_get_tkts while getting ccache",
10283                error_message(code),code);
10284         tkt_count = -1;
10285         goto exit_k5_get_tkt;
10286     }
10287
10288     flags = 0;                          /* turns off OPENCLOSE mode */
10289     if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10290         if (code == ENOENT) {
10291             debug(F111,"ck_krb5_get_tkts (ticket cache)",
10292                    krb5_cc_get_name(kcontext, cache),code);
10293         } else {
10294             debug(F111,
10295                  "ck_krb5_get_tkts while setting cache flags (ticket cache)",
10296                   krb5_cc_get_name(kcontext, cache),code);
10297         }
10298         tkt_count = -1;
10299         goto exit_k5_get_tkt;
10300     }
10301     if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
10302         debug(F101,"ck_krb5_get_tkts while retrieving principal name",
10303                "",code);
10304         tkt_count = -1;
10305         goto exit_k5_get_tkt;
10306     }
10307     if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
10308         debug(F101,"ck_krb5_get_tkts while unparsing principal name",
10309                "",code);
10310         tkt_count = -1;
10311         goto exit_k5_get_tkt;
10312     }
10313
10314     if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
10315         debug(F101,"ck_krb5_get_tkts while starting to retrieve tickets",
10316                "",code);
10317         tkt_count = -1;
10318         goto exit_k5_get_tkt;
10319     }
10320
10321     while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
10322         char *sname=NULL;
10323
10324         retval = krb5_unparse_name(kcontext, creds.server, &sname);
10325         if (retval) {
10326             debug(F101,
10327                   "ck_krb5_get_tkts while unparsing server name","",retval);
10328             tkt_count = -1;
10329             goto exit_k5_get_tkt;
10330         }
10331
10332         *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item));
10333         (*list)->name = sname;
10334         (*list)->next = NULL;
10335         list = &((*list)->next);
10336
10337         krb5_free_unparsed_name(kcontext,sname);
10338         krb5_free_cred_contents(kcontext, &creds);
10339         tkt_count++;
10340     }
10341
10342     if (code == KRB5_CC_END) {
10343         if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
10344             debug(F101,"ck_krb5_get_tkts while finishing ticket retrieval",
10345                    "",code);
10346             tkt_count = -1;
10347             goto exit_k5_get_tkt;
10348         }
10349         flags = KRB5_TC_OPENCLOSE;      /* turns on OPENCLOSE mode */
10350         if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10351             debug(F101,"ck_krb5_get_tkts while closing ccache",
10352                    "",code);
10353             tkt_count = -1;
10354             goto exit_k5_get_tkt;
10355         }
10356     } else {
10357         debug(F101,"ck_krb5_get_tkts while retrieving a ticket","",code);
10358         tkt_count = -1;
10359         goto exit_k5_get_tkt;
10360     }
10361
10362   exit_k5_get_tkt:
10363     krb5_free_principal(kcontext,princ);
10364     krb5_free_unparsed_name(kcontext,defname);
10365     krb5_cc_close(kcontext,cache);
10366     krb5_free_context(kcontext);
10367     return(tkt_count);
10368 #else /* HEIMDAL */
10369     return(-1);
10370 #endif /* HEIMDAL */
10371 #else /* KRB5 */
10372     return(0);
10373 #endif /* KRB5 */
10374 }
10375
10376 char *
10377 #ifdef CK_ANSIC
10378 ck_krb5_get_next_tkt(VOID)
10379 #else
10380 ck_krb5_get_next_tkt()
10381 #endif
10382 {
10383 #ifdef KRB5
10384 #ifndef HEIMDAL
10385     static char * s=NULL;
10386     struct tkt_list_item * next=NULL;
10387
10388     if ( s ) {
10389         free(s);
10390         s = NULL;
10391     }
10392
10393     if ( k5_tkt_list == NULL )
10394         return(NULL);
10395
10396     next = k5_tkt_list->next;
10397     s = k5_tkt_list->name;
10398     free(k5_tkt_list);
10399     k5_tkt_list = next;
10400     return(s);
10401 #else /* HEIMDAL */
10402     return("Not implemented");
10403 #endif /* HEIMDAL */
10404 #else /* KRB5 */
10405     return(NULL);
10406 #endif /* KRB5 */
10407 }
10408
10409 char *
10410 #ifdef CK_ANSIC
10411 ck_krb5_tkt_flags(char * cc_name, char * tktname)
10412 #else
10413 ck_krb5_tkt_flags(cc_name,tktname) char * cc_name; char * tktname;
10414 #endif
10415 {
10416 #ifdef KRB5
10417 #ifndef HEIMDAL
10418     krb5_context kcontext;
10419     krb5_error_code retval;
10420     krb5_ccache cache = NULL;
10421     krb5_cc_cursor cur;
10422     krb5_creds creds;
10423     krb5_principal princ=NULL;
10424     krb5_flags flags=0;
10425     krb5_error_code code=0;
10426     char * flag_str = "";
10427
10428     if ( !ck_krb5_is_installed() )
10429         return("");
10430
10431     retval = krb5_init_context(&kcontext);
10432     if (retval) {
10433         debug(F101,"ck_krb5_tkt_flags while initializing krb5","",retval);
10434         return("");
10435     }
10436
10437     code = k5_get_ccache(kcontext,&cache,cc_name);
10438     if (code != 0) {
10439         debug(F111,"ck_krb5_tkt_isvalid while getting ccache",
10440                error_message(code),code);
10441         goto exit_k5_get_tkt;
10442     }
10443
10444     flags = 0;                          /* turns off OPENCLOSE mode */
10445     if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10446         if (code == ENOENT) {
10447             debug(F111,"ck_krb5_tkt_flags (ticket cache)",
10448                    krb5_cc_get_name(kcontext, cache),code);
10449         } else {
10450             debug(F111,
10451                  "ck_krb5_tkt_flags while setting cache flags (ticket cache)",
10452                   krb5_cc_get_name(kcontext, cache),code);
10453         }
10454         retval = -1;
10455         goto exit_k5_get_tkt;
10456     }
10457     if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
10458         debug(F101,"ck_krb5_tkt_flags while retrieving principal name",
10459                "",code);
10460         retval = -1;
10461         goto exit_k5_get_tkt;
10462     }
10463     if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
10464         debug(F101,"ck_krb5_tkt_flags while unparsing principal name",
10465                "",code);
10466         retval = -1;
10467         goto exit_k5_get_tkt;
10468     }
10469
10470     if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
10471         debug(F101,"ck_krb5_tkt_flags while starting to retrieve tickets",
10472                "",code);
10473         retval = -1;
10474         goto exit_k5_get_tkt;
10475     }
10476
10477     if ((code = krb5_timeofday(kcontext, &now))) {
10478         if (!status_only)
10479             debug(F101,"ck_krb5_tkt_flags while getting time of day.",
10480                    "",code);
10481         retval = -1;
10482         goto exit_k5_get_tkt;
10483     }
10484
10485     while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
10486         char *sname=NULL;
10487
10488         retval = krb5_unparse_name(kcontext, creds.server, &sname);
10489         if (retval) {
10490             debug(F101,
10491                   "ck_krb5_tkt_flags while unparsing server name","",retval);
10492             retval = -1;
10493             krb5_free_cred_contents(kcontext, &creds);
10494             goto exit_k5_get_tkt;
10495         }
10496
10497         if ( !strcmp(sname,tktname) ) {
10498             /* we found the ticket we are looking for */
10499
10500             flag_str = flags_string(&creds);
10501
10502             krb5_free_unparsed_name(kcontext,sname);
10503             krb5_free_cred_contents(kcontext, &creds);
10504             code = KRB5_CC_END;
10505             break;
10506         }
10507         krb5_free_unparsed_name(kcontext,sname);
10508         krb5_free_cred_contents(kcontext, &creds);
10509     }
10510
10511     if (code == KRB5_CC_END) {
10512         if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
10513             debug(F101,"ck_krb5_tkt_flags while finishing ticket retrieval",
10514                    "",code);
10515             goto exit_k5_get_tkt;
10516         }
10517         flags = KRB5_TC_OPENCLOSE;      /* turns on OPENCLOSE mode */
10518         if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10519             debug(F101,"ck_krb5_tkt_flags while closing ccache",
10520                    "",code);
10521             goto exit_k5_get_tkt;
10522         }
10523     } else {
10524         debug(F101,"ck_krb5_tkt_flags while retrieving a ticket","",code);
10525         goto exit_k5_get_tkt;
10526     }
10527
10528   exit_k5_get_tkt:
10529     krb5_free_principal(kcontext,princ);
10530     krb5_free_unparsed_name(kcontext,defname);
10531     krb5_cc_close(kcontext,cache);
10532     krb5_free_context(kcontext);
10533     return(flag_str);
10534 #else /* HEIMDAL */
10535     return("Not implemented");
10536 #endif /* HEIMDAL */
10537 #else /* KRB5 */
10538     return("");
10539 #endif /* KRB5 */
10540 }
10541
10542
10543 int
10544 #ifdef CK_ANSIC
10545 ck_krb5_tkt_isvalid(char * cc_name, char * tktname)
10546 #else
10547 ck_krb5_tkt_isvalid(cc_name,tktname) char * cc_name; char * tktname;
10548 #endif
10549 {
10550 #ifdef KRB5
10551 #ifndef HEIMDAL
10552     krb5_context kcontext=NULL;
10553     krb5_error_code retval;
10554     krb5_ccache cache = NULL;
10555     krb5_cc_cursor cur;
10556     krb5_creds creds;
10557     krb5_principal princ=NULL;
10558     krb5_flags flags=0;
10559     krb5_error_code code=0;
10560 #ifdef CHECKADDRS
10561     krb5_address **     myAddrs=NULL;
10562     krb5_address **     p=NULL;
10563     BOOL                Addrfound = FALSE;
10564 #endif /*CHECKADDRS*/
10565
10566     if ( !ck_krb5_is_installed() )
10567         return(-1);
10568
10569     retval = krb5_init_context(&kcontext);
10570     if (retval) {
10571         debug(F101,"ck_krb5_tkt_isvalid while initializing krb5","",retval);
10572         return(-1);
10573     }
10574
10575     code = k5_get_ccache(kcontext,&cache,cc_name);
10576     if (code != 0) {
10577         debug(F111,"ck_krb5_tkt_isvalid while getting ccache",
10578                error_message(code),code);
10579         goto exit_k5_get_tkt;
10580     }
10581
10582     flags = 0;                          /* turns off OPENCLOSE mode */
10583     if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10584         if (code == ENOENT) {
10585             debug(F111,"ck_krb5_tkt_isvalid (ticket cache)",
10586                    krb5_cc_get_name(kcontext, cache),code);
10587         } else {
10588             debug(F111,
10589                 "ck_krb5_tkt_isvalid while setting cache flags (ticket cache)",
10590                   krb5_cc_get_name(kcontext, cache),code);
10591         }
10592         retval = -1;
10593         goto exit_k5_get_tkt;
10594     }
10595     if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
10596         debug(F101,"ck_krb5_tkt_isvalid while retrieving principal name",
10597                "",code);
10598         retval = -1;
10599         goto exit_k5_get_tkt;
10600     }
10601     if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
10602         debug(F101,"ck_krb5_tkt_isvalid while unparsing principal name",
10603                "",code);
10604         retval = -1;
10605         goto exit_k5_get_tkt;
10606     }
10607
10608     if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
10609         debug(F101,"ck_krb5_tkt_isvalid while starting to retrieve tickets",
10610                "",code);
10611         retval = -1;
10612         goto exit_k5_get_tkt;
10613     }
10614
10615     if ((code = krb5_timeofday(kcontext, &now))) {
10616         if (!status_only)
10617             debug(F101,"ck_krb5_tkt_isvalid while getting time of day.",
10618                    "",code);
10619         retval = -1;
10620         goto exit_k5_get_tkt;
10621     }
10622
10623     while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
10624         char *sname=NULL;
10625
10626         retval = krb5_unparse_name(kcontext, creds.server, &sname);
10627         if (retval) {
10628             debug(F101,
10629                   "ck_krb5_tkt_isvalid while unparsing server name","",retval);
10630             retval = -1;
10631             krb5_free_cred_contents(kcontext, &creds);
10632             goto exit_k5_get_tkt;
10633         }
10634
10635         if ( !strcmp(sname,tktname) ) {
10636             /* we found the ticket we are looking for */
10637
10638             /* We add a 5 minutes fudge factor to compensate for potential */
10639             /* clock skew errors between the KDC and K95's host OS         */
10640
10641             retval = ((creds.times.starttime > 0) &&
10642                        now >= (creds.times.starttime - 300) &&
10643                        now < (creds.times.endtime + 300) &&
10644                        !(creds.ticket_flags & TKT_FLG_INVALID));
10645
10646 #ifdef CHECKADDRS
10647             if ( retval && krb5_checkaddrs &&
10648                                  creds.addresses && creds.addresses[0] ) {
10649                 /* if we think it is valid, then lets check the IP Addresses */
10650                 /* to make sure it is valid for our current connection.      */
10651                 /* Also make sure it's for the correct IP address */
10652                 retval = krb5_os_localaddr(kcontext, &myAddrs);
10653                 if (retval) {
10654                     com_err(NULL, retval, "retrieving my IP address");
10655                     krb5_free_unparsed_name(kcontext,sname);
10656                     krb5_free_cred_contents(kcontext, &creds);
10657                     code = KRB5_CC_END;
10658                     retval = -1;
10659                     break;
10660                 }
10661
10662              /* See if any of our addresses match any in cached credentials */
10663
10664                 for (Addrfound=FALSE, p=myAddrs;
10665                      (Addrfound==FALSE) && (*p);
10666                      p++
10667                      ) {
10668                     if (krb5_address_search(kcontext, *p, creds.addresses)) {
10669                         Addrfound = TRUE;
10670                     }
10671                 }
10672                 krb5_free_addresses(k5_context, myAddrs);
10673
10674                 if (Addrfound) {
10675                     krb5_free_unparsed_name(kcontext,sname);
10676                     krb5_free_cred_contents(kcontext, &creds);
10677                     code = KRB5_CC_END;
10678                     retval = 1;
10679                     break;
10680                 } else {
10681                     krb5_free_unparsed_name(kcontext,sname);
10682                     krb5_free_cred_contents(kcontext, &creds);
10683                     code = KRB5_CC_END;
10684                     retval = 0;
10685                     break;
10686                 }
10687             }
10688 #endif /* CHECKADDRS */
10689
10690             krb5_free_unparsed_name(kcontext,sname);
10691             krb5_free_cred_contents(kcontext, &creds);
10692             code = KRB5_CC_END;
10693             break;
10694         }
10695         krb5_free_unparsed_name(kcontext,sname);
10696         krb5_free_cred_contents(kcontext, &creds);
10697     }
10698
10699     if (code == KRB5_CC_END) {
10700         if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
10701             debug(F101,"ck_krb5_tkt_isvalid while finishing ticket retrieval",
10702                    "",code);
10703             retval = -1;
10704             goto exit_k5_get_tkt;
10705         }
10706         flags = KRB5_TC_OPENCLOSE;      /* turns on OPENCLOSE mode */
10707         if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10708             debug(F101,"ck_krb5_tkt_isvalid while closing ccache",
10709                    "",code);
10710             retval = -1;
10711             goto exit_k5_get_tkt;
10712         }
10713     } else {
10714         debug(F101,"ck_krb5_tkt_isvalid while retrieving a ticket","",code);
10715         retval = -1;
10716         goto exit_k5_get_tkt;
10717     }
10718
10719   exit_k5_get_tkt:
10720     krb5_free_principal(kcontext,princ);
10721     krb5_free_unparsed_name(kcontext,defname);
10722     krb5_cc_close(kcontext,cache);
10723     krb5_free_context(kcontext);
10724     return(retval);
10725 #else /* HEIMDAL */
10726     return(-1);
10727 #endif /* HEIMDAL */
10728 #else /* KRB5 */
10729     return(-1);
10730 #endif /* KRB5 */
10731 }
10732
10733 int
10734 #ifdef CK_ANSIC
10735 ck_krb5_is_tgt_valid(VOID)
10736 #else
10737 ck_krb5_is_tgt_valid()
10738 #endif
10739 {
10740 #ifdef KRB5
10741 #ifndef HEIMDAL
10742     char tgt[256];
10743     char * s;
10744     int rc = 0;
10745
10746     s = ck_krb5_getrealm(krb5_d_cc);
10747     ckmakmsg(tgt,sizeof(tgt),"krbtgt/",s,"@",s);
10748     rc = ck_krb5_tkt_isvalid(krb5_d_cc,tgt);
10749     debug(F111,"ck_krb5_is_tgt_valid",tgt,rc);
10750     return(rc>0);
10751 #else /* HEIMDAL */
10752     return(-1);
10753 #endif /* HEIMDAL */
10754 #else /* KRB5 */
10755     return(0);
10756 #endif /* KRB5 */
10757 }
10758
10759 int
10760 #ifdef CK_ANSIC
10761 ck_krb5_tkt_time(char * cc_name, char * tktname)
10762 #else
10763 ck_krb5_tkt_time(cc_name, tktname) char * cc_name; char * tktname;
10764 #endif
10765 {
10766 #ifdef KRB5
10767 #ifndef HEIMDAL
10768     krb5_context kcontext;
10769     krb5_error_code retval;
10770     krb5_ccache cache = NULL;
10771     krb5_cc_cursor cur;
10772     krb5_creds creds;
10773     krb5_principal princ=NULL;
10774     krb5_flags flags=0;
10775     krb5_error_code code=0;
10776
10777     if ( !ck_krb5_is_installed() )
10778         return(-1);
10779
10780     retval = krb5_init_context(&kcontext);
10781     if (retval) {
10782         debug(F101,"ck_krb5_list_creds while initializing krb5","",retval);
10783         return(-1);
10784     }
10785
10786     code = k5_get_ccache(kcontext,&cache,cc_name);
10787     if (code != 0) {
10788         debug(F111,"ck_krb5_tkt_time while getting ccache",
10789                error_message(code),code);
10790         retval = -1;
10791         goto exit_k5_get_tkt;
10792     }
10793
10794     flags = 0;                          /* turns off OPENCLOSE mode */
10795     if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10796         if (code == ENOENT) {
10797             debug(F111,"ck_krb5_list_creds (ticket cache)",
10798                    krb5_cc_get_name(kcontext, cache),code);
10799         } else {
10800             debug(F111,
10801                  "ck_krb5_list_creds while setting cache flags (ticket cache)",
10802                   krb5_cc_get_name(kcontext, cache),code);
10803         }
10804         retval = -1;
10805         goto exit_k5_get_tkt;
10806     }
10807     if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
10808         debug(F101,"ck_krb5_list_creds while retrieving principal name",
10809                "",code);
10810         retval = -1;
10811         goto exit_k5_get_tkt;
10812     }
10813     if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
10814         debug(F101,"ck_krb5_list_creds while unparsing principal name",
10815                "",code);
10816         retval = -1;
10817         goto exit_k5_get_tkt;
10818     }
10819
10820     if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
10821         debug(F101,"ck_krb5_list_creds while starting to retrieve tickets",
10822                "",code);
10823         retval = -1;
10824         goto exit_k5_get_tkt;
10825     }
10826
10827     if ((code = krb5_timeofday(kcontext, &now))) {
10828         if (!status_only)
10829             debug(F101,"ck_krb5_list_creds while getting time of day.",
10830                    "",code);
10831         krb5_free_context(kcontext);
10832         return(-1);
10833     }
10834
10835     while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
10836         char *sname=NULL;
10837
10838         retval = krb5_unparse_name(kcontext, creds.server, &sname);
10839         if (retval) {
10840             debug(F101,
10841                   "ck_krb5_list_creds while unparsing server name","",retval);
10842             retval = -1;
10843             krb5_free_unparsed_name(kcontext,sname);
10844             krb5_free_cred_contents(kcontext, &creds);
10845             goto exit_k5_get_tkt;
10846         }
10847
10848         if ( !strcmp(sname,tktname) ) {
10849             /* we found the ticket we are looking for */
10850             int valid = (creds.times.starttime &&
10851                        now > creds.times.starttime &&
10852                        now < creds.times.endtime &&
10853                        !(creds.ticket_flags & TKT_FLG_INVALID));
10854             if ( valid ) {
10855                 retval = creds.times.endtime - now;
10856             }
10857             else
10858                 retval = 0;
10859             krb5_free_unparsed_name(kcontext,sname);
10860             krb5_free_cred_contents(kcontext, &creds);
10861             code = KRB5_CC_END;
10862             break;
10863         }
10864         krb5_free_unparsed_name(kcontext,sname);
10865         krb5_free_cred_contents(kcontext, &creds);
10866     }
10867
10868     if (code == KRB5_CC_END) {
10869         if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
10870             debug(F101,"ck_krb5_list_creds while finishing ticket retrieval",
10871                    "",code);
10872             retval = -1;
10873             goto exit_k5_get_tkt;
10874         }
10875         flags = KRB5_TC_OPENCLOSE;      /* turns on OPENCLOSE mode */
10876         if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
10877             debug(F101,"ck_krb5_list_creds while closing ccache",
10878                    "",code);
10879             retval = -1;
10880             goto exit_k5_get_tkt;
10881         }
10882     } else {
10883         debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code);
10884         retval = -1;
10885         goto exit_k5_get_tkt;
10886     }
10887
10888   exit_k5_get_tkt:
10889     krb5_free_principal(kcontext,princ);
10890     krb5_free_unparsed_name(kcontext,defname);
10891     krb5_cc_close(kcontext,cache);
10892     krb5_free_context(kcontext);
10893     return(retval);
10894 #else /* HEIMDAL */
10895     return(-1);
10896 #endif /* HEIMDAL */
10897 #else /* KRB5 */
10898     return(-1);
10899 #endif /* KRB5 */
10900 }
10901
10902 char *
10903 #ifdef CK_ANSIC
10904 ck_krb5_get_cc_name(void)
10905 #else
10906 ck_krb5_get_cc_name()
10907 #endif
10908 {
10909 #ifdef KRB5
10910 #ifndef HEIMDAL
10911     static char cc_name[CKMAXPATH+1]="";
10912     krb5_context kcontext = NULL;
10913     krb5_ccache ccache = NULL;
10914     krb5_error_code code;
10915     char * p=NULL;
10916
10917     cc_name[0] = '\0';
10918
10919     if ( !ck_krb5_is_installed() )
10920         return(cc_name);
10921
10922     p = getenv("KRB5CCNAME");
10923     if ( !p ) {
10924         code = krb5_init_context(&kcontext);
10925         if (code) {
10926             com_err("ck_krb5_get_cc_name",code,"while init_context");
10927             return(cc_name);
10928         }
10929         if ((code = krb5_cc_default(kcontext, &ccache))) {
10930             com_err("ck_krb5_get_cc_name",code,"while getting default ccache");
10931             goto exit_k5_get_cc;
10932         }
10933
10934         ckmakmsg(cc_name,sizeof(cc_name),
10935                  (char *)krb5_cc_get_type(kcontext,ccache),":",
10936                  (char *)krb5_cc_get_name(kcontext,ccache),NULL);
10937     } else {
10938         ckstrncpy(cc_name,p,CKMAXPATH);
10939     }
10940
10941     if ( !strncmp("FILE:",cc_name,5) ) {
10942         for ( p=cc_name; *p ; p++ )
10943             if ( *p == '\\' ) *p = '/';
10944     }
10945
10946   exit_k5_get_cc:
10947     if ( ccache )
10948         krb5_cc_close(kcontext,ccache);
10949     if ( kcontext )
10950         krb5_free_context(kcontext);
10951     return(cc_name);
10952 #else /* HEIMDAL */
10953     return("Not implemented");
10954 #endif /* HEIMDAL */
10955 #else /* KRB5 */
10956     return("");
10957 #endif /* KRB5 */
10958 }
10959
10960 char *
10961 #ifdef CK_ANSIC
10962 ck_krb5_getrealm(char * cc_name)
10963 #else
10964 ck_krb5_getrealm(cc_name) char * cc_name;
10965 #endif
10966 {
10967 #ifdef KRB5
10968 #ifndef HEIMDAL
10969     static char realm[256]="";
10970     krb5_context kcontext;
10971     krb5_ccache ccache = NULL;
10972     krb5_error_code code;
10973     krb5_principal me=NULL;
10974
10975     realm[0] = '\0';
10976
10977     if ( !ck_krb5_is_installed() )
10978         return(realm);
10979
10980     code = krb5_init_context(&kcontext);
10981     if (code) {
10982         return(realm);
10983     }
10984
10985     code = k5_get_ccache(kcontext,&ccache,cc_name);
10986     if (code != 0) {
10987         goto exit_k5_getrealm;
10988     }
10989
10990         code = krb5_cc_get_principal(kcontext, ccache, &me);
10991         if (code)
10992                 code = krb5_parse_name(kcontext, "foo", &me);
10993     if (code) {
10994         goto exit_k5_getrealm;
10995     }
10996     if ( krb5_princ_realm(kcontext, me)->length < sizeof(realm) ) {
10997         memcpy(realm,krb5_princ_realm(kcontext, me)->data,
10998                 krb5_princ_realm(kcontext, me)->length);        /* safe */
10999        realm[krb5_princ_realm(kcontext, me)->length]='\0';
11000     }
11001   exit_k5_getrealm:
11002     if ( me )
11003         krb5_free_principal(kcontext,me);
11004     if ( ccache )
11005         krb5_cc_close(kcontext,ccache);
11006     if (kcontext)
11007         krb5_free_context(kcontext);
11008     return(realm);
11009 #else /* HEIMDAL */
11010     return("Not implemented");
11011 #endif /* HEIMDAL */
11012 #else /* KRB5 */
11013     return("");
11014 #endif /* KRB5 */
11015 }
11016
11017 char *
11018 #ifdef CK_ANSIC
11019 ck_krb5_getprincipal(char * cc_name)
11020 #else
11021 ck_krb5_getprincipal(cc_name) char * cc_name;
11022 #endif
11023 {
11024 #ifdef KRB5
11025 #ifndef HEIMDAL
11026     static char principal[UIDBUFLEN+1]="";
11027     krb5_context kcontext;
11028     krb5_ccache ccache = NULL;
11029     krb5_error_code code;
11030     krb5_principal me;
11031     char * p=NULL;
11032     int i;
11033
11034     principal[0] = '\0';
11035
11036     if ( !ck_krb5_is_installed() )
11037         return(principal);
11038
11039     code = krb5_init_context(&kcontext);
11040     if (code) {
11041         return(principal);
11042     }
11043
11044     code = k5_get_ccache(kcontext,&ccache,cc_name);
11045     if (code != 0) {
11046         goto exit_k5_getprincipal;
11047     }
11048
11049     if ((code = krb5_cc_get_principal(kcontext, ccache, &me))) {
11050         goto exit_k5_getprincipal;
11051     }
11052
11053     if ((code = krb5_unparse_name (kcontext, me, &p))) {
11054         krb5_free_principal(kcontext,me);
11055         goto exit_k5_getprincipal;
11056     }
11057
11058     ckstrncpy(principal,p,UIDBUFLEN);
11059     i = ckindex("@",principal,0,0,0);
11060     if (i)
11061       principal[i-1] = '\0';
11062
11063     krb5_free_unparsed_name(kcontext,p);
11064
11065   exit_k5_getprincipal:
11066     if ( ccache )
11067         krb5_cc_close(kcontext,ccache);
11068     if (kcontext)
11069         krb5_free_context(kcontext);
11070     return(principal);
11071 #else /* HEIMDAL */
11072     return("Not implemented");
11073 #endif /* HEIMDAL */
11074 #else /* KRB5 */
11075     return("");
11076 #endif /* KRB5 */
11077 }
11078
11079 #ifndef CRYPT_DLL
11080 int
11081 ck_get_crypt_table(struct keytab ** pTable, int * pN)
11082 {
11083 #ifdef CK_ENCRYPTION
11084     return(get_crypt_table(pTable, pN));
11085 #else /* ENCRYPTION */
11086     int i=0;
11087 #ifndef OS2
11088     char * tmpstring = NULL;
11089 #endif /* OS2 */
11090
11091     if ( *pTable )
11092     {
11093         for ( i=0 ; i < *pN ; i++ )
11094             free( (*pTable)[i].kwd ) ;
11095         free ( *pTable )  ;
11096     }
11097     *pTable = NULL;
11098     *pN = 0;
11099
11100     *pTable = malloc( sizeof(struct keytab) * 2 ) ;
11101     if ( !(*pTable) )
11102         return(0);
11103
11104 #ifdef OS2
11105     (*pTable)[0].kwd =strdup("automatic");
11106 #else /* OS2 */
11107     makestr(&tmpstring,"automatic");
11108     (*pTable)[0].kwd = tmpstring;
11109     tmpstring = NULL;
11110 #endif /* OS2 */
11111     (*pTable)[0].kwval = ENCTYPE_ANY;
11112     (*pTable)[0].flgs = 0;
11113 #ifdef OS2
11114     (*pTable)[1].kwd =strdup("none");
11115 #else /* OS2 */
11116     makestr(&tmpstring,"none");
11117     (*pTable)[1].kwd = tmpstring;
11118     tmpstring = NULL;
11119 #endif /* OS2 */
11120     (*pTable)[1].kwval = 999;
11121     (*pTable)[1].flgs = 0;
11122     (*pN) = 2;
11123
11124     return(2);
11125 #endif /* ENCRYPTION */
11126 }
11127
11128 VOID
11129 ck_encrypt_send_support()
11130 {
11131 #ifdef CK_ENCRYPTION
11132     encrypt_send_support();
11133 #endif /* ENCRYPTION */
11134 }
11135 #endif /* CRYPT_DLL */
11136
11137 /*
11138  *
11139  * Kstream
11140  *
11141  * Emulates the kstream package in Kerberos 4
11142  *
11143  */
11144
11145 int
11146 kstream_destroy()
11147 {
11148     if (g_kstream != NULL) {
11149         auth_destroy();                       /* Destroy authorizing */
11150         free(g_kstream);
11151         g_kstream=NULL;
11152     }
11153     return 0;
11154 }
11155
11156 VOID
11157 #ifdef CK_ANSIC
11158 kstream_set_buffer_mode(int mode)
11159 #else
11160 kstream_set_buffer_mode(mode) int mode;
11161 #endif
11162 {
11163 }
11164
11165
11166 int
11167 #ifdef CK_ANSIC
11168 kstream_create_from_fd(int fd,
11169                        kstream_ptr data)
11170 #else
11171 kstream_create_from_fd(fd,data)
11172     int fd; kstream_ptr data;
11173 #endif
11174 {
11175     int n;
11176
11177     g_kstream = malloc(sizeof(struct kstream_int));
11178     if (g_kstream == NULL)
11179         return 0;
11180
11181     g_kstream->fd = fd;
11182
11183     n = auth_init(g_kstream);                   /* Initialize authorizing */
11184     if (n) {
11185         free(g_kstream);
11186         g_kstream = NULL;
11187         return 0;
11188     }
11189
11190     g_kstream->encrypt = NULL;
11191     g_kstream->decrypt = NULL;
11192     g_kstream->encrypt_type = ENCTYPE_ANY;
11193     g_kstream->decrypt_type = ENCTYPE_ANY;
11194     return 1;
11195 }
11196
11197 #ifdef CK_KERBEROS
11198 #ifdef RLOGCODE
11199 static int do_lencheck, use_ivecs;
11200 extern int rlog_inband;
11201
11202 #ifdef KRB5
11203 void
11204 rcmd_stream_init_krb5(in_keyblock, encrypt_flag, lencheck, am_client,
11205                            protonum)
11206      krb5_keyblock *in_keyblock;
11207      int encrypt_flag;
11208      int lencheck;
11209      int am_client;
11210      enum krb5_kcmd_proto protonum;
11211 {
11212     krb5_error_code status;
11213     size_t blocksize;
11214
11215     if (!encrypt_flag)
11216         return;
11217
11218     desinbuf.data = des_inbuf;
11219     desoutbuf.data = des_outpkt+4;      /* Set up des buffers */
11220     k5_session_key = in_keyblock;
11221
11222     do_lencheck = lencheck;
11223
11224     if ( protonum == KCMD_OLD_PROTOCOL ) {
11225         use_ivecs = 0;
11226         return;
11227     }
11228
11229     use_ivecs = 1;
11230
11231     if (status = krb5_c_block_size(k5_context, k5_session_key->enctype,
11232                                    &blocksize)) {
11233         /* XXX what do I do? */
11234         printf("fatal kerberos 5 crypto library error\n");
11235         ttclos(0);
11236         return;
11237     }
11238
11239     encivec_i[0].length = encivec_i[1].length = 
11240     encivec_o[0].length = encivec_o[1].length = blocksize;
11241
11242     if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) == NULL) {
11243         /* XXX what do I do? */
11244         printf("fatal malloc failed\n");
11245         ttclos(0);
11246         return;
11247     }
11248
11249     encivec_i[1].data = encivec_i[0].data + encivec_i[0].length;
11250     encivec_o[0].data = encivec_i[1].data + encivec_i[1].length;
11251     encivec_o[1].data = encivec_o[0].data + encivec_o[0].length;
11252
11253     /* is there a better way to initialize this? */
11254     memset(encivec_i[0].data, am_client, blocksize);
11255     memset(encivec_o[0].data, 1 - am_client, blocksize);
11256     memset(encivec_i[1].data, 2 | am_client, blocksize);
11257     memset(encivec_o[1].data, 2 | (1 - am_client), blocksize);
11258 }
11259 #endif /* KRB5 */
11260
11261 int
11262 #ifdef CK_ANSIC
11263 ck_krb_rlogin(CHAR * hostname, int port,
11264                CHAR * localuser, CHAR * remoteuser, CHAR * term_speed,
11265                struct sockaddr_in * l_addr, struct sockaddr_in * r_addr,
11266                int kversion, int encrypt_flag)
11267 #else /* CK_ANSIC */
11268 ck_krb_rlogin(hostname, port,
11269                localuser, remoteuser, term_speed, l_addr, r_addr, encrypt_flag)
11270     CHAR * hostname; int port;
11271     CHAR * localuser; CHAR * remoteuser; CHAR * term_speed;
11272     struct sockaddr_in * l_addr; struct sockaddr_in * r_addr;
11273     int kversion; int encrypt_flag;
11274 #endif /* CK_ANSIC */
11275 {
11276     unsigned long status;
11277     char * realm=NULL;
11278     extern int ttyfd;
11279     int c;
11280     long msglen;
11281
11282     debug(F111,"ck_krb_rlogin",hostname,port);
11283
11284     if ( kversion == 4 && !ck_krb4_is_installed() ) {
11285         printf("?Kerberos 4 is not installed\r\n");
11286         return(-1);
11287     } else if ( kversion == 5 && !ck_krb5_is_installed() ) {
11288         printf("?Kerberos 5 is not installed\r\n");
11289         return(-1);
11290     }
11291
11292     if ( encrypt_flag && !ck_crypt_is_installed() ) {
11293         printf("?Encryption is not installed\r\n");
11294         return(-1);
11295     }
11296
11297     if ( kversion == 5 ) {
11298 #ifdef KRB5
11299         krb5_flags authopts=0;
11300         krb5_ccache ccache=NULL;
11301         char *cksumbuf=NULL;
11302         char *service=NULL;
11303         char * kcmd_version=NULL;
11304         enum krb5_kcmd_proto use_proto;
11305         krb5_data cksumdat;
11306         krb5_creds *get_cred = 0;
11307         krb5_error_code status;
11308         krb5_error      *error = 0;
11309         krb5_ap_rep_enc_part *rep_ret = NULL;
11310         krb5_data outbuf;
11311         int rc;
11312         krb5_int32 seqno=0;
11313         krb5_int32 server_seqno=0;
11314         char ** realmlist=NULL;
11315         int buflen;
11316         char tgt[256];
11317
11318         debug(F100,"ck_krb_rlogin version 5","",0);
11319
11320         realm = ck_krb5_realmofhost((char *)hostname);
11321         if (!realm) {
11322             ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL);
11323             ckstrncat(strTmp, (char *)hostname,AUTHTMPBL);
11324             ckstrncat(strTmp, "\"",AUTHTMPBL);
11325             printf("?Kerberos 5 error: %s\r\n",strTmp);
11326             krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN;
11327             makestr(&krb5_errmsg,strTmp);
11328             return(0);
11329         }
11330
11331         ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
11332         debug(F110,"ck_rlog_rlogin TGT",tgt,0);
11333         if ( krb5_autoget &&
11334              !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
11335                 (ck_krb5_is_tgt_valid() > 0)) )
11336             ck_krb5_autoget_TGT(realm);
11337
11338         buflen = strlen((char *)term_speed) + strlen((char *)remoteuser) + 64;
11339         if ((cksumbuf = malloc(buflen)) == 0) {
11340             printf("Unable to allocate memory for checksum buffer.\r\n");
11341             return(-1);
11342         }
11343         ckmakmsg(cksumbuf,buflen,ckuitoa((unsigned short) ntohs(port)),":",
11344                  (char *)term_speed,(char *)remoteuser);
11345         cksumdat.data = cksumbuf;
11346         cksumdat.length = strlen(cksumbuf);
11347
11348         status = krb5_init_context(&k5_context);
11349         if (status) {
11350             debug(F110,"ck_krb_rlogin()","unable to init_context",0);
11351             return(-1);
11352         }
11353
11354         desinbuf.data = des_inbuf;
11355         desoutbuf.data = des_outpkt+4;  /* Set up des buffers */
11356
11357         rc = k5_get_ccache(k5_context,&ccache,NULL);
11358         if (rc != 0) {
11359             com_err(NULL, rc, "while getting ccache.");
11360             return(0);
11361         }
11362
11363         service = krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME;
11364
11365         if (!(get_cred = (krb5_creds *)calloc(1, sizeof(krb5_creds)))) {
11366             printf("ck_krb_rlogin: no memory\r\n");
11367             return(-1);
11368         }
11369         memset(get_cred,0,sizeof(krb5_creds));
11370         status = krb5_sname_to_principal(k5_context, (char *) hostname,
11371                                          service, KRB5_NT_SRV_HST,
11372                                          &get_cred->server);
11373         if (status) {
11374             printf("ck_krb_rlogin: krb5_sname_to_principal failed: %s\r\n",
11375                      error_message(status));
11376             return(-1);
11377         }
11378
11379         ttoc(0);
11380
11381         if (status = krb5_cc_get_principal(k5_context,
11382                                            ccache,
11383                                            &get_cred->client)
11384             ) {
11385             (void) krb5_cc_close(k5_context, ccache);
11386             krb5_free_creds(k5_context, get_cred);
11387             goto bad;
11388         }
11389
11390         if (krb5_rlog_ver == KCMD_OLD_PROTOCOL)
11391             get_cred->keyblock.enctype=ENCTYPE_DES_CBC_CRC;
11392
11393         /* Get ticket from credentials cache or kdc */
11394         status = krb5_get_credentials(k5_context,
11395                                       0,
11396                                       ccache,
11397                                       get_cred,
11398                                       &ret_cred
11399                                       );
11400         krb5_free_creds(k5_context, get_cred);
11401         get_cred = NULL;
11402         (void) krb5_cc_close(k5_context, ccache);
11403
11404         if (status) 
11405             goto bad;
11406
11407         /* Reset internal flags; these should not be set. */
11408         authopts &= (~OPTS_FORWARD_CREDS);
11409         authopts &= (~OPTS_FORWARDABLE_CREDS);
11410
11411         if (krb5_auth_con_init(k5_context, &auth_context))
11412             goto bad;
11413
11414         if (krb5_auth_con_setflags(k5_context, auth_context,
11415                                     KRB5_AUTH_CONTEXT_RET_TIME))
11416             goto bad;
11417
11418         /* Only need local address for mk_cred() to send to krlogind */
11419         if (!krb5_d_no_addresses)
11420             if (status = krb5_auth_con_genaddrs(k5_context,
11421                                                 auth_context,
11422                                                  ttyfd,
11423                                 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR
11424                                                  ))
11425                 goto bad;
11426
11427         /* Here is where we start to handle the new protocol in earnest */
11428         if ( krb5_rlog_ver == KCMD_PROTOCOL_COMPAT_HACK ) {
11429             krb5_boolean is_des;
11430
11431             if (status = krb5_c_enctype_compare( k5_context,
11432                                                  ENCTYPE_DES_CBC_CRC,
11433 #ifdef HEIMDAL
11434                                                  ret_cred->session.keytype,
11435 #else /* HEIMDAL */
11436                                                  ret_cred->keyblock.enctype,
11437 #endif /* HEIMDAL */
11438                                                  &is_des)) {
11439                 krb5_free_creds(k5_context, ret_cred);
11440                 ret_cred = NULL;
11441                 goto bad;
11442             }
11443
11444             if ( is_des ) {
11445                 kcmd_version = "KCMDV0.1";
11446                 use_proto = KCMD_OLD_PROTOCOL;
11447             } else {
11448                 authopts = AP_OPTS_USE_SUBKEY;
11449                 kcmd_version = "KCMDV0.2";
11450                 use_proto = KCMD_NEW_PROTOCOL;
11451             }
11452         } else {
11453             use_proto = krb5_rlog_ver;
11454             switch ( krb5_rlog_ver ) {
11455             case KCMD_NEW_PROTOCOL:
11456                 authopts = AP_OPTS_USE_SUBKEY;
11457                 kcmd_version = "KCMDV0.2";
11458                 break;
11459             case KCMD_OLD_PROTOCOL:
11460                 kcmd_version = "KCMDV0.1";
11461                 break;
11462             default:
11463                 goto bad;
11464             }
11465         }
11466
11467         /* call Kerberos library routine to obtain an authenticator,
11468            pass it over the socket to the server, and obtain mutual
11469            authentication.
11470          */
11471         status = krb5_sendauth(k5_context,
11472                                &auth_context,
11473                                (krb5_pointer) &ttyfd,
11474                                kcmd_version,
11475                                ret_cred->client,
11476                                ret_cred->server,
11477                                 authopts,
11478                                &cksumdat,
11479                                ret_cred,
11480                                0,
11481                                &error,
11482                                &rep_ret,
11483                                NULL
11484                                );
11485         krb5_free_data_contents(k5_context,&cksumdat);
11486
11487         if (status) {
11488             if ( !quiet )
11489                 printf("Couldn't authenticate to server: %s\r\n",
11490                         error_message(status));
11491             if (error) {
11492                 if ( !quiet ) {
11493                     printf("Server returned error code %d (%s)\r\n",
11494                         error->error,
11495                         error_message(ERROR_TABLE_BASE_krb5 + error->error));
11496                     if (error->text.length) {
11497                         printf("Error text sent from server: %s\r\n",
11498                                 error->text.data);
11499                     }
11500                 }
11501                 krb5_free_error(k5_context, error);
11502                 error = 0;
11503             }
11504             goto bad;
11505         }
11506
11507         if (rep_ret) {
11508             server_seqno = rep_ret->seq_number;
11509             krb5_free_ap_rep_enc_part(k5_context, rep_ret);
11510         }
11511
11512         (void) ttol(remoteuser, strlen((char *)remoteuser)+1);
11513         (void) ttol(term_speed, strlen((char *)term_speed)+1);
11514         (void) ttol(localuser, strlen((char *)localuser)+1);
11515
11516         if (forward_flag) {   /* Forward credentials (global) */
11517             if (status = krb5_fwd_tgt_creds( k5_context,
11518                                              auth_context,
11519                                              (char *)hostname,
11520                                              ret_cred->client,
11521                                              ret_cred->server,
11522                                              0,
11523                                              (forwardable_flag ?
11524                                                OPTS_FORWARDABLE_CREDS :
11525                                                0),
11526                                              &outbuf
11527                                              )
11528                  )
11529             {
11530                 printf("Error forwarding credentials: %s\r\n",
11531                          error_message(status));
11532                 goto bad2;
11533             }
11534
11535             /* Send forwarded credentials */
11536             status = krb5_write_message(k5_context,
11537                                          (krb5_pointer)&ttyfd,
11538                                          &outbuf
11539                                          );
11540         }
11541         else { /* Dummy write to signal no forwarding */
11542           bad2:
11543             outbuf.length = 0;
11544             status = krb5_write_message(k5_context,
11545                                          (krb5_pointer)&ttyfd,
11546                                          &outbuf);
11547         }       
11548
11549         if ((c = ttinc(0)) < 0) {
11550             if (c==-1) {
11551                 perror((char *)hostname);
11552             } else {
11553                 printf("ck_krb_rlogin: bad connection with remote host\r\n");
11554             }
11555             status = -1;
11556             goto bad;
11557         }
11558         if (c != 0) {
11559             while ((c = ttinc(1)) >= 0) {
11560                 (void) printf("%c",c);
11561                 if (c == '\n')
11562                     break;
11563             }
11564             status = -1;
11565             goto bad;
11566         }
11567
11568         if ( status == 0 ) {        /* success */
11569             krb5_keyblock * key = 0;
11570
11571             if ( use_proto == KCMD_NEW_PROTOCOL ) {
11572                 int on = 1;
11573                 rlog_inband = 1;
11574                 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,
11575                            (char *) &on, sizeof on);
11576
11577                 status = krb5_auth_con_getlocalsubkey( k5_context,
11578                                                        auth_context,
11579                                                        &key);
11580                 if ((status || !key) && encrypt_flag )
11581                     goto bad2;
11582             }
11583             if ( key == 0 ) {
11584 #ifdef HEIMDAL
11585                 key = &ret_cred->session;
11586 #else /* HEIMDAL */
11587                 key = &ret_cred->keyblock;
11588 #endif /* HEIMDAL */
11589             }
11590
11591             rcmd_stream_init_krb5(key, encrypt_flag, 1, 1, use_proto);
11592             if ( encrypt_flag )
11593                 rlog_encrypt = 1;
11594         }
11595         return (0);     /* success */
11596
11597       bad:
11598         if ( status && !quiet ) {
11599             printf("Kerberos authentication error: %s\r\n",
11600                     error_message(status));
11601         }
11602         if (ret_cred) {
11603             krb5_free_creds(k5_context, ret_cred);
11604             ret_cred = NULL;
11605         }
11606         return (status);
11607 #else /* KRB5 */
11608         return(-1);
11609 #endif /* KRB5 */
11610     } else if (kversion == 4) {
11611 #ifdef KRB4
11612         char tgt[4*REALM_SZ+1];
11613         debug(F100,"ck_krb_rlogin version 4","",0);
11614
11615         realm = (char *)krb_realmofhost(hostname);
11616         if (!realm) {
11617             strcpy(strTmp, "Can't find realm for host \"");
11618             ckstrncat(strTmp, hostname,AUTHTMPBL);
11619             ckstrncat(strTmp, "\"",AUTHTMPBL);
11620             printf("?Kerberos 4 error: %s\r\n",strTmp);
11621             krb4_errno = 0;
11622             makestr(&krb4_errmsg,strTmp);
11623             return(0);
11624         }
11625
11626         ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm);
11627         status = ck_krb4_tkt_isvalid(tgt);
11628
11629         if ( status <= 0 && krb4_autoget )
11630             ck_krb4_autoget_TGT(realm);
11631
11632         ttoc(0);        /* write a NUL */
11633
11634         status = krb_sendauth(encrypt_flag?KOPT_DO_MUTUAL:0,
11635                                ttyfd,
11636                                &k4_auth,
11637                                krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
11638                                hostname,
11639                                realm,
11640                                (unsigned long) getpid(),
11641                                &k4_msg_data,
11642                                &cred,
11643 #ifdef CK_ENCRYPTION
11644                                &k4_sched,
11645 #else /* ENCRYPTION */
11646                                NULL,
11647 #endif /* ENCRYPTION */
11648                                l_addr,
11649                                r_addr,
11650                                "KCMDV0.1");
11651         debug(F111,"ck_krb_rlogin","krb_sendauth",status);
11652         if (status != KSUCCESS) {
11653             printf( "krb_sendauth failed: %s\r\n",
11654                     krb_get_err_text_entry(status)
11655                     );
11656             return(-1);
11657         }
11658         ttol(remoteuser,strlen(remoteuser)+1);
11659         ttol(term_speed,strlen(term_speed)+1);
11660
11661       reread:
11662         if ((c = ttinc(0)) < 0) {
11663             printf("rcmd: bad connection with remote host\r\n");
11664             return(-1);
11665         }
11666         debug(F111,"ck_krb_rlogin","first byte",c);
11667
11668         if (c != 0) {
11669             char *check = "ld.so: warning:";
11670             /* If rlogind was compiled on SunOS4, and it somehow
11671             got the shared library version numbers wrong, it
11672             may give an ld.so warning about an old version of a
11673             shared library.  Just ignore any such warning.
11674             Note that the warning is a characteristic of the
11675             server; we may not ourselves be running under
11676             SunOS4.  */
11677             if (c == 'l') {
11678                 char *p;
11679                 char cc;
11680
11681                 p = &check[1];
11682                 while ((c = ttinc(0)) >= 0) {
11683                     if (*p == '\0') {
11684                         if (c == '\n')
11685                             break;
11686                     } else {
11687                         if (c != *p)
11688                             break;
11689                         ++p;
11690                     }
11691                 }
11692
11693                 if (*p == '\0')
11694                     goto reread;
11695             }
11696
11697             printf(check);
11698             while ((c = ttinc(1)) >= 0) {
11699                 printf("%c",c);
11700                 if (c == '\n')
11701                     break;
11702             }
11703             debug(F110,"ck_krb_rlogin","fatal error 1",0);
11704             return(-1);
11705         }
11706
11707 #ifdef CK_ENCRYPTION
11708         if ( encrypt_flag ) {
11709             /* if we are encrypting we need to setup the encryption */
11710             /* routines.                                            */
11711             des_key_sched(cred.session, k4_sched);
11712             rlog_encrypt = 1;
11713         }
11714 #endif /* ENCRYPTION */
11715 #else /* KRB4 */
11716         return(-1);
11717 #endif /* KRB4 */
11718     }
11719     return(0); /* success */
11720 }
11721
11722 #define SRAND   srand
11723 #define RAND    rand
11724 #define RAND_TYPE       int
11725
11726 static long
11727 random_confounder(size, fillin)
11728 size_t size;
11729 char * fillin;
11730 {
11731     static int seeded = 0;
11732     register unsigned char *real_fill;
11733     RAND_TYPE   rval;
11734
11735     if (!seeded) {
11736         /* time() defined in 4.12.2.4, but returns a time_t, which is an
11737            "arithmetic type" (4.12.1) */
11738         rval = (RAND_TYPE) time(0);
11739         SRAND(rval);
11740         rval = RAND();
11741         rval ^= getpid();
11742         SRAND(rval);
11743         seeded = 1;
11744     }
11745
11746     real_fill = (unsigned char *)fillin;
11747     while (size > 0) {
11748         rval = RAND();
11749         *real_fill = rval & 0xff;
11750         real_fill++;
11751         size--;
11752         if (size) {
11753             *real_fill = (rval >> 8) & 0xff;
11754             real_fill++;
11755             size--;
11756         }
11757     }
11758     return 0;
11759 }
11760
11761 #ifdef KRB5
11762 int
11763 krb5_des_avail(fd)
11764     int fd;
11765 {
11766     return(nstored);
11767 }
11768
11769 int
11770 krb5_des_read(fd, buf, len, secondary)
11771     int fd;
11772     register char *buf;
11773     int len;
11774     int secondary;
11775 {
11776     int nreturned = 0;
11777     long net_len,rd_len;
11778     int cc;
11779     krb5_error_code status;
11780     unsigned char c;
11781     krb5_data plain;
11782     krb5_enc_data cipher;
11783
11784     debug(F111,"krb5_des_read","len",len);
11785     debug(F111,"krb5_des_read","rlog_encrypt",rlog_encrypt);
11786     if ( !rlog_encrypt ) {
11787         cc = net_read(fd, buf, len);
11788         debug(F111,"krb5_des_read","chars read",cc);
11789         if ( cc < 0 )
11790             netclos();
11791         return(cc);
11792     }
11793
11794     if (nstored >= len) {
11795         if ( buf ) {
11796             memcpy(buf, store_ptr, len);        /* safe */
11797             store_ptr += len;
11798             nstored -= len;
11799             return(len);
11800         } else
11801             return(0);
11802     } else if (nstored) {
11803         if ( buf ) {
11804             memcpy(buf, store_ptr, nstored);    /* safe */
11805             nreturned += nstored;
11806             buf += nstored;
11807             len -= nstored;
11808             nstored = 0;
11809         }
11810         else
11811             return(0);
11812     }
11813
11814     /* See the comment in v4_des_read. */
11815     while (1) {
11816         cc = net_read(fd, &c, 1);
11817         /* we should check for non-blocking here, but we'd have
11818         to make it save partial reads as well. */
11819         if (cc <= 0) {
11820             return cc; /* read error */
11821         }
11822         if (cc == 1) {
11823             if (c == 0 || !do_lencheck) 
11824                 break;
11825         }
11826     }
11827
11828     rd_len = c;
11829     if ((cc = net_read(fd, &c, 1)) != 1) return 0;
11830     rd_len = (rd_len << 8) | c;
11831     if ((cc = net_read(fd, &c, 1)) != 1) return 0;
11832     rd_len = (rd_len << 8) | c;
11833     if ((cc = net_read(fd, &c, 1)) != 1) return 0;
11834     rd_len = (rd_len << 8) | c;
11835
11836     if (status = krb5_c_encrypt_length(k5_context, 
11837                                     k5_session_key->enctype,
11838                                     use_ivecs ? rd_len + 4 : rd_len,
11839                                     (size_t *)&net_len)) {
11840         errno = status;
11841         return(-1);
11842     }
11843
11844     if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) {
11845         /* preposterous length; assume out-of-sync; only
11846            recourse is to close connection, so return 0 */
11847         printf("Read size problem.\r\n");
11848         return(0);
11849     }
11850     if ((cc = net_read(fd, desinbuf.data, net_len)) != net_len )
11851     {
11852         /* pipe must have closed, return 0 */
11853         printf( "Read error: length received %d != expected %d.\r\n",
11854                 cc,
11855                 net_len
11856                 );
11857         return(cc);
11858     }
11859
11860
11861     /* decrypt info */
11862     cipher.enctype = ENCTYPE_UNKNOWN;
11863     cipher.ciphertext.length = net_len;
11864     cipher.ciphertext.data = desinbuf.data;
11865     plain.length = sizeof(storage);
11866     plain.data = storage;
11867
11868     if ( status = krb5_c_decrypt(k5_context, k5_session_key, KCMD_KEYUSAGE,
11869                                  use_ivecs ? encivec_i + secondary : 0,
11870                                   &cipher,&plain) ) {
11871         /* probably out of sync */
11872         printf("Cannot decrypt data from network: %s\r\n",
11873                  error_message(status));
11874         errno = EIO;
11875         return(-1);
11876     }
11877     
11878     store_ptr = storage;
11879     nstored = rd_len;
11880
11881     if ( use_ivecs ) {
11882         int rd_len2;
11883         rd_len2 = storage[0] & 0xff;
11884         rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff;
11885         rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff;
11886         rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff;
11887         if (rd_len2 != rd_len) {
11888             /* cleartext length trashed? */
11889             errno = EIO;
11890             return -1;
11891         }
11892         store_ptr += 4;
11893     }
11894
11895     if ( !buf )
11896         return(0);
11897
11898 #ifdef RLOGCODE                         /* blah */
11899     if (rlog_inband && (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN))
11900     {
11901         int i, left, n;
11902
11903         for (i = 0; i < nstored; i++) {
11904             if (store_ptr[i] == '\377' &&
11905                 store_ptr[i+1] == '\377') {
11906                 left = nstored - i;
11907                 n = rlog_ctrl(&store_ptr[i], left);
11908                 if (n < 0) {
11909                     left -= (-n);
11910                     nstored = left;
11911                     /* flush before, and (-n) bytes */
11912                     if (left > 0)
11913                         memmove(store_ptr, &store_ptr[i-n], left);
11914                 } else if (n) {
11915                     left -= n;
11916                     nstored -= n;
11917                     if (left > 0)
11918                         memmove(store_ptr, &store_ptr[n], left);
11919                 }
11920             }
11921         }
11922     }
11923 #endif /* RLOGCODE */
11924
11925     if (nstored > len) {
11926         memcpy(buf, store_ptr, len);            /* safe */
11927         nreturned += len;
11928         store_ptr += len;
11929         nstored -= len;
11930     } else {
11931         memcpy(buf, store_ptr, nstored);        /* safe */
11932         nreturned += nstored;
11933         nstored = 0;
11934     }
11935     return(nreturned);
11936 }
11937
11938 int
11939 krb5_des_write(fd, buf, len, secondary)
11940     int fd;
11941     char *buf;
11942     int len;
11943     int secondary;
11944 {
11945     char tmpbuf[2*RLOG_BUFSIZ+8];
11946     unsigned char *len_buf = (unsigned char *) tmpbuf;
11947     krb5_error_code status;
11948     krb5_data plain;
11949     krb5_enc_data cipher;
11950
11951     debug(F111,"krb5_des_write","rlog_encrypt",rlog_encrypt);
11952     if ( !rlog_encrypt ) {
11953         int cc = net_write(fd, buf, len);
11954         debug(F111,"net_write","chars written",cc);
11955         return(cc != len ? -1 : len);
11956     }
11957
11958     if (use_ivecs) {
11959         unsigned char *lenbuf2 = (unsigned char *) tmpbuf;
11960         if (len + 4 > sizeof(tmpbuf))
11961             abort ();
11962         lenbuf2[0] = (len & 0xff000000) >> 24;
11963         lenbuf2[1] = (len & 0xff0000) >> 16;
11964         lenbuf2[2] = (len & 0xff00) >> 8;
11965         lenbuf2[3] = (len & 0xff);
11966         memcpy (tmpbuf + 4, buf, len);
11967
11968         plain.data = tmpbuf;
11969         plain.length = len + 4;
11970     } else {
11971         plain.data = buf;
11972         plain.length = len;
11973     }
11974
11975     cipher.ciphertext.length = sizeof(des_outpkt)-4;
11976     cipher.ciphertext.data = desoutbuf.data;
11977
11978     if ( status = krb5_c_encrypt(k5_context, k5_session_key, KCMD_KEYUSAGE,
11979                          use_ivecs ? encivec_o + secondary : 0,
11980                          &plain, &cipher)) {
11981         printf("Write encrypt problem: %s.\r\n",
11982                  error_message(status));
11983         errno = EIO;
11984         return(-1);
11985     }
11986     desoutbuf.length = cipher.ciphertext.length;
11987
11988     len_buf = (unsigned char *) des_outpkt;
11989     len_buf[0] = (len & 0xff000000) >> 24;
11990     len_buf[1] = (len & 0xff0000) >> 16;
11991     len_buf[2] = (len & 0xff00) >> 8;
11992     len_buf[3] = (len & 0xff);
11993
11994     if (net_write(fd, des_outpkt,desoutbuf.length+4)
11995          != desoutbuf.length+4){
11996         printf("Could not write out all data\r\n");
11997         return(-1);
11998     }
11999     else return(len);
12000 }
12001 #endif /* KRB5 */
12002
12003 #ifdef KRB4
12004 /*
12005  * Note that the encrypted rlogin packets take the form of a four-byte
12006  * length followed by encrypted data.  On writing the data out, a significant
12007  * performance penalty is suffered (at least one RTT per character, two if we
12008  * are waiting for a shell to echo) by writing the data separately from the
12009  * length.  So, unlike the input buffer, which just contains the output
12010  * data, the output buffer represents the entire packet.
12011  */
12012
12013 int
12014 krb4_des_avail(fd)
12015     int fd;
12016 {
12017     return(nstored);
12018 }
12019
12020 int
12021 krb4_des_read(fd, buf, len)
12022 int fd;
12023 register char *buf;
12024 int len;
12025 {
12026     int nreturned = 0;
12027     unsigned long net_len, rd_len;
12028     int cc;
12029     unsigned char c;
12030     int gotzero = 0;
12031
12032     debug(F111,"krb4_des_read","rlog_encrypt",rlog_encrypt);
12033     debug(F111,"krb4_des_read","len",len);
12034     if ( !rlog_encrypt ) {
12035         cc = net_read(fd, buf, len);
12036         debug(F111,"krb4_des_read","chars read",cc);
12037         if ( cc < 0 )
12038             netclos();
12039         return(cc);
12040     }
12041
12042     if (nstored >= len) {
12043         if ( buf ) {
12044             debug(F111,"krb4_des_read (nstored >= len)","nstored",nstored);
12045             memcpy(buf, store_ptr, len);        /* safe */
12046             store_ptr += len;
12047             nstored -= len;
12048             return(len);
12049         } else
12050             return(0);
12051     } else if (nstored) {
12052         if ( buf ) {
12053             debug(F111,"krb4_des_read (nstored)","nstored",nstored);
12054             memcpy(buf, store_ptr, nstored);    /* safe */
12055             nreturned += nstored;
12056             buf += nstored;
12057             len -= nstored;
12058             nstored = 0;
12059         } else
12060             return(0);
12061     }
12062
12063     /* We're fetching the length which is MSB first, and the MSB
12064     has to be zero unless the client is sending more than 2^24
12065     (16M) bytes in a single write (which is why this code is in
12066     rlogin but not rcp or rsh.) The only reasons we'd get something
12067     other than zero are:
12068     -- corruption of the tcp stream (which will show up when
12069     everything else is out of sync too)
12070     -- un-caught Berkeley-style "pseudo out-of-band data" which
12071     happens any time the user hits ^C twice.
12072     The latter is *very* common, as shown by an 'rlogin -x -d'
12073     using the CNS V4 rlogin.         Mark EIchin 1/95
12074     */
12075     debug(F110,"krb4_des_read",
12076           "about to call net_read() this will block",
12077           0
12078           );
12079     do {
12080         cc = net_read(fd, &c, 1);
12081         debug(F111,"net_read","chars read",cc);
12082         if (cc <= 0) {
12083             netclos();
12084             return(-1);
12085         }
12086         if (cc != 1) return 0; /* read error */
12087         if (cc == 1) {
12088             if (c == 0) gotzero = 1;
12089         }
12090     } while (!gotzero);
12091
12092     debug(F110,"krb4_des_read","gotzero",0);
12093     cc = net_read(fd, &c, 1);
12094     debug(F111,"net_read","chars read",cc);
12095     if (cc < 0) {
12096         netclos();
12097         return(-1);
12098     } else if ( cc != 1 )
12099         return(0);
12100     net_len = c;
12101     cc = net_read(fd, &c, 1);
12102     debug(F111,"net_read","chars read",cc);
12103     if (cc < 0) {
12104         netclos();
12105         return(-1);
12106     } else if ( cc != 1 )
12107         return(0);
12108     net_len = (net_len << 8) | c;
12109     debug(F111,"net_read","chars read",cc);
12110     cc = net_read(fd, &c, 1);
12111     if (cc < 0) {
12112         netclos();
12113         return(-1);
12114     } else if ( cc != 1 )
12115         return(0);
12116     net_len = (net_len << 8) | c;
12117     debug(F111,"krb4_des_read","net_len",net_len);
12118
12119     /* Note: net_len is unsigned */
12120     if (net_len > sizeof(des_inbuf)) {
12121         /* XXX preposterous length, probably out of sync.
12122         act as if pipe closed */
12123         return(0);
12124     }
12125     /* the writer tells us how much real data we are getting, but
12126     we need to read the pad bytes (8-byte boundary) */
12127 #ifndef roundup
12128 #define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
12129 #endif /* roundup */
12130     rd_len = roundup(net_len, 8);
12131     debug(F111,"krb4_des_read","rd_len",rd_len);
12132     cc = net_read(fd, des_inbuf, rd_len);
12133     debug(F111,"net_read","chars read",cc);
12134     if (cc < 0) {
12135         netclos();
12136         return(-1);
12137     } else if ( cc != rd_len )
12138         return(0);
12139
12140     ckhexdump("krb4_des_read des_inbuf",des_inbuf,8);
12141 #ifdef CK_ENCRYPTION
12142 #ifdef KRB524
12143     (void) des_pcbc_encrypt(des_inbuf,
12144                              storage,
12145                              (net_len < 8) ? 8 : net_len,
12146                              k4_sched,
12147                              cred.session,
12148                              DECRYPT);
12149 #else /* KRB524 */
12150     (void) des_pcbc_encrypt((Block *)des_inbuf,
12151                              (Block *)storage,
12152                              (net_len < 8) ? 8 : net_len,
12153                              k4_sched,
12154                              &cred.session,
12155                              DECRYPT);
12156 #endif /* KRB524 */
12157 #endif /* ENCRYPTION */
12158     ckhexdump("krb4_des_read storage",storage,8);
12159
12160     /*
12161     * when the cleartext block is < 8 bytes, it is "right-justified"
12162     * in the block, so we need to adjust the pointer to the data
12163     */
12164     if (net_len < 8)
12165         store_ptr = storage + 8 - net_len;
12166     else
12167         store_ptr = storage;
12168     nstored = net_len;
12169
12170     if ( !buf )
12171         return(0);
12172
12173     if (nstored > len) {
12174         memcpy(buf, store_ptr, len);            /* safe */
12175         nreturned += len;
12176         store_ptr += len;
12177         nstored -= len;
12178     } else {
12179         memcpy(buf, store_ptr, nstored);        /* safe */
12180         nreturned += nstored;
12181         nstored = 0;
12182     }
12183
12184     debug(F111,"net_read","nreturned",nreturned);
12185     return(nreturned);
12186 }
12187
12188 int
12189 krb4_des_write(fd, buf, len)
12190 int fd;
12191 char *buf;
12192 int len;
12193 {
12194     static char garbage_buf[8];
12195     unsigned char *len_buf = (unsigned char *) des_outpkt;
12196     int cc;
12197
12198     debug(F111,"krb4_des_write","rlog_encrypt",rlog_encrypt);
12199     if ( !rlog_encrypt ) {
12200         cc = net_write(fd, buf, len);
12201         debug(F111,"net_write","chars written",cc);
12202         return(cc);
12203     }
12204
12205     /*
12206     * pcbc_encrypt outputs in 8-byte (64 bit) increments
12207     *
12208     * it zero-fills the cleartext to 8-byte padding,
12209     * so if we have cleartext of < 8 bytes, we want
12210     * to insert random garbage before it so that the ciphertext
12211     * differs for each transmission of the same cleartext.
12212     * if len < 8 - sizeof(long), sizeof(long) bytes of random
12213     * garbage should be sufficient; leave the rest as-is in the buffer.
12214     * if len > 8 - sizeof(long), just garbage fill the rest.
12215     */
12216     if (len < 8) {
12217         random_confounder(8 - len, garbage_buf);
12218         /* this "right-justifies" the data in the buffer */
12219         (void) memcpy(garbage_buf + 8 - len, buf, len); /* safe */
12220         ckhexdump("krb4_des_write garbage_buf",garbage_buf,8);
12221     } else
12222         ckhexdump("krb4_des_write buf",buf,8);
12223 #ifdef CK_ENCRYPTION
12224 #ifdef KRB524
12225     (void) des_pcbc_encrypt((len < 8) ? garbage_buf : buf,
12226                              des_outpkt+4,
12227                              (len < 8) ? 8 : len,
12228                              k4_sched,
12229                              cred.session,
12230                              ENCRYPT);
12231 #else /* KRB524 */
12232     (void) des_pcbc_encrypt((Block *)((len < 8) ? garbage_buf : buf),
12233                              (Block *)(des_outpkt+4),
12234                              (len < 8) ? 8 : len,
12235                              k4_sched,
12236                              &cred.session,
12237                              ENCRYPT);
12238 #endif /* KRB524 */
12239 #endif /* ENCRYPTION */
12240     if ( len < 8 )
12241         ckhexdump("krb4_des_write (post pcbc) garbage_buf",garbage_buf,8);
12242     else
12243         ckhexdump("krb4_des_write (post pcbc) buf",buf,8);
12244     ckhexdump("krb4_des_write (des_outpkt+4)",(des_outpkt+4),8);
12245
12246     /* tell the other end the real amount, but send an 8-byte padded
12247     packet */
12248     len_buf[0] = (len & 0xff000000) >> 24;
12249     len_buf[1] = (len & 0xff0000) >> 16;
12250     len_buf[2] = (len & 0xff00) >> 8;
12251     len_buf[3] = (len & 0xff);
12252     ckhexdump("krb4_des_write des_outpkt len",des_outpkt,12);
12253     cc = net_write(fd, des_outpkt, roundup(len,8)+4);
12254     debug(F111,"net_write","chars written",cc);
12255     return(len);
12256 }
12257 #endif /* KRB4 */
12258 #endif /* RLOGCODE */
12259
12260 #ifdef KRB524
12261 #ifndef OS2
12262 /* The following functions are missing from the compatibility library */
12263 const char *
12264 krb_get_err_text_entry(r) int r;
12265 {
12266     extern char krb_err_text[];
12267     return(krb_err_txt[r]);
12268 }
12269 #endif /* OS2 */
12270 #endif /* KRB524 */
12271 #endif /* CK_KERBEROS */
12272
12273 #ifdef CK_KERBEROS
12274 #ifdef KRB5_U2U
12275 /* Kerberos 5 User to User Client */
12276 int
12277 k5_user_to_user_client_auth()
12278 {
12279     extern int ttyfd;
12280     register int retval, i;
12281     char **srealms;             /* realm(s) of server */
12282     char *princ;                /* principal in credentials cache */
12283     krb5_ccache cc;
12284     krb5_creds creds, *new_creds;
12285     krb5_data reply, msg, msgtext, princ_data;
12286     krb5_ticket * ticket = NULL;
12287
12288     if (retval = k5_get_ccache(k5_context,&cc,NULL))
12289     {
12290         com_err("uu-client", retval, "getting credentials cache");
12291         return(-1);
12292     }
12293
12294     memset ((char*)&creds, 0, sizeof(creds));
12295     if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client))
12296     {
12297         com_err("uu-client", retval, "getting principal name");
12298         return(-1);
12299     }
12300
12301     if (retval = krb5_get_host_realm(k5_context, szHostName, &srealms))
12302     {
12303         com_err("uu-client", retval, "getting realms for \"%s\"", szHostName);
12304         return(-1);
12305     }
12306
12307     if (retval = krb5_build_principal_ext(k5_context, &creds.server,
12308                                           krb5_princ_realm(k5_context,
12309                                                          creds.client)->length,
12310                                           krb5_princ_realm(k5_context,
12311                                                          creds.client)->data,
12312                                           6, "krbtgt",
12313                                           krb5_princ_realm(k5_context,
12314                                                          creds.client)->length,
12315                                           krb5_princ_realm(k5_context,
12316                                                          creds.client)->data,
12317                                           0))
12318     {
12319         com_err("uu-client", retval, "setting up tgt server name");
12320         return(-1);
12321     }
12322
12323     /* Get TGT from credentials cache */
12324     if (retval = krb5_get_credentials(k5_context, KRB5_GC_CACHED, cc,
12325                                        &creds, &new_creds))
12326     {
12327         com_err("uu-client", retval, "getting TGT");
12328         return(-1);
12329     }
12330
12331     if (retval = krb5_unparse_name(k5_context, creds.client, &princ)) {
12332         com_err("uu-client", retval, "printing principal name");
12333         return(-1);
12334     }
12335     i = strlen(princ) + 1;
12336     princ_data.data = princ;
12337     princ_data.length = i;              /* include null terminator for
12338                                            server's convenience */
12339     retval = krb5_write_message(k5_context,
12340                                 (krb5_pointer) &ttyfd, &princ_data);
12341     if (retval)
12342     {
12343         com_err("uu-client", retval, "sending principal name to server");
12344         return(-1);
12345     }
12346     krb5_free_unparsed_name(k5_context,princ);
12347
12348     retval = krb5_write_message(k5_context,
12349                                 (krb5_pointer) &ttyfd, &new_creds->ticket);
12350     if (retval)
12351     {
12352         com_err("uu-client", retval, "sending ticket to server");
12353         return(-1);
12354     }
12355
12356     retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &reply);
12357     if (retval)
12358     {
12359         com_err("uu-client", retval, "reading reply from server");
12360         return(-1);
12361     }
12362
12363     if (retval = krb5_auth_con_init(k5_context, &auth_context)) {
12364         com_err("uu-client", retval, "initializing the auth_context");
12365         return(-1);
12366     }
12367
12368     if (!krb5_d_no_addresses) {
12369       if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
12370                         KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
12371                         KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) {
12372         com_err("uu-client", retval, "generating addrs for auth_context");
12373         return(-1);
12374       }
12375     }
12376
12377     if (retval = krb5_auth_con_setflags(k5_context, auth_context,
12378                                         KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
12379         com_err("uu-client", retval, "initializing the auth_context flags");
12380         return(-1);
12381     }
12382
12383     if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context,
12384                                               &new_creds->keyblock)) {
12385         com_err("uu-client", retval, "setting useruserkey for authcontext");
12386         return(-1);
12387     }
12388
12389     /* read the ap_req to get the session key */
12390     retval = krb5_rd_req(k5_context, &auth_context, &reply,
12391                           NULL, NULL, NULL, &ticket);
12392     if (retval) {
12393         com_err("uu-client", retval, "reading AP_REQ from server");
12394         return(-1);
12395     }
12396
12397     if (k5_u2u_read_msg(k5_context,&msg) < 0)
12398         return(-1);
12399
12400     if ( strcmp("Kermit implements Kerberos 5 User to User",msg.data) )
12401         return(-1);
12402     krb5_free_data_contents(k5_context,&msg);
12403
12404     msgtext.data = "As do I! :-)";
12405     msgtext.length = strlen(msgtext.data)+1;
12406
12407     if (k5_u2u_write_msg(k5_context,&msgtext) < 0)
12408         return(-1);
12409
12410     if (retval = krb5_unparse_name(k5_context,
12411 #ifdef HEIMDAL
12412                                     ticket->client,
12413 #else /* HEIMDAL */
12414                                     ticket->enc_part2->client,
12415 #endif /* HEIMDAL */
12416                                     &princ))
12417         com_err("uu-client", retval, "while unparsing client name");
12418     else {
12419         ckstrncpy(szUserNameAuthenticated,princ,UIDBUFLEN);
12420         validUser = AUTH_VALID;
12421         authentication_version = AUTHTYPE_KERBEROS_V5;
12422         if ( !quiet )
12423             printf("Peer name is \"%s\"\n", princ);
12424         krb5_free_unparsed_name(k5_context,princ);
12425     }
12426     return 0;
12427 }
12428
12429 /* Kerberos 5 User to User Server */
12430
12431 int
12432 k5_user_to_user_server_auth()
12433 {
12434     krb5_data pname_data, tkt_data;
12435     int retval;
12436     krb5_creds creds, *new_creds;
12437     krb5_ccache cc;
12438     krb5_data msg, msgtext;
12439     extern int ttyfd;
12440
12441     if (retval = krb5_read_message(k5_context,
12442                                    (krb5_pointer) &ttyfd, &pname_data)) {
12443         com_err ("uu-server", retval, "reading pname");
12444         return(-1);
12445     }
12446     /* client sends it already null-terminated. */
12447     if ( !quiet )
12448         printf ("Peer name is \"%s\".\n", pname_data.data);
12449     ckstrncpy(szUserNameAuthenticated,pname_data.data,UIDBUFLEN);
12450     validUser = AUTH_VALID;
12451     authentication_version = AUTHTYPE_KERBEROS_V5;
12452
12453     if (retval = krb5_read_message(k5_context,
12454                                    (krb5_pointer) &ttyfd, &tkt_data)) {
12455         com_err ("uu-server", retval, "reading ticket data");
12456         return(-1);
12457     }
12458
12459     if (retval = k5_get_ccache(k5_context,&cc,NULL))
12460     {
12461         com_err("uu-server", retval, "getting credentials cache");
12462         return(-1);
12463     }
12464
12465     memset ((char*)&creds, 0, sizeof(creds));
12466     if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client))
12467     {
12468         com_err("uu-server", retval, "getting principal name");
12469         return(-1);
12470     }
12471
12472     if (retval = krb5_parse_name(k5_context, pname_data.data, &creds.server))
12473     {
12474         com_err("uu-server", retval, "parsing client name");
12475         return(-1);
12476     }
12477     creds.second_ticket = tkt_data;
12478
12479     if (retval = krb5_get_credentials(k5_context, KRB5_GC_USER_USER,
12480                                        cc, &creds, &new_creds))
12481     {
12482         com_err("uu-server", retval, "getting user-user ticket");
12483         return(-1);
12484     }
12485
12486     /* send a ticket/authenticator to the other side, so it can get the key
12487        we're using for the krb_safe below. */
12488
12489     if (retval = krb5_auth_con_init(k5_context, &auth_context)) {
12490         com_err("uu-server", retval, "making auth_context");
12491         return(-1);
12492     }
12493
12494     if (retval = krb5_auth_con_setflags(k5_context, auth_context,
12495                                          KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
12496         com_err("uu-server", retval, "initializing the auth_context flags");
12497         return(-1);
12498     }
12499
12500     if (!krb5_d_no_addresses) {
12501       if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
12502                                 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
12503                                 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) {
12504         com_err("uu-server", retval, "generating addrs for auth_context");
12505         return(-1);
12506       }
12507     }
12508
12509     if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context,
12510                                               &new_creds->keyblock)) {
12511         com_err("uu-server", retval, "setting useruserkey for authcontext");
12512         return(-1);
12513     }
12514
12515     if (retval = krb5_mk_req_extended(k5_context, &auth_context,
12516                                       AP_OPTS_USE_SESSION_KEY |
12517                                       AP_OPTS_MUTUAL_REQUIRED,
12518                                       NULL, new_creds, &msg)) {
12519         com_err("uu-server", retval, "making AP_REQ");
12520         return(-1);
12521     }
12522     retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &msg);
12523     if (retval) {
12524         com_err("uu-server", retval, "writing message to client");
12525         return(-1);
12526     }
12527     krb5_free_data_contents(k5_context,&msg);
12528
12529     msgtext.data = "Kermit implements Kerberos 5 User to User";
12530     msgtext.length = strlen(msgtext.data)+1;
12531
12532     if (k5_u2u_write_msg(k5_context,&msgtext) < 0)
12533         return(-1);
12534
12535     if (k5_u2u_read_msg(k5_context,&msg) < 0)
12536         return(-1);
12537
12538     if ( strcmp("As do I! :-)",msg.data) )
12539         return(-1);
12540     krb5_free_data_contents(k5_context,&msg);
12541
12542
12543     return(0);
12544 }
12545
12546 int
12547 k5_u2u_read_msg(krb5_context context, int fd, krb5_data * msg)
12548 {
12549     int retval;
12550     krb5_data reply;
12551
12552     retval = krb5_read_message(context, (krb5_pointer) &fd, &reply);
12553     if (retval)
12554     {
12555         com_err("uu-client", retval, "reading reply");
12556         return(-1);
12557     }
12558
12559     if (retval = krb5_rd_priv(context, auth_context, &reply, msg, NULL)) {
12560         com_err("uu-client", retval, "decoding reply");
12561         return(-1);
12562     }
12563     return(0);
12564 }
12565
12566 int
12567 k5_u2u_write_msg(krb5_context context, int fd, krb5_data * msgtext)
12568 {
12569     int retval;
12570     krb5_data msg;
12571
12572     if (retval = krb5_mk_priv(k5_context, auth_context, msgtext, &msg, NULL))
12573     {
12574         com_err("uu-server", retval, "encoding message");
12575         return(-1);
12576     }
12577
12578     retval = krb5_write_message(k5_context, (krb5_pointer) &fd, &msg);
12579     krb5_free_data_contents(k5_context,&msg);
12580     if (retval)
12581     {
12582         com_err("uu-server", retval, "writing message");
12583         return(-1);
12584     }
12585     return(0);
12586 }
12587
12588 int
12589 krb5_u2u_avail(fd)
12590     int fd;
12591 {
12592     return(nstored);
12593 }
12594
12595 int
12596 krb5_u2u_read(fd, buf, len)
12597      int fd;
12598      register char *buf;
12599      int len;
12600 {
12601     int nreturned = 0;
12602     krb5_data msg;
12603
12604     debug(F111,"krb5_u2u_read","len",len);
12605
12606     if ( !buf )
12607         return(0);
12608
12609     if (nstored >= len) {
12610         memcpy(buf, store_ptr, len);        /* safe */
12611         store_ptr += len;
12612         nstored -= len;
12613         return(len);
12614     } else if (nstored) {
12615         memcpy(buf, store_ptr, nstored);    /* safe */
12616         nreturned += nstored;
12617         buf += nstored;
12618         len -= nstored;
12619         nstored = 0;
12620     }
12621
12622     if (k5_u2u_read_msg(k5_context, fd, &msg) < 0)
12623         return(-1);
12624
12625     if ( msg.length <= len ) {
12626         memcpy(buf, msg.data, msg.length);
12627         nreturned += msg.length;
12628         nstored = 0;
12629     } else {
12630         memcpy(buf, msg.data, len);
12631         nreturned += len;
12632
12633         if ( msg.length - len < sizeof(storage) ) {
12634             store_ptr = storage;
12635             nstored = msg.length - len;
12636             memcpy(storage,msg.data+len,nstored);
12637         } else {
12638             nstored = 0;
12639             return(-1);
12640         }
12641     }
12642     return(nreturned);
12643 }
12644
12645 int
12646 krb5_u2u_write(fd, buf, len)
12647      int fd;
12648      char *buf;
12649      int len;
12650 {
12651     krb5_data msg;
12652
12653     msg.length = len;
12654     msg.data = buf;
12655
12656     if ( k5_u2u_write_msg(k5_context, fd, &msg) < 0 )
12657         return(-1);
12658     else
12659         return(len);
12660 }
12661
12662 #endif /* KRB5_U2U */
12663 #endif /* CK_KERBEROS */
12664
12665 #ifdef CK_FORWARD_X
12666 /*
12667
12668 Copyright (c) 1988  X Consortium
12669
12670 Permission is hereby granted, free of charge, to any person obtaining a copy
12671 of this software and associated documentation files (the "Software"), to deal
12672 in the Software without restriction, including without limitation the rights
12673 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12674 copies of the Software, and to permit persons to whom the Software is
12675 furnished to do so, subject to the following conditions:
12676
12677 The above copyright notice and this permission notice shall be included in
12678 all copies or substantial portions of the Software.
12679
12680 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12681 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12682 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
12683 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
12684 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
12685 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12686
12687 Except as contained in this notice, the name of the X Consortium shall not be
12688 used in advertising or otherwise to promote the sale, use or other dealings
12689 in this Software without prior written authorization from the X Consortium.
12690
12691 */
12692 /*  Modified for stand-alone compiling by
12693  *  Peter 'Luna' Runestig <peter@runestig.com>
12694  */
12695
12696 #include <stdlib.h>
12697 #include <string.h>
12698 #include <fcntl.h>
12699 #include <sys/stat.h>
12700 #include <time.h>
12701 #define Time_t time_t
12702
12703 void
12704 XauDisposeAuth (auth)
12705 Xauth   *auth;
12706 {
12707     if (auth) {
12708         if (auth->address) (void) free (auth->address);
12709         if (auth->number) (void) free (auth->number);
12710         if (auth->name) (void) free (auth->name);
12711         if (auth->data) {
12712             (void) bzero (auth->data, auth->data_length);
12713             (void) free (auth->data);
12714         }
12715         free ((char *) auth);
12716     }
12717     return;
12718 }
12719
12720 char *
12721 XauFileName ()
12722 {
12723     char *slashDotXauthority = "/.Xauthority";
12724     char    *name;
12725     static char *buf=NULL;
12726     static int  bsize=0;
12727     int     size, namelen;
12728     extern char * tn_fwdx_xauthority;
12729
12730     if ( tn_fwdx_xauthority )
12731         return(tn_fwdx_xauthority);
12732
12733     if (name = getenv ("XAUTHORITY"))
12734         return(name);
12735     name = zhome();
12736     if ( !name )
12737         return(NULL);
12738     namelen = strlen (name);
12739     size = namelen + strlen(slashDotXauthority) + 1;
12740     if (size > bsize) {
12741         if (buf)
12742             free (buf);
12743         buf = malloc ((unsigned) size);
12744         if (!buf)
12745             return 0;
12746         bsize = size;
12747     }
12748     ckstrncpy (buf, name, bsize);
12749     if ( name[namelen-1] != '/'
12750 #ifdef OS2
12751          && name[namelen-1] != '\\'
12752 #endif /* OS2 */
12753          )
12754         ckstrncat (buf, slashDotXauthority, bsize);
12755     else
12756         ckstrncat (buf, &slashDotXauthority[1], bsize);
12757     return(buf);
12758 }
12759
12760 static int
12761 binaryEqual (a, b, len)
12762 register char   *a, *b;
12763 register int    len;
12764 {
12765     while (len--)
12766         if (*a++ != *b++)
12767             return 0;
12768     return 1;
12769 }
12770
12771 #ifndef R_OK
12772 #define R_OK 04
12773 #endif /* R_OK */
12774
12775 Xauth *
12776 XauGetAuthByAddr (family, address_length, address,
12777                           number_length, number,
12778                           name_length, name)
12779 unsigned int    family;
12780 unsigned int    address_length;
12781 const char      *address;
12782 unsigned int    number_length;
12783 const char      *number;
12784 unsigned int    name_length;
12785 const char      *name;
12786 {
12787     FILE    *auth_file;
12788     char    *auth_name;
12789     Xauth   *entry;
12790
12791     auth_name = XauFileName();
12792     if (!auth_name)
12793         return 0;
12794     if (access (auth_name, R_OK) != 0)          /* checks REAL id */
12795         return 0;
12796     auth_file = fopen (auth_name, "rb");
12797     if (!auth_file)
12798         return 0;
12799     for (;;) {
12800         entry = XauReadAuth (auth_file);
12801         if (!entry)
12802             break;
12803         /*
12804          * Match when:
12805          *   either family or entry->family are FamilyWild or
12806          *    family and entry->family are the same
12807          *  and
12808          *   either address or entry->address are empty or
12809          *    address and entry->address are the same
12810          *  and
12811          *   either number or entry->number are empty or
12812          *    number and entry->number are the same
12813          *  and
12814          *   either name or entry->name are empty or
12815          *    name and entry->name are the same
12816          */
12817
12818 /*      if ((family == FamilyWild || entry->family == FamilyWild ||
12819              (entry->family == family &&
12820               address_length == entry->address_length &&
12821               binaryEqual (entry->address, address, (int)address_length))) &&
12822             (number_length == 0 || entry->number_length == 0 ||
12823              (number_length == entry->number_length &&
12824               binaryEqual (entry->number, number, (int)number_length))) &&
12825             (name_length == 0 || entry->name_length == 0 ||
12826              (entry->name_length == name_length &&
12827               binaryEqual (entry->name, name, (int)name_length)))) */
12828         /* the original matching code above doesn't seem to meet the matching
12829          * algorithm, it doesn't check if "address_length == 0 ||
12830          * entry->address_length == 0". / Luna 2000-02-09
12831          */
12832         if ((family == FamilyWild || entry->family == FamilyWild ||
12833               entry->family == family) &&
12834             (address_length == 0 || entry->address_length == 0 ||
12835               (address_length == entry->address_length &&
12836               binaryEqual (entry->address, address, (int)address_length))) &&
12837             (number_length == 0 || entry->number_length == 0 ||
12838              (number_length == entry->number_length &&
12839               binaryEqual (entry->number, number, (int)number_length))) &&
12840             (name_length == 0 || entry->name_length == 0 ||
12841              (entry->name_length == name_length &&
12842               binaryEqual (entry->name, name, (int)name_length))))
12843             break;
12844         XauDisposeAuth (entry);
12845     }
12846     (void) fclose (auth_file);
12847     return entry;
12848 }
12849
12850 static int
12851 read_short (shortp, file)
12852 unsigned short  *shortp;
12853 FILE            *file;
12854 {
12855     unsigned char   file_short[2];
12856
12857     if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
12858         return 0;
12859     *shortp = file_short[0] * 256 + file_short[1];
12860     return 1;
12861 }
12862
12863 static int
12864 read_counted_string (countp, stringp, file)
12865 unsigned short  *countp;
12866 char    **stringp;
12867 FILE    *file;
12868 {
12869     unsigned short  len;
12870     char            *data;
12871
12872     if (read_short (&len, file) == 0)
12873         return 0;
12874     if (len == 0) {
12875         data = 0;
12876     } else {
12877         data = malloc ((unsigned) len);
12878         if (!data)
12879             return 0;
12880         if (fread (data, (int) sizeof (char), (int) len, file) != len) {
12881             bzero (data, len);
12882             free (data);
12883             return 0;
12884         }
12885     }
12886     *stringp = data;
12887     *countp = len;
12888     return 1;
12889 }
12890
12891 Xauth *
12892 XauReadAuth (auth_file)
12893 FILE    *auth_file;
12894 {
12895     Xauth   local;
12896     Xauth   *ret;
12897
12898     if (read_short (&local.family, auth_file) == 0)
12899         return 0;
12900     if (read_counted_string (&local.address_length,
12901                              &local.address, auth_file) == 0)
12902         return 0;
12903     if (read_counted_string (&local.number_length,
12904                              &local.number, auth_file) == 0) {
12905         if (local.address) free (local.address);
12906         return 0;
12907     }
12908     if (read_counted_string (&local.name_length,
12909                              &local.name, auth_file) == 0) {
12910         if (local.address) free (local.address);
12911         if (local.number) free (local.number);
12912         return 0;
12913     }
12914     if (read_counted_string (&local.data_length,
12915                              &local.data, auth_file) == 0) {
12916         if (local.address) free (local.address);
12917         if (local.number) free (local.number);
12918         if (local.name) free (local.name);
12919         return 0;
12920     }
12921     ret = (Xauth *) malloc (sizeof (Xauth));
12922     if (!ret) {
12923         if (local.address) free (local.address);
12924         if (local.number) free (local.number);
12925         if (local.name) free (local.name);
12926         if (local.data) {
12927             bzero (local.data, local.data_length);
12928             free (local.data);
12929         }
12930         return 0;
12931     }
12932     *ret = local;
12933     return ret;
12934 }
12935
12936 static int
12937 write_short (s, file)
12938 unsigned short  s;
12939 FILE            *file;
12940 {
12941     unsigned char   file_short[2];
12942
12943     file_short[0] = (s & (unsigned)0xff00) >> 8;
12944     file_short[1] = s & 0xff;
12945     if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
12946         return 0;
12947     return 1;
12948 }
12949
12950 static int
12951 write_counted_string (count, string, file)
12952 unsigned short  count;
12953 char    *string;
12954 FILE    *file;
12955 {
12956     if (write_short (count, file) == 0)
12957         return 0;
12958     if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
12959         return 0;
12960     return 1;
12961 }
12962
12963 int
12964 XauWriteAuth (auth_file, auth)
12965 FILE    *auth_file;
12966 Xauth   *auth;
12967 {
12968     if (write_short (auth->family, auth_file) == 0)
12969         return 0;
12970     if (write_counted_string (auth->address_length,
12971                               auth->address, auth_file) == 0)
12972         return 0;
12973     if (write_counted_string (auth->number_length,
12974                               auth->number, auth_file) == 0)
12975         return 0;
12976     if (write_counted_string (auth->name_length, auth->name, auth_file) == 0)
12977         return 0;
12978     if (write_counted_string (auth->data_length, auth->data, auth_file) == 0)
12979         return 0;
12980     return 1;
12981 }
12982
12983 #ifdef KRB5
12984 #ifdef K5_XAUTH
12985 /*
12986  * functions to encode/decode Kerberos V5 principals
12987  * into something that can be reasonable spewed over
12988  * the wire
12989  *
12990  * Author: Tom Yu <tlyu@MIT.EDU>
12991  *
12992  * Still needs to be fixed up wrt signed/unsigned lengths, but we'll worry
12993  * about that later.
12994  */
12995
12996 /*
12997  * XauKrb5Encode
12998  *
12999  * this function encodes the principal passed to it in a format that can
13000  * easily be dealt with by stuffing it into an X packet.  Encoding is as
13001  * follows:
13002  *   length count of the realm name
13003  *   realm
13004  *   component count
13005  *   length of component
13006  *   actual principal component
13007  *   etc....
13008  *
13009  * Note that this function allocates a hunk of memory, which must be
13010  * freed to avoid nasty memory leak type things.  All counts are
13011  * byte-swapped if needed. (except for the total length returned)
13012  *
13013  * nevermind.... stuffing the encoded packet in net byte order just to
13014  * always do the right thing.  Don't have to frob with alignment that way.
13015  */
13016 int
13017 XauKrb5Encode(princ, outbuf)
13018     krb5_principal princ;       /* principal to encode */
13019     krb5_data *outbuf;          /* output buffer */
13020 {
13021     CARD16 i, numparts, totlen = 0, plen, rlen;
13022     char *cp, *pdata;
13023
13024     rlen = krb5_princ_realm(princ)->length;
13025     numparts = krb5_princ_size(princ);
13026     totlen = 2 + rlen + 2;      /* include room for realm length
13027                                    and component count */
13028     for (i = 0; i < numparts; i++)
13029         totlen += krb5_princ_component(princ, i)->length + 2;
13030     /* add 2 bytes each time for length */
13031     if ((outbuf->data = (char *)malloc(totlen)) == NULL)
13032         return -1;
13033     cp = outbuf->data;
13034     *cp++ = (char)((int)(0xff00 & rlen) >> 8);
13035     *cp++ = (char)(0x00ff & rlen);
13036     memcpy(cp, krb5_princ_realm(princ)->data, rlen);    /* safe */
13037     cp += rlen;
13038     *cp++ = (char)((int)(0xff00 & numparts) >> 8);
13039     *cp++ = (char)(0x00ff & numparts);
13040     for (i = 0; i < numparts; i++)
13041     {
13042         plen = krb5_princ_component(princ, i)->length;
13043         pdata = krb5_princ_component(princ, i)->data;
13044         *cp++ = (char)((int)(0xff00 & plen) >> 8);
13045         *cp++ = (char)(0x00ff & plen);
13046         memcpy(cp, pdata, plen);                        /* safe */
13047         cp += plen;
13048     }
13049     outbuf->length = totlen;
13050     return 0;
13051 }
13052
13053 /*
13054  * XauKrb5Decode
13055  *
13056  * This function essentially reverses what XauKrb5Encode does.
13057  * return value: 0 if okay, -1 if malloc fails, -2 if inbuf format bad
13058  */
13059 int
13060 XauKrb5Decode(inbuf, princ)
13061     krb5_data inbuf;
13062     krb5_principal *princ;
13063 {
13064     CARD16 i, numparts, plen, rlen;
13065     CARD8 *cp, *pdata;
13066
13067     if (inbuf.length < 4)
13068     {
13069         return -2;
13070     }
13071     *princ = (krb5_principal)malloc(sizeof (krb5_principal_data));
13072     if (*princ == NULL)
13073         return -1;
13074     bzero(*princ, sizeof (krb5_principal_data));
13075     cp = (CARD8 *)inbuf.data;
13076     rlen = *cp++ << 8;
13077     rlen |= *cp++;
13078     if (inbuf.length < 4 + (int)rlen + 2)
13079     {
13080         krb5_free_principal(*princ);
13081         return -2;
13082     }
13083     krb5_princ_realm(*princ)->data = (char *)malloc(rlen);
13084     if (krb5_princ_realm(*princ)->data == NULL)
13085     {
13086         krb5_free_principal(*princ);
13087         return -1;
13088     }
13089     krb5_princ_realm(*princ)->length = rlen;
13090     memcpy(krb5_princ_realm(*princ)->data, cp, rlen);   /* safe */
13091     cp += rlen;
13092     numparts = *cp++ << 8;
13093     numparts |= *cp++;
13094     krb5_princ_name(*princ) =
13095         (krb5_data *)malloc(numparts * sizeof (krb5_data));
13096     if (krb5_princ_name(*princ) == NULL)
13097     {
13098         krb5_free_principal(*princ);
13099         return -1;
13100     }
13101     krb5_princ_size(*princ) = 0;
13102     for (i = 0; i < numparts; i++)
13103     {
13104         if (cp + 2 > (CARD8 *)inbuf.data + inbuf.length)
13105         {
13106             krb5_free_principal(*princ);
13107             return -2;
13108         }
13109         plen = *cp++ << 8;
13110         plen |= *cp++;
13111         if (cp + plen > (CARD8 *)inbuf.data + inbuf.length)
13112         {
13113             krb5_free_principal(*princ);
13114             return -2;
13115         }
13116         pdata = (CARD8 *)malloc(plen);
13117         if (pdata == NULL)
13118         {
13119             krb5_free_principal(*princ);
13120             return -1;
13121         }
13122         krb5_princ_component(*princ, i)->data = (char *)pdata;
13123         krb5_princ_component(*princ, i)->length = plen;
13124         memcpy(pdata, cp, plen);        /* safe */
13125         cp += plen;
13126         krb5_princ_size(*princ)++;
13127     }
13128     return 0;
13129 }
13130 #endif /* K5_XAUTH */
13131 #endif /* KRB5 */
13132 #endif /* CK_FORWARD_X */
13133 #endif /* CK_AUTHENTICATION */
13134
13135 /* C K _ A U T H _ I N I T
13136  * Initialize the Kerberos system for a pending connection
13137  *   hostname - a reverse DNS lookup of the hostname when possible
13138  *   ipaddr   - the ip address of the host
13139  *   username - the name the user wants to connect under not necessarily
13140  *              the same as principal
13141  *   socket   - the socket handle (ttyfd in Kermit speak)
13142  *
13143  * Returns: 1 on success and 0 on failure
13144  */
13145
13146 int
13147 #ifdef CK_ANSIC
13148 ck_auth_init( char * hostname, char * ipaddr, char * username, int socket )
13149 #else /* CK_ANSIC */
13150 ck_auth_init( hostname, ipaddr, username, socket )
13151     char * hostname; char * ipaddr; char *username; int socket;
13152 #endif /* CK_ANSIC */
13153 {
13154 #ifdef CK_AUTHENTICATION
13155 #ifdef OS2
13156     if ( !ck_security_loaddll() ) {
13157         TELOPT_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
13158         TELOPT_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
13159         return(0);
13160     }
13161 #endif /* OS2 */
13162 #endif /* CK_AUTHENTICAITON */
13163 #ifdef CK_ENCRYPTION
13164     if ( !!ck_crypt_is_installed() ) {
13165         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
13166         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
13167     }
13168 #endif /* CK_ENCRYPTION */
13169
13170     if (!hostname) hostname = "";
13171     if (!ipaddr) ipaddr = "";
13172     if (!username) username = "";
13173
13174     debug(F110,"ck_auth_init Username",username,0);
13175     debug(F110,"ck_auth_init Hostname",hostname,0);
13176     debug(F110,"ck_auth_init Ipaddr",ipaddr,0);
13177
13178     ckstrncpy( szUserName, username, UIDBUFLEN );
13179     ckstrncpy( szHostName, hostname, UIDBUFLEN );
13180     ckstrncpy( szIP, ipaddr, 16 );
13181     szUserNameRequested[0] = '\0';
13182     szUserNameAuthenticated[0] = '\0';
13183     validUser = AUTH_REJECT;
13184     accept_complete = 0;
13185     authentication_version = AUTHTYPE_NULL;
13186
13187 #ifdef CK_AUTHENTICATION
13188     auth_how = 0;
13189     auth_crypt = 0;
13190     auth_fwd = 0;
13191     mutual_complete = 0;
13192     if ( sstelnet )
13193         str_data[3] = TELQUAL_REPLY;
13194     else
13195         str_data[3] = TELQUAL_IS;
13196 #endif /* CK_AUTHENTICATION */
13197
13198 #ifdef CK_SRP
13199     srp_waitresp = 0;
13200 #endif /* SRP */
13201
13202 #ifdef CK_KERBEROS
13203 #ifdef KRB5
13204     /* free previous ret_cred  */
13205     if ( ret_cred ) {
13206 #ifdef CK_ENCRYPTION
13207 #ifdef HEIMDAL
13208         if ( k5_session_key == &ret_cred->session)
13209             k5_session_key = NULL;
13210 #else /* HEIMDAL */
13211         if ( k5_session_key == &ret_cred->keyblock)
13212             k5_session_key = NULL;
13213 #endif /* HEIMDAL */
13214 #endif /* CK_ENCRYPTION */
13215         krb5_free_creds(k5_context, ret_cred);
13216         ret_cred = NULL;
13217     }
13218     if (k5_ticket) {
13219         krb5_free_ticket(k5_context, k5_ticket);
13220         k5_ticket = NULL;
13221     }
13222     /* and context */
13223     if ( k5_context ) {
13224         krb5_free_context(k5_context);
13225         k5_context = NULL;
13226     }
13227
13228     /* create k5_context */
13229     krb5_init_context(&k5_context);
13230 #ifndef MIT_CURRENT
13231 #ifndef NO_KRB5_INIT_ETS
13232 /* This routine is a no-op in Kerberos 1.4.x and later */
13233 /* and in some installations it can't be found in which case */
13234 /* define NO_KRB5_INIT_ETS */
13235     if (k5_context)
13236         krb5_init_ets(k5_context);
13237 #endif  /* NO_KRB5_INIT_ETS */
13238 #endif /* MIT_CURRENT */
13239 #ifdef KRB524_CONV
13240     krb524_init_ets(k5_context);
13241 #endif /* KRB524_CONV */
13242     memset(&k5_auth,0,sizeof(k5_auth));
13243     if (auth_context) {
13244         krb5_auth_con_free(k5_context, auth_context);
13245         auth_context = 0;
13246     }
13247 #ifdef CK_ENCRYPTION
13248     if (k5_session_key) {
13249         krb5_free_keyblock(k5_context, k5_session_key);
13250         k5_session_key = 0;
13251     }
13252 #endif /* ENCRYPTION */
13253 #ifdef TLS_VERIFY
13254     krb5_tls_verified = 0;
13255 #endif /* TLS_VERIFY */
13256 #endif /* KRB5 */
13257
13258 #ifdef KRB4
13259 #ifdef CK_ENCRYPTION
13260     /* Initialize buffers used for authentication */
13261     memset(&k4_session_key, 0, sizeof(k4_session_key));
13262     memset(&k4_challenge, 0, sizeof(k4_challenge));
13263 #endif /* CK_ENCRYPTION */
13264 #endif /* KRB4 */
13265
13266 #ifdef RLOGCODE
13267     rlog_encrypt = 0;
13268 #endif /* RLOGCODE */
13269     nstored = 0;
13270     store_ptr = storage;
13271     memset(storage,0,sizeof(storage));
13272 #endif /* CK_KERBEROS */
13273
13274 #ifdef CK_ENCRYPTION
13275     kstream_destroy();
13276     if (!kstream_create_from_fd(socket, NULL))
13277         return(0);
13278 #endif /* CK_ENCRYPTION */
13279     return(1);
13280 }
13281
13282 void
13283 auth_finished(result) int result; {
13284     extern char uidbuf[];
13285     extern int sstelnet;
13286
13287     validUser = result;
13288     switch (result) {
13289     case AUTH_REJECT:           /* Rejected */
13290         if (sstelnet)
13291             uidbuf[0] = '\0';
13292         authentication_version = AUTHTYPE_NULL;
13293         break;
13294     case AUTH_UNKNOWN:          /* We don't know who he is, but he's okay */
13295         if (sstelnet)
13296             strcpy(uidbuf,"(unknown)");
13297         break;
13298     case AUTH_OTHER:            /* We know him, but not his name */
13299         if (sstelnet)
13300             strcpy(uidbuf,"(other)");
13301         break;
13302     case AUTH_USER:             /* We know he name */
13303     case AUTH_VALID:            /* We know him, and he needs no password */
13304         if (sstelnet)
13305             strcpy(uidbuf,szUserNameRequested);
13306         break;
13307     }
13308 }
13309
13310 #ifdef MACOSX
13311 #ifdef KRB5
13312
13313 krb5_error_code
13314 ck_krb5_write_message(krb5_context con, krb5_pointer ptr, krb5_data *data)
13315 {
13316     int fd = *((int *)ptr);
13317     long msglen;
13318
13319     msglen = htonl(data->length);
13320     if (net_write(fd,(CHAR *)&msglen,4) != 4) {
13321         return(-1);
13322     }
13323     if ( data->length ) {
13324         if (net_write(fd,data->data,data->length) != data->length) {
13325             return(-1);
13326         }
13327     }
13328     return(0);
13329 }
13330
13331 krb5_error_code
13332 ck_krb5_read_message( krb5_context context,
13333                       krb5_pointer ptr,
13334                       krb5_data * data)
13335 {
13336     extern int ttyfd;
13337     int fd = *((int *)ptr);
13338     long msglen;
13339     char *p;
13340     int i, rc;
13341
13342     if (net_read(fd,&msglen,4) < 0)
13343         return(-1);
13344
13345     data->length = ntohl(msglen);
13346     if ( data->length ) {
13347         data->data = malloc(data->length);
13348
13349         i = 0;
13350         while ( i < data->length ) {
13351             if ((rc = net_read(fd,&data->data[i],(data->length - i))) < 0)
13352                 return(-1);
13353             i += rc;
13354         }
13355     }
13356     return(0);
13357 }
13358 #endif /* KRB5 */
13359 #endif /* MACOSX */
13360 #endif /* CK_SECURITY */
13361
13362