1#include "betalk.h" 2#include "authentication.h" 3#include "sysdepdefs.h" 4#include "netdb.h" 5 6#include "ctype.h" 7#include "signal.h" 8#include "stdlib.h" 9 10bt_inPacket *btRPCSimpleCall(unsigned int serverIP, int port, bt_outPacket *outPacket); 11int btRPCConnect(unsigned int serverIP, int port); 12bool btRPCSend(int session, bt_outPacket *outPacket); 13bool btRPCCheckSignature(int session); 14bt_outPacket *btRPCPutHeader(unsigned char command, unsigned char argc, int32 length); 15void btRPCPutArg(bt_outPacket *packet, unsigned int type, void *data, int length); 16 17 18int btRPCConnect(unsigned int serverIP, int port) 19{ 20 struct sockaddr_in serverAddr; 21 int session; 22 23 // Initialize the server address structure. 24 memset(&serverAddr, 0, sizeof(serverAddr)); 25 serverAddr.sin_port = htons(port); 26 serverAddr.sin_family = AF_INET; 27 serverAddr.sin_addr.s_addr = htonl(serverIP); 28 29 // Create a new socket to receive incoming requests. 30 session = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 31 if (session == INVALID_SOCKET) 32 return INVALID_SOCKET; 33 34 // Bind that socket to the address constructed above. 35 if (connect(session, (struct sockaddr *) &serverAddr, sizeof(serverAddr))) 36 return INVALID_SOCKET; 37 38 return session; 39} 40 41bool btRPCSend(int session, bt_outPacket *outPacket) 42{ 43 // The XID will be 0. 44 btRPCPutInt32(outPacket, 0); 45 btRPCPutChar(outPacket, BT_CMD_TERMINATOR); 46 47 if (btSendMsg(session, outPacket->buffer, outPacket->length, 0) == -1) 48 return false; 49 50 return true; 51} 52 53bool btRPCCheckSignature(int session) 54{ 55 char signature[20]; 56 unsigned int sigLen; 57 58 sigLen = strlen(BT_RPC_SIGNATURE); 59 memset(signature, 0, sigLen); 60 if (btRecvMsg(session, signature, sigLen, 0) == -1) 61 return false; 62 63 // Check the signature's validity. 64 signature[sigLen] = 0; 65 return (strcmp(signature, BT_RPC_SIGNATURE) == 0); 66} 67 68// btRPCSimpleCall() 69// 70bt_inPacket *btRPCSimpleCall(unsigned int serverIP, int port, bt_outPacket *outPacket) 71{ 72 struct timeval timeout; 73 bt_inPacket *inPacket; 74 fd_set sockSet; 75 char *buffer; 76 int session; 77 int32 xid, length; 78 79 // Establish a connection with the requested server, on the requested port. 80 // If we can't connect, abort and return a NULL packet. 81 inPacket = NULL; 82 session = btRPCConnect(serverIP, port); 83 if (session == INVALID_SOCKET) 84 return NULL; 85 86 // If we connected, send the requested RPC packet. If the packet cannot be 87 // sent, the connection has dropped and we'll abort the call. 88 if (!btRPCSend(session, outPacket)) 89 { 90 closesocket(session); 91 return NULL; 92 } 93 94 // Set a reasonable timeout period. Select() is used in leiu of alarm() because 95 // select() also aborts on error, alarm() effects all threads in a process. 96 FD_ZERO(&sockSet); 97 timeout.tv_sec = 8; 98 timeout.tv_usec = 0; 99 100 // Block in select() waiting for activity. This will block until data is available 101 // or until a socket error is pending. 102 FD_SET(session, &sockSet); 103 select(session + 1, &sockSet, NULL, NULL, &timeout); 104 105 // If our socket has data pending, then read the incoming RPC response packet. 106 // This should consist of a valid RPC signature, a tranaction ID (xid), the length 107 // of the variable data, and the data itself. 108 if (FD_ISSET(session, &sockSet)) 109 if (btRPCCheckSignature(session)) 110 { 111 if (btRecvMsg(session, &xid, sizeof(int32), 0) == -1 || 112 btRecvMsg(session, &length, sizeof(int32), 0) == -1) 113 goto abortCall; 114 115 // Now allocate a buffer of the appropriate length. If one cannot be 116 // allocated, we won't be able to store incoming information and the call 117 // must be aborted. 118 xid = B_LENDIAN_TO_HOST_INT32(xid); 119 length = B_LENDIAN_TO_HOST_INT32(length); 120 if (length > 0 && length < BT_RPC_MAX_PACKET_SIZE) 121 { 122 buffer = (char *) malloc(length + 1); 123 if (buffer) 124 { 125 // Read the remaining packet contents. The btRecvMsg() function takes 126 // care of restarting the recv() when signal interrupts occur. It 127 // will always return -1 on error, even upon orderly shutdown of the peer. 128 if (btRecvMsg(session, buffer, length, 0) == -1) 129 { 130 free(buffer); 131 goto abortCall; 132 } 133 134 // Terminate the buffer. 135 buffer[length] = 0; 136 137 // Allocate a new incoming packet and set its buffer and length. 138 inPacket = (bt_inPacket *) malloc(sizeof(bt_inPacket)); 139 if (inPacket) 140 { 141 inPacket->buffer = buffer; 142 inPacket->length = length; 143 inPacket->offset = 0; 144 } 145 else 146 free(buffer); 147 } 148 } 149 } 150 151 // Execution can naturally lead here or we can jump here from a failed attempt to 152 // send or receive an RPC packet. The socket is closed and the current incoming 153 // packet returned, which will be NULL upon failure. 154abortCall: 155 shutdown(session, 2); 156 close(session); 157 return inPacket; 158} 159 160bt_outPacket *btRPCPutHeader(unsigned char command, unsigned char argc, int32 length) 161{ 162 bt_outPacket *packet; 163 164 packet = (bt_outPacket *) malloc(sizeof(bt_outPacket)); 165 if (!packet) 166 return NULL; 167 168 packet->size = BT_RPC_MIN_PACKET_SIZE; 169 packet->buffer = (char *) malloc(packet->size); 170 packet->length = 0; 171 172 if (!packet->buffer) 173 { 174 free(packet); 175 return NULL; 176 } 177 178 strcpy(packet->buffer, BT_RPC_SIGNATURE); 179 packet->length += strlen(BT_RPC_SIGNATURE); 180 181// btRPCPutChar(packet, BT_RPC_VERSION_HI); 182// btRPCPutChar(packet, BT_RPC_VERSION_LO); 183 btRPCPutInt32(packet, 7 + (8 * argc) + length); 184 btRPCPutChar(packet, command); 185 btRPCPutChar(packet, argc); 186 187 return packet; 188} 189 190void btRPCPutArg(bt_outPacket *packet, unsigned int type, void *data, int length) 191{ 192 btRPCPutInt32(packet, type); 193 btRPCPutInt32(packet, length); 194 btRPCPutBinary(packet, data, length); 195} 196 197bool authenticateUser(char *user, char *password) 198{ 199 extern unsigned int authServerIP; 200 bt_outPacket *outPacket; 201 bt_inPacket *inPacket; 202 bool authenticated = false; 203 int error; 204 205 outPacket = btRPCPutHeader(BT_CMD_AUTH, 2, strlen(user) + BT_AUTH_TOKEN_LENGTH); 206 if (outPacket) 207 { 208 btRPCPutArg(outPacket, B_STRING_TYPE, user, strlen(user)); 209 btRPCPutArg(outPacket, B_STRING_TYPE, password, BT_AUTH_TOKEN_LENGTH); 210 inPacket = btRPCSimpleCall(authServerIP, BT_BESURE_PORT, outPacket); 211 if (inPacket) 212 { 213 error = btRPCGetInt32(inPacket); 214 if (error == B_OK) 215 authenticated = true; 216 217 free(inPacket->buffer); 218 free(inPacket); 219 } 220 221 free(outPacket->buffer); 222 free(outPacket); 223 } 224 225 return authenticated; 226} 227 228void getUserGroups(char *user, char **groups) 229{ 230 extern unsigned int authServerIP; 231 bt_outPacket *outPacket; 232 bt_inPacket *inPacket; 233 int i, error; 234 235 outPacket = btRPCPutHeader(BT_CMD_WHICHGROUPS, 1, strlen(user)); 236 if (outPacket) 237 { 238 btRPCPutArg(outPacket, B_STRING_TYPE, user, strlen(user)); 239 inPacket = btRPCSimpleCall(authServerIP, BT_BESURE_PORT, outPacket); 240 if (inPacket) 241 { 242 i = 0; 243 error = btRPCGetInt32(inPacket); 244 while (error == B_OK) 245 { 246 groups[i++] = btRPCGetNewString(inPacket); 247 error = btRPCGetInt32(inPacket); 248 } 249 250 free(inPacket->buffer); 251 free(inPacket); 252 } 253 254 free(outPacket->buffer); 255 free(outPacket); 256 } 257} 258