PageRenderTime 60ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/wired-1.1/wired/wired/commands.c

https://bitbucket.org/balrog/zanka-full
C | 2352 lines | 1441 code | 525 blank | 386 comment | 326 complexity | a1168565e2e1b882be22384d4ce4083c MD5 | raw file
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2003-2004 Axel Andersson
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  19. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  23. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  24. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. * POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <sys/types.h>
  28. #include <sys/time.h>
  29. #include <limits.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <unistd.h>
  34. #include <syslog.h>
  35. #include <errno.h>
  36. #include <ctype.h>
  37. #include <libgen.h>
  38. #include <pthread.h>
  39. #include <openssl/err.h>
  40. #include "config.h"
  41. #include "accounts.h"
  42. #include "banlist.h"
  43. #include "commands.h"
  44. #include "files.h"
  45. #include "hotline.h"
  46. #include "main.h"
  47. #include "news.h"
  48. #include "server.h"
  49. #include "settings.h"
  50. #include "utility.h"
  51. struct wd_commands wd_commands[] = {
  52. { "BAN",
  53. WD_CLIENT_STATE_LOGGED_IN, true, true,
  54. WD_PRIV_BAN_USERS, wd_cmd_ban },
  55. { "BROADCAST",
  56. WD_CLIENT_STATE_LOGGED_IN, true, true,
  57. WD_PRIV_BROADCAST, wd_cmd_broadcast },
  58. { "CLEARNEWS",
  59. WD_CLIENT_STATE_LOGGED_IN, false, true,
  60. WD_PRIV_CLEAR_NEWS, wd_cmd_clearnews },
  61. { "CLIENT",
  62. WD_CLIENT_STATE_SAID_HELLO, true, true,
  63. WD_PRIV_NONE, wd_cmd_client },
  64. { "CREATEGROUP",
  65. WD_CLIENT_STATE_LOGGED_IN, true, true,
  66. WD_PRIV_CREATE_ACCOUNTS, wd_cmd_creategroup },
  67. { "CREATEUSER",
  68. WD_CLIENT_STATE_LOGGED_IN, true, true,
  69. WD_PRIV_CREATE_ACCOUNTS, wd_cmd_createuser },
  70. { "DECLINE",
  71. WD_CLIENT_STATE_LOGGED_IN, true, true,
  72. WD_PRIV_NONE, wd_cmd_decline },
  73. { "DELETE",
  74. WD_CLIENT_STATE_LOGGED_IN, true, true,
  75. WD_PRIV_DELETE_FILES, wd_cmd_delete },
  76. { "DELETEGROUP",
  77. WD_CLIENT_STATE_LOGGED_IN, true, true,
  78. WD_PRIV_DELETE_ACCOUNTS, wd_cmd_deletegroup },
  79. { "DELETEUSER",
  80. WD_CLIENT_STATE_LOGGED_IN, true, true,
  81. WD_PRIV_DELETE_ACCOUNTS, wd_cmd_deleteuser },
  82. { "EDITGROUP",
  83. WD_CLIENT_STATE_LOGGED_IN, true, true,
  84. WD_PRIV_EDIT_ACCOUNTS, wd_cmd_editgroup },
  85. { "EDITUSER",
  86. WD_CLIENT_STATE_LOGGED_IN, true, true,
  87. WD_PRIV_EDIT_ACCOUNTS, wd_cmd_edituser },
  88. { "FOLDER",
  89. WD_CLIENT_STATE_LOGGED_IN, true, true,
  90. WD_PRIV_NONE, wd_cmd_folder },
  91. { "GET",
  92. WD_CLIENT_STATE_LOGGED_IN, true, true,
  93. WD_PRIV_DOWNLOAD, wd_cmd_get },
  94. { "GROUPS",
  95. WD_CLIENT_STATE_LOGGED_IN, false, true,
  96. WD_PRIV_EDIT_ACCOUNTS, wd_cmd_groups },
  97. { "HELLO",
  98. WD_CLIENT_STATE_CONNECTED, false, true,
  99. WD_PRIV_NONE, wd_cmd_hello },
  100. { "ICON",
  101. WD_CLIENT_STATE_SAID_HELLO, true, true,
  102. WD_PRIV_NONE, wd_cmd_icon },
  103. { "INFO",
  104. WD_CLIENT_STATE_LOGGED_IN, true, true,
  105. WD_PRIV_GET_USER_INFO, wd_cmd_info },
  106. { "INVITE",
  107. WD_CLIENT_STATE_LOGGED_IN, true, true,
  108. WD_PRIV_NONE, wd_cmd_invite },
  109. { "JOIN",
  110. WD_CLIENT_STATE_LOGGED_IN, true, true,
  111. WD_PRIV_NONE, wd_cmd_join },
  112. { "KICK",
  113. WD_CLIENT_STATE_LOGGED_IN, true, true,
  114. WD_PRIV_KICK_USERS, wd_cmd_kick },
  115. { "LEAVE",
  116. WD_CLIENT_STATE_LOGGED_IN, true, true,
  117. WD_PRIV_NONE, wd_cmd_leave },
  118. { "LIST",
  119. WD_CLIENT_STATE_LOGGED_IN, true, true,
  120. WD_PRIV_NONE, wd_cmd_list },
  121. { "ME",
  122. WD_CLIENT_STATE_LOGGED_IN, true, true,
  123. WD_PRIV_NONE, wd_cmd_me },
  124. { "MOVE",
  125. WD_CLIENT_STATE_LOGGED_IN, true, true,
  126. WD_PRIV_MOVE_FILES, wd_cmd_move },
  127. { "MSG",
  128. WD_CLIENT_STATE_LOGGED_IN, true, true,
  129. WD_PRIV_NONE, wd_cmd_msg },
  130. { "NEWS",
  131. WD_CLIENT_STATE_LOGGED_IN, false, true,
  132. WD_PRIV_NONE, wd_cmd_news },
  133. { "NICK",
  134. WD_CLIENT_STATE_SAID_HELLO, true, true,
  135. WD_PRIV_NONE, wd_cmd_nick },
  136. { "PASS",
  137. WD_CLIENT_STATE_GAVE_USER, false, true,
  138. WD_PRIV_NONE, wd_cmd_pass },
  139. { "PING",
  140. WD_CLIENT_STATE_CONNECTED, false, false,
  141. WD_PRIV_NONE, wd_cmd_ping },
  142. { "POST",
  143. WD_CLIENT_STATE_LOGGED_IN, true, true,
  144. WD_PRIV_POST_NEWS, wd_cmd_post },
  145. { "PRIVCHAT",
  146. WD_CLIENT_STATE_LOGGED_IN, false, true,
  147. WD_PRIV_NONE, wd_cmd_privchat },
  148. { "PRIVILEGES",
  149. WD_CLIENT_STATE_LOGGED_IN, false, true,
  150. WD_PRIV_NONE, wd_cmd_privileges },
  151. { "PUT",
  152. WD_CLIENT_STATE_LOGGED_IN, true, true,
  153. WD_PRIV_NONE, wd_cmd_put },
  154. { "READGROUP",
  155. WD_CLIENT_STATE_LOGGED_IN, true, true,
  156. WD_PRIV_EDIT_ACCOUNTS, wd_cmd_readgroup },
  157. { "READUSER",
  158. WD_CLIENT_STATE_LOGGED_IN, true, true,
  159. WD_PRIV_EDIT_ACCOUNTS, wd_cmd_readuser },
  160. { "SAY",
  161. WD_CLIENT_STATE_LOGGED_IN, true, true,
  162. WD_PRIV_NONE, wd_cmd_say },
  163. { "SEARCH",
  164. WD_CLIENT_STATE_LOGGED_IN, true, true,
  165. WD_PRIV_NONE, wd_cmd_search },
  166. { "STAT",
  167. WD_CLIENT_STATE_LOGGED_IN, true, true,
  168. WD_PRIV_NONE, wd_cmd_stat },
  169. { "USER",
  170. WD_CLIENT_STATE_SAID_HELLO, true, true,
  171. WD_PRIV_NONE, wd_cmd_user },
  172. { "USERS",
  173. WD_CLIENT_STATE_LOGGED_IN, false, true,
  174. WD_PRIV_EDIT_ACCOUNTS, wd_cmd_users },
  175. { "WHO",
  176. WD_CLIENT_STATE_LOGGED_IN, false, true,
  177. WD_PRIV_NONE, wd_cmd_who },
  178. };
  179. void * wd_ctl_thread(void *arg) {
  180. struct wd_client *client = (struct wd_client *) arg;
  181. struct timeval tv;
  182. fd_set rfds;
  183. int bytes, pending, state;
  184. /* associate the struct with this thread */
  185. pthread_setspecific(wd_client_key, client);
  186. /* go client */
  187. while(client->state <= WD_CLIENT_STATE_LOGGED_IN) {
  188. if(client->buffer_offset == 0) {
  189. do {
  190. FD_ZERO(&rfds);
  191. FD_SET(client->sd, &rfds);
  192. tv.tv_sec = 0;
  193. tv.tv_usec = 100000;
  194. state = select(client->sd + 1, &rfds, NULL, NULL, &tv);
  195. } while(state == 0 && client->state <= WD_CLIENT_STATE_LOGGED_IN);
  196. if(client->state > WD_CLIENT_STATE_LOGGED_IN) {
  197. /* invalid state */
  198. break;
  199. }
  200. if(state < 0) {
  201. if(errno == EINTR) {
  202. /* got a signal */
  203. continue;
  204. } else {
  205. /* error in TCP communication */
  206. wd_log(LOG_WARNING, "Could not read from %s: %s",
  207. client->ip, strerror(errno));
  208. break;
  209. }
  210. }
  211. }
  212. /* read from SSL */
  213. pthread_mutex_lock(&(client->ssl_mutex));
  214. bytes = SSL_read(client->ssl, client->buffer + client->buffer_offset, client->buffer_size - client->buffer_offset);
  215. pthread_mutex_unlock(&(client->ssl_mutex));
  216. if(bytes == 0) {
  217. /* EOF */
  218. break;
  219. }
  220. else if(bytes < 0) {
  221. /* error in SSL communication */
  222. wd_log(LOG_WARNING, "Could not read from %s: %s",
  223. client->ip, ERR_get_error() != 0
  224. ? ERR_reason_error_string(ERR_get_error())
  225. : strerror(errno));
  226. break;
  227. }
  228. if(client->buffer[client->buffer_offset + bytes - 1] != 4) {
  229. /* increase buffer by SSL_pending() bytes or, if we've reached the 16k
  230. limit in SSL/TLS, by initial buffer size */
  231. pending = SSL_pending(client->ssl);
  232. if(pending == 0)
  233. pending = WD_BUFFER_SIZE;
  234. /* increase buffer size and set new offset */
  235. client->buffer_size += pending;
  236. client->buffer = realloc(client->buffer, client->buffer_size);
  237. client->buffer_offset += bytes;
  238. } else {
  239. /* chomp separator */
  240. client->buffer[client->buffer_offset + bytes - 1] = '\0';
  241. /* parse buffer */
  242. wd_parse_command(client->buffer);
  243. /* reset offset */
  244. client->buffer_offset = 0;
  245. }
  246. }
  247. /* announce parting if client disconnected by itself */
  248. if(client->state == WD_CLIENT_STATE_LOGGED_IN) {
  249. pthread_mutex_lock(&(wd_chats.mutex));
  250. wd_broadcast(1, 303, "%u%s%lu", 1, WD_FIELD_SEPARATOR, client->uid);
  251. pthread_mutex_unlock(&(wd_chats.mutex));
  252. /* hotline subsystem */
  253. if(wd_frozen_settings.hotline)
  254. wd_hl_relay_leave(client->uid);
  255. }
  256. /* update status for clients logged in and above */
  257. if(client->state >= WD_CLIENT_STATE_LOGGED_IN) {
  258. pthread_mutex_lock(&wd_status_mutex);
  259. wd_current_users--;
  260. pthread_mutex_unlock(&wd_status_mutex);
  261. wd_write_status();
  262. }
  263. /* log */
  264. wd_log(LOG_INFO, "Disconnect from %s", client->ip);
  265. /* now delete client */
  266. wd_delete_client(client);
  267. return NULL;
  268. }
  269. #pragma mark -
  270. void wd_parse_command(char *buffer) {
  271. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  272. char *p, *command = NULL, *arg = NULL;
  273. int i;
  274. /* loop over the command */
  275. for(p = buffer; *buffer && !isspace(*buffer); buffer++)
  276. ;
  277. /* get command */
  278. command = (char *) malloc(buffer - p + 1);
  279. memcpy(command, p, buffer - p);
  280. command[buffer - p] = NULL;
  281. /* verify command */
  282. i = wd_command_index(command);
  283. if(i < 0) {
  284. wd_reply(501, "Command Not Recognized");
  285. goto end;
  286. }
  287. /* loop over argument string */
  288. for(p = ++buffer; *buffer; buffer++)
  289. ;
  290. /* get argument */
  291. arg = (char *) malloc(buffer - p + 1);
  292. memcpy(arg, p, buffer - p);
  293. arg[buffer - p] = NULL;
  294. /* verify state */
  295. if(client->state < wd_commands[i].state)
  296. goto end;
  297. /* verify arg */
  298. if(wd_commands[i].args == true && strlen(arg) == 0) {
  299. wd_reply(503, "Syntax Error");
  300. goto end;
  301. }
  302. /* verify permission */
  303. if(wd_commands[i].permission != WD_PRIV_NONE) {
  304. if(wd_getpriv(client->login, wd_commands[i].permission) != 1) {
  305. wd_reply(516, "Permission Denied");
  306. goto end;
  307. }
  308. }
  309. /* update the idle time */
  310. if(wd_commands[i].activate) {
  311. client->idle_time = time(NULL);
  312. if(client->idle) {
  313. client->idle = 0;
  314. /* broadcast a user change */
  315. pthread_mutex_lock(&(wd_chats.mutex));
  316. wd_broadcast(1, 304, "%lu%s%u%s%u%s%lu%s%s",
  317. client->uid,
  318. WD_FIELD_SEPARATOR,
  319. client->idle,
  320. WD_FIELD_SEPARATOR,
  321. client->admin,
  322. WD_FIELD_SEPARATOR,
  323. client->icon,
  324. WD_FIELD_SEPARATOR,
  325. client->nick);
  326. pthread_mutex_unlock(&(wd_chats.mutex));
  327. /* hotline subsystem */
  328. if(wd_frozen_settings.hotline) {
  329. wd_hl_relay_nick(client->uid, client->nick, client->icon,
  330. client->idle, client->admin);
  331. }
  332. }
  333. }
  334. /* go server command */
  335. ((*wd_commands[i].action) (arg));
  336. end:
  337. /* clean up */
  338. if(command)
  339. free(command);
  340. if(arg)
  341. free(arg);
  342. }
  343. int wd_command_index(char *command) {
  344. int min, max, i, cmp;
  345. min = 0;
  346. max = ARRAY_SIZE(wd_commands) - 1;
  347. do {
  348. i = (min + max) / 2;
  349. cmp = strcasecmp(command, wd_commands[i].name);
  350. if(cmp == 0)
  351. return i;
  352. else if(cmp < 0)
  353. max = i - 1;
  354. else
  355. min = i + 1;
  356. } while(min <= max);
  357. return -1;
  358. }
  359. #pragma mark -
  360. /*
  361. BAN <uid> <reason>
  362. */
  363. void wd_cmd_ban(char *arg) {
  364. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  365. struct wd_client *peer;
  366. struct wd_tempban *tempban;
  367. char *ap, *uid = NULL, *message = NULL;
  368. unsigned long uid_l;
  369. int i = 0;
  370. /* split the arguments */
  371. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  372. if(i == 0)
  373. uid = strdup(ap);
  374. else if(i == 1)
  375. message = strdup(ap);
  376. i++;
  377. }
  378. /* make sure we got them all */
  379. if(!uid || !message) {
  380. wd_reply(503, "Syntax Error");
  381. goto end;
  382. }
  383. /* convert user id */
  384. uid_l = strtoul(uid, NULL, 10);
  385. /* get user */
  386. peer = wd_get_client(uid_l, 1);
  387. if(!peer) {
  388. wd_reply(512, "Client Not Found");
  389. goto end;
  390. }
  391. /* check priv */
  392. if(wd_getpriv(peer->login, WD_PRIV_CANNOT_BE_KICKED) == 1) {
  393. wd_reply(515, "Cannot Be Disconnected");
  394. goto end;
  395. }
  396. /* broadcast a 307 */
  397. pthread_mutex_lock(&(wd_chats.mutex));
  398. wd_broadcast(1, 307, "%lu%s%d%s%s",
  399. peer->uid,
  400. WD_FIELD_SEPARATOR,
  401. client->uid,
  402. WD_FIELD_SEPARATOR,
  403. message);
  404. pthread_mutex_unlock(&(wd_chats.mutex));
  405. /* log */
  406. wd_log_ll(LOG_INFO, "%s/%s/%s banned %s/%s/%s",
  407. client->nick,
  408. client->login,
  409. client->ip,
  410. peer->nick,
  411. peer->login,
  412. peer->ip);
  413. /* create a temporary ban */
  414. tempban = (struct wd_tempban *) malloc(sizeof(struct wd_tempban));
  415. memset(tempban, 0, sizeof(tempban));
  416. /* set values */
  417. strlcpy(tempban->ip, peer->ip, sizeof(tempban->ip));
  418. tempban->time = time(NULL);
  419. /* add to list */
  420. pthread_mutex_lock(&(wd_tempbans.mutex));
  421. wd_list_add(&wd_tempbans, (void *) tempban);
  422. pthread_mutex_unlock(&(wd_tempbans.mutex));
  423. /* disconnect */
  424. pthread_mutex_lock(&(peer->state_mutex));
  425. peer->state = WD_CLIENT_STATE_DISCONNECTED;
  426. pthread_mutex_unlock(&(peer->state_mutex));
  427. end:
  428. /* clean up */
  429. if(uid)
  430. free(uid);
  431. if(message)
  432. free(message);
  433. }
  434. /*
  435. BROADCAST <message>
  436. */
  437. void wd_cmd_broadcast(char *arg) {
  438. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  439. /* broadcast message */
  440. pthread_mutex_lock(&(wd_chats.mutex));
  441. wd_broadcast(1, 309, "%lu%s%s", client->uid, WD_FIELD_SEPARATOR, arg);
  442. pthread_mutex_unlock(&(wd_chats.mutex));
  443. }
  444. /*
  445. CLEARNEWS
  446. */
  447. void wd_cmd_clearnews(char *arg) {
  448. /* clear the news */
  449. wd_clear_news();
  450. }
  451. /*
  452. CLIENT <application-version>
  453. */
  454. void wd_cmd_client(char *arg) {
  455. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  456. /* copy version string */
  457. strlcpy(client->version, arg, sizeof(client->version));
  458. }
  459. /*
  460. CREATEGROUP <...>
  461. */
  462. void wd_cmd_creategroup(char *arg) {
  463. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  464. char *ap, *fields[WD_GROUP_LAST + 1];
  465. int i = 0;
  466. /* init */
  467. memset(&fields, 0, sizeof(fields));
  468. /* check for the groups file delimiter */
  469. if(strpbrk(arg, ":") != NULL) {
  470. wd_reply(503, "Syntax Error");
  471. goto end;
  472. }
  473. /* split the arguments */
  474. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  475. if(i > WD_GROUP_LAST) {
  476. wd_reply(503, "Syntax Error");
  477. goto end;
  478. }
  479. fields[i] = strdup(ap);
  480. i++;
  481. }
  482. /* fill in the blanks */
  483. for(i = 0; i < WD_GROUP_LAST; i++) {
  484. if(!fields[i])
  485. fields[i] = strdup("");
  486. }
  487. /* terminate */
  488. fields[WD_GROUP_LAST] = NULL;
  489. /* create the group */
  490. if(wd_create_group(fields) > 0) {
  491. /* log */
  492. wd_log_ll(LOG_INFO, "%s/%s/%s created the group \"%s\"",
  493. client->nick,
  494. client->login,
  495. client->ip,
  496. fields[WD_GROUP_NAME]);
  497. }
  498. end:
  499. /* clean up */
  500. for(i = 0; i < WD_GROUP_LAST; i++) {
  501. if(fields[i])
  502. free(fields[i]);
  503. }
  504. }
  505. /*
  506. CREATEUSER <...>
  507. */
  508. void wd_cmd_createuser(char *arg) {
  509. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  510. char *ap, *fields[WD_USER_LAST + 1];
  511. int i = 0;
  512. /* init */
  513. memset(&fields, 0, sizeof(fields));
  514. /* check for the accounts file delimiter */
  515. if(strpbrk(arg, ":") != NULL) {
  516. wd_reply(503, "Syntax Error");
  517. goto end;
  518. }
  519. /* split the arguments */
  520. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  521. if(i > WD_USER_LAST) {
  522. wd_reply(503, "Syntax Error");
  523. goto end;
  524. }
  525. fields[i] = strdup(ap);
  526. i++;
  527. }
  528. /* fill in the blanks */
  529. for(i = 0; i < WD_USER_LAST; i++) {
  530. if(!fields[i])
  531. fields[i] = strdup("");
  532. }
  533. /* terminate */
  534. fields[WD_USER_LAST] = NULL;
  535. /* create the user */
  536. if(wd_create_user(fields) > 0) {
  537. /* log */
  538. wd_log_ll(LOG_INFO, "%s/%s/%s created the user \"%s\"",
  539. client->nick,
  540. client->login,
  541. client->ip,
  542. fields[WD_USER_NAME]);
  543. }
  544. end:
  545. /* clean up */
  546. for(i = 0; i < WD_USER_LAST; i++) {
  547. if(fields[i])
  548. free(fields[i]);
  549. }
  550. }
  551. /*
  552. DECLINE <cid>
  553. */
  554. void wd_cmd_decline(char *arg) {
  555. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  556. unsigned long cid;
  557. /* convert argument */
  558. cid = strtoul(arg, NULL, 10);
  559. /* check if client is on chat */
  560. if(wd_get_client(client->uid, cid) != NULL)
  561. return;
  562. /* send declined message */
  563. pthread_mutex_lock(&(wd_chats.mutex));
  564. wd_broadcast(cid, 332, "%lu%s%lu", cid, WD_FIELD_SEPARATOR, client->uid);
  565. pthread_mutex_unlock(&(wd_chats.mutex));
  566. }
  567. /*
  568. DELETE <path>
  569. */
  570. void wd_cmd_delete(char *arg) {
  571. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  572. /* verify the path */
  573. if(wd_evaluate_path(arg) < 0) {
  574. wd_reply(520, "File or Directory Not Found");
  575. return;
  576. }
  577. /* delete tree attached to path */
  578. if(wd_delete_path(arg) > 0) {
  579. /* log */
  580. wd_log_ll(LOG_INFO, "%s/%s/%s deleted \"%s\"",
  581. client->nick,
  582. client->login,
  583. client->ip,
  584. arg);
  585. }
  586. }
  587. /*
  588. DELETEGROUP <name>
  589. */
  590. void wd_cmd_deletegroup(char *arg) {
  591. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  592. /* delete the group */
  593. if(wd_delete_group(arg) > 0) {
  594. /* log */
  595. wd_log_ll(LOG_INFO, "%s/%s/%s deleted the group \"%s\"",
  596. client->nick,
  597. client->login,
  598. client->ip,
  599. arg);
  600. }
  601. }
  602. /*
  603. DELETEUSER <name>
  604. */
  605. void wd_cmd_deleteuser(char *arg) {
  606. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  607. /* delete the user */
  608. if(wd_delete_user(arg) > 0) {
  609. /* log */
  610. wd_log_ll(LOG_INFO, "%s/%s/%s deleted the user \"%s\"",
  611. client->nick,
  612. client->login,
  613. client->ip,
  614. arg);
  615. }
  616. }
  617. /*
  618. EDITGROUP <...>
  619. */
  620. void wd_cmd_editgroup(char *arg) {
  621. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  622. struct wd_client *peer;
  623. struct wd_list *clients;
  624. struct wd_list_node *node;
  625. char *ap, *fields[WD_GROUP_LAST + 1], *group = NULL;
  626. int i = 0;
  627. unsigned int old_admin;
  628. /* init */
  629. memset(&fields, 0, sizeof(fields));
  630. /* check for the groups file delimiter */
  631. if(strchr(arg, ':') != NULL) {
  632. wd_reply(503, "Syntax Error");
  633. goto end;
  634. }
  635. /* split the arguments */
  636. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  637. if(i > WD_GROUP_LAST) {
  638. wd_reply(503, "Syntax Error");
  639. goto end;
  640. }
  641. fields[i] = strdup(ap);
  642. i++;
  643. }
  644. /* fill in the blanks */
  645. for(i = 0; i < WD_GROUP_LAST; i++) {
  646. if(!fields[i])
  647. fields[i] = strdup("");
  648. }
  649. /* terminate */
  650. fields[WD_GROUP_LAST] = NULL;
  651. /* edit the group */
  652. if(wd_edit_group(fields) > 0) {
  653. /* log */
  654. wd_log_ll(LOG_INFO, "%s/%s/%s modified the group \"%s\"",
  655. client->nick,
  656. client->login,
  657. client->ip,
  658. fields[WD_GROUP_NAME]);
  659. }
  660. /* get public chat */
  661. clients = &(((struct wd_chat *) ((wd_chats.first)->data))->clients);
  662. /* loop over clients and elevate to admin if changed */
  663. pthread_mutex_lock(&(wd_chats.mutex));
  664. for(node = clients->first; node != NULL; node = node->next) {
  665. peer = node->data;
  666. /* get group field */
  667. group = wd_getuserfield(peer->login, WD_USER_GROUP);
  668. if(peer->state == WD_CLIENT_STATE_LOGGED_IN && strcmp(group, fields[0]) == 0) {
  669. /* send new privileges information */
  670. wd_list_privileges(peer);
  671. /* elevate to admin if set */
  672. old_admin = peer->admin;
  673. pthread_mutex_lock(&(peer->admin_mutex));
  674. peer->admin = wd_getpriv(peer->login, WD_PRIV_KICK_USERS) |
  675. wd_getpriv(peer->login, WD_PRIV_BAN_USERS);
  676. pthread_mutex_unlock(&(peer->admin_mutex));
  677. if(peer->admin != old_admin) {
  678. /* broadcast change */
  679. wd_broadcast(1, 304, "%lu%s%u%s%u%s%lu%s%s",
  680. peer->uid,
  681. WD_FIELD_SEPARATOR,
  682. peer->idle,
  683. WD_FIELD_SEPARATOR,
  684. peer->admin,
  685. WD_FIELD_SEPARATOR,
  686. peer->icon,
  687. WD_FIELD_SEPARATOR,
  688. peer->nick);
  689. /* hotline subsystem */
  690. if(wd_frozen_settings.hotline) {
  691. wd_hl_relay_nick(client->uid, client->nick, client->icon,
  692. client->idle, client->admin);
  693. }
  694. }
  695. }
  696. free(group);
  697. }
  698. pthread_mutex_unlock(&(wd_chats.mutex));
  699. end:
  700. /* clean up */
  701. for(i = 0; i < WD_GROUP_LAST; i++) {
  702. if(fields[i])
  703. free(fields[i]);
  704. }
  705. }
  706. /*
  707. EDITUSER <...>
  708. */
  709. void wd_cmd_edituser(char *arg) {
  710. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  711. struct wd_client *peer;
  712. struct wd_list *clients;
  713. struct wd_list_node *node;
  714. char *ap, *fields[WD_USER_LAST + 1];
  715. int i = 0;
  716. unsigned int old_admin;
  717. /* init */
  718. memset(&fields, 0, sizeof(fields));
  719. /* check for the accounts file delimiter */
  720. if(strchr(arg, ':') != NULL) {
  721. wd_reply(503, "Syntax Error");
  722. goto end;
  723. }
  724. /* split the arguments */
  725. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  726. if(i > WD_USER_LAST) {
  727. wd_reply(503, "Syntax Error");
  728. goto end;
  729. }
  730. fields[i] = strdup(ap);
  731. i++;
  732. }
  733. /* fill in the blanks */
  734. for(i = 0; i < WD_USER_LAST; i++) {
  735. if(!fields[i])
  736. fields[i] = strdup("");
  737. }
  738. /* terminate */
  739. fields[WD_USER_LAST] = NULL;
  740. /* edit the user */
  741. if(wd_edit_user(fields) > 0) {
  742. /* log */
  743. wd_log_ll(LOG_INFO, "%s/%s/%s modified the user \"%s\"",
  744. client->nick,
  745. client->login,
  746. client->ip,
  747. fields[WD_USER_NAME]);
  748. }
  749. /* get public chat */
  750. clients = &(((struct wd_chat *) ((wd_chats.first)->data))->clients);
  751. /* loop over clients and elevate to admin if changed */
  752. pthread_mutex_lock(&(wd_chats.mutex));
  753. for(node = clients->first; node != NULL; node = node->next) {
  754. peer = node->data;
  755. if(peer->state == WD_CLIENT_STATE_LOGGED_IN && strcmp(peer->login, fields[0]) == 0) {
  756. /* send new privileges information */
  757. wd_list_privileges(peer);
  758. /* elevate to admin if set */
  759. old_admin = peer->admin;
  760. pthread_mutex_lock(&(peer->admin_mutex));
  761. peer->admin = wd_getpriv(peer->login, WD_PRIV_KICK_USERS) |
  762. wd_getpriv(peer->login, WD_PRIV_BAN_USERS);
  763. pthread_mutex_unlock(&(peer->admin_mutex));
  764. if(peer->admin != old_admin) {
  765. /* broadcast change */
  766. wd_broadcast(1, 304, "%lu%s%u%s%u%s%lu%s%s",
  767. peer->uid,
  768. WD_FIELD_SEPARATOR,
  769. peer->idle,
  770. WD_FIELD_SEPARATOR,
  771. peer->admin,
  772. WD_FIELD_SEPARATOR,
  773. peer->icon,
  774. WD_FIELD_SEPARATOR,
  775. peer->nick);
  776. /* hotline subsystem */
  777. if(wd_frozen_settings.hotline) {
  778. wd_hl_relay_nick(client->uid, client->nick, client->icon,
  779. client->idle, client->admin);
  780. }
  781. }
  782. }
  783. }
  784. pthread_mutex_unlock(&(wd_chats.mutex));
  785. end:
  786. /* clean up */
  787. for(i = 0; i < WD_USER_LAST; i++) {
  788. if(fields[i])
  789. free(fields[i]);
  790. }
  791. }
  792. /*
  793. FOLDER <path>
  794. */
  795. void wd_cmd_folder(char *arg) {
  796. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  797. char *dir, real_path[MAXPATHLEN];
  798. /* verify the path */
  799. if(wd_evaluate_path(arg) < 0) {
  800. wd_reply(520, "File or Directory Not Found");
  801. return;
  802. }
  803. /* get the directory name */
  804. dir = dirname(arg);
  805. if(!dir) {
  806. wd_reply(520, "File or Directory Not Found");
  807. return;
  808. }
  809. snprintf(real_path, sizeof(real_path), ".%s", dir);
  810. /* verify permissions */
  811. switch(wd_file_type(real_path, NULL)) {
  812. case WD_FILE_TYPE_UPLOADS:
  813. case WD_FILE_TYPE_DROPBOX:
  814. if(wd_getpriv(client->login, WD_PRIV_UPLOAD) != 1) {
  815. wd_reply(516, "Permission Denied");
  816. return;
  817. }
  818. break;
  819. default:
  820. if(wd_getpriv(client->login, WD_PRIV_UPLOAD_ANYWHERE) != 1 &&
  821. wd_getpriv(client->login, WD_PRIV_CREATE_FOLDERS) != 1) {
  822. wd_reply(516, "Permission Denied");
  823. return;
  824. }
  825. break;
  826. }
  827. /* create the directory */
  828. wd_create_path(arg);
  829. }
  830. /*
  831. GET <path> <offset>
  832. */
  833. void wd_cmd_get(char *arg) {
  834. char *ap, *path = NULL, *offset = NULL;
  835. unsigned long long offset_l;
  836. int i = 0;
  837. /* split the arguments */
  838. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  839. if(i == 0)
  840. path = strdup(ap);
  841. else if(i == 1)
  842. offset = strdup(ap);
  843. i++;
  844. }
  845. /* make sure we got them all */
  846. if(!path || !offset) {
  847. wd_reply(503, "Syntax Error");
  848. goto end;
  849. }
  850. /* verify the path */
  851. if(wd_evaluate_path(path) < 0) {
  852. wd_reply(520, "File or Directory Not Found");
  853. goto end;
  854. }
  855. /* convert offset */
  856. offset_l = strtoull(offset, NULL, 10);
  857. /* get the file */
  858. wd_queue_download(path, offset_l);
  859. end:
  860. /* clean up */
  861. if(path)
  862. free(path);
  863. if(offset)
  864. free(offset);
  865. }
  866. /*
  867. GROUPS
  868. */
  869. void wd_cmd_groups(char *arg) {
  870. /* list groups */
  871. wd_list_groups();
  872. }
  873. /*
  874. HELLO
  875. */
  876. void wd_cmd_hello(char *arg) {
  877. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  878. char start_time[26];
  879. /* check state */
  880. if(client->state != WD_CLIENT_STATE_CONNECTED)
  881. return;
  882. /* check ban */
  883. if(wd_check_ban(client->ip) < 0) {
  884. wd_reply(511, "Banned");
  885. wd_log(LOG_INFO, "Connection from %s denied, host is banned", client->ip);
  886. client->state = WD_CLIENT_STATE_DISCONNECTED;
  887. if(SSL_shutdown(client->ssl) == 0)
  888. SSL_shutdown(client->ssl);
  889. SSL_free(client->ssl);
  890. client->ssl = NULL;
  891. close(client->sd);
  892. client->sd = -1;
  893. return;
  894. }
  895. /* format time string */
  896. wd_time_to_iso8601(localtime(&wd_start_time), start_time, sizeof(start_time));
  897. /* reply a 200 */
  898. wd_reply(200, "%s%s%s%s%s%s%s%s%s",
  899. wd_version_string,
  900. WD_FIELD_SEPARATOR,
  901. WD_PROTOCOL_VERSION,
  902. WD_FIELD_SEPARATOR,
  903. wd_settings.name,
  904. WD_FIELD_SEPARATOR,
  905. wd_settings.description,
  906. WD_FIELD_SEPARATOR,
  907. start_time);
  908. /* elevate state */
  909. client->state = WD_CLIENT_STATE_SAID_HELLO;
  910. }
  911. /*
  912. ICON <icon>
  913. */
  914. void wd_cmd_icon(char *arg) {
  915. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  916. unsigned long icon;
  917. /* convert argument */
  918. icon = strtoul(arg, NULL, 10);
  919. /* copy icon if changed */
  920. if(client->icon != icon) {
  921. client->icon = icon;
  922. /* broadcast a 304 if the client is logged in */
  923. if(client->state == WD_CLIENT_STATE_LOGGED_IN) {
  924. pthread_mutex_lock(&(wd_chats.mutex));
  925. wd_broadcast(1, 304, "%lu%s%u%s%u%s%lu%s%s",
  926. client->uid,
  927. WD_FIELD_SEPARATOR,
  928. client->idle,
  929. WD_FIELD_SEPARATOR,
  930. client->admin,
  931. WD_FIELD_SEPARATOR,
  932. client->icon,
  933. WD_FIELD_SEPARATOR,
  934. client->nick);
  935. pthread_mutex_unlock(&(wd_chats.mutex));
  936. /* hotline subsystem */
  937. if(wd_frozen_settings.hotline) {
  938. wd_hl_relay_nick(client->uid, client->nick, client->icon,
  939. client->idle, client->admin);
  940. }
  941. }
  942. }
  943. }
  944. /*
  945. INFO <uid>
  946. */
  947. void wd_cmd_info(char *arg) {
  948. struct wd_client *peer;
  949. struct wd_list_node *node;
  950. struct wd_transfer *transfer;
  951. char logintime[26], idletime[26];
  952. char info[1024], downloads[2048], uploads[2048];
  953. unsigned long uid;
  954. int length;
  955. /* convert user id */
  956. uid = strtoul(arg, NULL, 10);
  957. /* get the client */
  958. peer = wd_get_client(uid, 1);
  959. if(!peer) {
  960. /* hotline subsystem */
  961. if(wd_frozen_settings.hotline)
  962. wd_hl_info(uid);
  963. else
  964. wd_reply(512, "Client Not Found");
  965. return;
  966. }
  967. /* format time strings */
  968. wd_time_to_iso8601(localtime(&(peer->login_time)), logintime, sizeof(logintime));
  969. wd_time_to_iso8601(localtime(&(peer->idle_time)), idletime, sizeof(idletime));
  970. /* format the downloads/uploads strings */
  971. memset(downloads, 0, sizeof(downloads));
  972. memset(uploads, 0, sizeof(uploads));
  973. pthread_mutex_lock(&(wd_transfers.mutex));
  974. for(node = wd_transfers.first; node != NULL; node = node->next) {
  975. transfer = node->data;
  976. if(transfer->client == peer && transfer->state == WD_XFER_STATE_RUNNING) {
  977. switch(transfer->type) {
  978. case WD_XFER_DOWNLOAD:
  979. snprintf(info, sizeof(info), "%s%s%llu%s%llu%s%d%s",
  980. transfer->path,
  981. WD_RECORD_SEPARATOR,
  982. transfer->transferred,
  983. WD_RECORD_SEPARATOR,
  984. transfer->size,
  985. WD_RECORD_SEPARATOR,
  986. transfer->speed,
  987. WD_GROUP_SEPARATOR);
  988. strncat(downloads, info, sizeof(downloads));
  989. break;
  990. case WD_XFER_UPLOAD:
  991. snprintf(info, sizeof(info), "%s%s%llu%s%llu%s%d%s",
  992. transfer->path,
  993. WD_RECORD_SEPARATOR,
  994. transfer->transferred,
  995. WD_RECORD_SEPARATOR,
  996. transfer->size,
  997. WD_RECORD_SEPARATOR,
  998. transfer->speed,
  999. WD_GROUP_SEPARATOR);
  1000. strncat(uploads, info, sizeof(uploads));
  1001. break;
  1002. }
  1003. }
  1004. }
  1005. pthread_mutex_unlock(&(wd_transfers.mutex));
  1006. /* chop off the last WD_GROUP_SEPARATOR */
  1007. length = strlen(downloads);
  1008. if(length > 0)
  1009. downloads[length - 1] = '\0';
  1010. length = strlen(uploads);
  1011. if(length > 0)
  1012. uploads[length - 1] = '\0';
  1013. /* send message */
  1014. wd_reply(308, "%lu%s%u%s%u%s%u%s%s%s%s%s%s%s%s%s%s%s%s%s%u%s%s%s%s%s%s%s%s",
  1015. peer->uid,
  1016. WD_FIELD_SEPARATOR,
  1017. peer->idle,
  1018. WD_FIELD_SEPARATOR,
  1019. peer->admin,
  1020. WD_FIELD_SEPARATOR,
  1021. peer->icon,
  1022. WD_FIELD_SEPARATOR,
  1023. peer->nick,
  1024. WD_FIELD_SEPARATOR,
  1025. peer->login,
  1026. WD_FIELD_SEPARATOR,
  1027. peer->ip,
  1028. WD_FIELD_SEPARATOR,
  1029. peer->host,
  1030. WD_FIELD_SEPARATOR,
  1031. peer->version,
  1032. WD_FIELD_SEPARATOR,
  1033. SSL_get_cipher_name(peer->ssl),
  1034. WD_FIELD_SEPARATOR,
  1035. SSL_get_cipher_bits(peer->ssl, NULL),
  1036. WD_FIELD_SEPARATOR,
  1037. logintime,
  1038. WD_FIELD_SEPARATOR,
  1039. idletime,
  1040. WD_FIELD_SEPARATOR,
  1041. downloads,
  1042. WD_FIELD_SEPARATOR,
  1043. uploads);
  1044. }
  1045. /*
  1046. INVITE <uid> <cid>
  1047. */
  1048. void wd_cmd_invite(char *arg) {
  1049. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1050. struct wd_client *peer;
  1051. char *ap, *uid = NULL, *cid = NULL;
  1052. unsigned long uid_l, cid_l;
  1053. int i = 0;
  1054. /* split the arguments */
  1055. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  1056. if(i == 0)
  1057. uid = strdup(ap);
  1058. else if(i == 1)
  1059. cid = strdup(ap);
  1060. i++;
  1061. }
  1062. /* make sure we got them all */
  1063. if(!uid || !cid) {
  1064. wd_reply(503, "Syntax Error");
  1065. goto end;
  1066. }
  1067. /* convert arguments */
  1068. uid_l = strtoul(uid, NULL, 10);
  1069. cid_l = strtoul(cid, NULL, 10);
  1070. /* get the client from the public chat */
  1071. peer = wd_get_client(uid_l, 1);
  1072. if(!peer) {
  1073. /* hotline subsystem */
  1074. if(wd_frozen_settings.hotline && hl_get_client(uid_l) != NULL)
  1075. wd_reply(500, "Command Failed");
  1076. else
  1077. wd_reply(512, "Client Not Found");
  1078. goto end;
  1079. }
  1080. /* check if client is on the chat */
  1081. if(wd_get_client(client->uid, cid_l) == NULL)
  1082. goto end;
  1083. /* check if peer is not on the chat */
  1084. if(wd_get_client(peer->uid, cid_l) != NULL)
  1085. goto end;
  1086. /* now we can send the invite message */
  1087. pthread_mutex_lock(&(peer->ssl_mutex));
  1088. wd_sreply(peer->ssl, 331, "%lu%s%lu", cid_l, WD_FIELD_SEPARATOR, client->uid);
  1089. pthread_mutex_unlock(&(peer->ssl_mutex));
  1090. end:
  1091. /* clean up */
  1092. if(uid)
  1093. free(uid);
  1094. if(cid)
  1095. free(cid);
  1096. }
  1097. /*
  1098. JOIN <cid>
  1099. */
  1100. void wd_cmd_join(char *arg) {
  1101. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1102. struct wd_list_node *chat_node;
  1103. struct wd_chat *chat;
  1104. unsigned long cid;
  1105. int found = 0;
  1106. /* convert argument */
  1107. cid = strtoul(arg, NULL, 10);
  1108. /* check if client is on the chat already */
  1109. if(wd_get_client(client->uid, cid) != NULL)
  1110. return;
  1111. /* add a copy of the record to the chat */
  1112. pthread_mutex_lock(&(wd_chats.mutex));
  1113. for(chat_node = wd_chats.first; chat_node != NULL; chat_node = chat_node->next) {
  1114. chat = chat_node->data;
  1115. if(chat->cid == cid) {
  1116. wd_list_add(&(chat->clients), client);
  1117. found = 1;
  1118. break;
  1119. }
  1120. }
  1121. pthread_mutex_unlock(&(wd_chats.mutex));
  1122. if(!found)
  1123. return;
  1124. /* send join message */
  1125. pthread_mutex_lock(&(wd_chats.mutex));
  1126. wd_broadcast(cid, 302, "%lu%s%lu%s%u%s%u%s%u%s%s%s%s%s%s%s%s",
  1127. cid,
  1128. WD_FIELD_SEPARATOR,
  1129. client->uid,
  1130. WD_FIELD_SEPARATOR,
  1131. client->idle,
  1132. WD_FIELD_SEPARATOR,
  1133. client->admin,
  1134. WD_FIELD_SEPARATOR,
  1135. client->icon,
  1136. WD_FIELD_SEPARATOR,
  1137. client->nick,
  1138. WD_FIELD_SEPARATOR,
  1139. client->login,
  1140. WD_FIELD_SEPARATOR,
  1141. client->ip,
  1142. WD_FIELD_SEPARATOR,
  1143. client->host);
  1144. pthread_mutex_unlock(&(wd_chats.mutex));
  1145. }
  1146. /*
  1147. KICK <uid> <reason>
  1148. */
  1149. void wd_cmd_kick(char *arg) {
  1150. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1151. struct wd_client *peer;
  1152. char *ap, *uid = NULL, *message = NULL;
  1153. unsigned long uid_l;
  1154. int i = 0;
  1155. /* split the arguments */
  1156. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  1157. if(i == 0)
  1158. uid = strdup(ap);
  1159. else if(i == 1)
  1160. message = strdup(ap);
  1161. i++;
  1162. }
  1163. /* make sure we got them all */
  1164. if(!uid || !message) {
  1165. wd_reply(503, "Syntax Error");
  1166. goto end;
  1167. }
  1168. /* convert user id */
  1169. uid_l = strtoul(uid, NULL, 10);
  1170. /* get user */
  1171. peer = wd_get_client(uid_l, 1);
  1172. if(!peer) {
  1173. wd_reply(512, "Client Not Found");
  1174. goto end;
  1175. }
  1176. /* check priv */
  1177. if(wd_getpriv(peer->login, WD_PRIV_CANNOT_BE_KICKED) == 1) {
  1178. wd_reply(515, "Cannot Be Disconnected");
  1179. goto end;
  1180. }
  1181. /* broadcast a 306 */
  1182. pthread_mutex_lock(&(wd_chats.mutex));
  1183. wd_broadcast(1, 306, "%lu%s%d%s%s",
  1184. peer->uid,
  1185. WD_FIELD_SEPARATOR,
  1186. client->uid,
  1187. WD_FIELD_SEPARATOR,
  1188. message);
  1189. pthread_mutex_unlock(&(wd_chats.mutex));
  1190. /* log */
  1191. wd_log_ll(LOG_INFO, "%s/%s/%s kicked %s/%s/%s",
  1192. client->nick,
  1193. client->login,
  1194. client->ip,
  1195. peer->nick,
  1196. peer->login,
  1197. peer->ip);
  1198. /* disconnect */
  1199. pthread_mutex_lock(&(peer->state_mutex));
  1200. peer->state = WD_CLIENT_STATE_DISCONNECTED;
  1201. pthread_mutex_unlock(&(peer->state_mutex));
  1202. end:
  1203. /* clean up */
  1204. if(uid)
  1205. free(uid);
  1206. if(message)
  1207. free(message);
  1208. }
  1209. /*
  1210. LEAVE <cid>
  1211. */
  1212. void wd_cmd_leave(char *arg) {
  1213. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1214. struct wd_client *peer;
  1215. struct wd_list_node *chat_node, *client_node;
  1216. struct wd_chat *chat;
  1217. unsigned long cid;
  1218. /* convert argument */
  1219. cid = strtoul(arg, NULL, 10);
  1220. /* no */
  1221. if(cid == 1)
  1222. return;
  1223. /* remove the client from this chat list */
  1224. pthread_mutex_lock(&(wd_chats.mutex));
  1225. for(chat_node = wd_chats.first; chat_node != NULL; chat_node = chat_node->next) {
  1226. chat = chat_node->data;
  1227. if(chat->cid == cid) {
  1228. for(client_node = (chat->clients).first; client_node != NULL; client_node = client_node->next) {
  1229. peer = client_node->data;
  1230. if(peer->sd == client->sd) {
  1231. wd_list_delete(&(chat->clients), client_node);
  1232. break;
  1233. }
  1234. }
  1235. break;
  1236. }
  1237. }
  1238. pthread_mutex_unlock(&(wd_chats.mutex));
  1239. /* send a leave message */
  1240. pthread_mutex_lock(&(wd_chats.mutex));
  1241. wd_broadcast(cid, 303, "%lu%s%lu", cid, WD_FIELD_SEPARATOR, client->uid);
  1242. pthread_mutex_unlock(&(wd_chats.mutex));
  1243. }
  1244. /*
  1245. LIST <path>
  1246. */
  1247. void wd_cmd_list(char *arg) {
  1248. /* verify the path */
  1249. if(wd_evaluate_path(arg) < 0) {
  1250. wd_reply(520, "File or Directory Not Found");
  1251. return;
  1252. }
  1253. /* list the directory */
  1254. wd_list_path(arg);
  1255. }
  1256. /*
  1257. ME <id> <chat>
  1258. */
  1259. void wd_cmd_me(char *arg) {
  1260. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1261. char *ap, *cid = NULL, *chat = NULL;
  1262. unsigned long cid_l;
  1263. int i = 0;
  1264. /* split the arguments */
  1265. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  1266. if(i == 0)
  1267. cid = strdup(ap);
  1268. else if(i == 1)
  1269. chat = strdup(ap);
  1270. i++;
  1271. }
  1272. /* make sure we got them all */
  1273. if(!cid || !chat) {
  1274. wd_reply(503, "Syntax Error");
  1275. goto end;
  1276. }
  1277. /* convert chat id */
  1278. cid_l = strtoul(cid, NULL, 10);
  1279. /* check if client is on chat */
  1280. if(wd_get_client(client->uid, cid_l) == NULL)
  1281. goto end;
  1282. while((ap = strsep(&chat, "\n\r"))) {
  1283. if(strlen(ap) > 0) {
  1284. pthread_mutex_lock(&(wd_chats.mutex));
  1285. wd_broadcast(cid_l, 301, "%lu%s%lu%s%s",
  1286. cid_l,
  1287. WD_FIELD_SEPARATOR,
  1288. client->uid,
  1289. WD_FIELD_SEPARATOR,
  1290. ap);
  1291. pthread_mutex_unlock(&(wd_chats.mutex));
  1292. /* hotline subsystem */
  1293. if(wd_frozen_settings.hotline && cid_l == 1)
  1294. wd_hl_relay_me(client->nick, ap);
  1295. }
  1296. }
  1297. end:
  1298. /* clean up */
  1299. if(cid)
  1300. free(cid);
  1301. if(chat)
  1302. free(chat);
  1303. }
  1304. /*
  1305. MOVE <path> <path>
  1306. */
  1307. void wd_cmd_move(char *arg) {
  1308. char *ap, *from = NULL, *to = NULL;
  1309. int i = 0;
  1310. /* split the arguments */
  1311. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  1312. if(i == 0)
  1313. from = strdup(ap);
  1314. else if(i == 1)
  1315. to = strdup(ap);
  1316. i++;
  1317. }
  1318. /* make sure we got them all */
  1319. if(!from || !to) {
  1320. wd_reply(503, "Syntax Error");
  1321. goto end;
  1322. }
  1323. /* verify the paths */
  1324. if(wd_evaluate_path(from) < 0 || wd_evaluate_path(to) < 0) {
  1325. wd_reply(520, "File or Directory Not Found");
  1326. goto end;
  1327. }
  1328. /* move the path */
  1329. wd_move_path(from, to);
  1330. end:
  1331. /* clean up */
  1332. if(from)
  1333. free(from);
  1334. if(to)
  1335. free(to);
  1336. }
  1337. /*
  1338. MSG <uid> <message>
  1339. */
  1340. void wd_cmd_msg(char *arg) {
  1341. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1342. struct wd_client *peer;
  1343. char *ap, *uid = NULL, *msg = NULL;
  1344. unsigned long uid_l;
  1345. int i = 0;
  1346. /* split the arguments */
  1347. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  1348. if(i == 0)
  1349. uid = strdup(ap);
  1350. else if(i == 1)
  1351. msg = strdup(ap);
  1352. i++;
  1353. }
  1354. /* make sure we got them all */
  1355. if(!uid || !msg) {
  1356. wd_reply(503, "Syntax Error");
  1357. goto end;
  1358. }
  1359. /* convert user id */
  1360. uid_l = strtoul(uid, NULL, 10);
  1361. /* get the client and send the message */
  1362. peer = wd_get_client(uid_l, 1);
  1363. if(peer) {
  1364. pthread_mutex_lock(&(peer->ssl_mutex));
  1365. wd_sreply(peer->ssl, 305, "%lu%s%s", client->uid, WD_FIELD_SEPARATOR, msg);
  1366. pthread_mutex_unlock(&(peer->ssl_mutex));
  1367. } else {
  1368. /* hotline subsystem */
  1369. if(wd_frozen_settings.hotline && hl_get_client(uid_l) != NULL)
  1370. wd_hl_relay_msg(client->uid, uid_l, client->nick, msg);
  1371. else
  1372. wd_reply(512, "Client Not Found");
  1373. }
  1374. end:
  1375. /* clean up */
  1376. if(uid)
  1377. free(uid);
  1378. if(msg)
  1379. free(msg);
  1380. }
  1381. /*
  1382. NEWS
  1383. */
  1384. void wd_cmd_news(char *arg) {
  1385. /* send the news */
  1386. wd_send_news();
  1387. }
  1388. /*
  1389. NICK <nick>
  1390. */
  1391. void wd_cmd_nick(char *arg) {
  1392. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1393. /* copy nick if changed */
  1394. if(strcmp(client->nick, arg) != 0) {
  1395. strlcpy(client->nick, arg, sizeof(client->nick));
  1396. /* broadcast a 304 if the client is logged in */
  1397. if(client->state == WD_CLIENT_STATE_LOGGED_IN) {
  1398. pthread_mutex_lock(&(wd_chats.mutex));
  1399. wd_broadcast(1, 304, "%lu%s%u%s%u%s%lu%s%s",
  1400. client->uid,
  1401. WD_FIELD_SEPARATOR,
  1402. client->idle,
  1403. WD_FIELD_SEPARATOR,
  1404. client->admin,
  1405. WD_FIELD_SEPARATOR,
  1406. client->icon,
  1407. WD_FIELD_SEPARATOR,
  1408. client->nick);
  1409. pthread_mutex_unlock(&(wd_chats.mutex));
  1410. /* hotline subsystem */
  1411. if(wd_frozen_settings.hotline) {
  1412. wd_hl_relay_nick(client->uid, client->nick, client->icon,
  1413. client->idle, client->admin);
  1414. }
  1415. }
  1416. }
  1417. }
  1418. /*
  1419. PASS <password>
  1420. */
  1421. void wd_cmd_pass(char *arg) {
  1422. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1423. if(client->state != WD_CLIENT_STATE_GAVE_USER)
  1424. return;
  1425. /* attempt to login user */
  1426. if(wd_check_login(client->login, arg) < 0) {
  1427. /* failed */
  1428. wd_log(LOG_INFO, "Login from %s/%s/%s failed",
  1429. client->nick,
  1430. client->login,
  1431. client->ip);
  1432. /* reply failure */
  1433. wd_reply(510, "Login Failed");
  1434. } else {
  1435. /* succeeded */
  1436. wd_log(LOG_INFO, "Login from %s/%s/%s succeeded",
  1437. client->nick,
  1438. client->login,
  1439. client->ip);
  1440. /* get admin flag */
  1441. pthread_mutex_lock(&(client->admin_mutex));
  1442. client->admin = wd_getpriv(client->login, WD_PRIV_KICK_USERS) |
  1443. wd_getpriv(client->login, WD_PRIV_BAN_USERS);
  1444. pthread_mutex_unlock(&(client->admin_mutex));
  1445. /* announce user join on public chat */
  1446. pthread_mutex_lock(&(wd_chats.mutex));
  1447. wd_broadcast(1, 302, "1%s%lu%s%u%s%u%s%u%s%s%s%s%s%s",
  1448. WD_FIELD_SEPARATOR,
  1449. client->uid,
  1450. WD_FIELD_SEPARATOR,
  1451. client->idle,
  1452. WD_FIELD_SEPARATOR,
  1453. client->admin,
  1454. WD_FIELD_SEPARATOR,
  1455. client->icon,
  1456. WD_FIELD_SEPARATOR,
  1457. client->nick,
  1458. WD_FIELD_SEPARATOR,
  1459. client->login,
  1460. WD_FIELD_SEPARATOR,
  1461. client->ip,
  1462. WD_FIELD_SEPARATOR,
  1463. client->host);
  1464. pthread_mutex_unlock(&(wd_chats.mutex));
  1465. /* hotline subsystem */
  1466. if(wd_frozen_settings.hotline) {
  1467. wd_hl_relay_join(client->uid, client->nick, client->icon,
  1468. client->idle, client->admin);
  1469. }
  1470. /* elevate state */
  1471. client->state = WD_CLIENT_STATE_LOGGED_IN;
  1472. /* reply success */
  1473. wd_reply(201, "%u", client->uid);
  1474. /* update status */
  1475. pthread_mutex_lock(&wd_status_mutex);
  1476. wd_current_users++;
  1477. wd_total_users++;
  1478. pthread_mutex_unlock(&wd_status_mutex);
  1479. wd_write_status();
  1480. }
  1481. }
  1482. /*
  1483. PING
  1484. */
  1485. void wd_cmd_ping(char *arg) {
  1486. /* reply ping */
  1487. wd_reply(202, "Pong");
  1488. }
  1489. /*
  1490. POST <message>
  1491. */
  1492. void wd_cmd_post(char *arg) {
  1493. /* post the news */
  1494. wd_post_news(arg);
  1495. }
  1496. /*
  1497. PRIVCHAT
  1498. */
  1499. void wd_cmd_privchat(char *arg) {
  1500. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1501. struct wd_list_node *chat_node;
  1502. struct wd_chat *chat;
  1503. unsigned long cid;
  1504. int loop = 1, found = 0;
  1505. /* locate a new unique chat id */
  1506. while(loop) {
  1507. found = 0;
  1508. cid = (unsigned long) random() % ULONG_MAX;
  1509. pthread_mutex_lock(&(wd_chats.mutex));
  1510. for(chat_node = wd_chats.first; chat_node != NULL; chat_node = chat_node->next) {
  1511. chat = chat_node->data;
  1512. if(chat->cid == cid) {
  1513. found = 1;
  1514. break;
  1515. }
  1516. }
  1517. pthread_mutex_unlock(&(wd_chats.mutex));
  1518. if(!found)
  1519. loop = 0;
  1520. }
  1521. /* create a new chat */
  1522. chat = (struct wd_chat *) malloc(sizeof(struct wd_chat));
  1523. chat->cid = cid;
  1524. wd_list_create(&(chat->clients));
  1525. /* add a copy of this client */
  1526. pthread_mutex_lock(&(wd_chats.mutex));
  1527. wd_list_add(&wd_chats, chat);
  1528. wd_list_add(&(chat->clients), client);
  1529. pthread_mutex_unlock(&(wd_chats.mutex));
  1530. /* chat created notice */
  1531. wd_reply(330, "%lu", cid);
  1532. }
  1533. /*
  1534. PRIVILEGES
  1535. */
  1536. void wd_cmd_privileges(char *arg) {
  1537. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1538. /* send privileges information */
  1539. wd_list_privileges(client);
  1540. }
  1541. /*
  1542. PUT <path> <size> <checksum>
  1543. */
  1544. void wd_cmd_put(char *arg) {
  1545. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1546. struct stat sb;
  1547. char *ap, *path = NULL, *size = NULL, *checksum = NULL;
  1548. char *dir, real_path[MAXPATHLEN];
  1549. unsigned long long size_l;
  1550. int i = 0;
  1551. /* split the arguments */
  1552. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  1553. if(i == 0)
  1554. path = strdup(ap);
  1555. else if(i == 1)
  1556. size = strdup(ap);
  1557. else if(i == 2)
  1558. checksum = strdup(ap);
  1559. i++;
  1560. }
  1561. /* make sure we got them all */
  1562. if(!path || !size || !checksum) {
  1563. wd_reply(503, "Syntax Error");
  1564. goto end;
  1565. }
  1566. /* convert size */
  1567. size_l = strtoull(size, NULL, 10);
  1568. /* get the directory name */
  1569. dir = dirname(path);
  1570. if(!dir) {
  1571. wd_reply(520, "File or Directory Not Found");
  1572. return;
  1573. }
  1574. /* verify destination path */
  1575. if(wd_evaluate_path(dir) < 0) {
  1576. wd_reply(520, "File or Directory Not Found");
  1577. goto end;
  1578. }
  1579. /* verify file doesn't already exist */
  1580. snprintf(real_path, sizeof(real_path), ".%s", path);
  1581. if(stat(real_path, &sb) == 0) {
  1582. wd_reply(521, "File or Directory Exists");
  1583. goto end;
  1584. }
  1585. /* verify permissions on directory */
  1586. snprintf(real_path, sizeof(real_path), ".%s", dir);
  1587. switch(wd_file_type(real_path, NULL)) {
  1588. case WD_FILE_TYPE_UPLOADS:
  1589. case WD_FILE_TYPE_DROPBOX:
  1590. if(wd_getpriv(client->login, WD_PRIV_UPLOAD) != 1) {
  1591. wd_reply(516, "Permission Denied");
  1592. goto end;
  1593. }
  1594. break;
  1595. default:
  1596. if(wd_getpriv(client->login, WD_PRIV_UPLOAD_ANYWHERE) != 1) {
  1597. wd_reply(516, "Permission Denied");
  1598. goto end;
  1599. }
  1600. break;
  1601. }
  1602. /* enter upload */
  1603. wd_queue_upload(path, size_l, checksum);
  1604. end:
  1605. /* clean up */
  1606. if(path)
  1607. free(path);
  1608. if(size)
  1609. free(size);
  1610. if(checksum)
  1611. free(checksum);
  1612. }
  1613. /*
  1614. READGROUP <name>
  1615. */
  1616. void wd_cmd_readgroup(char *arg) {
  1617. char *field, value[1024], out[1024];
  1618. char *group = NULL;
  1619. int i, length;
  1620. /* check for account */
  1621. group = wd_getgroup(arg);
  1622. if(!group) {
  1623. wd_reply(513, "Account Not Found");
  1624. goto end;
  1625. }
  1626. memset(out, 0, sizeof(out));
  1627. /* get all the fields of the account */
  1628. for(i = 0; i < WD_GROUP_LAST; i++) {
  1629. field = wd_getgroupfield(arg, i);
  1630. /* append this value to the out string */
  1631. snprintf(value, sizeof(value), "%s%s",
  1632. field
  1633. ? field
  1634. : "",
  1635. WD_FIELD_SEPARATOR);
  1636. strncat(out, value, strlen(value));
  1637. if(field)
  1638. free(field);
  1639. }
  1640. /* chop off the last WD_FIELD_SEPARATOR */
  1641. length = strlen(out);
  1642. if(length > 0)
  1643. out[length - 1] = '\0';
  1644. /* send the account info */
  1645. wd_reply(601, out);
  1646. end:
  1647. /* clean up */
  1648. if(group)
  1649. free(group);
  1650. }
  1651. /*
  1652. READUSER <name>
  1653. */
  1654. void wd_cmd_readuser(char *arg) {
  1655. char *field, value[1024], out[1024];
  1656. char *user = NULL;
  1657. int i, length;
  1658. /* check for account */
  1659. user = wd_getuser(arg);
  1660. if(!user) {
  1661. wd_reply(513, "Account Not Found");
  1662. goto end;
  1663. }
  1664. memset(out, 0, sizeof(out));
  1665. /* get all the fields of the account */
  1666. for(i = 0; i < WD_USER_LAST; i++) {
  1667. field = wd_getuserfield(arg, i);
  1668. /* append this value to the out string */
  1669. snprintf(value, sizeof(value), "%s%s",
  1670. field
  1671. ? field
  1672. : "",
  1673. WD_FIELD_SEPARATOR);
  1674. strncat(out, value, strlen(value));
  1675. if(field)
  1676. free(field);
  1677. }
  1678. /* chop off the last WD_FIELD_SEPARATOR */
  1679. length = strlen(out);
  1680. if(length > 0)
  1681. out[length - 1] = '\0';
  1682. /* send the account info */
  1683. wd_reply(600, out);
  1684. end:
  1685. /* clean up */
  1686. if(user)
  1687. free(user);
  1688. }
  1689. /*
  1690. SAY <id> <chat>
  1691. */
  1692. void wd_cmd_say(char *arg) {
  1693. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1694. char *ap, *cid = NULL, *chat = NULL;
  1695. unsigned long cid_l;
  1696. int i = 0;
  1697. /* split the arguments */
  1698. while((ap = strsep(&arg, WD_FIELD_SEPARATOR)) != NULL) {
  1699. if(i == 0)
  1700. cid = strdup(ap);
  1701. else if(i == 1)
  1702. chat = strdup(ap);
  1703. i++;
  1704. }
  1705. /* make sure we got them all */
  1706. if(!cid || !chat) {
  1707. wd_reply(503, "Syntax Error");
  1708. goto end;
  1709. }
  1710. /* convert chat id */
  1711. cid_l = strtoul(cid, NULL, 10);
  1712. /* check if client is on chat */
  1713. if(wd_get_client(client->uid, cid_l) == NULL)
  1714. goto end;
  1715. /* split by newlines */
  1716. arg = chat;
  1717. while((ap = strsep(&arg, "\n\r"))) {
  1718. if(strlen(ap) > 0) {
  1719. pthread_mutex_lock(&(wd_chats.mutex));
  1720. wd_broadcast(cid_l, 300, "%lu%s%lu%s%s",
  1721. cid_l,
  1722. WD_FIELD_SEPARATOR,
  1723. client->uid,
  1724. WD_FIELD_SEPARATOR,
  1725. ap);
  1726. pthread_mutex_unlock(&(wd_chats.mutex));
  1727. /* hotline subsystem */
  1728. if(wd_frozen_settings.hotline && cid_l == 1)
  1729. wd_hl_relay_say(client->nick, ap);
  1730. }
  1731. }
  1732. end:
  1733. /* clean up */
  1734. if(cid)
  1735. free(cid);
  1736. if(chat)
  1737. free(chat);
  1738. }
  1739. /*
  1740. SEARCH <query>
  1741. */
  1742. void wd_cmd_search(char *arg) {
  1743. /* start search */
  1744. wd_search(".", arg, true);
  1745. }
  1746. /*
  1747. STAT <path>
  1748. */
  1749. void wd_cmd_stat(char *arg) {
  1750. /* verify the path */
  1751. if(wd_evaluate_path(arg) < 0) {
  1752. wd_reply(520, "File or Directory Not Found");
  1753. return;
  1754. }
  1755. /* request file information */
  1756. wd_stat_path(arg);
  1757. }
  1758. /*
  1759. USER <user>
  1760. */
  1761. void wd_cmd_user(char *arg) {
  1762. struct wd_client *client = (struct wd_client *) pthread_getspecific(wd_client_key);
  1763. if(client->state != WD_CLIENT_STATE_SAID_HELLO)
  1764. return;
  1765. /* copy login */
  1766. strlcpy(client->login, arg, sizeof(client->login));
  1767. /* set the username as nick if none else provided */
  1768. if(strlen(client->nick) == 0)
  1769. strlcpy(client->nick, client->login, sizeof(client->nick));
  1770. /* elevate state */
  1771. client->state = WD_CLIENT_STATE_GAVE_USER;
  1772. }
  1773. /*
  1774. USERS
  1775. */
  1776. void wd_cmd_users(char *arg) {
  1777. /* list users */
  1778. wd_list_users();
  1779. }
  1780. /*
  1781. WHO
  1782. */
  1783. void wd_cmd_who(char *arg) {
  1784. struct wd_list_node *chat_node, *client_node;
  1785. struct wd_chat *chat;
  1786. struct wd_client *client;
  1787. unsigned long cid;
  1788. /* convert argument */
  1789. cid = strtoul(arg, NULL, 10);
  1790. /* loop over all clients and reply 310 */
  1791. pthread_mutex_lock(&(wd_chats.mutex));
  1792. for(chat_node = wd_chats.first; chat_node != NULL; chat_node = chat_node->next) {
  1793. chat = chat_node->data;
  1794. if(chat->cid == cid) {
  1795. for(client_node = (chat->clients).first; client_node != NULL; client_node = client_node->next) {
  1796. client = client_node->data;
  1797. if(client->state == WD_CLIENT_STATE_LOGGED_IN) {
  1798. wd_reply(310, "%lu%s%lu%s%u%s%u%s%u%s%s%s%s%s%s%s%s",
  1799. cid,
  1800. WD_FIELD_SEPARATOR,
  1801. client->uid,
  1802. WD_FIELD_SEPARATOR,
  1803. client->idle,
  1804. WD_FIELD_SEPARATOR,
  1805. client->admin,
  1806. WD_FIELD_SEPARATOR,
  1807. client->icon,
  1808. WD_FIELD_SEPARATOR,
  1809. client->nick,
  1810. WD_FIELD_SEPARATOR,
  1811. client->login,
  1812. WD_FIELD_SEPARATOR,
  1813. client->ip,
  1814. WD_FIELD_SEPARATOR,
  1815. client->host);
  1816. }
  1817. }
  1818. break;
  1819. }
  1820. }
  1821. pthread_mutex_unlock(&(wd_chats.mutex));
  1822. /* hotline subsystem */
  1823. if(wd_frozen_settings.hotline)
  1824. wd_hl_who(cid);
  1825. /* reply end marker */
  1826. wd_reply(311, "%u", cid);
  1827. }