-[ 0x06 ]--------------------------------------------------------------------
-[ GINA y moviles ]----------------------------------------------------------
-[ by FCA00000 ]-----------------------------------------------------SET-30--

/*
Una vez ms, me presento ante vosotros para explicar un concepto de seguridad
de Windows NT, llamado GINA: Graphical Identification and Authentication.
En pocas palabras, GINA es el modelo de login interactivo. Gracias a que
es extendible, se puede programar otro mecanismo de autentificacin que
extienda o reemplace al definido normalmente en Windows NT.

Por ejemplo, las tarjetas inteligentes SmartCard, o los de reconocimiento
de la huella dactilar, o autentificacin en sub-dominios, se llevan a cabo
mediante GINA.

En este artculo, voy a hacer que el nombre de usuario se pida mediante
el dilogo normal de windows, pero la clave se solicite a traves del
telfono mvil.

La mayora de los datos necesarios para entender GINA los he sacado de un
ejemplo llamado GINASTUB y GINA que se encuentran en el DDK de WindowsNT.
Agradezco a sus autores la claridad con que estan presentados.

Existe una librera en Windows llamada MSGINA que es invocada por el programa
Winlogon para que el usuario presente sus credenciales. Para realmente
validar al usuario, usa la funcin LogonUser .

Pero en un substituto de MSGINA, lo que hay que hacer es proporcionar nuestra
propia autentificacin. Adems de esto, el usuario debe estar definido
en Windows, o si no hay que proveer mucha ms funcionalidad. Por ejemplo, las
horas en las que el usuario puede acceder, el directorio inicial, ...
Para no complicarnos la vida en exceso, lo que voy a hacer es un nuevo GINA
llamado FCA_GINA que llamar a las funciones orginales de MSGINA, excepto
cuando el usuario pretende meter su clave, que entonces conectar con el mvil.

Esto hay que hacerlo porque GINA no solo provee funciones para logon, sino
tambien para el salvapantallas, logoff, bloqueo del terminal, apagado, y
algunas ms. Si quieres implementar una, tienes que definir todas.

As que tan pronto como sea posible (y este momento es cuando Winlogon
llama a nuestra funcin WlxNegotiate) hay que cargar la librera
original MSGINA.DLL y obtener punteros a sus funciones.
Para eso, se usan las funciones LoadLibrary y GetProcAddress.

A partir de entonces el sistema nos ir llamando. Por ejemplo, cuando
el usuario esta inactivo ms de un tiempo establecido, llamar a la
funcion WlxScreenSaverNotify. En nuestro caso, como no queremos hacer
nada especial, simplemente llamamos a la funcin original con los
mismos parametros:
BOOL WINAPI WlxScreenSaverNotify(
 PVOID pWlxContext,
 BOOL * pSecure
 )
{
 return GWlxScreenSaverNotify( pWlxContext, pSecure );
}

Notar que esto tiene un claro comportamiento erroneo: si el sistema tiene ya
definido un sustituto para MSGINA, por ejemplo para un sistema que muestra
un salvapantallas distinto, y con nombre GINA_EXT, lo que hacemos en
realidad es llamar al MSGINA despus de nuestro manejo (inexistente) del
evento WlxScreenSaverNotify, cuando lo correcto sera llamar al
GINA_EXT.WlxScreenSaverNotify

Pero sigamos con lo que interesa.
Lo gracioso est en la funcin de login: WlxLoggedOutSAS
Los parmetros que Winlogon nos manda son:
 PVOID pWlxContext = Contexto de la ventana.
 DWORD dwSasType = tipo de evento. Es WLX_SAS_TYPE_CTRL_ALT_DEL para login
 PLUID pAuthenticationId = identificador de autentificacin. Podemos
    cambiar las estadsticas del usuario, por ejemplo la hora de ltimo login
 PSID pLogonSid = identificador de seguridad. Nmero nico para cada sesin.
 PDWORD pdwOptions = opciones para el logon, por ejemplo para cargar el perfil
 PHANDLE phToken = handle representando el usario que ha accedido.
 PWLX_MPR_NOTIFY_INFO pMprNotifyInfo = puntero al nombre, dominio, y clave.
    Se usa si tenemos que acceder a otro dominio. Nosotros lo usaremos.
 PVOID *pProfile = tipo, y datos del perfil. Dejaremos que MSGINA lo maneje.

El parametro de salida es
WLX_SAS_ACTION_LOGON	El usuario ha accedido.
WLX_SAS_ACTION_NONE	El intento de acceso no tiene xito.
WLX_SAS_ACTION_SHUTDOWN	El usuario ha solicitado apagar el sistema. Supongo
   que es de todos conocido que existe una opcion del registro llamada
   ShutdownWithoutLogon que permite apagar el sistema sin necesidad de logon.

Si queremos mostrar ms informacin, o la razn por la que el usuario no
puede conectar (ej. El mvil no esta enchufado) podemos mostrar un dilogo.
Dado que en este momento no existe todava un entorno (desktop) de usuario, no
se pueden usar las funciones MessageBox y DialogBox, as que hay que usar
otras equivalentes llamadas WlxMessageBox y WlxDialogBox. Por supuesto, tambin
tenemos nuestra propia ventana, asi que podemos mostrar all cualquier otra
cosa, tal como un dibujo, o un dialogo a nuestra medida. Esto es lo que
hace el ejemplo GINA incluido en el DDK.

Pero para mantener las cosas simples, yo voy a llamar al dilogo estandar
de Windows, a traves de su puntero original GWlxLoggedOutSAS:
 int iRet;

 iRet = GWlxLoggedOutSAS( pWlxContext, dwSasType, pAuthenticationId,
                pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile );

que me devolvera iRet == WLX_SAS_ACTION_LOGON
cuando el usario ha escrito su nombre y su clave (que ser vaca).

A partir de ah ya es todo mo: la estructura  pMprNotifyInfo  me proporciona
acceso al nombre de usuario, clave, y dominio.

Si fuera un programador malvolo, podra crear un GINA troyanizado que
escribiera en un fichero esta informacin:
 if(iRet == WLX_SAS_ACTION_LOGON)
  {
  ap=fopen("FCA_GINA.log","a+");
  fprintf(ap,"Usuario = %s\n", pMprNotifyInfo->pszUserName[i] );
  fprintf(ap,"Clave = %s\n", pMprNotifyInfo->pszPassword[i] );
  fprintf(ap,"Dominio = %s\n", pMprNotifyInfo->pszDomain[i] );
  fclose(ap);
  }
y no tendra ms que pedir a un administrador que usara mi ordenador para
as averiguar su clave. Bueno, estoy pensando en un entorno corporativo
donde hay cientos de ordenadores y los usuarios no tienen permisos locales
de administrador, claro.

As;i que confo en que los administradores de servidores NT (que espero lean
ste artculo) vigilen que no hay un GINA instalado en su sistema.

Vamos a lo nuestro, que ando otra vez por las ramas.
Como describ en un artculo anterior, es posible usar comandos AT para
manejar la tarjeta SIM albergada en un telfono mvil Siemens-S45 conectado
al ordenador.
Cuando digo "conectado", me refiero a 2 metodos:
-El primero es mediante la red de telefona. Es decir, mandando
 un SMS que pedir la  clave en la pantalla del mvil.
 Este metodo no es efectivo, porque puede haber un retraso de varios minutos, y
 ademas, se supone que el usuario  esta delante del ordenador, no?
 Sin embargo, podra ser til para autorizacin remota del ordenador.
 Por ejemplo, un usuario necesita la clave de su jefe para acceder.
 Asi que se sienta delante del ordenador, y escribe su nombre.
 El ordenador tiene un mdem (o un telfono mvil) que manda un SMS al
 telfono del jefe.
 Este responde con otro SMS que tiene la clave, y que el mdem recibe.
 Extrae la clave, se completan los datos de autentificacin, y el usuario
 accede al ordenador.
-El segundo es mediante cable o infrarrojos. En este escenario, todos los
 usuarios disponen de un telfono con capacidad de conectarse (si es por
 infrarrojos, mejor, pues prcticamente todos los mviles tienen infrarrojos)
 El usuario escribe su nombre en el ordenador (este paso puede
 ser omitido, ya que el nombre de usuario se puede almacenar en el movil).
 Despues, apunta su mvil hacia el puerto del ordenador.
 El ordenador encuentra el mvil, y tras el establecimiento del protocolo,
 le pide al mvil que solicite la clave al usuario. La clave se devuelve
 al ordenador, que completa el proceso de login.

En este punto hay varias alternativas:
-la clave se almacena en el mvil. El usuario no necesita recordarla. Lo malo
 es que si le roban el telfono al usuario, el ladrn puede acceder al sistema.
 La clave no tiene porqu ser un numero. Por ejemplo, puede ser el propio
 nmero de telefono, o una registro en la agenda de direcciones.
-la clave es el PIN. La validacin se realiza internamente en el mvil, y
 el ordenador recibe la confirmacin de que el usuario conoce su propio PIN.
 Con este metodo, la autentificacin queda delegada en el mvil. Esto
 permite usar los mecanismos de seguridad del SIM.
-la clave se almacena en el ordenador. El mvil sirve unicamente para
 escribirla, y el ordenador tiene que validarla. Esto permite que la clave
 se pueda transmitir a otros ordenadores, por ejemplo si es necesaria
 autentificacin en otros dominios.
 Este procedimiento es el que voy a usar. No es el ms seguro, ya que la clave
 se transmite sin codificar, pero es el que mejor ilustra el proceso.

As que el punto de entrada es la funcin obtener_clave_movil.
Solo por comodidad, esta funcion llama a otra llamada  main   .
Tengo que compilar FCA_GINA como una DLL, pero nadie me impide que tambin
lo convierta en un progama. As me resulta ms fcil debugear, antes de
instalarla adecuadamente.
Tenemos que   main   se encarga de abrir el puerto de comunicaciones COM4.
Mi ordenador tiene 1 puerto serie y otro de infrarrojos. Gracias al programa
IrCOMM2k , se convierte el puerto infrarrojos en COM4 que puedo abrir con
ttyfd = CreateFile ("COM4", GENERIC_READ, ...

y puedo establecer los parametros con
GetCommState(ttyfd, &dcb);
seguido de
dcb.BaudRate = CBR_57600;
y similares, finalizando con
SetCommState(ttyfd, &dcb);

Tambien me interesa cambiar los tiempos de time-out:
ctTimeOuts.ReadIntervalTimeout = 100;
SetCommTimeouts(ttyfd, &ctTimeOuts);

Declaro los datos que quiero mandar:
strcpy(tmpbuf, "at^sstk=22,0\r" );
y los escribo en el puerto con
WriteFile(ttyfd, tmpbuf, ...

La segunda parte del comando es la que vale para que el SIM solicite la clave.
Para el formato y su significado, ver el artculo de esta misma entrega, que
creo que se llamar "moviles3" o "SIM application Toolkit".
En la pantalla del mvil slo aparece la pregunta "SI?" que es poco
informativa, ya lo s. Tambin podra haber hecho que sonara un pitido, pero
no quiero complicar la cosa.
La clave tiene un mnimo de 5 y un mximo de 8 caracteres numricos.
El usuario ve lo que est escibiendo. Es posible hacer que cada pulsacin de
tecla muestre un asterisco, pero es mejor as.


Ahora solo tengo que esperar la respuesta:
ReadFile(ttyfd, ...

Gracias al timeout, cada 1000 milisegundos miramos a ver si hay un dato
para nosotros. Si no, decremento el contador del bucle y sigo.
Esto quiere decir que el usuario tiene 20 segundos para escribir la clave.

Cuando se ha escrito y pulsado el boton "OK" del mvil, se responde con
el comando
^SSTK: 8103012300820282818301008D0704303030303030
si la clave es '000000'
Esto corresponde a las ultimas cifras 30 30 30 30 30 30
As que saco los caracteres de 2 en 2 a partir de la posicin 32 tras '^SSTK:'
Ya s que podra interpretar el resultado segun el formato, pero esto es
slo para mostrar como se hace.

La clave la almaceno en una variable global.
Esto es una metodologa sumamente peligrosa, pues queda en memoria
durante toda la sesin, con el riesgo de que el siguiente
usuario en usar el ordenador la pueda extraer analizando toda la memoria.

Ya puedo retornar a la rutina para evaluar si la clave es correcta.

En mi caso, lo que hago es llamar otra vez a Windows para que me diga si
existe un usuario "securizado" y la clave es correcta.
Supongamos que el usuario se llama "prueba" , y lo hemos autentificado
correctamente con la primera llamada a GWlxLoggedOutSAS. Bueno, pues si
el usuario ha metido la clave mediante el mvil, entonces intento
autentificar a "prueba_seguro" con la clave introducida.
strcat(pMprNotifyInfo->pszUserName, "_seguro" );
strcpy(pMprNotifyInfo->pszPassword, clave_movil );

Y llamo a
 iRet = GWlxLoggedOutSAS(
 pWlxContext,
 dwSasType,
 pAuthenticationId,
 pLogonSid,
 pdwOptions,
 phToken,
 pMprNotifyInfo,
 pProfile
 );

Si esta segunda autentificacin tiene xito, devolvera WLX_SAS_ACTION_LOGON.
Si algo ha ido mal durante el proceso, se devuelve WLX_SAS_ACTION_NONE

Para probarlo, hay que seguir los pasos para instalacin de GINA. En breve, esto
es copiar la DLL al directorio local \WINNT\System32  y
crear una nueva clave REG_SZ en el registro
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
llamada GinaDLL con el nombre de nuestra libreria, en este caso FCA_GINA
As se entiende que no puede haber 2 libreras de autentificacin alternativa.
Si tienes, por ejemplo, un sistema de SmartCard, no puedes apilarlo sobre
un sistema de huella digital.
Similarmente, no es posible usarlos alternativamente, es decir, que unos
usuarios usen uno, y otros usen otro.
La solucin a esto es que el nuevo sistema de autentificacin guarde nota del
sistema anterior, antes de copiarse en \WINNT\System32  , y que lo invoque
cada vez que haya acabado con su propia autentificacin.


Hay muchas cosas a tener en cuenta.

Lo primero es que la librera se llama cuando intentas acceder al sistema. Si
te equivocas en el programa y no funciona, seras incapaz de entrar.
Por eso yo he puesto una doble medida: si hay un disquete en la disquetera
y existe un archivo llamado "si.txt", entonces se intenta la autentificacin
mediante el mvil. En un entorno real de produccin debe ser justo lo opuesto.
Por ejemplo, Administrador debera ser capaz de entrar aunque no tenga mvil.
Esto servir tambin para el caso en que el puerto deja de funcionar.

Segundo: la librera declarada en el registro debe existir en \WINNT\System32
o de lo contrario Windows se negar a autentificar a cualquier usuario.
En el manual dice que si no funciona correctamente, lo mejor es borrarla, pues
as no se usara. Mentira. Si la borras, Winlogon no deja entrar a nadie.

Tercero: imagnate que no funciona como esperas. Gracias a que has seguido
la primera indicacin, eres capaz de entrar "por la puerta de atrs". Pero
cuando haces los cambios, e intentas instalar la librera modificada, Windows
te dice que no es posible sobre-escribir el archivo porque esta siendo usado.
La solucin es tener un sistema dual de arranque, por ejemplo otra particin
con Windows que permita acceder a la primera. Lo malo es que cada vez que
haces un cambio, eso implica arrancar el otro sistema, copiar la nueva
librera, y arrancar de nuevo con el sistema de prueba. Para que sirva
de escarmiento, yo he tenido que hacer eso unas 7-8 veces.

Para saber por dnde va tu programa, puedes usar ventanas de dilogo, o bien
escribir la traza en un fichero. Eso facilita las cosas, pues si compartes
la unidad \WINNT\System32  , puedes verla desde otro ordenador, a pesar de
que no haya ningun usuario "logueado" en el ordenador de prueba.

Por supuesto, la manera de atenuar los riesgos anteriores es usar el debugger
para Windows  NTSD. Cualquier otro posiblemente necesite que el usuario
haya iniciado una sesin, asi que no valen. Animo; NTSD no es tan dificil, y
es el debugger usado en la propia Microsoft.

La documentacion de GINA dice "en sistemas compartidos antiguos, los usuarios
podan ir a un terminal aparentemente no usado, y al pulsar la tecla ENTER se
les solicitaba su usuario y clave. El problema con esto era que en realidad
haba un Caballo de Troya que recoga la clave pero indicaba que era errnea.
El resultado era que el usuario le haba proporcionado su clave a otro.
En Windows NT, los usuarios pueden usar una Secuencia de Atencin Segura, a
la que ningun Caballo de Troya puede acceder. Eso se hace con CTRL+ALT+DEL."
Y yo me pregunto: ?que es GINA, sino una puerta para caballos de troya?
De acuerdo que el usuario necesita tener permiso para copiar archivos a
sistema, y para crear claves del registro, pero eso tampoco es inhabitual.

En resmen, es sencillo modificar los sistemas de login y sustituirlos
por uno hecho a medida.




Relacionado con este tema, hay otra posibilidad llamada SubAutentificacin.
Sirve solo para autentificar, sin la parte del interface
grfico, ni la gestin de logoff o el salvapantallas.
Lo bueno es que puede apilarse sobre otros mecanismos.

Para que funcione, debe haber un dato llamado "Authentication Packages"
con el valor   msv1_0 en la rama
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa

Entonces en la rama del registro
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
se encuentran una lista de DLL que permiten autentificacin.

Por ejemplo, en mi sistema hay definidas:
-FPNWCLNT para clientes NetWare
-RASSFM para clientes de acceso telefnico
-IISSUBA para el servidor web (cuando acta como cliente del Sistema Operativo)


Cuando se intenta entrar al ordenador, un subsistema puede solicitar un
metodo de autentificacin particular. Entonces se carga la librera
y se ejecuta el metodo Msv1_0SubAuthenticationRoutine.
Eso es lo que hace RAS, por ejemplo. Como no se le puede pressentar al usuario
una ventana de login en el ordenador servidor, la clave se solicita en el cliente
y se enva mediante el mdem hacia el ordenador servidor, quien la verifica.

Entonces la librera decide dejar entrar al usuario, o no.
A diferencia de GINA, el usuario ya ha sido localizado en el dominio, por
lo que sta rutina puede solamente re-confirmar el acceso, o bien denegarlo.
Es por esto que las credenciales del usuario ya estan disponibles, y la
clave en limpio no se puede usar, sino que hay que usar el hash.
Notar que el usuario todava no esta autentificado. Esto es lo que
precisamente tenemos que hacer.

Grosso modo, hay que definir
NTSTATUS
NTAPI
Msv1_0SubAuthenticationRoutine (
    IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
    IN PVOID LogonInformation,
    IN ULONG Flags,
    IN PUSER_ALL_INFORMATION UserAll,
    OUT PULONG WhichFields,
    OUT PULONG UserFlags,
    OUT PBOOLEAN Authoritative,
    OUT PLARGE_INTEGER LogoffTime,
    OUT PLARGE_INTEGER KickoffTime
)
{
    // en este ejemplo tonto, nunca dejamos entrar al usuario "prueba"
    if ( UserAll->UserId != DOMAIN_USER_RID_ADMIN &&
         strcmp(UserAll->UserName.Buffer,"prueba")!=0 )
	{
            *Authoritative = TRUE;
            return STATUS_INVALID_LOGON_HOURS;
	}
    else
	{
            *Authoritative = TRUE;
            return STATUS_SUCCESS;
	}
}


La rama
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\Auth0
es especial. En vez de tener que ser invocada por un subsistema, es
invocada por todos los sistemas, despus de que el acceso ha sido dado.
En otras palabras, es un filtro adicional.
En lugar de llamar a la funcin anterior, se llamar a
NTSTATUS
NTAPI
Msv1_0SubAuthenticationFilter(
    IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
    IN PVOID LogonInformation,
    IN ULONG Flags,
    IN PUSER_ALL_INFORMATION UserAll,
    OUT PULONG WhichFields,
    OUT PULONG UserFlags,
    OUT PBOOLEAN Authoritative,
    OUT PLARGE_INTEGER LogoffTime,
    OUT PLARGE_INTEGER KickoffTime
);


Para los administradores que deseen imponer mas restricciones al login, este
es el sitio adecuado.

*/

#include <windows.h>
#include <stdio.h>
#include <winwlx.h>

typedef BOOL (WINAPI *PGWLXNEGOTIATE)( DWORD, DWORD* );
typedef BOOL (WINAPI *PGWLXINITIALIZE)( LPWSTR, HANDLE, PVOID, PVOID, PVOID* );
typedef VOID (WINAPI *PGWLXDISPLAYSASNOTICE)( PVOID );
typedef int (WINAPI *PGWLXLOGGEDOUTSAS)( PVOID, DWORD, PLUID, PSID, PDWORD,
 PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID *);
typedef BOOL (WINAPI *PGWLXACTIVATEUSERSHELL)( PVOID, PWSTR, PWSTR, PVOID );
typedef int (WINAPI *PGWLXLOGGEDONSAS)( PVOID, DWORD, PVOID );
typedef VOID (WINAPI *PGWLXDISPLAYLOCKEDNOTICE)( PVOID );
typedef int (WINAPI *PGWLXWKSTALOCKEDSAS)( PVOID, DWORD );
typedef BOOL (WINAPI *PGWLXISLOCKOK)( PVOID );
typedef BOOL (WINAPI *PGWLXISLOGOFFOK)( PVOID );
typedef VOID (WINAPI *PGWLXLOGOFF)( PVOID );
typedef VOID (WINAPI *PGWLXSHUTDOWN)( PVOID, DWORD );
typedef BOOL (WINAPI *PGWLXSCREENSAVERNOTIFY)( PVOID, BOOL * );
typedef BOOL (WINAPI *PGWLXSTARTAPPLICATION)( PVOID, PWSTR, PVOID, PWSTR );

PWLX_DISPATCH_VERSION_1_0 g_pWinlogon;

// Punteros globales a las direcciones originales
PGWLXNEGOTIATE GWlxNegotiate;
PGWLXINITIALIZE GWlxInitialize;
PGWLXDISPLAYSASNOTICE GWlxDisplaySASNotice;
PGWLXLOGGEDOUTSAS GWlxLoggedOutSAS;
PGWLXACTIVATEUSERSHELL GWlxActivateUserShell;
PGWLXLOGGEDONSAS GWlxLoggedOnSAS;
PGWLXDISPLAYLOCKEDNOTICE GWlxDisplayLockedNotice;
PGWLXWKSTALOCKEDSAS GWlxWkstaLockedSAS;
PGWLXISLOCKOK GWlxIsLockOk;
PGWLXISLOGOFFOK GWlxIsLogoffOk;
PGWLXLOGOFF GWlxLogoff;
PGWLXSHUTDOWN GWlxShutdown;
PGWLXSTARTAPPLICATION GWlxStartApplication;
PGWLXSCREENSAVERNOTIFY GWlxScreenSaverNotify;

char clave_movil[] = "00000000000000000000000000000000000000000000000";

int main(int argc, char *argv[])
{
 DWORD actual;
 int datos = 0, otra_vez=20, i;
 HANDLE ttyfd;
 DCB dcb;
 COMMTIMEOUTS ctTimeOuts;
 char tmpbuf[200] = {0,};
 char *p;
 char CTRL_Z[] = {0x1A, 0x00};
 FILE *ap;

 ttyfd = CreateFile ("COM1", GENERIC_READ | GENERIC_WRITE,
	0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

 GetCommState(ttyfd, &dcb);
 dcb.fBinary = TRUE; dcb.BaudRate = CBR_57600; dcb.fParity = FALSE;
 dcb.Parity = 0; dcb.ByteSize = 8; dcb.StopBits = 1;

 SetCommState(ttyfd, &dcb);
 ctTimeOuts.ReadIntervalTimeout = 100;
 ctTimeOuts.ReadTotalTimeoutMultiplier = 1;
 ctTimeOuts.ReadTotalTimeoutConstant = 1000;
 ctTimeOuts.WriteTotalTimeoutMultiplier = 1;
 ctTimeOuts.WriteTotalTimeoutConstant = 5000;
 SetCommTimeouts(ttyfd, &ctTimeOuts);

 Sleep(500);

 PurgeComm(ttyfd, PURGE_RXABORT | PURGE_RXCLEAR);

 strcpy(tmpbuf, "at^sstk=22,0\r" );
 WriteFile(ttyfd, tmpbuf, strlen(tmpbuf), &actual, NULL);
 Sleep(500);

 strcpy(tmpbuf, "D0138103012300820281028D040453493F11020508" );
 strcat(tmpbuf, CTRL_Z );
 WriteFile(ttyfd, tmpbuf, strlen(tmpbuf), &actual, NULL);
 Sleep(500);

 while(otra_vez)
 {
  ReadFile(ttyfd, tmpbuf, sizeof(tmpbuf), &actual, NULL);
  otra_vez--;
  if(strchr(tmpbuf, ':')!=NULL )
   {
   otra_vez = 0;
   }
  };
 p=strchr(tmpbuf, ':');
 i=0;
 // los primeros 32 caracteres tras el 'SSTK :' son 
 // cabeceras del protocolo
 for(datos=32;datos<52;datos+=2)
  {
  if(p[datos]==0)
   break;
  if(p[datos]!='3') //los caracteres son '3x' donde x es la tecla
   break;
  clave_movil[i++]=p[datos+1];
  }
 clave_movil[i++]=0;
 printf("clave_movil=%s\n", clave_movil );
 ap=fopen("FCA_GINA.log","a+");
 fprintf(ap,"clave_movil =%s\n", clave_movil );
 fclose(ap);
 close(ttyfd);

}

int obtener_clave_movil()
{
main(0,NULL);
return 0;
}

BOOL
inicializa( void )
{
 HINSTANCE hDll;
	
 hDll = LoadLibrary( TEXT("MSGINA.DLL") );

 // Obtener las direcciones de las funciones originales
 GWlxNegotiate = (PGWLXNEGOTIATE)GetProcAddress( hDll, "WlxNegotiate" );
 GWlxInitialize = (PGWLXINITIALIZE)GetProcAddress( hDll, "WlxInitialize" );
 GWlxDisplaySASNotice =
	(PGWLXDISPLAYSASNOTICE)GetProcAddress( hDll, "WlxDisplaySASNotice" );
 GWlxLoggedOutSAS =
	(PGWLXLOGGEDOUTSAS)GetProcAddress( hDll, "WlxLoggedOutSAS" );
 GWlxActivateUserShell =
	(PGWLXACTIVATEUSERSHELL)GetProcAddress( hDll, "WlxActivateUserShell" );
 GWlxLoggedOnSAS = (PGWLXLOGGEDONSAS)GetProcAddress( hDll, "WlxLoggedOnSAS" );
 GWlxDisplayLockedNotice =
	(PGWLXDISPLAYLOCKEDNOTICE)GetProcAddress( hDll, "WlxDisplayLockedNotice");
 GWlxIsLockOk = (PGWLXISLOCKOK)GetProcAddress( hDll, "WlxIsLockOk" );
 GWlxWkstaLockedSAS =
	(PGWLXWKSTALOCKEDSAS)GetProcAddress( hDll, "WlxWkstaLockedSAS" );
 GWlxIsLogoffOk = (PGWLXISLOGOFFOK)GetProcAddress( hDll, "WlxIsLogoffOk" );
 GWlxLogoff = (PGWLXLOGOFF)GetProcAddress( hDll, "WlxLogoff" );
 GWlxShutdown = (PGWLXSHUTDOWN)GetProcAddress( hDll, "WlxShutdown" );
 GWlxStartApplication =
	(PGWLXSTARTAPPLICATION) GetProcAddress( hDll, "WlxStartApplication" );
 GWlxScreenSaverNotify =
	(PGWLXSCREENSAVERNOTIFY) GetProcAddress( hDll, "WlxScreenSaverNotify" );

 return TRUE;
}

BOOL WINAPI WlxNegotiate(
 DWORD dwWinlogonVersion,
 DWORD *pdwDllVersion)
{
 if( !inicializa() )
 return FALSE;

 return GWlxNegotiate( dwWinlogonVersion, pdwDllVersion );
}

BOOL WINAPI WlxInitialize(
 LPWSTR lpWinsta,
 HANDLE hWlx,
 PVOID pvReserved,
 PVOID pWinlogonFunctions,
 PVOID *pWlxContext)
{
 return GWlxInitialize(
 lpWinsta,
 hWlx,
 pvReserved,
 pWinlogonFunctions,
 pWlxContext
 );
}

int WINAPI WlxLoggedOutSAS(
 PVOID pWlxContext,
 DWORD dwSasType,
 PLUID pAuthenticationId,
 PSID pLogonSid,
 PDWORD pdwOptions,
 PHANDLE phToken,
 PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
 PVOID *pProfile)
{
 int iRet;

 iRet = GWlxLoggedOutSAS(
 pWlxContext,
 dwSasType,
 pAuthenticationId,
 pLogonSid,
 pdwOptions,
 phToken,
 pMprNotifyInfo,
 pProfile
 );

 if(iRet == WLX_SAS_ACTION_LOGON) {

		int lll, i;
		FILE *ap;

		ap=fopen("a:\\si.txt","r");
		if(ap!=NULL)
			{
			fclose(ap);
			}
		else
			{
			return iRet;
			}

		lll=wcslen(pMprNotifyInfo->pszPassword);
		ap=fopen("FCA_GINA.log","a+");
		fprintf(ap,"pszPassword = %s\n", pMprNotifyInfo->pszPassword );
		fclose(ap);

		i=obtener_clave_movil(0, NULL);
		lll=strlen(clave_movil);

		strcat(pMprNotifyInfo->pszUserName, "_seguro" );
		strcpy(pMprNotifyInfo->pszPassword, clave_movil );

		iRet = GWlxLoggedOutSAS(
		 pWlxContext,
		 dwSasType,
		 pAuthenticationId,
		 pLogonSid,
		 pdwOptions,
		 phToken,
		 pMprNotifyInfo,
		 pProfile
		 );
 // pMprNotifyInfo->pszUserName
 // pMprNotifyInfo->pszDomain
 // pMprNotifyInfo->pszPassword
 // pMprNotifyInfo->pszOldPassword

 }

 return iRet;
}

// A partir de aqui, simplemente llaman a la funcion original

VOID WINAPI WlxDisplaySASNotice(
 PVOID pWlxContext)
{
 GWlxDisplaySASNotice( pWlxContext );
}

BOOL WINAPI WlxActivateUserShell(
 PVOID pWlxContext,
 PWSTR pszDesktopName,
 PWSTR pszMprLogonScript,
 PVOID pEnvironment)
{
 return GWlxActivateUserShell(
 pWlxContext,
 pszDesktopName,
 pszMprLogonScript,
 pEnvironment
 );
}

int WINAPI WlxLoggedOnSAS(
 PVOID pWlxContext,
 DWORD dwSasType,
 PVOID pReserved)
{
 return GWlxLoggedOnSAS( pWlxContext, dwSasType, pReserved );
}

VOID WINAPI WlxDisplayLockedNotice(
 PVOID pWlxContext )
{
 GWlxDisplayLockedNotice( pWlxContext );
}

BOOL WINAPI WlxIsLockOk(
 PVOID pWlxContext)
{
 return GWlxIsLockOk( pWlxContext );
}

int WINAPI WlxWkstaLockedSAS(
 PVOID pWlxContext,
 DWORD dwSasType )
{
 return GWlxWkstaLockedSAS( pWlxContext, dwSasType );
}

BOOL WINAPI WlxIsLogoffOk(
 PVOID pWlxContext
 )
{
 BOOL bSuccess;

 bSuccess = GWlxIsLogoffOk( pWlxContext );

 return bSuccess;
}

VOID WINAPI WlxLogoff(
 PVOID pWlxContext
 )
{
 GWlxLogoff( pWlxContext );
}

VOID WINAPI WlxShutdown(
 PVOID pWlxContext,
 DWORD ShutdownType
 )
{
 GWlxShutdown( pWlxContext, ShutdownType );
}

BOOL WINAPI WlxScreenSaverNotify(
 PVOID pWlxContext,
 BOOL * pSecure
 )
{
 return GWlxScreenSaverNotify( pWlxContext, pSecure );
}

BOOL WINAPI WlxStartApplication(
 PVOID pWlxContext,
 PWSTR pszDesktopName,
 PVOID pEnvironment,
 PWSTR pszCmdLine
 )
{
 return GWlxStartApplication(
 pWlxContext,
 pszDesktopName,
 pEnvironment,
 pszCmdLine
 );
}

*EOF*