157416Smarkm/*-
257416Smarkm * Copyright (c) 1991, 1993
357416Smarkm *	The Regents of the University of California.  All rights reserved.
457416Smarkm *
557416Smarkm * Redistribution and use in source and binary forms, with or without
657416Smarkm * modification, are permitted provided that the following conditions
757416Smarkm * are met:
857416Smarkm * 1. Redistributions of source code must retain the above copyright
957416Smarkm *    notice, this list of conditions and the following disclaimer.
1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1157416Smarkm *    notice, this list of conditions and the following disclaimer in the
1257416Smarkm *    documentation and/or other materials provided with the distribution.
1357416Smarkm * 3. All advertising materials mentioning features or use of this software
1457416Smarkm *    must display the following acknowledgement:
1557416Smarkm *	This product includes software developed by the University of
1657416Smarkm *	California, Berkeley and its contributors.
1757416Smarkm * 4. Neither the name of the University nor the names of its contributors
1857416Smarkm *    may be used to endorse or promote products derived from this software
1957416Smarkm *    without specific prior written permission.
2057416Smarkm *
2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2457416Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3157416Smarkm * SUCH DAMAGE.
3257416Smarkm */
3357416Smarkm
3457416Smarkm/*
3557416Smarkm * Copyright (C) 1990 by the Massachusetts Institute of Technology
3657416Smarkm *
3757416Smarkm * Export of this software from the United States of America is assumed
3857416Smarkm * to require a specific license from the United States Government.
3957416Smarkm * It is the responsibility of any person or organization contemplating
4057416Smarkm * export to obtain such a license before exporting.
4157416Smarkm *
4257416Smarkm * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
4357416Smarkm * distribute this software and its documentation for any purpose and
4457416Smarkm * without fee is hereby granted, provided that the above copyright
4557416Smarkm * notice appear in all copies and that both that copyright notice and
4657416Smarkm * this permission notice appear in supporting documentation, and that
4757416Smarkm * the name of M.I.T. not be used in advertising or publicity pertaining
4857416Smarkm * to distribution of the software without specific, written prior
4957416Smarkm * permission.  M.I.T. makes no representations about the suitability of
5057416Smarkm * this software for any purpose.  It is provided "as is" without express
5157416Smarkm * or implied warranty.
5257416Smarkm */
5357416Smarkm
5457416Smarkm
5557416Smarkm#include <config.h>
5657416Smarkm
57233294SstasRCSID("$Id$");
5857416Smarkm
5957416Smarkm#if	defined(ENCRYPTION)
6057416Smarkm
6157416Smarkm#define	ENCRYPT_NAMES
6257416Smarkm#include <arpa/telnet.h>
6357416Smarkm
6457416Smarkm#include <stdio.h>
6557416Smarkm#include <stdlib.h>
6657416Smarkm#include <string.h>
6757416Smarkm#include <roken.h>
6857416Smarkm#ifdef SOCKS
6957416Smarkm#include <socks.h>
7057416Smarkm#endif
7157416Smarkm
72233294Sstas#include "encrypt.h"
73233294Sstas#include "misc.h"
7457416Smarkm
75233294Sstas
7657416Smarkm/*
7757416Smarkm * These functions pointers point to the current routines
7857416Smarkm * for encrypting and decrypting data.
7957416Smarkm */
8057416Smarkmvoid	(*encrypt_output) (unsigned char *, int);
8157416Smarkmint	(*decrypt_input) (int);
8257416Smarkmchar	*nclearto;
8357416Smarkm
8457416Smarkmint encrypt_debug_mode = 0;
8557416Smarkmstatic int decrypt_mode = 0;
8657416Smarkmstatic int encrypt_mode = 0;
8757416Smarkmstatic int encrypt_verbose = 0;
8857416Smarkmstatic int autoencrypt = 0;
8957416Smarkmstatic int autodecrypt = 0;
9057416Smarkmstatic int havesessionkey = 0;
9157416Smarkmstatic int Server = 0;
9257416Smarkmstatic const char *Name = "Noname";
9357416Smarkm
9457416Smarkm#define	typemask(x)	((x) > 0 ? 1 << ((x)-1) : 0)
9557416Smarkm
9657416Smarkmstatic long i_support_encrypt = typemask(ENCTYPE_DES_CFB64)
9757416Smarkm     | typemask(ENCTYPE_DES_OFB64);
9857416Smarkm     static long i_support_decrypt = typemask(ENCTYPE_DES_CFB64)
9957416Smarkm     | typemask(ENCTYPE_DES_OFB64);
10057416Smarkm     static long i_wont_support_encrypt = 0;
10157416Smarkm     static long i_wont_support_decrypt = 0;
10257416Smarkm#define	I_SUPPORT_ENCRYPT	(i_support_encrypt & ~i_wont_support_encrypt)
10357416Smarkm#define	I_SUPPORT_DECRYPT	(i_support_decrypt & ~i_wont_support_decrypt)
10457416Smarkm
10557416Smarkm     static long remote_supports_encrypt = 0;
10657416Smarkm     static long remote_supports_decrypt = 0;
10757416Smarkm
10857416Smarkm     static Encryptions encryptions[] = {
10957416Smarkm#if	defined(DES_ENCRYPTION)
11057416Smarkm	 { "DES_CFB64",	ENCTYPE_DES_CFB64,
111233294Sstas	   cfb64_encrypt,
11257416Smarkm	   cfb64_decrypt,
11357416Smarkm	   cfb64_init,
11457416Smarkm	   cfb64_start,
11557416Smarkm	   cfb64_is,
11657416Smarkm	   cfb64_reply,
11757416Smarkm	   cfb64_session,
11857416Smarkm	   cfb64_keyid,
11957416Smarkm	   cfb64_printsub },
12057416Smarkm	 { "DES_OFB64",	ENCTYPE_DES_OFB64,
121233294Sstas	   ofb64_encrypt,
12257416Smarkm	   ofb64_decrypt,
12357416Smarkm	   ofb64_init,
12457416Smarkm	   ofb64_start,
12557416Smarkm	   ofb64_is,
12657416Smarkm	   ofb64_reply,
12757416Smarkm	   ofb64_session,
12857416Smarkm	   ofb64_keyid,
12957416Smarkm	   ofb64_printsub },
13057416Smarkm#endif
13157416Smarkm	 { 0, },
13257416Smarkm     };
13357416Smarkm
13457416Smarkmstatic unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT,
13557416Smarkm				      ENCRYPT_SUPPORT };
13657416Smarkmstatic unsigned char str_suplen = 0;
13757416Smarkmstatic unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT };
13857416Smarkmstatic unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE };
13957416Smarkm
14057416SmarkmEncryptions *
14157416Smarkmfindencryption(int type)
14257416Smarkm{
14357416Smarkm    Encryptions *ep = encryptions;
14457416Smarkm
14557416Smarkm    if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type)))
14657416Smarkm	return(0);
14757416Smarkm    while (ep->type && ep->type != type)
14857416Smarkm	++ep;
14957416Smarkm    return(ep->type ? ep : 0);
15057416Smarkm}
15157416Smarkm
15257416SmarkmEncryptions *
15357416Smarkmfinddecryption(int type)
15457416Smarkm{
15557416Smarkm    Encryptions *ep = encryptions;
15657416Smarkm
15757416Smarkm    if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type)))
15857416Smarkm	return(0);
15957416Smarkm    while (ep->type && ep->type != type)
16057416Smarkm	++ep;
16157416Smarkm    return(ep->type ? ep : 0);
16257416Smarkm}
16357416Smarkm
16457416Smarkm#define	MAXKEYLEN 64
16557416Smarkm
16657416Smarkmstatic struct key_info {
16757416Smarkm    unsigned char keyid[MAXKEYLEN];
16857416Smarkm    int keylen;
16957416Smarkm    int dir;
17057416Smarkm    int *modep;
17157416Smarkm    Encryptions *(*getcrypt)();
17257416Smarkm} ki[2] = {
17357416Smarkm    { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption },
17457416Smarkm    { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption },
17557416Smarkm};
17657416Smarkm
17757416Smarkmvoid
17857416Smarkmencrypt_init(const char *name, int server)
17957416Smarkm{
18057416Smarkm    Encryptions *ep = encryptions;
18157416Smarkm
18257416Smarkm    Name = name;
18357416Smarkm    Server = server;
18457416Smarkm    i_support_encrypt = i_support_decrypt = 0;
18557416Smarkm    remote_supports_encrypt = remote_supports_decrypt = 0;
18657416Smarkm    encrypt_mode = 0;
18757416Smarkm    decrypt_mode = 0;
18857416Smarkm    encrypt_output = 0;
18957416Smarkm    decrypt_input = 0;
19057416Smarkm#ifdef notdef
19157416Smarkm    encrypt_verbose = !server;
19257416Smarkm#endif
19357416Smarkm
19457416Smarkm    str_suplen = 4;
19557416Smarkm
19657416Smarkm    while (ep->type) {
19757416Smarkm	if (encrypt_debug_mode)
19857416Smarkm	    printf(">>>%s: I will support %s\r\n",
19957416Smarkm		   Name, ENCTYPE_NAME(ep->type));
20057416Smarkm	i_support_encrypt |= typemask(ep->type);
20157416Smarkm	i_support_decrypt |= typemask(ep->type);
20257416Smarkm	if ((i_wont_support_decrypt & typemask(ep->type)) == 0)
20357416Smarkm	    if ((str_send[str_suplen++] = ep->type) == IAC)
20457416Smarkm		str_send[str_suplen++] = IAC;
20557416Smarkm	if (ep->init)
20657416Smarkm	    (*ep->init)(Server);
20757416Smarkm	++ep;
20857416Smarkm    }
20957416Smarkm    str_send[str_suplen++] = IAC;
21057416Smarkm    str_send[str_suplen++] = SE;
21157416Smarkm}
21257416Smarkm
21357416Smarkmvoid
21457416Smarkmencrypt_list_types(void)
21557416Smarkm{
21657416Smarkm    Encryptions *ep = encryptions;
21757416Smarkm
21857416Smarkm    printf("Valid encryption types:\n");
21957416Smarkm    while (ep->type) {
22057416Smarkm	printf("\t%s (%d)\r\n", ENCTYPE_NAME(ep->type), ep->type);
22157416Smarkm	++ep;
22257416Smarkm    }
22357416Smarkm}
22457416Smarkm
22557416Smarkmint
22657416SmarkmEncryptEnable(char *type, char *mode)
22757416Smarkm{
22857416Smarkm    if (isprefix(type, "help") || isprefix(type, "?")) {
22957416Smarkm	printf("Usage: encrypt enable <type> [input|output]\n");
23057416Smarkm	encrypt_list_types();
23157416Smarkm	return(0);
23257416Smarkm    }
23357416Smarkm    if (EncryptType(type, mode))
23457416Smarkm	return(EncryptStart(mode));
23557416Smarkm    return(0);
23657416Smarkm}
23757416Smarkm
23857416Smarkmint
23957416SmarkmEncryptDisable(char *type, char *mode)
24057416Smarkm{
24157416Smarkm    Encryptions *ep;
24257416Smarkm    int ret = 0;
24357416Smarkm
24457416Smarkm    if (isprefix(type, "help") || isprefix(type, "?")) {
24557416Smarkm	printf("Usage: encrypt disable <type> [input|output]\n");
24657416Smarkm	encrypt_list_types();
24757416Smarkm    } else if ((ep = (Encryptions *)genget(type, (char**)encryptions,
24857416Smarkm					   sizeof(Encryptions))) == 0) {
24957416Smarkm	printf("%s: invalid encryption type\n", type);
25057416Smarkm    } else if (Ambiguous(ep)) {
25157416Smarkm	printf("Ambiguous type '%s'\n", type);
25257416Smarkm    } else {
25357416Smarkm	if ((mode == 0) || (isprefix(mode, "input") ? 1 : 0)) {
25457416Smarkm	    if (decrypt_mode == ep->type)
25557416Smarkm		EncryptStopInput();
25657416Smarkm	    i_wont_support_decrypt |= typemask(ep->type);
25757416Smarkm	    ret = 1;
25857416Smarkm	}
25957416Smarkm	if ((mode == 0) || (isprefix(mode, "output"))) {
26057416Smarkm	    if (encrypt_mode == ep->type)
26157416Smarkm		EncryptStopOutput();
26257416Smarkm	    i_wont_support_encrypt |= typemask(ep->type);
26357416Smarkm	    ret = 1;
26457416Smarkm	}
26557416Smarkm	if (ret == 0)
26657416Smarkm	    printf("%s: invalid encryption mode\n", mode);
26757416Smarkm    }
26857416Smarkm    return(ret);
26957416Smarkm}
27057416Smarkm
27157416Smarkmint
27257416SmarkmEncryptType(char *type, char *mode)
27357416Smarkm{
27457416Smarkm    Encryptions *ep;
27557416Smarkm    int ret = 0;
27657416Smarkm
27757416Smarkm    if (isprefix(type, "help") || isprefix(type, "?")) {
27857416Smarkm	printf("Usage: encrypt type <type> [input|output]\n");
27957416Smarkm	encrypt_list_types();
28057416Smarkm    } else if ((ep = (Encryptions *)genget(type, (char**)encryptions,
28157416Smarkm					   sizeof(Encryptions))) == 0) {
28257416Smarkm	printf("%s: invalid encryption type\n", type);
28357416Smarkm    } else if (Ambiguous(ep)) {
28457416Smarkm	printf("Ambiguous type '%s'\n", type);
28557416Smarkm    } else {
28657416Smarkm	if ((mode == 0) || isprefix(mode, "input")) {
28757416Smarkm	    decrypt_mode = ep->type;
28857416Smarkm	    i_wont_support_decrypt &= ~typemask(ep->type);
28957416Smarkm	    ret = 1;
29057416Smarkm	}
29157416Smarkm	if ((mode == 0) || isprefix(mode, "output")) {
29257416Smarkm	    encrypt_mode = ep->type;
29357416Smarkm	    i_wont_support_encrypt &= ~typemask(ep->type);
29457416Smarkm	    ret = 1;
29557416Smarkm	}
29657416Smarkm	if (ret == 0)
29757416Smarkm	    printf("%s: invalid encryption mode\n", mode);
29857416Smarkm    }
29957416Smarkm    return(ret);
30057416Smarkm}
30157416Smarkm
30257416Smarkmint
30357416SmarkmEncryptStart(char *mode)
30457416Smarkm{
30557416Smarkm    int ret = 0;
30657416Smarkm    if (mode) {
30757416Smarkm	if (isprefix(mode, "input"))
30857416Smarkm	    return(EncryptStartInput());
30957416Smarkm	if (isprefix(mode, "output"))
31057416Smarkm	    return(EncryptStartOutput());
31157416Smarkm	if (isprefix(mode, "help") || isprefix(mode, "?")) {
31257416Smarkm	    printf("Usage: encrypt start [input|output]\n");
31357416Smarkm	    return(0);
31457416Smarkm	}
31557416Smarkm	printf("%s: invalid encryption mode 'encrypt start ?' for help\n", mode);
31657416Smarkm	return(0);
31757416Smarkm    }
31857416Smarkm    ret += EncryptStartInput();
31957416Smarkm    ret += EncryptStartOutput();
32057416Smarkm    return(ret);
32157416Smarkm}
32257416Smarkm
32357416Smarkmint
32457416SmarkmEncryptStartInput(void)
32557416Smarkm{
32657416Smarkm    if (decrypt_mode) {
32757416Smarkm	encrypt_send_request_start();
32857416Smarkm	return(1);
32957416Smarkm    }
33057416Smarkm    printf("No previous decryption mode, decryption not enabled\r\n");
33157416Smarkm    return(0);
33257416Smarkm}
33357416Smarkm
33457416Smarkmint
33557416SmarkmEncryptStartOutput(void)
33657416Smarkm{
33757416Smarkm    if (encrypt_mode) {
33857416Smarkm	encrypt_start_output(encrypt_mode);
33957416Smarkm	return(1);
34057416Smarkm    }
34157416Smarkm    printf("No previous encryption mode, encryption not enabled\r\n");
34257416Smarkm    return(0);
34357416Smarkm}
34457416Smarkm
34557416Smarkmint
34657416SmarkmEncryptStop(char *mode)
34757416Smarkm{
34857416Smarkm    int ret = 0;
34957416Smarkm    if (mode) {
35057416Smarkm	if (isprefix(mode, "input"))
35157416Smarkm	    return(EncryptStopInput());
35257416Smarkm	if (isprefix(mode, "output"))
35357416Smarkm	    return(EncryptStopOutput());
35457416Smarkm	if (isprefix(mode, "help") || isprefix(mode, "?")) {
35557416Smarkm	    printf("Usage: encrypt stop [input|output]\n");
35657416Smarkm	    return(0);
35757416Smarkm	}
35857416Smarkm	printf("%s: invalid encryption mode 'encrypt stop ?' for help\n", mode);
35957416Smarkm	return(0);
36057416Smarkm    }
36157416Smarkm    ret += EncryptStopInput();
36257416Smarkm    ret += EncryptStopOutput();
36357416Smarkm    return(ret);
36457416Smarkm}
36557416Smarkm
36657416Smarkmint
36757416SmarkmEncryptStopInput(void)
36857416Smarkm{
36957416Smarkm    encrypt_send_request_end();
37057416Smarkm    return(1);
37157416Smarkm}
37257416Smarkm
37357416Smarkmint
37457416SmarkmEncryptStopOutput(void)
37557416Smarkm{
37657416Smarkm    encrypt_send_end();
37757416Smarkm    return(1);
37857416Smarkm}
37957416Smarkm
38057416Smarkmvoid
38157416Smarkmencrypt_display(void)
38257416Smarkm{
38357416Smarkm    printf("Autoencrypt for output is %s. Autodecrypt for input is %s.\r\n",
38457416Smarkm	   autoencrypt?"on":"off", autodecrypt?"on":"off");
38557416Smarkm
38657416Smarkm    if (encrypt_output)
38757416Smarkm	printf("Currently encrypting output with %s\r\n",
38857416Smarkm	       ENCTYPE_NAME(encrypt_mode));
38957416Smarkm    else
39057416Smarkm	printf("Currently not encrypting output\r\n");
391233294Sstas
39257416Smarkm    if (decrypt_input)
39357416Smarkm	printf("Currently decrypting input with %s\r\n",
39457416Smarkm	       ENCTYPE_NAME(decrypt_mode));
39557416Smarkm    else
39657416Smarkm	printf("Currently not decrypting input\r\n");
39757416Smarkm}
39857416Smarkm
39957416Smarkmint
40057416SmarkmEncryptStatus(void)
40157416Smarkm{
40257416Smarkm    printf("Autoencrypt for output is %s. Autodecrypt for input is %s.\r\n",
40357416Smarkm	   autoencrypt?"on":"off", autodecrypt?"on":"off");
40457416Smarkm
40557416Smarkm    if (encrypt_output)
40657416Smarkm	printf("Currently encrypting output with %s\r\n",
40757416Smarkm	       ENCTYPE_NAME(encrypt_mode));
40857416Smarkm    else if (encrypt_mode) {
40957416Smarkm	printf("Currently output is clear text.\r\n");
41057416Smarkm	printf("Last encryption mode was %s\r\n",
41157416Smarkm	       ENCTYPE_NAME(encrypt_mode));
41257416Smarkm    } else
41357416Smarkm	printf("Currently not encrypting output\r\n");
414233294Sstas
41557416Smarkm    if (decrypt_input) {
41657416Smarkm	printf("Currently decrypting input with %s\r\n",
41757416Smarkm	       ENCTYPE_NAME(decrypt_mode));
41857416Smarkm    } else if (decrypt_mode) {
41957416Smarkm	printf("Currently input is clear text.\r\n");
42057416Smarkm	printf("Last decryption mode was %s\r\n",
42157416Smarkm	       ENCTYPE_NAME(decrypt_mode));
42257416Smarkm    } else
42357416Smarkm	printf("Currently not decrypting input\r\n");
42457416Smarkm
42557416Smarkm    return 1;
42657416Smarkm}
42757416Smarkm
42857416Smarkmvoid
42957416Smarkmencrypt_send_support(void)
43057416Smarkm{
43157416Smarkm    if (str_suplen) {
43257416Smarkm	/*
43357416Smarkm	 * If the user has requested that decryption start
43457416Smarkm	 * immediatly, then send a "REQUEST START" before
43557416Smarkm	 * we negotiate the type.
43657416Smarkm	 */
43757416Smarkm	if (!Server && autodecrypt)
43857416Smarkm	    encrypt_send_request_start();
43957416Smarkm	telnet_net_write(str_send, str_suplen);
44057416Smarkm	printsub('>', &str_send[2], str_suplen - 2);
44157416Smarkm	str_suplen = 0;
44257416Smarkm    }
44357416Smarkm}
44457416Smarkm
44557416Smarkmint
44657416SmarkmEncryptDebug(int on)
44757416Smarkm{
44857416Smarkm    if (on < 0)
44957416Smarkm	encrypt_debug_mode ^= 1;
45057416Smarkm    else
45157416Smarkm	encrypt_debug_mode = on;
45257416Smarkm    printf("Encryption debugging %s\r\n",
45357416Smarkm	   encrypt_debug_mode ? "enabled" : "disabled");
45457416Smarkm    return(1);
45557416Smarkm}
45657416Smarkm
45757416Smarkm/* turn on verbose encryption, but dont keep telling the whole world
45857416Smarkm */
45957416Smarkmvoid encrypt_verbose_quiet(int on)
46057416Smarkm{
46157416Smarkm    if(on < 0)
46257416Smarkm	encrypt_verbose ^= 1;
46357416Smarkm    else
46457416Smarkm	encrypt_verbose = on ? 1 : 0;
46557416Smarkm}
46657416Smarkm
46757416Smarkmint
46857416SmarkmEncryptVerbose(int on)
46957416Smarkm{
47057416Smarkm    encrypt_verbose_quiet(on);
47157416Smarkm    printf("Encryption %s verbose\r\n",
47257416Smarkm	   encrypt_verbose ? "is" : "is not");
47357416Smarkm    return(1);
47457416Smarkm}
47557416Smarkm
47657416Smarkmint
47757416SmarkmEncryptAutoEnc(int on)
47857416Smarkm{
47957416Smarkm    encrypt_auto(on);
48057416Smarkm    printf("Automatic encryption of output is %s\r\n",
48157416Smarkm	   autoencrypt ? "enabled" : "disabled");
48257416Smarkm    return(1);
48357416Smarkm}
48457416Smarkm
48557416Smarkmint
48657416SmarkmEncryptAutoDec(int on)
48757416Smarkm{
48857416Smarkm    decrypt_auto(on);
48957416Smarkm    printf("Automatic decryption of input is %s\r\n",
49057416Smarkm	   autodecrypt ? "enabled" : "disabled");
49157416Smarkm    return(1);
49257416Smarkm}
49357416Smarkm
49457416Smarkm/* Called when we receive a WONT or a DONT ENCRYPT after we sent a DO
49557416Smarkm   encrypt */
49657416Smarkmvoid
49757416Smarkmencrypt_not(void)
49857416Smarkm{
49957416Smarkm    if (encrypt_verbose)
50057416Smarkm  	printf("[ Connection is NOT encrypted ]\r\n");
50157416Smarkm    else
50257416Smarkm  	printf("\r\n*** Connection not encrypted! "
50357416Smarkm	       "Communication may be eavesdropped. ***\r\n");
50457416Smarkm}
50557416Smarkm
50657416Smarkm/*
50757416Smarkm * Called when ENCRYPT SUPPORT is received.
50857416Smarkm */
50957416Smarkmvoid
51057416Smarkmencrypt_support(unsigned char *typelist, int cnt)
51157416Smarkm{
51257416Smarkm    int type, use_type = 0;
51357416Smarkm    Encryptions *ep;
51457416Smarkm
51557416Smarkm    /*
51657416Smarkm     * Forget anything the other side has previously told us.
51757416Smarkm     */
51857416Smarkm    remote_supports_decrypt = 0;
51957416Smarkm
52057416Smarkm    while (cnt-- > 0) {
52157416Smarkm	type = *typelist++;
52257416Smarkm	if (encrypt_debug_mode)
52357416Smarkm	    printf(">>>%s: He is supporting %s (%d)\r\n",
52457416Smarkm		   Name,
52557416Smarkm		   ENCTYPE_NAME(type), type);
52657416Smarkm	if ((type < ENCTYPE_CNT) &&
52757416Smarkm	    (I_SUPPORT_ENCRYPT & typemask(type))) {
52857416Smarkm	    remote_supports_decrypt |= typemask(type);
52957416Smarkm	    if (use_type == 0)
53057416Smarkm		use_type = type;
53157416Smarkm	}
53257416Smarkm    }
53357416Smarkm    if (use_type) {
53457416Smarkm	ep = findencryption(use_type);
53557416Smarkm	if (!ep)
53657416Smarkm	    return;
53757416Smarkm	type = ep->start ? (*ep->start)(DIR_ENCRYPT, Server) : 0;
53857416Smarkm	if (encrypt_debug_mode)
53957416Smarkm	    printf(">>>%s: (*ep->start)() returned %d\r\n",
54057416Smarkm		   Name, type);
54157416Smarkm	if (type < 0)
54257416Smarkm	    return;
54357416Smarkm	encrypt_mode = use_type;
54457416Smarkm	if (type == 0)
54557416Smarkm	    encrypt_start_output(use_type);
54657416Smarkm    }
54757416Smarkm}
54857416Smarkm
54957416Smarkmvoid
55057416Smarkmencrypt_is(unsigned char *data, int cnt)
55157416Smarkm{
55257416Smarkm    Encryptions *ep;
55357416Smarkm    int type, ret;
55457416Smarkm
55557416Smarkm    if (--cnt < 0)
55657416Smarkm	return;
55757416Smarkm    type = *data++;
55857416Smarkm    if (type < ENCTYPE_CNT)
55957416Smarkm	remote_supports_encrypt |= typemask(type);
56057416Smarkm    if (!(ep = finddecryption(type))) {
56157416Smarkm	if (encrypt_debug_mode)
56257416Smarkm	    printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
56357416Smarkm		   Name,
56457416Smarkm		   ENCTYPE_NAME_OK(type)
56557416Smarkm		   ? ENCTYPE_NAME(type) : "(unknown)",
56657416Smarkm		   type);
56757416Smarkm	return;
56857416Smarkm    }
56957416Smarkm    if (!ep->is) {
57057416Smarkm	if (encrypt_debug_mode)
57157416Smarkm	    printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
57257416Smarkm		   Name,
57357416Smarkm		   ENCTYPE_NAME_OK(type)
57457416Smarkm		   ? ENCTYPE_NAME(type) : "(unknown)",
57557416Smarkm		   type);
57657416Smarkm	ret = 0;
57757416Smarkm    } else {
57857416Smarkm	ret = (*ep->is)(data, cnt);
57957416Smarkm	if (encrypt_debug_mode)
58057416Smarkm	    printf("(*ep->is)(%p, %d) returned %s(%d)\n", data, cnt,
58157416Smarkm		   (ret < 0) ? "FAIL " :
58257416Smarkm		   (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
58357416Smarkm    }
58457416Smarkm    if (ret < 0) {
58557416Smarkm	autodecrypt = 0;
58657416Smarkm    } else {
58757416Smarkm	decrypt_mode = type;
58857416Smarkm	if (ret == 0 && autodecrypt)
58957416Smarkm	    encrypt_send_request_start();
59057416Smarkm    }
59157416Smarkm}
59257416Smarkm
59357416Smarkmvoid
59457416Smarkmencrypt_reply(unsigned char *data, int cnt)
59557416Smarkm{
59657416Smarkm    Encryptions *ep;
59757416Smarkm    int ret, type;
59857416Smarkm
59957416Smarkm    if (--cnt < 0)
60057416Smarkm	return;
60157416Smarkm    type = *data++;
60257416Smarkm    if (!(ep = findencryption(type))) {
60357416Smarkm	if (encrypt_debug_mode)
60457416Smarkm	    printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
60557416Smarkm		   Name,
60657416Smarkm		   ENCTYPE_NAME_OK(type)
60757416Smarkm		   ? ENCTYPE_NAME(type) : "(unknown)",
60857416Smarkm		   type);
60957416Smarkm	return;
61057416Smarkm    }
61157416Smarkm    if (!ep->reply) {
61257416Smarkm	if (encrypt_debug_mode)
61357416Smarkm	    printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
61457416Smarkm		   Name,
61557416Smarkm		   ENCTYPE_NAME_OK(type)
61657416Smarkm		   ? ENCTYPE_NAME(type) : "(unknown)",
61757416Smarkm		   type);
61857416Smarkm	ret = 0;
61957416Smarkm    } else {
62057416Smarkm	ret = (*ep->reply)(data, cnt);
62157416Smarkm	if (encrypt_debug_mode)
62257416Smarkm	    printf("(*ep->reply)(%p, %d) returned %s(%d)\n",
62357416Smarkm		   data, cnt,
62457416Smarkm		   (ret < 0) ? "FAIL " :
62557416Smarkm		   (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
62657416Smarkm    }
62757416Smarkm    if (encrypt_debug_mode)
62857416Smarkm	printf(">>>%s: encrypt_reply returned %d\n", Name, ret);
62957416Smarkm    if (ret < 0) {
63057416Smarkm	autoencrypt = 0;
63157416Smarkm    } else {
63257416Smarkm	encrypt_mode = type;
63357416Smarkm	if (ret == 0 && autoencrypt)
63457416Smarkm	    encrypt_start_output(type);
63557416Smarkm    }
63657416Smarkm}
63757416Smarkm
63857416Smarkm/*
639178825Sdfr * Called when ENCRYPT START is received.
64057416Smarkm */
64157416Smarkmvoid
64257416Smarkmencrypt_start(unsigned char *data, int cnt)
64357416Smarkm{
64457416Smarkm    Encryptions *ep;
64557416Smarkm
64657416Smarkm    if (!decrypt_mode) {
64757416Smarkm	/*
64857416Smarkm	 * Something is wrong.  We should not get a START
64957416Smarkm	 * command without having already picked our
65057416Smarkm	 * decryption scheme.  Send a REQUEST-END to
65157416Smarkm	 * attempt to clear the channel...
65257416Smarkm	 */
65357416Smarkm	printf("%s: Warning, Cannot decrypt input stream!!!\r\n", Name);
65457416Smarkm	encrypt_send_request_end();
65557416Smarkm	return;
65657416Smarkm    }
65757416Smarkm
65857416Smarkm    if ((ep = finddecryption(decrypt_mode))) {
65957416Smarkm	decrypt_input = ep->input;
66057416Smarkm	if (encrypt_verbose)
66157416Smarkm	    printf("[ Input is now decrypted with type %s ]\r\n",
66257416Smarkm		   ENCTYPE_NAME(decrypt_mode));
66357416Smarkm	if (encrypt_debug_mode)
66457416Smarkm	    printf(">>>%s: Start to decrypt input with type %s\r\n",
66557416Smarkm		   Name, ENCTYPE_NAME(decrypt_mode));
66657416Smarkm    } else {
66757416Smarkm	printf("%s: Warning, Cannot decrypt type %s (%d)!!!\r\n",
66857416Smarkm	       Name,
66957416Smarkm	       ENCTYPE_NAME_OK(decrypt_mode)
67057416Smarkm	       ? ENCTYPE_NAME(decrypt_mode)
67157416Smarkm	       : "(unknown)",
67257416Smarkm	       decrypt_mode);
67357416Smarkm	encrypt_send_request_end();
67457416Smarkm    }
67557416Smarkm}
67657416Smarkm
67757416Smarkmvoid
67857416Smarkmencrypt_session_key(Session_Key *key, int server)
67957416Smarkm{
68057416Smarkm    Encryptions *ep = encryptions;
68157416Smarkm
68257416Smarkm    havesessionkey = 1;
68357416Smarkm
68457416Smarkm    while (ep->type) {
68557416Smarkm	if (ep->session)
68657416Smarkm	    (*ep->session)(key, server);
68757416Smarkm	++ep;
68857416Smarkm    }
68957416Smarkm}
69057416Smarkm
69157416Smarkm/*
69257416Smarkm * Called when ENCRYPT END is received.
69357416Smarkm */
69457416Smarkmvoid
69557416Smarkmencrypt_end(void)
69657416Smarkm{
69757416Smarkm    decrypt_input = 0;
69857416Smarkm    if (encrypt_debug_mode)
69957416Smarkm	printf(">>>%s: Input is back to clear text\r\n", Name);
70057416Smarkm    if (encrypt_verbose)
70157416Smarkm	printf("[ Input is now clear text ]\r\n");
70257416Smarkm}
70357416Smarkm
70457416Smarkm/*
70557416Smarkm * Called when ENCRYPT REQUEST-END is received.
70657416Smarkm */
70757416Smarkmvoid
70857416Smarkmencrypt_request_end(void)
70957416Smarkm{
71057416Smarkm    encrypt_send_end();
71157416Smarkm}
71257416Smarkm
71357416Smarkm/*
71457416Smarkm * Called when ENCRYPT REQUEST-START is received.  If we receive
71557416Smarkm * this before a type is picked, then that indicates that the
71657416Smarkm * other side wants us to start encrypting data as soon as we
717233294Sstas * can.
71857416Smarkm */
71957416Smarkmvoid
72057416Smarkmencrypt_request_start(unsigned char *data, int cnt)
72157416Smarkm{
72257416Smarkm    if (encrypt_mode == 0)  {
72357416Smarkm	if (Server)
72457416Smarkm	    autoencrypt = 1;
72557416Smarkm	return;
72657416Smarkm    }
72757416Smarkm    encrypt_start_output(encrypt_mode);
72857416Smarkm}
72957416Smarkm
73057416Smarkmstatic unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT };
73157416Smarkm
73257416Smarkmstatic void
73357416Smarkmencrypt_keyid(struct key_info *kp, unsigned char *keyid, int len)
73457416Smarkm{
73557416Smarkm    Encryptions *ep;
73657416Smarkm    int dir = kp->dir;
73757416Smarkm    int ret = 0;
73857416Smarkm
739228843Scperciva    if (len > MAXKEYLEN)
740234027Sstas	len = MAXKEYLEN;
741228843Scperciva
74257416Smarkm    if (!(ep = (*kp->getcrypt)(*kp->modep))) {
74357416Smarkm	if (len == 0)
74457416Smarkm	    return;
74557416Smarkm	kp->keylen = 0;
74657416Smarkm    } else if (len == 0) {
74757416Smarkm	/*
74857416Smarkm	 * Empty option, indicates a failure.
74957416Smarkm	 */
75057416Smarkm	if (kp->keylen == 0)
75157416Smarkm	    return;
75257416Smarkm	kp->keylen = 0;
75357416Smarkm	if (ep->keyid)
75457416Smarkm	    (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
75557416Smarkm
75657416Smarkm    } else if ((len != kp->keylen) || (memcmp(keyid,kp->keyid,len) != 0)) {
75757416Smarkm	/*
75857416Smarkm	 * Length or contents are different
75957416Smarkm	 */
76057416Smarkm	kp->keylen = len;
76157416Smarkm	memcpy(kp->keyid,keyid, len);
76257416Smarkm	if (ep->keyid)
76357416Smarkm	    (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
76457416Smarkm    } else {
76557416Smarkm	if (ep->keyid)
76657416Smarkm	    ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen);
76757416Smarkm	if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt)
76857416Smarkm	    encrypt_start_output(*kp->modep);
76957416Smarkm	return;
77057416Smarkm    }
77157416Smarkm
77257416Smarkm    encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0);
77357416Smarkm}
77457416Smarkm
77557416Smarkmvoid encrypt_enc_keyid(unsigned char *keyid, int len)
77657416Smarkm{
77757416Smarkm    encrypt_keyid(&ki[1], keyid, len);
77857416Smarkm}
77957416Smarkm
78057416Smarkmvoid encrypt_dec_keyid(unsigned char *keyid, int len)
78157416Smarkm{
78257416Smarkm    encrypt_keyid(&ki[0], keyid, len);
78357416Smarkm}
78457416Smarkm
78557416Smarkm
78657416Smarkmvoid encrypt_send_keyid(int dir, unsigned char *keyid, int keylen, int saveit)
78757416Smarkm{
78857416Smarkm    unsigned char *strp;
78957416Smarkm
79057416Smarkm    str_keyid[3] = (dir == DIR_ENCRYPT)
79157416Smarkm	? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID;
79257416Smarkm    if (saveit) {
79357416Smarkm	struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1];
79457416Smarkm	memcpy(kp->keyid,keyid, keylen);
79557416Smarkm	kp->keylen = keylen;
79657416Smarkm    }
79757416Smarkm
79857416Smarkm    for (strp = &str_keyid[4]; keylen > 0; --keylen) {
79957416Smarkm	if ((*strp++ = *keyid++) == IAC)
80057416Smarkm	    *strp++ = IAC;
80157416Smarkm    }
80257416Smarkm    *strp++ = IAC;
80357416Smarkm    *strp++ = SE;
80457416Smarkm    telnet_net_write(str_keyid, strp - str_keyid);
80557416Smarkm    printsub('>', &str_keyid[2], strp - str_keyid - 2);
80657416Smarkm}
80757416Smarkm
80857416Smarkmvoid
80957416Smarkmencrypt_auto(int on)
81057416Smarkm{
81157416Smarkm    if (on < 0)
81257416Smarkm	autoencrypt ^= 1;
81357416Smarkm    else
81457416Smarkm	autoencrypt = on ? 1 : 0;
81557416Smarkm}
81657416Smarkm
81757416Smarkmvoid
81857416Smarkmdecrypt_auto(int on)
81957416Smarkm{
82057416Smarkm    if (on < 0)
82157416Smarkm	autodecrypt ^= 1;
82257416Smarkm    else
82357416Smarkm	autodecrypt = on ? 1 : 0;
82457416Smarkm}
82557416Smarkm
82657416Smarkmvoid
82757416Smarkmencrypt_start_output(int type)
82857416Smarkm{
82957416Smarkm    Encryptions *ep;
83057416Smarkm    unsigned char *p;
83157416Smarkm    int i;
83257416Smarkm
83357416Smarkm    if (!(ep = findencryption(type))) {
83457416Smarkm	if (encrypt_debug_mode) {
83557416Smarkm	    printf(">>>%s: Can't encrypt with type %s (%d)\r\n",
83657416Smarkm		   Name,
83757416Smarkm		   ENCTYPE_NAME_OK(type)
83857416Smarkm		   ? ENCTYPE_NAME(type) : "(unknown)",
83957416Smarkm		   type);
84057416Smarkm	}
84157416Smarkm	return;
84257416Smarkm    }
84357416Smarkm    if (ep->start) {
84457416Smarkm	i = (*ep->start)(DIR_ENCRYPT, Server);
84557416Smarkm	if (encrypt_debug_mode) {
84657416Smarkm	    printf(">>>%s: Encrypt start: %s (%d) %s\r\n",
847233294Sstas		   Name,
84857416Smarkm		   (i < 0) ? "failed" :
84957416Smarkm		   "initial negotiation in progress",
85057416Smarkm		   i, ENCTYPE_NAME(type));
85157416Smarkm	}
85257416Smarkm	if (i)
85357416Smarkm	    return;
85457416Smarkm    }
85557416Smarkm    p = str_start + 3;
85657416Smarkm    *p++ = ENCRYPT_START;
85757416Smarkm    for (i = 0; i < ki[0].keylen; ++i) {
85857416Smarkm	if ((*p++ = ki[0].keyid[i]) == IAC)
85957416Smarkm	    *p++ = IAC;
86057416Smarkm    }
86157416Smarkm    *p++ = IAC;
86257416Smarkm    *p++ = SE;
86357416Smarkm    telnet_net_write(str_start, p - str_start);
86457416Smarkm    net_encrypt();
86557416Smarkm    printsub('>', &str_start[2], p - &str_start[2]);
86657416Smarkm    /*
86757416Smarkm     * If we are already encrypting in some mode, then
86857416Smarkm     * encrypt the ring (which includes our request) in
86957416Smarkm     * the old mode, mark it all as "clear text" and then
87057416Smarkm     * switch to the new mode.
87157416Smarkm     */
87257416Smarkm    encrypt_output = ep->output;
87357416Smarkm    encrypt_mode = type;
87457416Smarkm    if (encrypt_debug_mode)
87557416Smarkm	printf(">>>%s: Started to encrypt output with type %s\r\n",
87657416Smarkm	       Name, ENCTYPE_NAME(type));
87757416Smarkm    if (encrypt_verbose)
87857416Smarkm	printf("[ Output is now encrypted with type %s ]\r\n",
87957416Smarkm	       ENCTYPE_NAME(type));
88057416Smarkm}
88157416Smarkm
88257416Smarkmvoid
88357416Smarkmencrypt_send_end(void)
88457416Smarkm{
88557416Smarkm    if (!encrypt_output)
88657416Smarkm	return;
88757416Smarkm
88857416Smarkm    str_end[3] = ENCRYPT_END;
88957416Smarkm    telnet_net_write(str_end, sizeof(str_end));
89057416Smarkm    net_encrypt();
89157416Smarkm    printsub('>', &str_end[2], sizeof(str_end) - 2);
89257416Smarkm    /*
89357416Smarkm     * Encrypt the output buffer now because it will not be done by
89457416Smarkm     * netflush...
89557416Smarkm     */
89657416Smarkm    encrypt_output = 0;
89757416Smarkm    if (encrypt_debug_mode)
89857416Smarkm	printf(">>>%s: Output is back to clear text\r\n", Name);
89957416Smarkm    if (encrypt_verbose)
90057416Smarkm	printf("[ Output is now clear text ]\r\n");
90157416Smarkm}
90257416Smarkm
90357416Smarkmvoid
90457416Smarkmencrypt_send_request_start(void)
90557416Smarkm{
90657416Smarkm    unsigned char *p;
90757416Smarkm    int i;
90857416Smarkm
90957416Smarkm    p = &str_start[3];
91057416Smarkm    *p++ = ENCRYPT_REQSTART;
91157416Smarkm    for (i = 0; i < ki[1].keylen; ++i) {
91257416Smarkm	if ((*p++ = ki[1].keyid[i]) == IAC)
91357416Smarkm	    *p++ = IAC;
91457416Smarkm    }
91557416Smarkm    *p++ = IAC;
91657416Smarkm    *p++ = SE;
91757416Smarkm    telnet_net_write(str_start, p - str_start);
91857416Smarkm    printsub('>', &str_start[2], p - &str_start[2]);
91957416Smarkm    if (encrypt_debug_mode)
92057416Smarkm	printf(">>>%s: Request input to be encrypted\r\n", Name);
92157416Smarkm}
92257416Smarkm
92357416Smarkmvoid
92457416Smarkmencrypt_send_request_end(void)
92557416Smarkm{
92657416Smarkm    str_end[3] = ENCRYPT_REQEND;
92757416Smarkm    telnet_net_write(str_end, sizeof(str_end));
92857416Smarkm    printsub('>', &str_end[2], sizeof(str_end) - 2);
92957416Smarkm
93057416Smarkm    if (encrypt_debug_mode)
93157416Smarkm	printf(">>>%s: Request input to be clear text\r\n", Name);
93257416Smarkm}
93357416Smarkm
93457416Smarkm
93557416Smarkmvoid encrypt_wait(void)
93657416Smarkm{
93757416Smarkm    if (encrypt_debug_mode)
93857416Smarkm	printf(">>>%s: in encrypt_wait\r\n", Name);
93957416Smarkm    if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt))
94057416Smarkm	return;
94157416Smarkm    while (autoencrypt && !encrypt_output)
94257416Smarkm	if (telnet_spin())
94357416Smarkm	    return;
94457416Smarkm}
94557416Smarkm
94657416Smarkmint
94757416Smarkmencrypt_delay(void)
94857416Smarkm{
94957416Smarkm    if(!havesessionkey ||
95057416Smarkm       (I_SUPPORT_ENCRYPT & remote_supports_decrypt) == 0 ||
95157416Smarkm       (I_SUPPORT_DECRYPT & remote_supports_encrypt) == 0)
95257416Smarkm	return 0;
95357416Smarkm    if(!(encrypt_output && decrypt_input))
95457416Smarkm	return 1;
95557416Smarkm    return 0;
95657416Smarkm}
95757416Smarkm
95890926Snectarint encrypt_is_encrypting()
95990926Snectar{
96090926Snectar    if (encrypt_output && decrypt_input)
96190926Snectar	return 1;
96290926Snectar    return 0;
96390926Snectar}
96490926Snectar
96557416Smarkmvoid
96657416Smarkmencrypt_debug(int mode)
96757416Smarkm{
96857416Smarkm    encrypt_debug_mode = mode;
96957416Smarkm}
97057416Smarkm
971233294Sstasvoid encrypt_gen_printsub(unsigned char *data, size_t cnt,
972233294Sstas			  unsigned char *buf, size_t buflen)
97357416Smarkm{
97457416Smarkm    char tbuf[16], *cp;
97557416Smarkm
97657416Smarkm    cnt -= 2;
97757416Smarkm    data += 2;
97857416Smarkm    buf[buflen-1] = '\0';
97957416Smarkm    buf[buflen-2] = '*';
98057416Smarkm    buflen -= 2;;
98157416Smarkm    for (; cnt > 0; cnt--, data++) {
98257416Smarkm	snprintf(tbuf, sizeof(tbuf), " %d", *data);
98357416Smarkm	for (cp = tbuf; *cp && buflen > 0; --buflen)
98457416Smarkm	    *buf++ = *cp++;
98557416Smarkm	if (buflen <= 0)
98657416Smarkm	    return;
98757416Smarkm    }
98857416Smarkm    *buf = '\0';
98957416Smarkm}
99057416Smarkm
99157416Smarkmvoid
992233294Sstasencrypt_printsub(unsigned char *data, size_t cnt,
993233294Sstas		 unsigned char *buf, size_t buflen)
99457416Smarkm{
99557416Smarkm    Encryptions *ep;
99657416Smarkm    int type = data[1];
99757416Smarkm
99857416Smarkm    for (ep = encryptions; ep->type && ep->type != type; ep++)
99957416Smarkm	;
100057416Smarkm
100157416Smarkm    if (ep->printsub)
100257416Smarkm	(*ep->printsub)(data, cnt, buf, buflen);
100357416Smarkm    else
100457416Smarkm	encrypt_gen_printsub(data, cnt, buf, buflen);
100557416Smarkm}
100657416Smarkm#endif
1007