DatabaseStuff.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. #include "DatabaseStuff.h"
  2. #include "Debug.h"
  3. #include "DatabaseInfo.h"
  4. #include <string.h>
  5. #include <stdio.h>
  6. // Returns true if the server is a http or https url.
  7. bool DatabaseStuff::IsServerAUrl(const char *server)
  8. {
  9. if (strncmp("http://",server,7)==0) {
  10. return true;
  11. }
  12. if (strncmp("https://",server,8)==0) {
  13. return true;
  14. }
  15. return false;
  16. }
  17. void DatabaseStuff::GetLastBannedTime(const char *server,char *output,unsigned long maxLength)
  18. {
  19. DEBUG;
  20. bool isUrl;
  21. mysqli db;
  22. unsigned long length;
  23. mysqli_stmt stmt;
  24. mysqli_bind outputs(1);
  25. isUrl = IsServerAUrl(server);
  26. if (isUrl) {
  27. // server is a url.
  28. throw "Url is not supported for this command.";
  29. } else {
  30. // server is a database.
  31. DEBUG;
  32. OpenDatabase(db,server);
  33. DEBUG;
  34. PrepareGetLastBannedTimeQuery(db,stmt);
  35. DEBUG;
  36. int param_count = stmt.param_count();
  37. DEBUG;
  38. if (param_count != 0) {
  39. throw "Incorrect number of parameters.";
  40. }
  41. DEBUG;
  42. stmt.execute();
  43. DEBUG;
  44. // Build outputs for the loop.
  45. length = 0;
  46. outputs.bind(0,output,maxLength,length);
  47. DEBUG;
  48. if (!stmt.bind_result(outputs)) {
  49. throw "bind results failed.";
  50. }
  51. DEBUG;
  52. if (!stmt.store_result()) {
  53. throw "Error in store_result.";
  54. }
  55. strncpy(output,"No data returned.",maxLength);
  56. DEBUG;
  57. while (stmt.fetch())
  58. {
  59. DEBUG;
  60. }
  61. DEBUG;
  62. if ((length >= 0) && (length < maxLength)) {
  63. output[length] = 0;
  64. }
  65. DEBUG;
  66. stmt.close();
  67. DEBUG;
  68. db.close();
  69. DEBUG;
  70. }
  71. }
  72. // Get the list of IPs to ban from the database.
  73. void DatabaseStuff::GetIPsToBan(Tree<IPAddress> &tree,const char *server)
  74. {
  75. const int BufferSize = 1024;
  76. const int OutputBannedIPSize = 50;
  77. char command[BufferSize+100];
  78. int ch;
  79. IPAddress *ip;
  80. mysqli db;
  81. bool outOfMemory;
  82. mysqli_stmt stmt;
  83. int inputBannedID;
  84. int outputBannedID;
  85. char outputBannedIP[OutputBannedIPSize+20];
  86. unsigned long outputBannedIPLength;
  87. int numberofsaves;
  88. bool isUrl;
  89. FILE *response;
  90. mysqli_bind outputs(2);
  91. DEBUG;
  92. outOfMemory = false;
  93. outputBannedIP[50] = 0;
  94. isUrl = IsServerAUrl(server);
  95. if (isUrl)
  96. {
  97. // server is a url.
  98. if (strlen(server) > BufferSize) {
  99. throw "Server url is longer than 1024 characters.";
  100. }
  101. // This is unsafe if server comes from an untrusted source.
  102. snprintf(command,BufferSize+5,"curl --no-progress-meter \"%s\"",server);
  103. DEBUG;
  104. response = popen(command,"r");
  105. if (response == NULL) {
  106. throw "Error opening the server url.";
  107. }
  108. } else {
  109. // server is a database.
  110. OpenDatabase(db,server);
  111. PrepareGetNewBannedQuery(db,stmt);
  112. int param_count = stmt.param_count();
  113. if (param_count != 1) {
  114. throw "Incorrect number of parameters.";
  115. }
  116. DEBUG;
  117. mysqli_bind inputs(1);
  118. inputBannedID = 0; // In the future, this will be a different number.
  119. inputs.bind(0,inputBannedID);
  120. stmt.bind_param(inputs);
  121. DEBUG;
  122. stmt.execute();
  123. DEBUG;
  124. // Build outputs for the loop.
  125. outputs.bind(0,outputBannedID);
  126. outputs.bind(1,outputBannedIP,OutputBannedIPSize,outputBannedIPLength);
  127. DEBUG;
  128. if (!stmt.bind_result(outputs)) {
  129. throw "bind results failed.";
  130. }
  131. DEBUG;
  132. if (!stmt.store_result()) {
  133. throw "Error in store_result.";
  134. }
  135. }
  136. DEBUG;
  137. numberofsaves = 0;
  138. if (isUrl) {
  139. // Find the first [
  140. while (true) {
  141. ch = fgetc(response);
  142. if (ch == EOF) {
  143. break;
  144. }
  145. if (ch == '[') {
  146. break;
  147. }
  148. }
  149. }
  150. // Loop throught the input.
  151. while (true)
  152. {
  153. // Get one record.
  154. if (isUrl) {
  155. outputBannedID = 0;
  156. outputBannedIPLength = 0;
  157. if (ch == ']') {
  158. while (fgetc(response) != EOF) { };
  159. break;
  160. }
  161. if (ch == EOF) {
  162. break;
  163. }
  164. // Read outputBannedID
  165. while (true) {
  166. ch = fgetc(response);
  167. if ((ch == EOF) || (ch == ',')) {
  168. break;
  169. }
  170. outputBannedID = outputBannedID * 10 + ch - '0';
  171. }
  172. if (ch == EOF) {
  173. break;
  174. }
  175. // Read outputBannedIP.
  176. while (true) {
  177. ch = fgetc(response);
  178. if ((ch == EOF)
  179. || (ch == ',')
  180. || (ch == ']')) {
  181. break;
  182. }
  183. if (outputBannedIPLength == OutputBannedIPSize) {
  184. while (fgetc(response) != EOF) { };
  185. pclose(response);
  186. throw "The IP address is too long.";
  187. }
  188. if ((ch != '"') && (ch != 39)) {
  189. outputBannedIP[outputBannedIPLength++] = (char) ch;
  190. }
  191. }
  192. outputBannedIP[outputBannedIPLength] = 0;
  193. } else {
  194. // Read one record from the database.
  195. if (!stmt.fetch())
  196. {
  197. break;
  198. }
  199. }
  200. // Save the record.
  201. DEBUG;
  202. if (outOfMemory) {
  203. continue;
  204. }
  205. if (!IPAddress::IsIP(outputBannedIP)) {
  206. continue; // Is this an IP address? You can't trust the database because it might have been hacked.
  207. }
  208. ip = new IPAddress();
  209. if (ip == nullptr) {
  210. outOfMemory = true;
  211. continue;
  212. }
  213. *ip = outputBannedIP;
  214. if (ip->IP == nullptr) {
  215. delete ip;
  216. ip = nullptr;
  217. outOfMemory = true;
  218. continue;
  219. }
  220. if (!tree.Add(&ip,IPAddress::Compare)) {
  221. outOfMemory = true;
  222. if (ip != nullptr) {
  223. delete ip;
  224. ip = nullptr;
  225. }
  226. continue;
  227. }
  228. DEBUG;
  229. }
  230. if (isUrl) {
  231. pclose(response);
  232. } else {
  233. stmt.close();
  234. db.close();
  235. }
  236. DEBUG;
  237. if (outOfMemory) {
  238. DEBUG;
  239. throw "Out of memory reading the list of IPs from the database.";
  240. }
  241. DEBUG;
  242. }
  243. // Opens a database connection.
  244. void DatabaseStuff::OpenDatabase(mysqli &db,const char *server)
  245. {
  246. char username[50];
  247. char password[50];
  248. char database[50];
  249. DEBUG;
  250. rot13(DatabaseInfo::UserName(),username);
  251. rot13(DatabaseInfo::Password(),password);
  252. rot13(DatabaseInfo::Database(),database);
  253. DEBUG;
  254. db.real_connect(server,username,password,database,3306);
  255. DEBUG;
  256. return;
  257. }
  258. void DatabaseStuff::rot13(const char *original,char *output)
  259. {
  260. // A simple cipher that's
  261. // good enough to beat someone with a hex editor.
  262. // Not exactly rot13.
  263. // Assumes that output is a buffer big enough to hold the data.
  264. // output is probably a char array on the stack.
  265. const char *input;
  266. char *loop;
  267. char ch;
  268. input = original;
  269. loop = output;
  270. while (true) {
  271. ch = *(input++);
  272. if (ch == 0) {
  273. break;
  274. }
  275. if ((ch >='A') && (ch <= 'Z')) {
  276. ch = ('A'+'Z') - ch;
  277. }
  278. if ((ch >='a') && (ch <= 'z')) {
  279. ch = ('a'+'z') - ch;
  280. }
  281. if ((ch >='0') && (ch <= '9')) {
  282. ch = ('0'+'9')-ch;
  283. }
  284. *(loop++) = ch;
  285. }
  286. *loop = 0;
  287. return;
  288. }
  289. // Prepares the query to get new banned IPs.
  290. void DatabaseStuff::PrepareGetNewBannedQuery(mysqli &db,mysqli_stmt &stmt)
  291. {
  292. char query[100];
  293. rot13("xzoo yzmmvw.hk_tvg_mvd_yzmmvw(?)",query); // "call banned.sp_get_new_banned(?)";
  294. db.prepare(query,strlen(query),stmt);
  295. return;
  296. }
  297. void DatabaseStuff::PrepareGetLastBannedTimeQuery(mysqli &db,mysqli_stmt &stmt)
  298. {
  299. char query[100];
  300. DEBUG;
  301. rot13("xzoo yzmmvw.hk_tvg_ozhg_yzmmvw_grnv",query); // call banned.sp_get_last_banned_time
  302. DEBUG;
  303. db.prepare(query,strlen(query),stmt);
  304. DEBUG;
  305. return;
  306. }