xenocara/xserver/os/xdmauth.c
2006-11-26 18:13:41 +00:00

498 lines
11 KiB
C

/*
Copyright 1988, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.
*/
/*
* XDM-AUTHENTICATION-1 (XDMCP authentication) and
* XDM-AUTHORIZATION-1 (client authorization) protocols
*
* Author: Keith Packard, MIT X Consortium
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdio.h>
#include <X11/X.h>
#define XSERV_t
#define TRANS_SERVER
#define TRANS_REOPEN
#include <X11/Xtrans/Xtrans.h>
#include "os.h"
#include "osdep.h"
#include "dixstruct.h"
#ifdef HASXDMAUTH
static Bool authFromXDMCP;
#ifdef XDMCP
#include <X11/Xmd.h>
#undef REQUEST
#include <X11/Xdmcp.h>
/* XDM-AUTHENTICATION-1 */
static XdmAuthKeyRec privateKey;
static char XdmAuthenticationName[] = "XDM-AUTHENTICATION-1";
#define XdmAuthenticationNameLen (sizeof XdmAuthenticationName - 1)
static XdmAuthKeyRec rho;
static Bool
XdmAuthenticationValidator (ARRAY8Ptr privateData, ARRAY8Ptr incomingData,
xdmOpCode packet_type)
{
XdmAuthKeyPtr incoming;
XdmcpUnwrap (incomingData->data, &privateKey,
incomingData->data,incomingData->length);
if (packet_type == ACCEPT) {
if (incomingData->length != 8)
return FALSE;
incoming = (XdmAuthKeyPtr) incomingData->data;
XdmcpDecrementKey (incoming);
return XdmcpCompareKeys (incoming, &rho);
}
return FALSE;
}
static Bool
XdmAuthenticationGenerator (ARRAY8Ptr privateData, ARRAY8Ptr outgoingData,
xdmOpCode packet_type)
{
outgoingData->length = 0;
outgoingData->data = 0;
if (packet_type == REQUEST) {
if (XdmcpAllocARRAY8 (outgoingData, 8))
XdmcpWrap (&rho, &privateKey, outgoingData->data, 8);
}
return TRUE;
}
static Bool
XdmAuthenticationAddAuth (int name_len, char *name,
int data_len, char *data)
{
Bool ret;
XdmcpUnwrap (data, (unsigned char *)&privateKey, data, data_len);
authFromXDMCP = TRUE;
ret = AddAuthorization (name_len, name, data_len, data);
authFromXDMCP = FALSE;
return ret;
}
#define atox(c) ('0' <= c && c <= '9' ? c - '0' : \
'a' <= c && c <= 'f' ? c - 'a' + 10 : \
'A' <= c && c <= 'F' ? c - 'A' + 10 : -1)
static int
HexToBinary (char *in, char *out, int len)
{
int top, bottom;
while (len > 0)
{
top = atox(in[0]);
if (top == -1)
return 0;
bottom = atox(in[1]);
if (bottom == -1)
return 0;
*out++ = (top << 4) | bottom;
in += 2;
len -= 2;
}
if (len)
return 0;
*out++ = '\0';
return 1;
}
void
XdmAuthenticationInit (char *cookie, int cookie_len)
{
bzero (privateKey.data, 8);
if (!strncmp (cookie, "0x", 2) || !strncmp (cookie, "0X", 2))
{
if (cookie_len > 2 + 2 * 8)
cookie_len = 2 + 2 * 8;
HexToBinary (cookie + 2, (char *)privateKey.data, cookie_len - 2);
}
else
{
if (cookie_len > 7)
cookie_len = 7;
memmove (privateKey.data + 1, cookie, cookie_len);
}
XdmcpGenerateKey (&rho);
XdmcpRegisterAuthentication (XdmAuthenticationName, XdmAuthenticationNameLen,
(unsigned char *)&rho,
sizeof (rho),
(ValidatorFunc)XdmAuthenticationValidator,
(GeneratorFunc)XdmAuthenticationGenerator,
(AddAuthorFunc)XdmAuthenticationAddAuth);
}
#endif /* XDMCP */
/* XDM-AUTHORIZATION-1 */
typedef struct _XdmAuthorization {
struct _XdmAuthorization *next;
XdmAuthKeyRec rho;
XdmAuthKeyRec key;
XID id;
} XdmAuthorizationRec, *XdmAuthorizationPtr;
static XdmAuthorizationPtr xdmAuth;
typedef struct _XdmClientAuth {
struct _XdmClientAuth *next;
XdmAuthKeyRec rho;
char client[6];
long time;
} XdmClientAuthRec, *XdmClientAuthPtr;
static XdmClientAuthPtr xdmClients;
static long clockOffset;
static Bool gotClock;
#define TwentyMinutes (20 * 60)
#define TwentyFiveMinutes (25 * 60)
static Bool
XdmClientAuthCompare (XdmClientAuthPtr a, XdmClientAuthPtr b)
{
int i;
if (!XdmcpCompareKeys (&a->rho, &b->rho))
return FALSE;
for (i = 0; i < 6; i++)
if (a->client[i] != b->client[i])
return FALSE;
return a->time == b->time;
}
static void
XdmClientAuthDecode (unsigned char *plain, XdmClientAuthPtr auth)
{
int i, j;
j = 0;
for (i = 0; i < 8; i++)
{
auth->rho.data[i] = plain[j];
++j;
}
for (i = 0; i < 6; i++)
{
auth->client[i] = plain[j];
++j;
}
auth->time = 0;
for (i = 0; i < 4; i++)
{
auth->time |= plain[j] << ((3 - i) << 3);
j++;
}
}
static void
XdmClientAuthTimeout (long now)
{
XdmClientAuthPtr client, next, prev;
prev = 0;
for (client = xdmClients; client; client=next)
{
next = client->next;
if (abs (now - client->time) > TwentyFiveMinutes)
{
if (prev)
prev->next = next;
else
xdmClients = next;
xfree (client);
}
else
prev = client;
}
}
static XdmClientAuthPtr
XdmAuthorizationValidate (unsigned char *plain, int length,
XdmAuthKeyPtr rho, ClientPtr xclient, char **reason)
{
XdmClientAuthPtr client, existing;
long now;
int i;
if (length != (192 / 8)) {
if (reason)
*reason = "Bad XDM authorization key length";
return NULL;
}
client = (XdmClientAuthPtr) xalloc (sizeof (XdmClientAuthRec));
if (!client)
return NULL;
XdmClientAuthDecode (plain, client);
if (!XdmcpCompareKeys (&client->rho, rho))
{
xfree (client);
if (reason)
*reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)";
return NULL;
}
for (i = 18; i < 24; i++)
if (plain[i] != 0) {
xfree (client);
if (reason)
*reason = "Invalid XDM-AUTHORIZATION-1 key (failed NULL check)";
return NULL;
}
if (xclient) {
int family, addr_len;
Xtransaddr *addr;
if (_XSERVTransGetPeerAddr(((OsCommPtr)xclient->osPrivate)->trans_conn,
&family, &addr_len, &addr) == 0
&& _XSERVTransConvertAddress(&family, &addr_len, &addr) == 0) {
#if defined(TCPCONN) || defined(STREAMSCONN)
if (family == FamilyInternet &&
memcmp((char *)addr, client->client, 4) != 0) {
xfree (client);
xfree (addr);
if (reason)
*reason = "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)";
return NULL;
}
#endif
xfree (addr);
}
}
now = time(0);
if (!gotClock)
{
clockOffset = client->time - now;
gotClock = TRUE;
}
now += clockOffset;
XdmClientAuthTimeout (now);
if (abs (client->time - now) > TwentyMinutes)
{
xfree (client);
if (reason)
*reason = "Excessive XDM-AUTHORIZATION-1 time offset";
return NULL;
}
for (existing = xdmClients; existing; existing=existing->next)
{
if (XdmClientAuthCompare (existing, client))
{
xfree (client);
if (reason)
*reason = "XDM authorization key matches an existing client!";
return NULL;
}
}
return client;
}
int
XdmAddCookie (unsigned short data_length, char *data, XID id)
{
XdmAuthorizationPtr new;
unsigned char *rho_bits, *key_bits;
switch (data_length)
{
case 16: /* auth from files is 16 bytes long */
#ifdef XDMCP
if (authFromXDMCP)
{
/* R5 xdm sent bogus authorization data in the accept packet,
* but we can recover */
rho_bits = rho.data;
key_bits = (unsigned char *) data;
key_bits[0] = '\0';
}
else
#endif
{
rho_bits = (unsigned char *) data;
key_bits = (unsigned char *) (data + 8);
}
break;
#ifdef XDMCP
case 8: /* auth from XDMCP is 8 bytes long */
rho_bits = rho.data;
key_bits = (unsigned char *) data;
break;
#endif
default:
return 0;
}
/* the first octet of the key must be zero */
if (key_bits[0] != '\0')
return 0;
new = (XdmAuthorizationPtr) xalloc (sizeof (XdmAuthorizationRec));
if (!new)
return 0;
new->next = xdmAuth;
xdmAuth = new;
memmove (new->key.data, key_bits, (int) 8);
memmove (new->rho.data, rho_bits, (int) 8);
new->id = id;
return 1;
}
XID
XdmCheckCookie (unsigned short cookie_length, char *cookie,
ClientPtr xclient, char **reason)
{
XdmAuthorizationPtr auth;
XdmClientAuthPtr client;
unsigned char *plain;
/* Auth packets must be a multiple of 8 bytes long */
if (cookie_length & 7)
return (XID) -1;
plain = (unsigned char *) xalloc (cookie_length);
if (!plain)
return (XID) -1;
for (auth = xdmAuth; auth; auth=auth->next) {
XdmcpUnwrap (cookie, (unsigned char *)&auth->key, plain, cookie_length);
if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, xclient, reason)) != NULL)
{
client->next = xdmClients;
xdmClients = client;
xfree (plain);
return auth->id;
}
}
xfree (plain);
return (XID) -1;
}
int
XdmResetCookie (void)
{
XdmAuthorizationPtr auth, next_auth;
XdmClientAuthPtr client, next_client;
for (auth = xdmAuth; auth; auth=next_auth)
{
next_auth = auth->next;
xfree (auth);
}
xdmAuth = 0;
for (client = xdmClients; client; client=next_client)
{
next_client = client->next;
xfree (client);
}
xdmClients = (XdmClientAuthPtr) 0;
return 1;
}
XID
XdmToID (unsigned short cookie_length, char *cookie)
{
XdmAuthorizationPtr auth;
XdmClientAuthPtr client;
unsigned char *plain;
plain = (unsigned char *) xalloc (cookie_length);
if (!plain)
return (XID) -1;
for (auth = xdmAuth; auth; auth=auth->next) {
XdmcpUnwrap (cookie, (unsigned char *)&auth->key, plain, cookie_length);
if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, NULL, NULL)) != NULL)
{
xfree (client);
xfree (cookie);
xfree (plain);
return auth->id;
}
}
xfree (cookie);
xfree (plain);
return (XID) -1;
}
int
XdmFromID (XID id, unsigned short *data_lenp, char **datap)
{
XdmAuthorizationPtr auth;
for (auth = xdmAuth; auth; auth=auth->next) {
if (id == auth->id) {
*data_lenp = 16;
*datap = (char *) &auth->rho;
return 1;
}
}
return 0;
}
int
XdmRemoveCookie (unsigned short data_length, char *data)
{
XdmAuthorizationPtr auth;
XdmAuthKeyPtr key_bits, rho_bits;
switch (data_length)
{
case 16:
rho_bits = (XdmAuthKeyPtr) data;
key_bits = (XdmAuthKeyPtr) (data + 8);
break;
#ifdef XDMCP
case 8:
rho_bits = &rho;
key_bits = (XdmAuthKeyPtr) data;
break;
#endif
default:
return 0;
}
for (auth = xdmAuth; auth; auth=auth->next) {
if (XdmcpCompareKeys (rho_bits, &auth->rho) &&
XdmcpCompareKeys (key_bits, &auth->key))
{
xdmAuth = auth->next;
xfree (auth);
return 1;
}
}
return 0;
}
#endif