📄 protocol.c
字号:
/*
** BPALogin v2.0 - lightweight portable BIDS2 login client
** Copyright (c) 1999 Shane Hyde (shyde@trontech.com.au)
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
*/
#include "bpalogin.h"
#include "md5.h"
void genmd5(char *p,int len,char *digest)
{
MD5_CTX context;
MD5Init(&context);
MD5Update(&context, p, len);
MD5Final(digest, &context);
}
/*
** This functions makes the MD5 based data packet which is used to login,
** logout and handle heartbeats
*/
void makecredentials(char * credentials,struct session *s,INT2 msg,INT4 extra)
{
INT2 j = htons(msg);
int i=0;
char buffer[150];
INT4 ts = htonl(extra);
memcpy(buffer,s->nonce,16);
i += 16;
memcpy(buffer+i,s->password,strlen(s->password));
i += strlen(s->password);
memcpy(buffer+i,&(ts),sizeof(INT4));
i += sizeof(INT4);
memcpy(buffer+i,&j,sizeof(INT2));
i += sizeof(INT2);
genmd5(buffer,i,credentials);
}
/*
** Login to the Authentication server
**
** Returns - 0 - failed to login for some reason.
** 1 - Logged in successfully
*/
int bpa_login(struct session * s)
{
int err;
char credentials[16];
char * asctime_P;
time_t logintime;
int authsocket;
struct transaction t;
INT2 transactiontype;
struct hostent * he;
char *he_buffer = NULL;
he_buffer = (char *) malloc(512);
s->localaddr.sin_port = htons(0);
authsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (authsocket < 0)
{
return 0;
}
err = bind(authsocket, (struct sockaddr *)&s->localaddr, sizeof(struct sockaddr_in));
if (err)
{
socketerror(s, "Error binding auth socket");
closesocket(authsocket);
return 0;
}
err = connect(authsocket,(struct sockaddr *)&s->authhost,sizeof(struct sockaddr_in));
if (err)
{
socketerror(s, "Cant connect to auth server");
closesocket(authsocket);
return 0;
}
/*
** start the negotiation
*/
start_transaction(&t, T_MSG_PROTOCOL_NEG_REQ, s->sessionid);
add_field_INT2(s, &t, T_PARAM_CLIENT_VERSION, LOGIN_VERSION * 100);
add_field_string(s, &t, T_PARAM_OS_IDENTITY, s->osname);
add_field_string(s, &t, T_PARAM_OS_VERSION, s->osrelease);
add_field_INT2(s, &t, T_PARAM_PROTOCOL_LIST, T_PROTOCOL_CHAL);
send_transaction(s,authsocket,&t);
transactiontype = receive_transaction(s,authsocket,&t);
if (transactiontype != T_MSG_PROTOCOL_NEG_RESP)
{
s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - error transaction type (%d)",transactiontype);
closesocket(authsocket);
return 0;
}
extract_valueINT2(s, &t, T_PARAM_STATUS_CODE, &s->retcode);
extract_valuestring(s, &t, T_PARAM_LOGIN_SERVER_HOST, s->loginserverhost);
extract_valueINT2(s, &t, T_PARAM_PROTOCOL_SELECT, &s->protocol);
if(s->protocol != T_PROTOCOL_CHAL)
{
s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Unsupported protocol (%d)",s->protocol);
closesocket(authsocket);
return 0;
}
switch(s->retcode)
{
case T_STATUS_SUCCESS:
case T_STATUS_LOGIN_SUCCESS_SWVER:
break;
case T_STATUS_LOGIN_FAIL_SWVER:
{
s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Login failure: software version");
closesocket(authsocket);
return 0;
}
case T_STATUS_LOGIN_FAIL_INV_PROT:
{
s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Login failure: invalid protocol");
closesocket(authsocket);
return 0;
}
case T_STATUS_LOGIN_UNKNOWN:
{
s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Login failure: unknown");
closesocket(authsocket);
return 0;
}
}
closesocket(authsocket);
/* Do login after negotiation */
authsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (authsocket < 0)
{
return 0;
}
err = bind(authsocket,(struct sockaddr *)&s->localaddr,sizeof(struct sockaddr_in));
if (err)
{
socketerror(s, "Error binding auth socket 2");
closesocket(authsocket);
return 0;
}
err = connect(authsocket,(struct sockaddr *)&s->authhost,sizeof(struct sockaddr_in));
if (err)
{
socketerror(s, "Error connecting auth socket 2");
closesocket(authsocket);
return 0;
}
start_transaction(&t, T_MSG_LOGIN_REQ, s->sessionid);
add_field_string(s, &t,T_PARAM_USERNAME, s->username);
add_field_INT2 (s, &t,T_PARAM_CLIENT_VERSION, LOGIN_VERSION * 100);
add_field_string(s, &t,T_PARAM_OS_IDENTITY, s->osname);
add_field_string(s, &t,T_PARAM_OS_VERSION, s->osrelease);
add_field_INT2 (s, &t,T_PARAM_REASON_CODE, T_LOGIN_REASON_CODE_NORMAL);
add_field_INT2 (s, &t,T_PARAM_REQ_PORT, s->listenport);
send_transaction(s,authsocket, &t);
transactiontype = receive_transaction(s, authsocket, &t);
if (transactiontype == T_MSG_LOGIN_RESP)
goto skippo;
if (transactiontype != T_MSG_AUTH_RESP)
{
s->debug(0,"T_MSG_AUTH_RESP - error transaction type (%d)",transactiontype);
closesocket(authsocket);
return 0;
}
if (!extract_valueINT2(s, &t, T_PARAM_HASH_METHOD, &s->hashmethod))
{
s->debug(0,"T_MSG_AUTH_RESP - no hashmethod provided");
closesocket(authsocket);
return 0;
}
if(!extract_valuestring(s, &t, T_PARAM_NONCE, s->nonce))
{
s->debug(0,"T_MSG_AUTH_RESP - no nonce supplied");
closesocket(authsocket);
return 0;
}
if(s->hashmethod == T_AUTH_MD5_HASH)
{
genmd5(s->password,strlen(s->password),s->password);
}
start_transaction(&t,T_MSG_LOGIN_AUTH_REQ,s->sessionid);
s->timestamp = time(NULL);
makecredentials(credentials,s,T_MSG_LOGIN_AUTH_REQ,s->timestamp);
add_field_data(s,&t,T_PARAM_AUTH_CREDENTIALS,credentials,16);
add_field_INT4(s,&t,T_PARAM_TIMESTAMP,s->timestamp);
send_transaction(s,authsocket,&t);
transactiontype = receive_transaction(s,authsocket,&t);
skippo:
if (transactiontype != T_MSG_LOGIN_RESP)
{
s->debug(0,"T_MSG_LOGIN_RESP - error transaction type (%d)",transactiontype);
closesocket(authsocket);
return 0;
}
extract_valueINT2(s,&t,T_PARAM_STATUS_CODE,&s->retcode);
switch(s->retcode)
{
case T_STATUS_SUCCESS:
case T_STATUS_LOGIN_SUCCESSFUL_SWVER:
case T_STATUS_LOGIN_SUCCESSFUL_ALREADY_LOGGED_IN:
break;
case T_STATUS_USERNAME_NOT_FOUND:
{
s->debug(0,"T_MSG_LOGIN_RESP - Login failure: username not known");
closesocket(authsocket);
return 0;
}
case T_STATUS_INCORRECT_PASSWORD:
{
s->debug(0,"T_MSG_LOGIN_RESP - Login failure: incorrect password");
closesocket(authsocket);
return 0;
}
case T_STATUS_ACCOUNT_DISABLED:
{
s->debug(0,"T_MSG_LOGIN_RESP - Login failure: Account disabled");
closesocket(authsocket);
return 0;
}
case T_STATUS_LOGIN_RETRY_LIMIT:
case T_STATUS_USER_DISABLED:
case T_STATUS_FAIL_USERNAME_VALIDATE:
case T_STATUS_FAIL_PASSWORD_VALIDATE:
case T_STATUS_LOGIN_UNKNOWN:
{
s->debug(0,"T_MSG_LOGIN_RESP - Login failure: other error");
closesocket(authsocket);
return 0;
}
default:
closesocket(authsocket);
return 0;
}
extract_valueINT2(s,&t,T_PARAM_LOGOUT_SERVICE_PORT,&s->logoutport);
extract_valueINT2(s,&t,T_PARAM_STATUS_SERVICE_PORT,&s->statusport);
extract_valuestring(s,&t,T_PARAM_TSMLIST,s->tsmlist);
extract_valuestring(s,&t,T_PARAM_RESPONSE_TEXT,s->resptext);
{
int i,n;
char * p = s->tsmlist;
char t[200];
s->tsmcount = 0;
while((n = strcspn(p," ,"))!=0)
{
strncpy(t,p,n);
t[n] = 0;
p += n +1;
strcpy(s->tsmlist_s[s->tsmcount], t);
strcat(s->tsmlist_s[s->tsmcount++], s->authdomain);
}
for(i=0; i<s->tsmcount; i++)
{
he = gethostbyname(s->tsmlist_s[i]);
if (he)
{
s->tsmlist_in[i].sin_addr.s_addr = *((int*)(he->h_addr_list[0]));
}
else
{
s->tsmlist_in[i].sin_addr.s_addr = inet_addr(s->tsmlist_s[i]);
}
s->debug(1, "Will accept heartbeats from %s = %s", s->tsmlist_s[i], inet_ntoa(s->tsmlist_in[i].sin_addr));
}
}
logintime = time(NULL);
s->debug(0, "Logged on as %s - successful at %s", s->username, asctime(localtime(&logintime)));
s->sequence = 0;
s->lastheartbeat = time(NULL);
s->recenthb = 0;
closesocket(authsocket);
if (he_buffer != NULL)
{
free(he_buffer);
he_buffer = NULL;
}
return 1;
}
/*
** Handle heartbeats, wait for the following events to happen -
**
** 1. A heartbeat packet arrives, in which case we reply correctly
** 2. A timeout occured (ie no heartbeat arrived within 7 minutes)
** 3. The socket was closed.
**
** Returns - 0 - Heartbeat timeout, and subsequent login failed to connect
** 1 - Socket closed on us, presuming the user wants to shut down.
*/
int handle_heartbeats(struct session *s)
{
//INT2 transactiontype;
int transactiontype; // Simon added for user shutdown check
struct transaction t;
while(1)
{
transactiontype = receive_udp_transaction(s, s->listensock, &t, &s->fromaddr);
// Simon added for user shutdown check
if (transactiontype == -1)
return 1; // User shutdown here
if (transactiontype == 0xffff)
{
s->debug(0, "Timed out waiting for heartbeat - logging on\n");
if(!bpa_login(s))
return 0;
}
else if (transactiontype == 0xfffd)
{
s->debug(0, "Badly structured packet received - discarding\n");
}
else if (transactiontype == 0xfffe)
{
s->debug(0,"Socket closed - shutting down\n");
//return 1;
return 0; // Simon, try again
}
else if (transactiontype == T_MSG_STATUS_REQ)
{
char buf[16];
start_transaction(&t, T_MSG_STATUS_RESP, s->sessionid);
add_field_INT2(s, &t, T_PARAM_STATUS_CODE, T_STATUS_TRANSACTION_OK);
s->sequence++;
makecredentials(buf, s, T_MSG_STATUS_RESP, s->sequence);
add_field_data(s, &t, T_PARAM_STATUS_AUTH, buf, 16);
add_field_INT4(s, &t, T_PARAM_SEQNUM, s->sequence);
send_udp_transaction(s, &t);
s->lastheartbeat = time(NULL);
s->debug(1,"Responded to heartbeat at %s", asctime(localtime(&s->lastheartbeat)));
}
else if (transactiontype == T_MSG_RESTART_REQ)
{
s->debug(0, "Restart request - unimplemented");
return 0;
}
else
{
/*
** Melbourne servers were sending spurious UDP packets after authentication
** This works around it.
*/
s->debug(0, "Unknown heartbeat message %d ", transactiontype);
}
}
/*
** Should never get here
*/
return 0;
}
/*
** Logout of the BIDS2 system
**
** Returns - 0 - Could not connect to logout.
** 1 - Logout successful.
*/
int bpa_logout(INT2 reason, struct session *s)
{
int err;
char credentials[16];
time_t logintime;
int authsocket;
struct transaction t;
INT2 transactiontype;
s->localaddr.sin_port = htons(0);
authsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (authsocket)
return 0;
err = bind(authsocket,(struct sockaddr *)&s->localaddr,sizeof(struct sockaddr_in));
if (err)
{
socketerror(s, "Error binding logout auth socket");
closesocket(authsocket);
return 0;
}
err = connect(authsocket, (struct sockaddr *)&s->authhost,sizeof(struct sockaddr_in));
if (err)
{
socketerror(s, "Error connecting logout auth socket");
closesocket(authsocket);
return 0;
}
/*
** start the negotiation
*/
start_transaction(&t,T_MSG_LOGOUT_REQ,s->sessionid);
add_field_string(s,&t,T_PARAM_USERNAME,s->username);
add_field_INT2(s,&t,T_PARAM_CLIENT_VERSION,LOGIN_VERSION * 100);
add_field_string(s,&t,T_PARAM_OS_IDENTITY,s->osname);
add_field_string(s,&t,T_PARAM_OS_VERSION,s->osrelease);
add_field_INT2(s,&t,T_PARAM_REASON_CODE,reason);
send_transaction(s, authsocket,&t);
transactiontype = receive_transaction(s, authsocket, &t);
if (transactiontype != T_MSG_AUTH_RESP)
{
s->critical("logic error");
closesocket(authsocket);
return 0;
}
if(!extract_valueINT2(s,&t,T_PARAM_HASH_METHOD,&s->hashmethod))
{
s->critical("AUTH: no hashmethod");
closesocket(authsocket);
return 0;
}
if(!extract_valuestring(s,&t,T_PARAM_NONCE,s->nonce))
{
s->critical("Auth: no nonce");
closesocket(authsocket);
return 0;
}
if(s->hashmethod == T_AUTH_MD5_HASH)
{
genmd5(s->password,strlen(s->password),s->password);
closesocket(authsocket);
return 0;
}
start_transaction(&t,T_MSG_LOGOUT_AUTH_RESP,s->sessionid);
s->timestamp = time(NULL);
makecredentials(credentials,s,T_MSG_LOGOUT_AUTH_RESP,s->timestamp);
add_field_data(s,&t,T_PARAM_AUTH_CREDENTIALS,credentials,16);
add_field_INT4(s,&t,T_PARAM_TIMESTAMP,s->timestamp);
send_transaction(s,authsocket,&t);
transactiontype = receive_transaction(s,authsocket,&t);
if(transactiontype != T_MSG_LOGOUT_RESP)
{
s->critical("logic error");
closesocket(authsocket);
return 0;
}
extract_valueINT2(s,&t,T_PARAM_STATUS_CODE,&s->retcode);
switch(s->retcode)
{
case T_STATUS_SUCCESS:
case T_STATUS_LOGOUT_SUCCESSFUL_ALREADY_DISCONNECTED:
break;
case T_STATUS_USERNAME_NOT_FOUND:
s->critical("Login failure: username not known");
closesocket(authsocket);
return 0;
case T_STATUS_INCORRECT_PASSWORD:
s->critical("Login failure: incorrect password");
closesocket(authsocket);
return 0;
case T_STATUS_ACCOUNT_DISABLED:
s->critical("Login failure: disabled");
closesocket(authsocket);
return 0;
case T_STATUS_LOGIN_RETRY_LIMIT:
case T_STATUS_USER_DISABLED:
case T_STATUS_FAIL_USERNAME_VALIDATE:
case T_STATUS_FAIL_PASSWORD_VALIDATE:
case T_STATUS_LOGIN_UNKNOWN:
s->critical("Login failure: other error");
closesocket(authsocket);
return 0;
default:
s->critical("known error");
closesocket(authsocket);
return 0;
}
extract_valueINT2(s,&t,T_PARAM_LOGOUT_SERVICE_PORT,&s->logoutport);
extract_valueINT2(s,&t,T_PARAM_STATUS_SERVICE_PORT,&s->statusport);
extract_valuestring(s,&t,T_PARAM_TSMLIST,s->tsmlist);
extract_valuestring(s,&t,T_PARAM_RESPONSE_TEXT,s->resptext);
logintime = time(NULL);
s->debug(0, "Logged out successful at %s", asctime(localtime(&logintime)));
closesocket(authsocket);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -