441 lines
11 KiB
C
441 lines
11 KiB
C
|
/*
|
|||
|
* Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska H<EFBFBD>gskolan
|
|||
|
* (Royal Institute of Technology, Stockholm, Sweden).
|
|||
|
* All rights reserved.
|
|||
|
*
|
|||
|
* Redistribution and use in source and binary forms, with or without
|
|||
|
* modification, are permitted provided that the following conditions
|
|||
|
* are met:
|
|||
|
*
|
|||
|
* 1. Redistributions of source code must retain the above copyright
|
|||
|
* notice, this list of conditions and the following disclaimer.
|
|||
|
*
|
|||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|||
|
* notice, this list of conditions and the following disclaimer in the
|
|||
|
* documentation and/or other materials provided with the distribution.
|
|||
|
*
|
|||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
|||
|
* may be used to endorse or promote products derived from this software
|
|||
|
* without specific prior written permission.
|
|||
|
*
|
|||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|||
|
* SUCH DAMAGE.
|
|||
|
*/
|
|||
|
|
|||
|
/* KClient.c - KClient glue to krb4.dll
|
|||
|
* Author: J<EFBFBD>rgen Karlsson - d93-jka@nada.kth.se
|
|||
|
* Date: June 1996
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef HAVE_CONFIG_H
|
|||
|
#include <config.h>
|
|||
|
RCSID("$Id: KClient.c,v 1.14 1999/12/02 16:58:40 joda Exp $");
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef WIN32 /* Visual C++ 4.0 (Windows95/NT) */
|
|||
|
#include <Windows.h>
|
|||
|
#endif /* WIN32 */
|
|||
|
|
|||
|
//#include <string.h>
|
|||
|
#include <winsock.h>
|
|||
|
#include "passwd_dlg.h"
|
|||
|
#include "KClient.h"
|
|||
|
#include "krb.h"
|
|||
|
|
|||
|
char guser[64];
|
|||
|
|
|||
|
void
|
|||
|
msg(char *text)
|
|||
|
{
|
|||
|
HWND wnd = GetActiveWindow();
|
|||
|
MessageBox(wnd, text, "KClient message", MB_OK|MB_APPLMODAL);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SendTicketForService(LPSTR service, LPSTR version, int fd)
|
|||
|
{
|
|||
|
KTEXT_ST ticket;
|
|||
|
MSG_DAT mdat;
|
|||
|
CREDENTIALS cred;
|
|||
|
des_key_schedule schedule;
|
|||
|
char name[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
|
|||
|
int ret;
|
|||
|
static KClientSessionInfo foo;
|
|||
|
KClientKey key;
|
|||
|
|
|||
|
kname_parse(name, inst, realm, service);
|
|||
|
strlcpy(foo.realm, realm, sizeof(foo.realm));
|
|||
|
|
|||
|
if(KClientStatus(&foo) == KClientNotLoggedIn)
|
|||
|
KClientLogin(&foo, &key);
|
|||
|
|
|||
|
ret = krb_sendauth (0, fd, &ticket,
|
|||
|
name, inst, realm, 17, &mdat,
|
|||
|
&cred, &schedule, NULL, NULL, version);
|
|||
|
if(ret)
|
|||
|
return FALSE;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL WINAPI
|
|||
|
DllMain(HANDLE hInst, ULONG reason, LPVOID lpReserved)
|
|||
|
{
|
|||
|
WORD wVersionRequested;
|
|||
|
WSADATA wsaData;
|
|||
|
int err;
|
|||
|
|
|||
|
switch(reason){
|
|||
|
case DLL_PROCESS_ATTACH:
|
|||
|
wVersionRequested = MAKEWORD(1, 1);
|
|||
|
|
|||
|
err = WSAStartup(wVersionRequested, &wsaData);
|
|||
|
|
|||
|
if (err != 0)
|
|||
|
{
|
|||
|
/* Tell the user that we couldn't find a useable */
|
|||
|
/* winsock.dll. */
|
|||
|
msg("Cannot find winsock.dll");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
break;
|
|||
|
case DLL_PROCESS_DETACH:
|
|||
|
WSACleanup();
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
Kerr
|
|||
|
KClientMessage(char *text, Kerr error)
|
|||
|
{
|
|||
|
msg(text);
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
/* KClientInitSession
|
|||
|
* You need to call this routine before calling most other routines.
|
|||
|
* It initializes a KClientSessionInfo structure.
|
|||
|
* The local and remote addresses are for use in KClientEncrypt,
|
|||
|
* KClientDecrypt, KClientMakeSendAuth and KClientVerifySendAuth.
|
|||
|
* If you don't use any of these routines it's perfectly OK to do the following...
|
|||
|
* err = KClientInitSession(session,0,0,0,0);
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientInitSession(KClientSessionInfo *session,
|
|||
|
unsigned long lAddr,
|
|||
|
unsigned short lPort,
|
|||
|
unsigned long fAddr,
|
|||
|
unsigned short fPort)
|
|||
|
{
|
|||
|
session->lAddr = lAddr;
|
|||
|
session->lPort = lPort;
|
|||
|
session->fAddr = fAddr;
|
|||
|
session->fPort = fPort;
|
|||
|
if(tf_get_pname(session->user) != KSUCCESS)
|
|||
|
*(session->user) = '\0';
|
|||
|
if(tf_get_pinst(session->inst) != KSUCCESS)
|
|||
|
*(session->inst) = '\0';
|
|||
|
krb_get_lrealm (session->realm, 1);
|
|||
|
if(*(session->user))
|
|||
|
strlcpy(guser, session->user, sizeof(guser));
|
|||
|
else
|
|||
|
*guser ='\0';
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientGetTicketForService
|
|||
|
* This routine gets an authenticator to be passed to a service.
|
|||
|
* If the user isn't already logged in the user is prompted for a password.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientGetTicketForService(KClientSessionInfo *session,
|
|||
|
char *service,
|
|||
|
void *buf,
|
|||
|
unsigned long *buflen)
|
|||
|
{
|
|||
|
CREDENTIALS c;
|
|||
|
KClientKey k;
|
|||
|
KTEXT_ST ticket;
|
|||
|
char serv[255], inst[255], realm[255];
|
|||
|
Kerr err;
|
|||
|
|
|||
|
// KClientSetUserName(session->user);
|
|||
|
err = kname_parse(serv,inst,realm,service);
|
|||
|
if(*realm)
|
|||
|
strlcpy(session->realm, realm, sizeof(session->realm));
|
|||
|
else
|
|||
|
strlcpy(realm, session->realm, sizeof(realm));
|
|||
|
if(KClientStatus(session) == KClientNotLoggedIn)
|
|||
|
if((err = KClientLogin(session, &k)) != KSUCCESS)
|
|||
|
return err;
|
|||
|
|
|||
|
if((err = krb_mk_req(&ticket, serv, inst, realm, 0)) != KSUCCESS)
|
|||
|
return KClientMessage(KClientErrorText(err,0),err);
|
|||
|
if((err = krb_get_cred(serv, inst, realm, &c)) != KSUCCESS)
|
|||
|
return KClientMessage(KClientErrorText(err,0),err);
|
|||
|
|
|||
|
if(*buflen >= ticket.length)
|
|||
|
{
|
|||
|
*buflen = ticket.length + sizeof(unsigned long);
|
|||
|
CopyMemory(buf, &ticket, *buflen);
|
|||
|
CopyMemory(session->key, c.session, sizeof(session->key));
|
|||
|
}
|
|||
|
else
|
|||
|
err = -1;
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientLogin
|
|||
|
* This routine "logs in" by getting a ticket granting ticket from kerberos.
|
|||
|
* It returns the user's private key which can be used to automate login at
|
|||
|
* a later time with KClientKeyLogin.
|
|||
|
*/
|
|||
|
|
|||
|
Kerr
|
|||
|
KClientLogin(KClientSessionInfo *session,
|
|||
|
KClientKey *privateKey)
|
|||
|
{
|
|||
|
CREDENTIALS c;
|
|||
|
Kerr err;
|
|||
|
char passwd[100];
|
|||
|
|
|||
|
if((err = pwd_dialog(guser, passwd)))
|
|||
|
return err;
|
|||
|
if(KClientStatus(session) == KClientNotLoggedIn)
|
|||
|
{
|
|||
|
|
|||
|
if((err = krb_get_pw_in_tkt(guser, session->inst, session->realm,
|
|||
|
"krbtgt", session->realm,
|
|||
|
DEFAULT_TKT_LIFE, passwd)) != KSUCCESS)
|
|||
|
return KClientMessage(KClientErrorText(err,0),err);
|
|||
|
}
|
|||
|
if((err = krb_get_cred("krbtgt", session->realm,
|
|||
|
session->realm, &c)) == KSUCCESS)
|
|||
|
CopyMemory(privateKey, c.session, sizeof(*privateKey));
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientPasswordLogin
|
|||
|
* This routine is similiar to KClientLogin but instead of prompting the user
|
|||
|
* for a password it uses the password supplied to establish login.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientPasswordLogin(KClientSessionInfo *session,
|
|||
|
char *password,
|
|||
|
KClientKey *privateKey)
|
|||
|
{
|
|||
|
return krb_get_pw_in_tkt(guser, session->inst, session->realm,
|
|||
|
"krbtgt",
|
|||
|
session->realm,
|
|||
|
DEFAULT_TKT_LIFE,
|
|||
|
password);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static key_proc_t
|
|||
|
key_proc(void *arg)
|
|||
|
{
|
|||
|
return arg;
|
|||
|
}
|
|||
|
|
|||
|
/* KClientKeyLogin
|
|||
|
* This routine is similiar to KClientLogin but instead of prompting the user
|
|||
|
* for a password it uses the private key supplied to establish login.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientKeyLogin(KClientSessionInfo *session,
|
|||
|
KClientKey *privateKey)
|
|||
|
{
|
|||
|
return krb_get_in_tkt(guser, session->inst, session->realm,
|
|||
|
"krbtgt",
|
|||
|
session->realm,
|
|||
|
DEFAULT_TKT_LIFE,
|
|||
|
key_proc,
|
|||
|
0,
|
|||
|
privateKey);
|
|||
|
}
|
|||
|
|
|||
|
/* KClientLogout
|
|||
|
* This routine destroys all credentials stored in the credential cache
|
|||
|
* effectively logging the user out.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientLogout(void)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientStatus
|
|||
|
* This routine returns the user's login status which can be
|
|||
|
* KClientLoggedIn or KClientNotLoggedIn.
|
|||
|
*/
|
|||
|
short
|
|||
|
KClientStatus(KClientSessionInfo *session)
|
|||
|
{
|
|||
|
CREDENTIALS c;
|
|||
|
if(krb_get_cred("krbtgt",
|
|||
|
session->realm,
|
|||
|
session->realm, &c) == KSUCCESS)
|
|||
|
return KClientLoggedIn;
|
|||
|
else
|
|||
|
return KClientNotLoggedIn;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientGetUserName
|
|||
|
* This routine returns the name the user supplied in the login dialog.
|
|||
|
* No name is returned if the user is not logged in.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientGetUserName(char *user)
|
|||
|
{
|
|||
|
strcpy(user, guser);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientSetUserName
|
|||
|
* This routine sets the name that will come up in the login dialog
|
|||
|
* the next time the user is prompted for a password.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientSetUserName(char *user)
|
|||
|
{
|
|||
|
strlcpy(guser, user, sizeof(guser));
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientCacheInitialTicket
|
|||
|
* This routine is used to obtain a ticket for the password changing service.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientCacheInitialTicket(KClientSessionInfo *session,
|
|||
|
char *service)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientGetSessionKey
|
|||
|
* This routine can be used to obtain the session key which is stored
|
|||
|
* in the KClientSessionInfo record. The session key has no usefullness
|
|||
|
* with any KClient calls but it can be used to with the MIT kerberos API.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientGetSessionKey(KClientSessionInfo *session,
|
|||
|
KClientKey *sessionKey)
|
|||
|
{
|
|||
|
CopyMemory(sessionKey, session->key, sizeof(*sessionKey));
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientMakeSendAuth
|
|||
|
* This routine is used to create an authenticator that is the same as those
|
|||
|
* created by the kerberos routine SendAuth.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientMakeSendAuth(KClientSessionInfo *session,
|
|||
|
char *service,
|
|||
|
void *buf,
|
|||
|
unsigned long *buflen,
|
|||
|
long checksum,
|
|||
|
char *applicationVersion)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientVerifySendAuth
|
|||
|
* This routine is used to verify a response made by a server doing RecvAuth.
|
|||
|
* The two routines KClientMakeSendAuth and KClientVerifySendAuth together
|
|||
|
* provide the functionality of SendAuth minus the transmission of authenticators
|
|||
|
* between client->server->client.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientVerifySendAuth(KClientSessionInfo *session,
|
|||
|
void *buf,
|
|||
|
unsigned long *buflen)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientEncrypt
|
|||
|
* This routine encrypts a series a bytes for transmission to the remote host.
|
|||
|
* For this to work properly you must be logged in and you must have specified
|
|||
|
* the remote and local addresses in KClientInitSession. The unencrypted
|
|||
|
* message pointed to by buf and of length buflen is returned encrypted
|
|||
|
* in encryptBuf of length encryptLength.
|
|||
|
* The encrypted buffer must be at least 26 bytes longer the buf.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientEncrypt(KClientSessionInfo *session,
|
|||
|
void *buf,
|
|||
|
unsigned long buflen,
|
|||
|
void *encryptBuf,
|
|||
|
unsigned long *encryptLength)
|
|||
|
{
|
|||
|
int num = 64;
|
|||
|
des_cfb64_encrypt(buf, encryptBuf, buflen,
|
|||
|
(struct des_ks_struct*) session->key,
|
|||
|
0, &num, 1);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientDecrypt
|
|||
|
* This routine decrypts a series of bytes received from the remote host.
|
|||
|
|
|||
|
* NOTE: this routine will not reverse a KClientEncrypt call.
|
|||
|
* It can only decrypt messages sent from the remote host.
|
|||
|
|
|||
|
* Instead of copying the decrypted message to an out buffer,
|
|||
|
* the message is decrypted in place and you are returned
|
|||
|
* an offset into the buffer where the decrypted message begins.
|
|||
|
*/
|
|||
|
Kerr
|
|||
|
KClientDecrypt(KClientSessionInfo *session,
|
|||
|
void *buf,
|
|||
|
unsigned long buflen,
|
|||
|
unsigned long *decryptOffset,
|
|||
|
unsigned long *decryptLength)
|
|||
|
{
|
|||
|
int num;
|
|||
|
des_cfb64_encrypt(buf, buf, buflen,
|
|||
|
(struct des_ks_struct*)session->key, 0, &num, 0);
|
|||
|
*decryptOffset = 0;
|
|||
|
*decryptLength = buflen;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* KClientErrorText
|
|||
|
* This routine returns a text description of errors returned by any of
|
|||
|
* the calls in this library.
|
|||
|
*/
|
|||
|
char *
|
|||
|
KClientErrorText(Kerr err,
|
|||
|
char *text)
|
|||
|
{
|
|||
|
char *t = krb_get_err_text(err);
|
|||
|
if(text)
|
|||
|
strcpy(text, t);
|
|||
|
return t;
|
|||
|
}
|