Advertisement
Guest User

Untitled

a guest
Mar 29th, 2017
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.49 KB | None | 0 0
  1. /*
  2. * Login server for WildCard
  3. * Alpha Version 0.0.1
  4. * Written by Alpha-V
  5. */
  6.  
  7. // Standard includes
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <errno.h>
  13. #include <time.h>
  14. // Networking specific includes
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <netdb.h>
  18. #include <arpa/inet.h>
  19. #include <netinet/in.h>
  20. #include <sys/wait.h>
  21. #include <signal.h>
  22. // MySQL
  23. #include <mysql.h>
  24. // Multithreading
  25. #include <pthread.h>
  26. #include <semaphore.h>
  27. // Crypto
  28. #include <openssl/sha.h>
  29. #include <openssl/rand.h>
  30. #include <openssl/md5.h>
  31. // Parameters
  32. #define CONNECTIONBACKLOG 5
  33. #define MAXUSERS 5
  34.  
  35. // Function Prototpyes
  36. void sigchld_handler(int s);
  37. void *get_in_addr(struct sockaddr *sa);
  38. int parse(char *source, char **username, char **password);
  39. int LoginUser(MYSQL *connection, MYSQL_STMT *stmt_connection, char *username, char *password, /* OUT */char **sessionID);
  40. void MySQLQueryFail_Handler(MYSQL *connection);
  41.  
  42. // Just here for now
  43. int tokencounter;
  44.  
  45. int main(int argc, char *argv[])
  46. {
  47. // Check if the porgram was run with the correct command line arguements
  48. if(argc != 2)
  49. {
  50. fprintf(stderr, "Usage: %s [port]\n", argv[0]);
  51. return -1;
  52. }
  53.  
  54. fprintf(stdout, "Wildcard Server Starting Up!\n");
  55. fprintf(stdout, "Wildcard Server Version: %s running on port %s\nMySQL Version: %s\n", "0.0.1", argv[1], mysql_get_client_info());
  56.  
  57. tokencounter = 0;
  58.  
  59. struct addrinfo hints, *res;
  60. struct sigaction sa;
  61. struct sockaddr_storage cli_addr;
  62. socklen_t addr_len;
  63.  
  64. char s[INET6_ADDRSTRLEN];
  65.  
  66. int sock_fd, cli_fd;
  67.  
  68. memset(&hints, 0, sizeof(hints));
  69. hints.ai_family = AF_UNSPEC;
  70. hints.ai_socktype = SOCK_STREAM;
  71. hints.ai_flags = AI_PASSIVE;
  72.  
  73. // The MySQL *object*
  74. MYSQL *databasecon;
  75. MYSQL_STMT *stmt_databasecon;
  76.  
  77. /*
  78. * MySQL Login data!
  79. */
  80.  
  81. char *mysqluser = "root";
  82. char *mysqlpasswd = "mysql";
  83.  
  84. // Attempt to initialize the the MySQL object
  85. if((databasecon = mysql_init(NULL)) == NULL)
  86. {
  87. fprintf(stderr, "Error initializing database connection: %s\n", mysql_error(databasecon));
  88. return -20;
  89. }
  90.  
  91. // Connect to the MySQL database
  92. if(mysql_real_connect(databasecon, "localhost", mysqluser, mysqlpasswd, "Accounts", 0, NULL, 0) == NULL)
  93. {
  94. fprintf(stderr, "Error connecting to database: %s\n", mysql_error(databasecon));
  95. mysql_close(databasecon);
  96. return -21;
  97. }
  98.  
  99. if((stmt_databasecon = mysql_stmt_init(databasecon)) == NULL)
  100. {
  101. fprintf(stderr, "Error creating stmt object: %s\n", mysql_error(databasecon));
  102. mysql_close(databasecon);
  103. return -22;
  104. }
  105. if(getaddrinfo(NULL, argv[1], &hints, &res) != 0)
  106. {
  107. perror("Error getting server address info");
  108. return -10;
  109. }
  110. else
  111. {
  112. if((sock_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1)
  113. {
  114. perror("Error creating socket");
  115. return -11;
  116. }
  117. else
  118. {
  119. if(bind(sock_fd, res->ai_addr, res->ai_addrlen) == -1)
  120. {
  121. perror("Error binding socket");
  122. close(sock_fd);
  123. return -12;
  124. }
  125. else
  126. {
  127. if(listen(sock_fd, CONNECTIONBACKLOG) == -1)
  128. {
  129. perror("Error starting listener");
  130. close(sock_fd);
  131. return -13;
  132. }
  133. else
  134. {
  135. sa.sa_handler = sigchld_handler;
  136. sigemptyset(&sa.sa_mask);
  137. sa.sa_flags = SA_RESTART;
  138. if(sigaction(SIGCHLD, &sa, NULL) == -1)
  139. {
  140. perror("Error working with sigaction");
  141. return -14;
  142. }
  143. while(1)
  144. {
  145. addr_len = sizeof(cli_addr);
  146. cli_fd = accept(sock_fd, (struct sockaddr *)&cli_addr, &addr_len);
  147.  
  148. if(cli_fd == -1)
  149. {
  150. perror("Error accepting connection");
  151. }
  152.  
  153. inet_ntop(cli_addr.ss_family, get_in_addr((struct sockaddr *)&cli_addr), s, sizeof(s));
  154. fprintf(stdout, "Recieved connection from: %s\n", s);
  155.  
  156. if(!fork())
  157. {
  158. // TODO evaluate if this is indeed a safe/the best way to do it!
  159. while(1)
  160. {
  161. int buffsize = sizeof(char) * 1024;
  162. char *recvbuff = malloc(buffsize);
  163. int bytesRecieved = 0;
  164.  
  165. if((bytesRecieved = recv(cli_fd, recvbuff, buffsize, 0)) == -1)
  166. {
  167. perror("Error recieving data");
  168. // Close the socket; The client shall have to open a new one for a new request
  169. break;
  170. }
  171. else
  172. {
  173. // Copy it to a \0 terminated string
  174. char *buff = malloc((bytesRecieved + 1) * sizeof(char));
  175.  
  176. // Copy all of the read characters
  177. for(int i = 0; i < bytesRecieved; i++)
  178. {
  179. buff[i] = recvbuff[i];
  180. }
  181.  
  182. // Null terminate the string (to avoid buffer overflow)
  183. buff[bytesRecieved] = '\0';
  184.  
  185. //printf("Recieved (%i bytes): %s\n", bytesRecieved, buff);
  186. char *username;
  187. char *password;
  188. char *token;
  189.  
  190. if(parse(buff, &username, &password))
  191. {
  192. if(LoginUser(databasecon, stmt_databasecon, username, password, &token))
  193. {
  194. // The user successfully logged in! TODO: return token too
  195. char *returnmsg = malloc(strlen("OKE_") + strlen(token) + 1);
  196. sprintf(returnmsg, "OKE_%s", token);
  197. //char *returnmsg = "OKE_123\0";
  198. if(send(cli_fd, returnmsg, strlen(returnmsg), 0) == -1)
  199. {
  200. perror("Error sending login confimration");
  201. }
  202.  
  203. // If it successfully sent off the message, exit the loop
  204. break;
  205. }
  206. else
  207. {
  208. // The users credentials whre invalid
  209. if(send(cli_fd, "NOK", sizeof("NOK"), 0) == -1)
  210. {
  211. perror("Error sending login error");
  212. }
  213.  
  214. // If it successfully sent off the message, exit the loop
  215. break;
  216. }
  217. }
  218. else
  219. {
  220. // The parse failed so return NOK
  221. if(send(cli_fd, "NOK", sizeof("NOK"), 0) == -1)
  222. {
  223. perror("Error sending parse error");
  224. }
  225.  
  226. // If it successfully sent off the message, exit the loop
  227. break;
  228. }
  229. }
  230. }
  231.  
  232. // Close the connection to the client
  233. close(cli_fd);
  234. }
  235. }
  236. }
  237. }
  238. }
  239. }
  240. }
  241.  
  242. void sigchld_handler(int s)
  243. {
  244. int saved_errno = errno;
  245.  
  246. while(waitpid(-1, NULL, WNOHANG) > 0);
  247.  
  248. errno = saved_errno;
  249. }
  250.  
  251. void *get_in_addr(struct sockaddr *sa)
  252. {
  253. if(sa->sa_family == AF_INET)
  254. {
  255. return &(((struct sockaddr_in *)sa)->sin_addr);
  256. }
  257. else
  258. {
  259. return &(((struct sockaddr_in6 *)sa)->sin6_addr);
  260. }
  261. }
  262.  
  263. int parse(char *source, char **username, char **password)
  264. {
  265. // Init a variable to 0 to keep track of where in the parse we are
  266. int stage = 0;
  267.  
  268. // Make a buff to store part of the parse
  269. char buff[1024];
  270. // To avoid overflow
  271. int buffused = 0;
  272.  
  273. for(int i = 0, n = strlen(source); i < n; i++)
  274. {
  275. // Should it switch stage? AKA did this part of the parse finish?
  276. if(source[i] == '\n')
  277. {
  278. if(stage == 0)
  279. {
  280. // Allocate the right ammount of memory to username
  281. *username = malloc((buffused + 1) * sizeof(char));
  282.  
  283. // Copy the buffer to the username (cant use strcpy as buff isn't null terminated)
  284. for(int i = 0; i < buffused; i++)
  285. {
  286. (*username)[i] = buff[i];
  287. }
  288.  
  289. // Null-terminate the string
  290. (*username)[buffused] = '\0';
  291.  
  292. }
  293. else if(stage == 1)
  294. {
  295. // Allocate the right ammount of memory to username
  296. *password = malloc((buffused + 1) * sizeof(char));
  297.  
  298. // Copy the buffer to the password (cant use strcpy as buff isn't null terminated)
  299. for(int i = 0; i < buffused; i++)
  300. {
  301. (*password)[i] = buff[i];
  302. }
  303.  
  304. // Null-terminate the string
  305. (*password)[buffused] = '\0';
  306. }
  307. else
  308. {
  309. // Something didn't go quite right!
  310. stage++;
  311. printf("Error while parsing!!!\n");
  312. break;
  313. }
  314.  
  315. // Reset the buffer that has been used and increase the stage #
  316. buffused = 0;
  317. stage++;
  318. }
  319. else
  320. {
  321. // Copy the current character to the buffer and increment the buffer size
  322. buff[buffused] = source[i];
  323. buffused++;
  324. }
  325. }
  326.  
  327. // Was the parse valid? (where there too many or too little stages? If so it failed)
  328. if(stage != 1)
  329. {
  330. return 0;
  331. }
  332. // Does it still need to process the password?
  333. else if(stage == 1)
  334. {
  335. // Allocate the right ammount of memory to username
  336. *password = malloc((buffused + 1) * sizeof(char));
  337.  
  338. // Copy the buffer to the password (cant use strcpy as buff isn't null terminated)
  339. for(int i = 0; i < buffused; i++)
  340. {
  341. (*password)[i] = buff[i];
  342. }
  343.  
  344. // Null-terminate the string
  345. (*password)[buffused] = '\0';
  346. }
  347.  
  348. // Otherwise assume everything went fine
  349. return 1;
  350. }
  351.  
  352. void MySQLQueryFail_Handler(MYSQL *connection)
  353. {
  354. fprintf(stderr, "Error while executing query: %s\n", mysql_error(connection));
  355. mysql_close(connection);
  356. exit(-23);
  357. }
  358.  
  359. int LoginUser(MYSQL *connection, MYSQL_STMT *stmt_connection, char *username, char *password, /* OUT */char **sessionID)
  360. {
  361. /* TODO fix this
  362. // TODO make this a prepared statement!!! And use the the below escape real etc
  363. // mysql_real_escape_string(username);
  364.  
  365. char *stmtquery = malloc(strlen("SELECT * FROM PlayerAccounts WHERE UserName = \"?\"") * sizeof(char) + strlen(username) * sizeof(char) + sizeof(char));
  366. sprintf(stmtquery, "SELECT * FROM PlayerAccounts WHERE UserName = \"?\"");
  367.  
  368. unsigned long length = strlen(stmtquery);
  369.  
  370. if(mysql_stmt_prepare(stmt_connection, stmtquery, length) != 0)
  371. {
  372. fprintf(stderr, "Error preparing prepared statement: %s\n", mysql_stmt_error(stmt_connection));
  373. }
  374.  
  375. if(mysql_stmt_param_count(stmt_connection) != 1)
  376. {
  377. fprintf(stderr, "Params: %lu\n", mysql_stmt_param_count(stmt_connection));
  378. // Too many or too little parameters setup!
  379. //fprintf(stderr, "Error preparing prepared statement: Invalid ammount of ?'s in statement!\n");
  380. }
  381.  
  382. // Setup the bind params
  383. MYSQL_BIND queryVars[1];
  384.  
  385. memset(&queryVars, 0, sizeof(queryVars));
  386.  
  387. unsigned long strlength = strlen(username);
  388.  
  389. queryVars[1].buffer_type = MYSQL_TYPE_STRING;
  390. queryVars[1].buffer = username;
  391. queryVars[1].buffer_length = strlen(username);
  392. queryVars[1].is_null = 0;
  393. queryVars[1].length = &strlength;
  394. exit(-100);
  395. */
  396.  
  397. // TODO replace this!!! Buffer overflow!!!
  398.  
  399. char *tokenbuffer = malloc(16384);
  400.  
  401. struct tm *tm;
  402. time_t t;
  403. char str_time[1024];
  404.  
  405. t = time(NULL);
  406. tm = localtime(&t);
  407.  
  408. strftime(str_time, sizeof(str_time), "%H %M %S", tm);
  409.  
  410. tokencounter++;
  411.  
  412. sprintf(tokenbuffer, "%s%s%i%s%s%s", "@)^NKVDSLfdsf@%$FS", username, tokencounter, ",.,.kjsFDASgfn6349hj", str_time, "F**DSGSG(YSY#*@(&R@&#$#");
  413.  
  414. printf("Created token!");
  415.  
  416. unsigned char digest[16];
  417. const char* string = tokenbuffer;
  418. MD5_CTX context;
  419. MD5_Init(&context);
  420. MD5_Update(&context, string, strlen(string));
  421. MD5_Final(digest, &context);
  422. char md5string[33];
  423. for(int i = 0; i < 16; ++i)
  424. sprintf(&md5string[i*2], "%02x", (unsigned int)digest[i]);
  425.  
  426. // TODO replace the * with only the required stuff
  427. // Create a variable to store the query and format the query
  428. char *query = malloc(strlen("SELECT * FROM PlayerAccounts WHERE UserName = \"\"`") * sizeof(char) + strlen(username) * sizeof(char) + sizeof(char));
  429. sprintf(query, "SELECT * FROM PlayerAccounts WHERE UserName = \"%s\"", username);
  430.  
  431. // Look the user up in the database
  432. if(mysql_query(connection, query))
  433. {
  434. MySQLQueryFail_Handler(connection);
  435. }
  436.  
  437. MYSQL_RES *entries = mysql_store_result(connection);
  438.  
  439. if(entries == NULL)
  440. {
  441. MySQLQueryFail_Handler(connection);
  442. }
  443.  
  444. int numFields = mysql_num_fields(entries);
  445. MYSQL_ROW entry;
  446.  
  447. while((entry = mysql_fetch_row(entries)))
  448. {
  449. // Are the passwords different sizes?
  450. if(strlen(entry[2]) < strlen(password))
  451. {
  452. // Then it can't be the correct password.
  453. return 0;
  454. }
  455.  
  456. // entry[2] is the password row. TODO make this encrypted/hashed
  457. if(strncmp(entry[2], password, strlen(entry[2])) == 0)
  458. {
  459. // The user login was correct.
  460.  
  461. // Insert the random token
  462. char *query2 = malloc(strlen("UPDATE PlayerAccounts SET SessionID=\"\" WHERE UserName = \"\"") * sizeof(char) + strlen(username) * sizeof(char) + strlen(username) * sizeof(char) + strlen(md5string) * sizeof(char) + sizeof(char));
  463. sprintf(query2, "UPDATE PlayerAccounts SET SessionID=\"%s\" WHERE UserName = \"%s\"", md5string, username);
  464.  
  465. // Attempt to insert
  466. // Look the user up in the database
  467. if(mysql_query(connection, query2))
  468. {
  469. MySQLQueryFail_Handler(connection);
  470. }
  471.  
  472. *sessionID = md5string;
  473.  
  474. return 1;
  475. }
  476. else
  477. {
  478. // The users password was incorrect.
  479. // But if there are more records for this user? Continue through those.
  480. }
  481. }
  482.  
  483. // The username was not found!
  484. return 0;
  485.  
  486. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement