1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2004 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26
27 #include "wzd_all.h"
28
29 #ifndef WZD_USE_PCH
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #ifdef WIN32
39 #include <winsock2.h>
40 #include <process.h> /* _getpid() */
41 #include <direct.h> /* _rmdir() */
42 #include <sys/utime.h>
43 #else
44 #include <unistd.h>
45 #include <sys/resource.h>
46
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51
52 #include <utime.h>
53
54 #include <dirent.h> /* opendir, readdir, closedir */
55 #endif
56
57 #include <errno.h>
58 #include <signal.h>
59 #include <fcntl.h>
60
61 #include "wzd_structs.h"
62
63 #include "wzd_commands.h"
64 #include "wzd_log.h"
65 #include "wzd_misc.h"
66 #include "wzd_messages.h"
67 #include "wzd_site.h"
68 #include "wzd_site_group.h"
69 #include "wzd_site_user.h"
70 #include "wzd_vars.h"
71 #include "wzd_vfs.h"
72 #include "wzd_cache.h"
73 #include "wzd_configfile.h"
74 #include "wzd_events.h"
75 #include "wzd_file.h"
76 #include "wzd_fs.h"
77 #include "wzd_group.h"
78 #include "wzd_dir.h"
79 #include "wzd_mod.h"
80 #include "wzd_perm.h"
81 #include "wzd_tls.h"
82 #include "wzd_user.h"
83
84 #include <libwzd-auth/wzd_tls.h> /* XXX test only */
85
86 #include "wzd_debug.h"
87
88 #else /* WZD_USE_PCH */
89
90 #ifdef WIN32
91 # include <sys/utime.h>
92 #endif
93
94 #endif /* WZD_USE_PCH */
95
96 #include "wzd_version.h"
97
98 extern int serverstop;
99 extern time_t server_start;
100
101 #define BUFFER_LEN 4096
102
103 void do_site_print_file_raw(const char *filename, wzd_context_t *context);
104
105 /********************* do_site_test ************************/
106
do_site_test(wzd_string_t * command,wzd_string_t * param,wzd_context_t * context)107 int do_site_test(wzd_string_t *command, wzd_string_t *param, wzd_context_t * context)
108 {
109 int ret;
110
111 /* backend_commit_changes();*/
112 /*if (context->userinfo.flags)
113 out_err(LEVEL_CRITICAL,"FLAGS '%s'\n",context->userinfo.flags);*/
114 #if 0
115 {
116 wzd_sfv_file sfv;
117 char buffer[BUFFER_LEN];
118 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
119 if ( (ret = checkpath(command,buffer,context)) == 0 ) {
120 buffer[strlen(buffer)-1] = '\0'; /* remove '/', appended by checkpath */
121 sfv_init(&sfv);
122 ret = sfv_read(buffer,&sfv);
123 sfv_free(&sfv);
124 ret = sfv_check(buffer);
125 }
126 }
127 #endif
128 /* prints some stats */
129 out_err(LEVEL_INFO,"# Connections: %ld\n",mainConfig->stats.num_connections);
130 out_err(LEVEL_INFO,"# Childs : %ld\n",mainConfig->stats.num_childs);
131 ret = 0;
132
133 fd_dump();
134
135 #if 0
136 {
137 char buffer[WZD_MAX_PATH+1];
138 ret = checkpath_new(command, buffer, context);
139 if (!ret)
140 out_err(LEVEL_INFO,"[%s] => [%s]\n",command,buffer);
141 else
142 out_err(LEVEL_INFO,"[%s] : error %d\n",command,ret);
143 }
144 #endif
145
146 /* ret = module_unload(&mainConfig->module,command);*/
147
148 /* libtest(); ret = 0; */
149
150 #if 0
151 {
152 wzd_user_t *me = GetUserByID(context->userid);
153 ret = check_certificate(me->username,me->userpass);
154 }
155 #endif
156
157 #if 0
158 {
159 fs_dir_t * dir;
160 char buffer[WZD_MAX_PATH+1];
161 fs_fileinfo_t * finfo;
162
163 ret = checkpath_new(context->currentpath, buffer, context);
164
165 ret = fs_dir_open(buffer,&dir);
166
167 while (!ret) {
168 ret = fs_dir_read(dir,&finfo);
169 }
170
171 ret = fs_dir_close(dir);
172
173 ret = 0;
174 }
175 #endif
176
177 #ifdef HAVE_GNUTLS
178 ret = tls_dh_params_regenerate();
179 #endif
180
181 out_err(LEVEL_CRITICAL,"Ret: %d\n",ret);
182
183 /*
184 ret = send_message_with_args(200,context,"TEST command ok");
185 */
186
187 reply_push(context,"TEST command ok");
188 reply_set_code(context,200);
189 reply_send(context);
190
191 return 0;
192 }
193
194 /** Display generic help (controlled by the "help_file" config variable).
195 *
196 * If an argument is provided, the specific help function for this command is called. The help
197 * function must have been registered when calling \ref commands_add
198 */
do_site_help_command(wzd_string_t * command,wzd_string_t * command_line,wzd_context_t * context)199 int do_site_help_command(wzd_string_t *command, wzd_string_t *command_line, wzd_context_t * context)
200 {
201 wzd_string_t *argument, *str;
202 wzd_command_t * c;
203
204 argument = str_tok(command_line," \t\r\n");
205
206 if (argument) {
207 str_prepend(argument,"site_");
208 c = commands_find(mainConfig->commands_list,argument);
209 if (c == NULL) {
210 reply_push(context,"command does not exist");
211 reply_set_code(context,501);
212 return 0;
213 }
214
215 if (c->help_function == NULL) {
216 reply_push(context,"command does not provide help");
217 reply_set_code(context,200);
218 return 0;
219 }
220
221 return (c->help_function)(command,command_line,context);
222 }
223
224 /* generic help */
225 str = config_get_string(mainConfig->cfg_file,"GLOBAL","help_file",NULL);
226 if (str != NULL) {
227 do_site_print_file_raw(str_tochar(str),context);
228 str_deallocate(str);
229 return 0;
230 }
231
232 reply_push(context,"command ok");
233 reply_set_code(context,200);
234
235 return 0;
236 }
237
238 /********************* do_site_help ************************/
239
do_site_help(const char * site_command,wzd_context_t * context)240 void do_site_help(const char *site_command, wzd_context_t * context)
241 {
242 char buffer[BUFFER_LEN];
243
244 send_message_raw("501-\r\n",context);
245 if (strcasecmp(site_command,"backend")==0) {
246 send_message_raw("operations on backend\r\n",context);
247 send_message_raw("site backend command backend_name\r\n",context);
248 send_message_raw("command can be one of:\r\n",context);
249 send_message_raw(" close (unloads backend)\r\n",context);
250 send_message_raw(" commit (commits changes synchronously)\r\n",context);
251 send_message_raw(" init (loads new backend)\r\n",context);
252 send_message_raw(" reload (close and init)\r\n",context);
253 send_message_raw("\r\n",context);
254 send_message_raw("e.g: site backend commit plaintext\r\n",context);
255 send_message_raw("\r\n",context);
256 send_message_raw(" THIS IS A DANGEROUS COMMAND\r\n",context);
257 } else
258 if (strcasecmp(site_command,"checkperm")==0) {
259 send_message_raw("checks access for a user on a file/dir\r\n",context);
260 send_message_raw("site checkperm user file rights\r\n",context);
261 send_message_raw(" rights can be one of:\r\n",context);
262 send_message_raw(" RIGHT_LIST\r\n",context);
263 send_message_raw(" RIGHT_CWD\r\n",context);
264 send_message_raw(" RIGHT_RETR\r\n",context);
265 send_message_raw(" RIGHT_STOR\r\n",context);
266 send_message_raw(" RIGHT_RNFR\r\n",context);
267 send_message_raw("e.g: site checkperm toto dir RIGHT_CWD\r\n",context);
268 } else
269 if (strcasecmp(site_command,"chgrp")==0) {
270 send_message_raw("change the group of a file or directory\r\n",context);
271 send_message_raw("usage: site chgrp group file1 [file2 ...]\r\n",context);
272 send_message_raw("e.g: site chgrp admin file1\r\n",context);
273 } else
274 if (strcasecmp(site_command,"chmod")==0) {
275 send_message_raw("change permissions of a file or directory\r\n",context);
276 send_message_raw("usage: site chmod mode file1 [file2 ...]\r\n",context);
277 send_message_raw("e.g: site chmod 644 file1\r\n",context);
278 } else
279 if (strcasecmp(site_command,"chown")==0) {
280 send_message_raw("change the owner of a file or directory\r\n",context);
281 send_message_raw("usage: site chown user file1 [file2 ...]\r\n",context);
282 send_message_raw("e.g: site chown toto file1\r\n",context);
283 } else
284 if (strcasecmp(site_command,"chpass")==0) {
285 send_message_raw("change the password of a user\r\n",context);
286 send_message_raw("site chpass [user] new_pass\r\n",context);
287 } else
288 if (strcasecmp(site_command,"grpkill")==0) {
289 send_message_raw("kill all connected users from a group\r\n",context);
290 send_message_raw("site grpkill groupname\r\n",context);
291 } else
292 if (strcasecmp(site_command,"link")==0) {
293 send_message_raw("create/remove symbolink links\r\n",context);
294 send_message_raw("site link create dir linkname\r\n",context);
295 send_message_raw("site link remove linkname\r\n",context);
296 } else
297 if (strcasecmp(site_command,"msg")==0) {
298 send_message_raw("manage directory messages\r\n",context);
299 send_message_raw("site msg show\r\n",context);
300 send_message_raw("site msg new msg_line\r\n",context);
301 send_message_raw("site msg append msg_line\r\n",context);
302 send_message_raw("site msg convert file\r\n",context);
303 send_message_raw("site msg delete\r\n",context);
304 } else
305 if (strcasecmp(site_command,"perm")==0) {
306 send_message_raw("manage permissions\r\n",context);
307 send_message_raw("site perm show (show all permissions)\r\n",context);
308 send_message_raw("site perm show name (show permissions for commands starting with perm_name)\r\n",context);
309 send_message_raw("site perm add name perms\r\n",context);
310 send_message_raw("site perm change name perms\r\n",context);
311 send_message_raw("site perm remove\r\n",context);
312 send_message_raw("\r\n",context);
313 send_message_raw("ex: site perm add site_newcmd +O\r\n",context);
314 } else
315 if (strcasecmp(site_command,"user")==0) {
316 send_message_raw("show user info\r\n",context);
317 send_message_raw("site user username\r\n",context);
318 } else
319 if (strcasecmp(site_command,"vars")==0) {
320 send_message_raw("access server variables\r\n",context);
321 send_message_raw("site vars get varname\r\n",context);
322 } else
323 if (strcasecmp(site_command,"vars_user")==0) {
324 send_message_raw("access user variables\r\n",context);
325 send_message_raw("site vars_user get user varname\r\n",context);
326 } else
327 if (strcasecmp(site_command,"vars_group")==0) {
328 send_message_raw("access group variables\r\n",context);
329 send_message_raw("site vars_group get group varname\r\n",context);
330 } else
331 {
332 snprintf(buffer,BUFFER_LEN,"Syntax error in command %s\r\n",site_command);
333 send_message_raw(buffer,context);
334 }
335 send_message_raw("501 \r\n",context);
336 }
337
338 /********************* do_site_backend *********************/
339 /** backend: close / reload / init / commit
340 */
do_site_backend(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)341 int do_site_backend(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
342 {
343 wzd_string_t * command, *name;
344 int ret;
345
346 command = str_tok(command_line," \t\r\n");
347 if (!command) {
348 do_site_help("backend",context);
349 return 1;
350 }
351 name = str_tok(command_line," \t\r\n");
352 if (!name) {
353 do_site_help("backend",context);
354 str_deallocate(command);
355 return 1;
356 }
357 if (strcasecmp(str_tochar(command),"close")==0) {
358 str_deallocate(command);
359 ret = backend_close(str_tochar(name));
360 if (ret) {
361 ret = send_message_with_args(501,context,"Could not close backend");
362 } else {
363 ret = send_message_with_args(200,context,"Backend close successfully");
364 }
365 str_deallocate(name);
366 return 0;
367 } /* close */
368 if (strcasecmp(str_tochar(command),"init")==0) {
369 str_deallocate(command);
370 #if 0
371 ret = backend_init(str_tochar(name));
372 if (ret) {
373 ret = send_message_with_args(501,context,"Could not init backend");
374 } else {
375 ret = send_message_with_args(200,context,"Backend loaded successfully");
376 }
377 #endif
378 ret = send_message_with_args(501,context,"Not yet implemented");
379 str_deallocate(name);
380 return 0;
381 } /* init */
382 if (strcasecmp(str_tochar(command),"reload")==0) {
383 str_deallocate(command);
384 ret = backend_reload(str_tochar(name));
385 if (ret) {
386 ret = send_message_with_args(501,context,"Could not reload backend ** WARNING you could have NO backend NOW");
387 } else {
388 ret = send_message_with_args(200,context,"Backend reloaded successfully");
389 }
390 str_deallocate(name);
391 return 0;
392 } /* reload */
393 if (strcasecmp(str_tochar(command),"commit")==0) {
394 str_deallocate(command);
395 ret = backend_commit_changes(str_tochar(name));
396 if (ret) {
397 ret = send_message_with_args(501,context,"Could not commit backend");
398 } else {
399 ret = send_message_with_args(200,context,"Backend committed successfully");
400 }
401 str_deallocate(name);
402 return 0;
403 } /* commit */
404 do_site_help("backend",context);
405 str_deallocate(command);
406 str_deallocate(name);
407 return 0;
408 }
409
410 /********************* do_site_chacl ***********************/
411 /** chacl: user mode file1 [file2 ...]
412 */
413
do_site_chacl(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)414 int do_site_chacl(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
415 {
416 char buffer[BUFFER_LEN];
417 wzd_string_t * mode, *username, *filename;
418 int ret;
419 wzd_user_t * user;
420 unsigned long long_perms;
421 char str_perms[64];
422 char * endptr;
423
424 username = str_tok(command_line," \t\r\n");
425 if (!username) {
426 do_site_help("chacl",context);
427 return 1;
428 }
429 /* check that username exists */
430 user = GetUserByName( str_tochar(username) );
431 str_deallocate(username);
432 if ( !user ) {
433 ret = send_message_with_args(501,context,"User does not exist");
434 return 1;
435 }
436 mode = str_tok(command_line," \t\r\n");
437 if (!mode) {
438 do_site_help("chacl",context);
439 return 1;
440 }
441 /* TODO check that mode is ok */
442 if (strlen(str_tochar(mode)) > 15) {
443 do_site_help("chacl",context);
444 str_deallocate(mode);
445 return 1;
446 }
447 long_perms = strtoul(str_tochar(mode),&endptr,8);
448 if (endptr != str_tochar(mode)) {
449 snprintf(str_perms,63,"%c%c%c",
450 (long_perms & 01) ? 'r' : '-',
451 (long_perms & 02) ? 'w' : '-',
452 (long_perms & 04) ? 'x' : '-'
453 );
454 } else
455 strncpy(str_perms,str_tochar(mode),63);
456 str_deallocate(mode);
457
458 while ( (filename = str_tok(command_line," \t\r\n")) )
459 {
460 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
461 if (!checkpath(str_tochar(filename),buffer,context))
462 {
463 _setPerm(buffer,user->username,0,0,str_perms,(unsigned long)-1,context);
464 }
465 str_deallocate(filename);
466 }
467
468 snprintf(buffer,BUFFER_LEN,"acl successfully set");
469 ret = send_message_with_args(200,context,buffer);
470 return 0;
471 }
472
473 /********************* do_site_chgrp ***********************/
474 /** chgrp: group file1 [file2 ...]
475 */
476
do_site_chgrp(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)477 int do_site_chgrp(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
478 {
479 char * buffer;
480 wzd_string_t * groupname, *filename;
481 int ret;
482 wzd_group_t * group;
483
484 groupname = str_tok(command_line," \t\r\n");
485 if (!groupname) {
486 do_site_help("chgrp",context);
487 return 1;
488 }
489 /* check that groupname exists */
490 group=GetGroupByName(str_tochar(groupname));
491 if ( !group ) {
492 ret = send_message_with_args(501,context,"Group does not exist");
493 str_deallocate(groupname);
494 return 1;
495 }
496
497 buffer = malloc(WZD_MAX_PATH+1);
498
499 while ( (filename = str_tok(command_line," \t\r\n")) )
500 {
501 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
502 if (!checkpath(str_tochar(filename),buffer,context))
503 {
504 _setPerm(buffer,0,0,str_tochar(groupname),0,(unsigned long)-1,context);
505 }
506 str_deallocate(filename);
507 }
508
509 snprintf(buffer,WZD_MAX_PATH,"group changed to '%s'",str_tochar(groupname));
510 ret = send_message_with_args(200,context,buffer);
511
512 free(buffer);
513 str_deallocate(groupname);
514 return 0;
515 }
516
517 /********************* do_site_chmod ***********************/
518 /** chmod: mode file1 [file2 ...]
519 */
do_site_chmod(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)520 int do_site_chmod(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
521 {
522 char * buffer;
523 char * endptr;
524 const char * mode;
525 wzd_string_t * str_mode, *filename;
526 int ret;
527 unsigned long long_perms;
528
529 str_mode = str_tok(command_line," \t\r\n");
530 if (!str_mode) {
531 do_site_help("chmod",context);
532 return 1;
533 }
534 mode = str_tochar(str_mode);
535 /* TODO check that mode is ok */
536 if (strlen(mode) > 15) {
537 do_site_help("chmod",context);
538 str_deallocate(str_mode);
539 return 1;
540 }
541 long_perms = strtoul(mode,&endptr,8);
542
543 if (endptr == mode) {
544 unsigned short error = 0, i;
545 unsigned int mask = 1 << 8;
546 /* try to read perm in text mode ? */
547 long_perms = 0;
548 for (i = 0; i<3; i++) {
549 if (*mode == 'r') { long_perms += mask; }
550 else if (*mode != '-') { error = 1; break; }
551 mask >>= 1; mode++;
552 if (*mode == 'w') { long_perms += mask; }
553 else if (*mode != '-') { error = 1; break; }
554 mask >>= 1; mode++;
555 if (*mode == 'x') { long_perms += mask; }
556 else if (*mode != '-') { error = 1; break; }
557 mask >>= 1; mode++;
558 }
559
560 if (error) {
561 ret = send_message_with_args(501,context,"Invalid permission");
562 str_deallocate(str_mode);
563 return 0;
564 }
565 }
566 str_deallocate(str_mode);
567
568 buffer = malloc(WZD_MAX_PATH+1);
569
570 while ( (filename = str_tok(command_line," \t\r\n")) )
571 {
572 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
573 if (!checkpath_new(str_tochar(filename),buffer,context)) {
574 _setPerm(buffer,0,0,0,0,long_perms,context);
575 }
576 str_deallocate(filename);
577 }
578
579 snprintf(buffer,WZD_MAX_PATH,"mode changed to '%lo'",long_perms);
580 ret = send_message_with_args(200,context,buffer);
581
582 free(buffer);
583 return 0;
584 }
585
586 /********************* do_site_chown ***********************/
587 /** chown: user file1 [file2 ...]
588 */
589
do_site_chown(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)590 int do_site_chown(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
591 {
592 char * buffer;
593 wzd_string_t * username, *filename;
594 int ret;
595 wzd_user_t *user;
596
597 username = str_tok(command_line," \t\r\n");
598 if (!username) {
599 do_site_help("chown",context);
600 str_deallocate(username);
601 return 1;
602 }
603 /* check that username exists */
604 user = GetUserByName(str_tochar(username));
605 if ( !user ) {
606 ret = send_message_with_args(501,context,"User does not exist");
607 str_deallocate(username);
608 return 1;
609 }
610
611 buffer = malloc(WZD_MAX_PATH+1);
612
613 while ( (filename = str_tok(command_line," \t\r\n")) )
614 {
615 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
616 if (!checkpath_new(str_tochar(filename),buffer,context))
617 {
618 _setPerm(buffer,0,str_tochar(username),0,0,(unsigned long)-1,context);
619 }
620 str_deallocate(filename);
621 }
622
623 snprintf(buffer,WZD_MAX_PATH,"owner changed to '%s'",str_tochar(username));
624 ret = send_message_with_args(200,context,buffer);
625
626 free(buffer);
627 str_deallocate(username);
628 return 0;
629 }
630
631 /********************* do_site_chpass **********************/
632 /** chpass: [user] new_pass
633 * siteops can change everyones password
634 * gadmins can change the groups password
635 * everyone can change their own password
636 * noone can change a siteops password except himself
637 */
do_site_chpass(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)638 int do_site_chpass(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
639 {
640 wzd_string_t * username, *new_pass;
641 int ret;
642 wzd_user_t *user, *me;
643 short is_gadmin;
644 unsigned long mod_type;
645
646 me = GetUserByID(context->userid);
647 is_gadmin = (me->flags && strchr(me->flags,FLAG_GADMIN)) ? 1 : 0;
648
649 username = str_tok(command_line," \t\r\n");
650 if (!username) {
651 do_site_help("chpass",context);
652 return 1;
653 }
654 new_pass = str_tok(command_line," \t\r\n");
655 if (!new_pass) { /* assume changing own password */
656 new_pass = username;
657 username = NULL;
658 user = me;
659 }
660 else {
661 /* check that username exists */
662 user = GetUserByName(str_tochar(username));
663 str_deallocate(username);
664 username = NULL;
665 if ( !user ) {
666 ret = send_message_with_args(501,context,"User does not exist");
667 str_deallocate(username); str_deallocate(new_pass);
668 return 1;
669 }
670 }
671
672 /* GAdmin ? */
673 if (is_gadmin)
674 {
675 if (me->group_num==0 || user->group_num==0 || me->groups[0]!=user->groups[0]) {
676 ret = send_message_with_args(501,context,"You can't change this user");
677 str_deallocate(username); str_deallocate(new_pass);
678 return 1;
679 }
680 }
681 else {
682 if ( !(me->flags && strchr(me->flags,FLAG_SITEOP))
683 && me->uid != user->uid )
684 {
685 ret = send_message_with_args(501,context,"You can't change password for other users");
686 str_deallocate(username); str_deallocate(new_pass);
687 return 1;
688 }
689 }
690 if ( (user->flags && strchr(user->flags,FLAG_SITEOP))
691 && me->uid != user->uid )
692 {
693 ret = send_message_with_args(501,context,"You can't change password for a siteop");
694 str_deallocate(username); str_deallocate(new_pass);
695 return 1;
696 }
697
698 mod_type = _USER_USERPASS;
699 strncpy(user->userpass,str_tochar(new_pass),sizeof(user->userpass));
700 str_deallocate(new_pass);
701
702 /* commit to backend */
703 ret = backend_mod_user(mainConfig->backends->filename,user->uid,user,mod_type);
704
705 if (ret)
706 ret = send_message_with_args(501,context,"An error occurred during password change");
707 else
708 ret = send_message_with_args(200,context,"Password changed");
709 return 0;
710 }
711
712 /********************* do_site_checkperm *******************/
do_site_checkperm(UNUSED wzd_string_t * ignored,wzd_string_t * commandline,wzd_context_t * context)713 int do_site_checkperm(UNUSED wzd_string_t *ignored, wzd_string_t * commandline, wzd_context_t * context)
714 {
715 unsigned long word;
716 char * buffer;
717 wzd_string_t *username, *filename, *perms;
718 wzd_user_t *user;
719
720 username = str_tok(commandline," \t\r\n");
721 if (!username) { do_site_help("checkperm",context); return 1; }
722 filename = str_tok(commandline," \t\r\n");
723 if (!filename) {
724 str_deallocate(username);
725 do_site_help("checkperm",context);
726 return 1;
727 }
728 perms = str_tok(commandline,"\r\n");
729 if (!perms) {
730 str_deallocate(username); str_deallocate(filename);
731 do_site_help("checkperm",context);
732 return 1;
733 }
734
735 word = right_text2word(str_tochar(perms));
736 str_deallocate(perms);
737 if (word == 0) {
738 str_deallocate(username); str_deallocate(filename);
739 send_message_with_args(501,context,"Invalid permission");
740 return 1;
741 }
742
743 user = GetUserByName(str_tochar(username));
744 str_deallocate(username);
745 if ( !user ) {
746 str_deallocate(filename);
747 send_message_with_args(501,context,"User does not exist");
748 return 1;
749 }
750
751 buffer = malloc(WZD_MAX_PATH+1);
752
753 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
754 if (checkpath(str_tochar(filename),buffer,context)) {
755 send_message_with_args(501,context,"File does not exist");
756 str_deallocate(filename);
757 free(buffer);
758 return 1;
759 }
760 str_deallocate(filename);
761
762 /* buffer[strlen(buffer)-1] = '\0';*/ /* remove '/', appended by checkpath */
763
764 if (_checkPerm(buffer,word,user)==0) {
765 wzd_strncpy(buffer,"Right okay",WZD_MAX_PATH);
766 } else {
767 wzd_strncpy(buffer,"Refused",WZD_MAX_PATH);
768 }
769
770 send_message_with_args(200,context,buffer);
771 free(buffer);
772 return 0;
773 }
774
775 /********************* do_site_free ************************/
776 /** free sectionname
777 */
778
do_site_free(UNUSED wzd_string_t * ignored,UNUSED wzd_string_t * param,wzd_context_t * context)779 int do_site_free(UNUSED wzd_string_t *ignored, UNUSED wzd_string_t *param, wzd_context_t * context)
780 {
781 char * buffer;
782 int ret;
783 /* char * ptr;
784 char * sectionname;
785 wzd_user_t user;
786 int uid;
787 wzd_context_t user_context;*/
788 long f_type, f_bsize, f_blocks, f_free;
789 float freeb,totalb;
790 char unit;
791
792 /* ptr = command_line;
793 username = strtok_r(command_line," \t\r\n",&ptr);
794 if (!username) {
795 do_site_help("user",context);
796 return;
797 }*/
798
799 buffer = malloc(WZD_MAX_PATH+1);
800
801 if (checkpath_new(".",buffer,context)) {
802 send_message_with_args(501,context,". does not exist?!");
803 free(buffer);
804 return -1;
805 }
806
807 ret = get_device_info(buffer,&f_type, &f_bsize, &f_blocks, &f_free);
808
809 unit='k';
810 freeb = f_free*(f_bsize/1024.f);
811 totalb = f_blocks*(f_bsize/1024.f);
812
813 if (totalb > 1000.f) {
814 unit='M';
815 freeb /= 1024.f;
816 totalb /= 1024.f;
817 }
818 if (totalb > 1000.f) {
819 unit='G';
820 freeb /= 1024.f;
821 totalb /= 1024.f;
822 }
823
824 snprintf(buffer,WZD_MAX_PATH,"[FREE] + [current dir: %.2f / %.2f %c] -",freeb,totalb,unit);
825
826 ret = send_message_with_args(200,context,buffer);
827
828 free(buffer);
829 return 0;
830 }
831
832 /********************* do_site_invite **********************/
833 /** invite: ircnick
834 */
do_site_invite(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)835 int do_site_invite(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
836 {
837 wzd_string_t * ircnick;
838 int ret;
839 wzd_user_t *user;
840 wzd_group_t *group;
841 char buffer[2048], path[2048];
842
843 ircnick = str_tok(command_line," \t\r\n");
844 if (!ircnick) {
845 do_site_help("invite",context);
846 return 1;
847 }
848 /* TODO check that user is allowed to be invited ? */
849 user = GetUserByID(context->userid);
850 group = GetGroupByID(user->groups[0]);
851
852 strncpy(buffer,context->currentpath,sizeof(buffer));
853 stripdir(buffer,path,2047);
854
855 log_message("INVITE","\"%s\" \"%s\" \"%s\" \"%s\"",
856 path, /* ftp-absolute path */
857 user->username,
858 (group->groupname)?group->groupname:"No Group",
859 str_tochar(ircnick));
860
861 ret = send_message_with_args(200,context,"SITE INVITE command okay");
862 str_deallocate(ircnick);
863 return 0;
864 }
865
866 /********************* do_site_link ************************/
867 /** link: create dir linkname
868 * link: remove linkname
869 */
870
do_site_link(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)871 int do_site_link(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
872 {
873 char buffer_dir[BUFFER_LEN], buffer_link[BUFFER_LEN];
874 wzd_string_t * dirname, *linkname;
875 wzd_string_t * command;
876 int ret;
877
878 command = str_read_token(command_line);
879 if (!command) {
880 do_site_help("link",context);
881 return 1;
882 }
883 dirname = str_read_token(command_line);
884 if (!dirname) {
885 do_site_help("link",context);
886 str_deallocate(command);
887 return 1;
888 }
889
890 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
891 if (checkpath_new(str_tochar(dirname),buffer_dir,context)) {
892 ret = send_message_with_args(501,context,"Dirname is invalid");
893 str_deallocate(command); str_deallocate(dirname);
894 return 0;
895 }
896 str_deallocate(dirname);
897 /* remove the last slash */
898 if(buffer_dir[strlen(buffer_dir)-1]=='/') buffer_dir[strlen(buffer_dir)-1]=0;
899
900 if (strcasecmp(str_tochar(command),"CREATE")==0)
901 {
902 linkname = str_read_token(command_line);
903 if (!linkname) {
904 do_site_help("link",context);
905 str_deallocate(command);
906 str_deallocate(linkname);
907 return 1;
908 }
909 if ( (ret = checkpath_new(str_tochar(linkname),buffer_link,context) ) && ret != E_FILE_NOEXIST) { /* of course it returns no_exist */
910 ret = send_message_with_args(501,context,"Linkname is invalid");
911 str_deallocate(command);
912 str_deallocate(linkname);
913 return 0;
914 }
915 str_deallocate(linkname);
916 if(buffer_link[strlen(buffer_link)-1]=='/') buffer_link[strlen(buffer_link)-1]=0;
917
918 ret = symlink_create(buffer_dir, buffer_link);
919 }
920 else if (strcasecmp(str_tochar(command),"REMOVE")==0)
921 {
922 ret = symlink_remove(buffer_dir);
923 }
924 else {
925 do_site_help("link",context);
926 str_deallocate(command);
927 return 1;
928 }
929
930 ret ? send_message_with_args(501,context,"Command failed") : send_message_with_args(200,context,"Command okay");
931 str_deallocate(command);
932
933 return 0;
934 }
935
936
937 /********************* do_site_msg *************************/
938 /** msg: show
939 * new msg_line
940 * append msg_line
941 * convert filename
942 * delete
943 */
do_site_msg(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)944 int do_site_msg(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
945 {
946 /* int ret;*/
947 wzd_string_t * command, * filename;
948 char msg_file[2048];
949 char other_file[2048];
950 unsigned int length;
951 fs_filestat_t s;
952
953 if (!mainConfig->dir_message) {
954 send_message_with_args(501,context,"No dir_message defined in config");
955 return 1;
956 }
957
958 if (checkpath_new(".",msg_file,context)) {
959 send_message_with_args(501,context,". does not exist?!");
960 return 1;
961 } else {
962 length = strlen(msg_file);
963 if (msg_file[length-1] != '/') msg_file[length++] = '/'; /** \bug now we are _sure_ that checkpath_new appends a / so we can remove check ? */
964 strncpy(other_file,msg_file,2048);
965 strncpy(msg_file+length,mainConfig->dir_message,2048-length-1);
966 }
967
968 command = str_tok(command_line," \t\r\n");
969 if (!command) {
970 do_site_help("msg",context);
971 return 1;
972 }
973
974 if (strcasecmp(str_tochar(command),"show")==0)
975 {
976 str_deallocate(command);
977 do_site_print_file_raw(msg_file,context);
978 return 0;
979 }
980 else if (strcasecmp(str_tochar(command),"convert")==0)
981 {
982 str_deallocate(command);
983 filename = str_tok(command_line,"\r\n");
984 if (!filename) {
985 do_site_help("msg",context);
986 return 1;
987 }
988 strncpy(other_file+length,str_tochar(filename),2048-length-1);
989 str_deallocate(filename);
990 if (fs_file_stat(other_file,&s) || !S_ISREG(s.mode))
991 {
992 send_message_with_args(501,context,"Inexistant file, or not a regular file");
993 return -1;
994 }
995 unlink(msg_file);
996 if (!safe_rename(other_file,msg_file))
997 {
998 send_message_with_args(200,context,"Message file loaded");
999 return 0;
1000 }
1001 send_message_with_args(501,context,"Error while renaming file");
1002 return -1;
1003 }
1004 else if (strcasecmp(str_tochar(command),"delete")==0)
1005 {
1006 str_deallocate(command);
1007 unlink(msg_file);
1008 send_message_with_args(200,context,"Message file deleted");
1009 return 0;
1010 }
1011 else if (strcasecmp(str_tochar(command),"new")==0)
1012 {
1013 FILE * fp;
1014 wzd_string_t * buf;
1015 unsigned int length;
1016
1017 str_deallocate(command);
1018 fp = fopen(msg_file,"w");
1019 if (!fp) {
1020 send_message_with_args(501,context,"Unable to open message file for writing");
1021 return 1;
1022 }
1023 buf = str_tok(command_line,"\r\n");
1024 if (!buf) {
1025 fclose(fp);
1026 do_site_help("msg",context);
1027 return 1;
1028 }
1029 length = strlen(str_tochar(buf));
1030 if (length != fwrite(str_tochar(buf),1,length,fp)) {
1031 fclose(fp);
1032 send_message_with_args(501,context,"Unable to write message");
1033 str_deallocate(buf);
1034 return 1;
1035 }
1036 fclose(fp);
1037 send_message_with_args(200,context,"Message file written");
1038 str_deallocate(buf);
1039 return 0;
1040 }
1041 else if (strcasecmp(str_tochar(command),"append")==0)
1042 {
1043 FILE * fp;
1044 wzd_string_t * buf;
1045 unsigned int length;
1046
1047 str_deallocate(command);
1048 fp = fopen(msg_file,"a");
1049 if (!fp) {
1050 send_message_with_args(501,context,"Unable to open message file for writing");
1051 return 1;
1052 }
1053 buf = str_tok(command_line,"\r\n");
1054 if (!buf) {
1055 fclose(fp);
1056 do_site_help("msg",context);
1057 return 1;
1058 }
1059 length = strlen(str_tochar(buf));
1060 if (length != fwrite(str_tochar(buf),1,length,fp)) {
1061 fclose(fp);
1062 send_message_with_args(501,context,"Unable to write message");
1063 str_deallocate(buf);
1064 return 1;
1065 }
1066 fclose(fp);
1067 send_message_with_args(200,context,"Message file written");
1068 str_deallocate(buf);
1069 return 0;
1070 }
1071
1072 do_site_help("msg",context);
1073 str_deallocate(command);
1074 return 0;
1075 }
1076
subcmp(const char * string,const char * substring)1077 static int subcmp(const char * string, const char * substring)
1078 {
1079 return strncasecmp(string,substring,strlen(substring));
1080 }
1081
1082
1083
1084 /********************* do_site_perm ************************/
1085 /** perm: show (show all permissions)
1086 * show perm_name (show permissions for all commands starting with perm_name)
1087 * add perm_name perms
1088 * change perm_name perms
1089 * remove perm_name
1090 * XXX FIXME sort perms before sending !
1091 */
do_site_perm(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1092 int do_site_perm(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
1093 {
1094 /* int ret;*/
1095 wzd_string_t * command_name, * perm_name, * ptr;
1096 char perm_buffer[256];
1097 char buffer[2048];
1098 wzd_command_t * command;
1099 int ret;
1100
1101 command_name = str_tok(command_line," \t\r\n");
1102 if (!command_name) {
1103 do_site_help("perm",context);
1104 return 1;
1105 }
1106 perm_name = str_tok(command_line," \t\r\n");
1107
1108 if (strcasecmp(str_tochar(command_name),"show")==0)
1109 {
1110 str_deallocate(command_name);
1111 send_message_raw("200-\r\n",context);
1112 if ( !perm_name ) {
1113 /* no argument: print all perms */
1114 List * list;
1115 ListElmt * elmnt;
1116
1117 list = chtbl_extract(mainConfig->commands_list, NULL, NULL, (cmp_function)strcmp);
1118
1119 if (list) {
1120 for (elmnt=list_head(list); elmnt; elmnt=list_next(elmnt)) {
1121 command = list_data(elmnt);
1122 if (command && !perm2str(command->perms,perm_buffer,sizeof(perm_buffer)) ) {
1123 snprintf( buffer, sizeof(buffer), " %s%s\r\n", command->name, perm_buffer);
1124 send_message_raw(buffer,context);
1125 }
1126 }
1127 list_destroy(list);
1128 free(list);
1129 }
1130 } else {
1131 /* search on perms name */
1132 int found=0;
1133 List * list;
1134 ListElmt * elmnt;
1135
1136 list = chtbl_extract(mainConfig->commands_list, (cmp_function)subcmp, str_tochar(perm_name), (cmp_function)strcmp);
1137
1138 if (list) {
1139 if (list_size(list)>0) found=1;
1140 for (elmnt=list_head(list); elmnt; elmnt=list_next(elmnt)) {
1141 command = list_data(elmnt);
1142 if (command && !perm2str(command->perms,perm_buffer,sizeof(perm_buffer)) ) {
1143 snprintf( buffer, sizeof(buffer), " %s%s\r\n", command->name, perm_buffer);
1144 send_message_raw(buffer,context);
1145 }
1146 }
1147 list_destroy(list);
1148 free(list);
1149 }
1150 if (!found)
1151 send_message_raw(" permission not found\r\n",context);
1152 str_deallocate(perm_name);
1153 }
1154 send_message_raw("200 \r\n",context);
1155 return 0;
1156 }
1157 else if (strcasecmp(str_tochar(command_name),"change")==0)
1158 {
1159 str_deallocate(command_name);
1160 ptr = str_tok(command_line,"\r\n");
1161 if (!perm_name || !ptr) {
1162 do_site_help("perm",context);
1163 str_deallocate(perm_name);
1164 return 1;
1165 }
1166
1167 ret = commands_set_permission(mainConfig->commands_list,str_tochar(perm_name),str_tochar(ptr));
1168
1169 str_deallocate(perm_name);
1170 str_deallocate(ptr);
1171 if (ret) {send_message_with_args(501,context,"Error changing permission"); return 1; }
1172 send_message_with_args(200,context,"Command okay, permission changed");
1173 return -1;
1174 }
1175 else if (strcasecmp(str_tochar(command_name),"remove")==0)
1176 {
1177 str_deallocate(command_name);
1178 if (!perm_name) {
1179 do_site_help("perm",context);
1180 return 1;
1181 }
1182 if ( commands_delete_permission(mainConfig->commands_list,perm_name) )
1183 send_message_with_args(501,context,"Error, permission NOT deleted");
1184 else
1185 send_message_with_args(200,context,"Command okay, permission deleted");
1186 str_deallocate(perm_name);
1187 return 0;
1188 }
1189 else if (strcasecmp(str_tochar(command_name),"add")==0)
1190 {
1191 str_deallocate(command_name);
1192 ptr = str_tok(command_line,"\r\n");
1193 if (!perm_name || !ptr) {
1194 do_site_help("perm",context);
1195 str_deallocate(perm_name); str_deallocate(ptr);
1196 return 1;
1197 }
1198
1199 ret = commands_add_permission(mainConfig->commands_list,str_tochar(perm_name),str_tochar(ptr));
1200
1201 str_deallocate(perm_name);
1202 str_deallocate(ptr);
1203 if (ret) {send_message_with_args(501,context,"Error adding permission"); return 1; }
1204 send_message_with_args(200,context,"Command okay, permission changed");
1205 return 0;
1206 }
1207
1208 do_site_help("perm",context);
1209 str_deallocate(command_name);
1210 str_deallocate(perm_name);
1211 return 0;
1212 }
1213
1214
1215 /********************* do_site_print_file ******************/
1216 /** Print filename to control connection. Cookies are replaced as usual.
1217 */
do_site_print_file(const char * filename,wzd_user_t * user,wzd_group_t * group,wzd_context_t * context)1218 void do_site_print_file(const char *filename, wzd_user_t *user, wzd_group_t *group, wzd_context_t *context)
1219 {
1220 wzd_cache_t * fp;
1221 char * file_buffer;
1222 unsigned int size, filesize;
1223 u64_t sz64;
1224 fp = wzd_cache_open(filename,O_RDONLY,0644);
1225 if (!fp) {
1226 send_message_with_args(501,context,"Inexistant file");
1227 return;
1228 }
1229 sz64 = wzd_cache_getsize(fp);
1230 if (sz64 > INT_MAX) {
1231 out_log(LEVEL_HIGH,"%s:%d couldn't allocate %" PRIu64 "bytes for file %s\n",__FILE__,__LINE__,sz64,filename);
1232 wzd_cache_close(fp);
1233 send_message_with_args(501,context,"Internal error (see log)");
1234 return;
1235 }
1236 filesize = (unsigned int)sz64;
1237 file_buffer = malloc(filesize+1);
1238 if ( (size=wzd_cache_read(fp,file_buffer,filesize))!=filesize )
1239 {
1240 out_err(LEVEL_HIGH,"Could not read file %s read %u instead of %u (%s:%d)\n",filename,size,filesize,__FILE__,__LINE__);
1241 free(file_buffer);
1242 wzd_cache_close(fp);
1243 send_message_with_args(501,context,"Internal error (see log)");
1244 return;
1245 }
1246 file_buffer[filesize]='\0';
1247
1248 /* send header */
1249 send_message_raw("200-\r\n",context);
1250
1251 cookie_parse_buffer(file_buffer,user,group,context,NULL,0);
1252
1253 wzd_cache_close(fp);
1254
1255 send_message_raw("200 \r\n",context);
1256
1257 free(file_buffer);
1258 }
1259
1260 /********************* do_site_print_file_raw **************/
1261 /** Print filename to control connection, without replacing cookies.
1262 */
do_site_print_file_raw(const char * filename,wzd_context_t * context)1263 void do_site_print_file_raw(const char *filename, wzd_context_t *context)
1264 {
1265 wzd_cache_t * fp;
1266 char buffer[1024];
1267 unsigned int length;
1268
1269 fp = wzd_cache_open(filename,O_RDONLY,0644);
1270 if (!fp) {
1271 send_message_with_args(501,context,"Inexistant file");
1272 return;
1273 }
1274
1275 /* send header */
1276 send_message_raw("200--\r\n",context);
1277
1278 strncpy(buffer,"200-",5);
1279 while (wzd_cache_gets(fp, buffer+4, sizeof(buffer)-8))
1280 {
1281 chop(buffer);
1282 length = strlen(buffer);
1283 buffer[length ] = '\r';
1284 buffer[length+1] = '\n';
1285 buffer[length+2] = '\0';
1286 send_message_raw(buffer,context);
1287 }
1288
1289 wzd_cache_close(fp);
1290
1291 send_message_raw("200 -\r\n",context);
1292 }
1293
1294 /********************* do_site_reload **********************/
1295
do_site_reload(UNUSED wzd_string_t * ignored,UNUSED wzd_string_t * param,wzd_context_t * context)1296 int do_site_reload(UNUSED wzd_string_t * ignored, UNUSED wzd_string_t *param, wzd_context_t * context)
1297 {
1298 int ret;
1299 pid_t pid;
1300 #ifndef WIN32
1301 char buffer[256];
1302 #endif
1303
1304 #ifdef WZD_MULTIPROCESS
1305 pid = getppid();
1306 #else
1307 pid = getpid();
1308 #endif
1309 if (pid <2) {
1310 ret = send_message_with_args(501,context,"ARG! Getting invalid pid?!");
1311 return 1;
1312 }
1313 out_log(LEVEL_CRITICAL,"Target pid: %d\n",pid);
1314
1315 #ifndef WIN32
1316 ret = send_message_raw("200-Sending SIGHUP to main server, waiting for result\r\n",context);
1317 ret = kill(pid,SIGHUP);
1318 if (ret)
1319 snprintf(buffer,255,"200 ERROR kill returned %d (%s)\r\n",ret,strerror(errno));
1320 else
1321 snprintf(buffer,255,"200 kill returned ok\r\n");
1322 ret = send_message_raw(buffer,context);
1323 #else
1324 /* FIXME VISUAL : call server_restart explicitely ? */
1325 /*ret = send_message_with_args(501,context,"kill(getpid(),SIGHUP) not supported on visual ...");*/
1326 ret = send_message_with_args(501, context, "Restarting server, cross your fingers...");
1327 server_restart(SIGHUP);
1328 return 1;
1329 #endif
1330 return 0;
1331 }
1332
1333 /********************* do_site_rusage **********************/
1334
do_site_rusage(UNUSED wzd_string_t * ignored,UNUSED wzd_string_t * param,wzd_context_t * context)1335 int do_site_rusage(UNUSED wzd_string_t * ignored, UNUSED wzd_string_t *param, wzd_context_t * context)
1336 {
1337 #ifndef WIN32
1338 int ret=0;
1339 char buffer[256];
1340 struct rusage ru;
1341 struct rlimit rlim;
1342
1343 send_message_raw("200-\r\n",context);
1344
1345 if (getrusage(RUSAGE_SELF,&ru)<0)
1346 {
1347 ret=errno; /* save errno value */
1348 send_message_raw("200- getrusage() failed !\r\n",context);
1349 snprintf(buffer,255,"200-errno: %d (%s)\r\n",ret,strerror(ret));
1350 send_message_raw(buffer,context);
1351 send_message_raw("200 \r\n",context);
1352 return 0;
1353 }
1354 send_message_raw("200- Ressources used for wzdftpd:\r\n",context);
1355 sprintf(buffer,"200- user time used: %ld s %ld ms\r\n",ru.ru_utime.tv_sec,ru.ru_utime.tv_usec/1000);
1356 send_message_raw(buffer,context);
1357 sprintf(buffer,"200- system time used: %ld s %ld ms\r\n",ru.ru_stime.tv_sec,ru.ru_stime.tv_usec/1000);
1358 send_message_raw(buffer,context);
1359 /* system time used */
1360 /* maximum resident set size */
1361 /* integral shared memory size */
1362 /* integral unshared data size */
1363 /* integral unshared stack size */
1364 /* page reclaims */
1365 /* page faults */
1366 /* swaps */
1367 /* block input operations */
1368 /* block output operations */
1369 /* messages sent */
1370 /* messages received */
1371 /* signals received */
1372 /* voluntary context switches */
1373 /* involuntary context switches */
1374
1375 /* Number of opened files:
1376 * LINUX: read directory /proc/`getpid()`/fd/
1377 * contains symlinks, destination is file
1378 */
1379 #ifdef __linux__
1380 {
1381 char dirname[256], buflink[256];
1382 unsigned int childs[256];
1383 unsigned int child;
1384 pid_t mother;
1385 DIR * d;
1386 struct dirent *dent;
1387 int count, rdi, fdcount;
1388
1389 send_message_raw("200- LINUX specific:\r\n",context);
1390 mother = getpid();
1391 sprintf(buffer,"200- mother pid: %ld\r\n",(long)mother);
1392 send_message_raw(buffer,context);
1393
1394 /* searching for child threads */
1395 count = 0;
1396 snprintf(dirname,sizeof(dirname),"/proc/%ld/task",(long)mother); /** \todo XXX 2.6 specific ? */
1397 d = opendir(dirname);
1398 if (d) {
1399 while ( (dent = readdir(d)) ) {
1400 if (dent->d_name[0] == '.') continue;
1401 child = atoi(dent->d_name);
1402 childs[count] = child;
1403 count ++;
1404 sprintf(buffer,"200- |-> child pid: %s\r\n",dent->d_name);
1405 send_message_raw(buffer,context);
1406 }
1407 closedir(d);
1408 }
1409
1410 sprintf(buffer,"200- resources for: %d\r\n",mother);
1411 send_message_raw(buffer,context);
1412 snprintf(dirname,sizeof(dirname),"/proc/%d/task/%d/fd",mother,mother); /** \todo XXX 2.6 specific ? */
1413 d = opendir(dirname);
1414 if (d) {
1415 fdcount = 0;
1416 while ( (dent = readdir(d)) ) {
1417 if (dent->d_name[0] == '.') continue;
1418 fdcount ++;
1419 snprintf(dirname,sizeof(dirname),"/proc/%d/task/%d/fd/%s",mother,mother,dent->d_name); /** \todo XXX 2.6 specific ? */
1420 rdi = readlink(dirname,buflink,sizeof(buflink));
1421 if (rdi > 0) {
1422 buflink[rdi] = '\0';
1423 sprintf(buffer,"200- |-> %s -> %s\r\n",dent->d_name,buflink);
1424 send_message_raw(buffer,context);
1425 }
1426 }
1427 closedir(d);
1428
1429 sprintf(buffer,"200- number of open files: %d\r\n",fdcount);
1430 send_message_raw(buffer,context);
1431 }
1432 }
1433 #endif /* __linux__ */
1434
1435 if (getrlimit(RLIMIT_NOFILE,&rlim)<0) {
1436 send_message_raw("200- getrlimit(RLIMIT_NOFILE) failed !\r\n",context);
1437 snprintf(buffer,255,"200-errno: %d (%s)\r\n",ret,strerror(ret));
1438 send_message_raw(buffer,context);
1439 send_message_raw("200 \r\n",context);
1440 return 0;
1441 }
1442
1443 send_message_raw("200- LIMITS:\r\n",context);
1444 sprintf(buffer,"200- number of open files: %ld ; max: %ld\r\n",(long)rlim.rlim_cur,(long)rlim.rlim_max);
1445 send_message_raw(buffer,context);
1446
1447 send_message_raw("200 \r\n",context);
1448 #else /* _MSC_VER */
1449 send_message_with_args(501,context,"Can't be implemented on win32!");
1450 #endif /* _MSC_VER */
1451 return 0;
1452 }
1453
1454 /********************* do_site_savecfg *********************/
do_site_savecfg(UNUSED wzd_string_t * ignored,UNUSED wzd_string_t * command_line,wzd_context_t * context)1455 int do_site_savecfg(UNUSED wzd_string_t *ignored, UNUSED wzd_string_t *command_line, wzd_context_t * context)
1456 {
1457 wzd_string_t * data = NULL;
1458 size_t length = 0, written;
1459 int fd;
1460 int do_backup;
1461 int err = 0;
1462
1463 do_backup = config_get_boolean(mainConfig->cfg_file, "GLOBAL", "backup config", &err);
1464 if (err == CF_ERROR_NOT_FOUND) do_backup = 0; /* default: no backup */
1465 else if (err != CF_OK) {
1466 out_log(LEVEL_HIGH,"ERROR Could not save config (error while getting option 'backup config')\n");
1467 send_message_with_args(501,context,"Cannot save server config");
1468 return -1;
1469 }
1470
1471 if (do_backup)
1472 {
1473 int backup_fd;
1474 char buffer[1024];
1475 ssize_t ret;
1476 char * filename = NULL;
1477 size_t name_length;
1478
1479 name_length = strlen(mainConfig->config_filename);
1480 filename = malloc(name_length + 6);
1481 snprintf(filename,name_length+5,"%s.old",mainConfig->config_filename);
1482 out_log(LEVEL_FLOOD,"DEBUG Config file saved to [%s]\n",filename);
1483
1484 fd = open(mainConfig->config_filename, O_RDONLY, 0644);
1485 backup_fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC, 0644);
1486 if (fd < 0 || backup_fd < 0) {
1487 out_log(LEVEL_HIGH,"ERROR Could not save config (error when opening files)\n");
1488 send_message_with_args(501,context,"Cannot save server config");
1489 close(fd);
1490 close(backup_fd);
1491 return -1;
1492 }
1493 while ((ret = read(fd,buffer,sizeof(buffer))) > 0) {
1494 write(backup_fd,buffer,ret);
1495 }
1496 close(fd);
1497 close(backup_fd);
1498 }
1499
1500 out_log(LEVEL_NORMAL,"INFO saving config to %s\n",mainConfig->config_filename);
1501
1502 fd = open(mainConfig->config_filename, O_WRONLY | O_TRUNC, 0644); /** XXX file mode is hardcoded */
1503 if (fd < 0) {
1504 out_log(LEVEL_HIGH,"ERROR Could not save config (error while creating a temporary file: %d: %s)\n",errno,strerror(errno));
1505 send_message_with_args(501,context,"Cannot save server config");
1506 return -1;
1507 }
1508
1509 data = config_to_data(mainConfig->cfg_file,&length);
1510
1511 if (data == NULL) {
1512 out_log(LEVEL_HIGH,"ERROR Could not save config (error in config_to_data)\n");
1513 send_message_with_args(501,context,"Cannot save server config");
1514 close(fd);
1515 return -1;
1516 }
1517
1518 written = write(fd, str_tochar(data), length);
1519 if (written != length) {
1520 out_log(LEVEL_HIGH,"ERROR Could not save config (written %ld bytes instead of %ld\n",(long)written,(long)length);
1521 }
1522 close(fd);
1523
1524 send_message_with_args(200,context,"Server config saved");
1525
1526 str_deallocate(data);
1527 return 0;
1528 }
1529
1530 /********************* do_site_sections ******************/
1531 /** Print all sections
1532 */
do_site_sections(UNUSED wzd_string_t * ignored,UNUSED wzd_string_t * param,wzd_context_t * context)1533 int do_site_sections(UNUSED wzd_string_t *ignored, UNUSED wzd_string_t *param, wzd_context_t * context)
1534 {
1535 wzd_section_t * section;
1536 wzd_string_t * buffer = str_allocate();
1537
1538 /* send header */
1539 send_message_raw("200-\r\n",context);
1540 send_message_raw(" NAME MASK REGEX\r\n",context);
1541
1542 for (section = mainConfig->section_list; section; section = section->next_section) {
1543 str_sprintf(buffer, " %s %s %s\r\n", section->sectionname, section->sectionmask, section->sectionre);
1544 send_message_raw(str_tochar(buffer), context);
1545 }
1546
1547 send_message_raw("200 \r\n",context);
1548 str_deallocate(buffer);
1549
1550 return 0;
1551 }
1552
1553 /** \brief Show last log messages (10 by default)
1554 */
do_site_showlog(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1555 int do_site_showlog(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
1556 {
1557 int i;
1558 struct memory_log_t * log = get_log_buffer();
1559 wzd_string_t * buffer = str_allocate();
1560 int lines_to_show = 10;
1561 int offset = 0;
1562 char *ptr;
1563 unsigned long ul;
1564
1565 /* check if we have an argument (the number of lines to display) */
1566 if (str_length(command_line) > 0) {
1567 ul = strtoul(str_tochar(command_line),&ptr,10);
1568 if (ptr != NULL && *ptr == '\0' && ul < (long)log->size) {
1569 lines_to_show = (int)ul;
1570
1571 /* change offset to match the last line to display */
1572 for (i=log->size-1; i>=0; i--) {
1573 if (log->data[i] != NULL) {
1574 offset = i;
1575 break;
1576 }
1577 }
1578 /* then go back to print the correct number of lines */
1579 offset -= lines_to_show;
1580 if (offset < 0) offset = 0;
1581
1582 } else {
1583 lines_to_show = log->size;
1584 }
1585 }
1586
1587 /* send header */
1588 send_message_raw("200-\r\n",context);
1589
1590 for (i=offset; i<offset+lines_to_show; i++) {
1591 if (log->data[i] != NULL) {
1592 str_sprintf(buffer, " %s", log->data[i]);
1593 send_message_raw(str_tochar(buffer),context);
1594 }
1595 }
1596
1597 send_message_raw("200 \r\n",context);
1598 str_deallocate(buffer);
1599
1600 return 0;
1601 }
1602
1603 /********************* do_site_unlock **********************/
1604 /** unlock: file1 [file2 ...]
1605 */
1606
do_site_unlock(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1607 int do_site_unlock(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
1608 {
1609 char buffer[BUFFER_LEN];
1610 wzd_string_t * filename;
1611 int ret=0;
1612
1613 filename = str_tok(command_line," \t\r\n");
1614 if (!filename) {
1615 do_site_help("unlock",context);
1616 return 1;
1617 }
1618
1619 do
1620 {
1621 /* convert file to absolute path, remember file_unlock wants ABSOLUTE paths ! */
1622 ret = checkpath(str_tochar(filename),buffer,context);
1623 str_deallocate(filename);
1624 if (ret) continue; /* path is NOT ok ! */
1625 /* buffer[strlen(buffer)-1] = '\0';*/ /* remove '/', appended by checkpath */
1626
1627 /* we need to use open() directly because file_open uses file_islocked ... */
1628 ret = file_force_unlock(buffer);
1629 if (ret < 0) {
1630 break;
1631 }
1632 }
1633 while ( (filename = str_tok(command_line," \t\r\n")) );
1634
1635 if (ret == 0) {
1636 ret = send_message_with_args(200,context,"File(s) unlocked");
1637 } else {
1638 ret = send_message_with_args(501,context,"UNLOCK FAILED");
1639 }
1640
1641 return 0;
1642 }
1643 /********************* do_site_user ************************/
1644 /** user username
1645 */
1646
do_site_user(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1647 int do_site_user(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
1648 {
1649 const char * username;
1650 int ret;
1651 wzd_user_t user;
1652 int uid;
1653 wzd_string_t * str;
1654 wzd_user_t * me = NULL;
1655
1656 if (context) me = GetUserByID(context->userid); /*get self*/
1657
1658 username = str_tochar(command_line);
1659 if (!username) {
1660 do_site_help("user",context);
1661 return 0;
1662 }
1663 /* check that username exists */
1664 if ( backend_find_user(username,&user,&uid) ) {
1665 ret = send_message_with_args(501,context,"User does not exist");
1666 return 0;
1667 }
1668 if ( strchr(user.flags,FLAG_ULTRAHIDDEN )&&
1669 (me) &&
1670 (strcmp(username,me->username)!=0)/* do not hide to self ! */
1671 ) {
1672 /* for siteops we could send a different message, like 'user is hidden' */
1673 ret = send_message_with_args(501,context,"User does not exist");
1674 return 0;
1675 }
1676
1677 str = config_get_string(mainConfig->cfg_file,"GLOBAL","sitefile_user",NULL);
1678 if (!str) {
1679 ret = send_message_with_args(501,context,"File [GLOBAL] / sitefile_user does not exist");
1680 return 0;
1681 }
1682
1683 do_site_print_file(str_tochar(str),&user,NULL,context);
1684
1685 str_deallocate(str);
1686 return 0;
1687 }
1688
1689 /********************* do_site_utime ***********************/
1690 /** utime filename YYYYMMDDhhmmss YYYYMMDDhhmmss YYYYMMDDhhmmss UTC
1691 * change access time, modification time, modification of status of a file
1692 */
1693
do_site_utime(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1694 int do_site_utime(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
1695 {
1696 #ifdef HAVE_STRPTIME
1697 extern char *strptime (__const char *__restrict __s,
1698 __const char *__restrict __fmt, struct tm *__tp);
1699 #endif
1700 char buffer[BUFFER_LEN];
1701 char * ptr;
1702 wzd_string_t * filename;
1703 wzd_string_t * new_atime, * new_mtime, * new_ctime;
1704 wzd_string_t * timezone;
1705 struct tm tm_atime, tm_mtime, tm_ctime;
1706 struct utimbuf utime_buf;
1707 int ret;
1708 wzd_user_t * user;
1709
1710 user = GetUserByID(context->userid);
1711
1712 filename = str_tok(command_line," \t\r\n");
1713 if (!filename) {
1714 do_site_help("utime",context);
1715 return 1;
1716 }
1717 new_atime = str_tok(command_line," \t\r\n");
1718 if (!new_atime) {
1719 do_site_help("utime",context);
1720 str_deallocate(filename);
1721 return 1;
1722 }
1723 new_mtime = str_tok(command_line," \t\r\n");
1724 if (!new_mtime) {
1725 do_site_help("utime",context);
1726 str_deallocate(filename); str_deallocate(new_atime);
1727 return 1;
1728 }
1729 new_ctime = str_tok(command_line," \t\r\n");
1730 if (!new_ctime) {
1731 do_site_help("utime",context);
1732 str_deallocate(filename); str_deallocate(new_atime); str_deallocate(new_mtime);
1733 return 1;
1734 }
1735 timezone = str_tok(command_line," \t\r\n");
1736 if (!timezone) {
1737 do_site_help("utime",context);
1738 str_deallocate(filename); str_deallocate(new_atime); str_deallocate(new_mtime);
1739 str_deallocate(new_ctime);
1740 return 1;
1741 }
1742 /* TODO check that timezone is UTC */
1743 memset(&tm_atime,0,sizeof(struct tm));
1744 ptr=strptime((char*)str_tochar(new_atime),"%Y%m%d%H%M%S",&tm_atime);
1745 if (ptr == NULL || *ptr != '\0') {
1746 do_site_help("utime",context);
1747 str_deallocate(filename); str_deallocate(new_atime); str_deallocate(new_mtime);
1748 str_deallocate(new_ctime); str_deallocate(timezone);
1749 return 1;
1750 }
1751 str_deallocate(new_atime);
1752 memset(&tm_mtime,0,sizeof(struct tm));
1753 ptr=strptime((char*)str_tochar(new_mtime),"%Y%m%d%H%M%S",&tm_mtime);
1754 if (ptr == NULL || *ptr != '\0') {
1755 do_site_help("utime",context);
1756 str_deallocate(filename); str_deallocate(new_mtime);
1757 str_deallocate(new_ctime); str_deallocate(timezone);
1758 return 1;
1759 }
1760 str_deallocate(new_mtime);
1761 /* TODO ctime is useless in *nix systems ... */
1762 memset(&tm_ctime,0,sizeof(struct tm));
1763 ptr=strptime((char*)str_tochar(new_ctime),"%Y%m%d%H%M%S",&tm_ctime);
1764 if (ptr == NULL || *ptr != '\0') {
1765 do_site_help("utime",context);
1766 str_deallocate(filename); str_deallocate(new_ctime); str_deallocate(timezone);
1767 return 1;
1768 }
1769 str_deallocate(new_ctime);
1770 str_deallocate(timezone);
1771
1772 utime_buf.actime = mktime(&tm_atime);
1773 utime_buf.modtime = mktime(&tm_mtime);
1774 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
1775 if (checkpath(str_tochar(filename),buffer,context)) { /* path is NOT ok ! */
1776 ret = send_message_with_args(501,context,"File does not exist");
1777 str_deallocate(filename);
1778 return 1;
1779 }
1780 str_deallocate(filename);
1781 /* buffer[strlen(buffer)-1] = '\0';*/ /* remove '/', appended by checkpath */
1782 ret = _checkPerm(buffer,RIGHT_RNFR,user);
1783 if (ret) {
1784 ret = send_message_with_args(501,context,"Access denied");
1785 return 1;
1786 }
1787
1788 ret = utime(buffer,&utime_buf);
1789
1790 ret = send_message_with_args(200,context,"UTIME command okay");
1791 return 0;
1792 }
1793
1794 /********************* do_site_vars *********************/
1795
do_site_vars(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1796 int do_site_vars(UNUSED wzd_string_t *ignored, wzd_string_t * command_line, wzd_context_t * context)
1797 {
1798 wzd_string_t *command, *varname, *value;
1799 char * buffer;
1800 int ret;
1801
1802 command = str_tok(command_line," \t\r\n");
1803 if (!command) {
1804 do_site_help("vars",context);
1805 return 1;
1806 }
1807 str_tolower(command);
1808
1809 varname = str_tok(command_line," \t\r\n");
1810 if (!varname) {
1811 do_site_help("vars",context);
1812 str_deallocate(command);
1813 return 1;
1814 }
1815
1816 if (strcmp(str_tochar(command),"get")==0) {
1817 str_deallocate(command);
1818 buffer = malloc(1024); /** \todo XXX harcoded value ! */
1819 ret = vars_get(str_tochar(varname),buffer,1024,mainConfig);
1820
1821 if (ret)
1822 send_message_with_args(200,context,"An error occurred inside vars_get");
1823 else
1824 send_message_with_args(200,context,buffer);
1825
1826 free(buffer);
1827 str_deallocate(varname);
1828 return 0;
1829 }
1830 else if (strcmp(str_tochar(command),"set")==0) {
1831 str_deallocate(command);
1832 value = str_tok(command_line," \t\r\n");
1833 if (!value) {
1834 do_site_help("vars",context);
1835 str_deallocate(varname);
1836 return 1;
1837 }
1838
1839 ret = vars_set(str_tochar(varname),str_tochar(value),strlen(str_tochar(value)),mainConfig);
1840
1841 if (ret)
1842 send_message_with_args(200,context,"An error occurred inside vars_set");
1843 else
1844 send_message_with_args(200,context,"Command okay");
1845
1846 str_deallocate(varname);
1847 str_deallocate(value);
1848 return 0;
1849 }
1850
1851 send_message_with_args(200,context,"Command okay");
1852 str_deallocate(command);
1853 str_deallocate(varname);
1854 return 0;
1855 }
1856
1857 /****************** do_site_vars_group *******************/
1858
do_site_vars_group(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1859 int do_site_vars_group(UNUSED wzd_string_t *ignored, wzd_string_t * command_line, wzd_context_t * context)
1860 {
1861 wzd_string_t *groupname, *command, *varname, *value;
1862 char * buffer;
1863 int ret;
1864 wzd_group_t * group;
1865
1866 command = str_tok(command_line," \t\r\n");
1867 if (!command) {
1868 do_site_help("vars_group",context);
1869 return 1;
1870 }
1871 str_tolower(command);
1872
1873 groupname = str_tok(command_line," \t\r\n");
1874 if (!groupname) {
1875 do_site_help("vars_group",context);
1876 str_deallocate(command);
1877 return 1;
1878 }
1879 group = GetGroupByName(str_tochar(groupname));
1880 str_deallocate(groupname);
1881 if ( !group ) {
1882 send_message_with_args(501,context,"Group does not exist");
1883 str_deallocate(command);
1884 return 1;
1885 }
1886
1887 varname = str_tok(command_line," \t\r\n");
1888 if (!varname) {
1889 do_site_help("vars_group",context);
1890 str_deallocate(command);
1891 return 1;
1892 }
1893
1894 if (strcmp(str_tochar(command),"get")==0) {
1895 str_deallocate(command);
1896 buffer = malloc(1024); /** \todo XXX harcoded value ! */
1897 ret = vars_group_get(group->groupname,str_tochar(varname),buffer,1024,mainConfig);
1898
1899 if (ret)
1900 send_message_with_args(200,context,"An error occurred inside vars_group_get");
1901 else
1902 send_message_with_args(200,context,buffer);
1903
1904 free(buffer);
1905 str_deallocate(varname);
1906 return 0;
1907 }
1908 else if (strcmp(str_tochar(command),"set")==0) {
1909 str_deallocate(command);
1910 value = str_tok(command_line," \t\r\n");
1911 if (!value) {
1912 do_site_help("vars_group",context);
1913 str_deallocate(varname);
1914 return 1;
1915 }
1916
1917 ret = vars_group_set(group->groupname,str_tochar(varname),str_tochar(value),strlen(str_tochar(value)),mainConfig);
1918
1919 if (ret)
1920 send_message_with_args(200,context,"An error occurred inside vars_group_set");
1921 else
1922 send_message_with_args(200,context,"Command okay");
1923 str_deallocate(value);
1924 str_deallocate(varname);
1925 return 0;
1926 }
1927
1928 send_message_with_args(200,context,"Command okay");
1929 str_deallocate(command);
1930 str_deallocate(varname);
1931 return 0;
1932 }
1933
1934 /****************** do_site_vars_user *******************/
1935
do_site_vars_user(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)1936 int do_site_vars_user(UNUSED wzd_string_t *ignored, wzd_string_t * command_line, wzd_context_t * context)
1937 {
1938 wzd_string_t *username, *command, *varname, *value;
1939 char * buffer;
1940 int ret;
1941 wzd_user_t * user;
1942
1943 command = str_tok(command_line," \t\r\n");
1944 if (!command) {
1945 do_site_help("vars_user",context);
1946 return 1;
1947 }
1948 str_tolower(command);
1949
1950 username = str_tok(command_line," \t\r\n");
1951 if (!username) {
1952 do_site_help("vars_user",context);
1953 str_deallocate(command);
1954 return 1;
1955 }
1956 user = GetUserByName(str_tochar(username));
1957 str_deallocate(username);
1958 if ( !user ) {
1959 send_message_with_args(501,context,"User does not exist");
1960 str_deallocate(command);
1961 return 1;
1962 }
1963
1964 varname = str_tok(command_line," \t\r\n");
1965 if (!varname) {
1966 do_site_help("vars_user",context);
1967 str_deallocate(command);
1968 return 1;
1969 }
1970
1971 if (strcmp(str_tochar(command),"get")==0) {
1972 str_deallocate(command);
1973 buffer = malloc(1024); /** \todo XXX harcoded value ! */
1974 ret = vars_user_get(user->username,str_tochar(varname),buffer,1024,mainConfig);
1975
1976 if (ret)
1977 send_message_with_args(200,context,"An error occurred inside vars_user_get");
1978 else
1979 send_message_with_args(200,context,buffer);
1980
1981 free(buffer);
1982 str_deallocate(varname);
1983 return 0;
1984 }
1985 else if (strcmp(str_tochar(command),"set")==0) {
1986 str_deallocate(command);
1987 value = str_tok(command_line," \t\r\n");
1988 if (!value) {
1989 do_site_help("vars_user",context);
1990 str_deallocate(varname);
1991 str_deallocate(value);
1992 return 1;
1993 }
1994
1995 ret = vars_user_set(user->username,str_tochar(varname),str_tochar(value),strlen(str_tochar(value)),mainConfig);
1996
1997 if (ret)
1998 send_message_with_args(200,context,"An error occurred inside vars_user_set");
1999 else
2000 send_message_with_args(200,context,"Command okay");
2001 str_deallocate(varname);
2002 str_deallocate(value);
2003 return 0;
2004 }
2005
2006 send_message_with_args(200,context,"Command okay");
2007 str_deallocate(varname);
2008 return 0;
2009 }
2010
2011 /********************* do_site_version *********************/
2012
do_site_version(UNUSED wzd_string_t * ignored,UNUSED wzd_string_t * param,wzd_context_t * context)2013 int do_site_version(UNUSED wzd_string_t * ignored, UNUSED wzd_string_t * param, wzd_context_t * context)
2014 {
2015 char str[256];
2016 snprintf(str,256,"%s build %s (%s)",
2017 WZD_VERSION_LONG,WZD_BUILD_NUM,WZD_BUILD_OPTS);
2018 send_message_with_args(200,context,str);
2019 return 0;
2020 }
2021
2022 /********************* do_site_vfsadd **********************/
2023 /** vfsadd |/home/vfsroot|/physical/path| +O =user
2024 */
2025
do_site_vfsadd(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)2026 int do_site_vfsadd(UNUSED wzd_string_t * ignored, wzd_string_t * command_line, wzd_context_t * context)
2027 {
2028 char *vpath, *ppath, *target;
2029 /* int i;*/
2030 int ret;
2031 char sep;
2032 const char *ptr;
2033 char * dstptr;
2034 unsigned int dstlen, length;
2035 char buffer[1024];
2036
2037 strncpy(buffer,str_tochar(command_line),1024);
2038
2039 /* allocate enough memory */
2040 length = strlen(buffer);
2041 vpath = malloc(length);
2042 ppath = malloc(length);
2043
2044 /* parse command line */
2045 ptr = buffer;
2046 sep = *ptr++;
2047
2048 dstptr = vpath;
2049 dstlen = 0;
2050
2051 while (*ptr) {
2052 if (*ptr == sep) break; /* end */
2053 if (dstlen++ == length-1) break; /* too long */
2054 *dstptr++ = *ptr++;
2055 }
2056 if (!*ptr || *ptr != sep) {
2057 free(vpath); free(ppath);
2058 send_message_with_args(501,context,"site vfsadd |/home/vfsroot|/physical/path| [PERM]");
2059 return 1;
2060 }
2061 *dstptr = '\0';
2062
2063 dstptr = ppath;
2064 dstlen = 0;
2065 ptr++;
2066
2067 while (*ptr) {
2068 if (*ptr == sep) break; /* end */
2069 if (dstlen++ == length-1) break; /* too long */
2070 *dstptr++ = *ptr++;
2071 }
2072 if (!*ptr || *ptr != sep) {
2073 free(vpath); free(ppath);
2074 send_message_with_args(501,context,"site vfsadd |/home/vfsroot|/physical/path| [PERM]");
2075 return 1;
2076 }
2077 *dstptr = '\0';
2078
2079 target = NULL;
2080 ptr++;
2081
2082 if (*ptr) {
2083 while( *ptr && (*ptr==' ' || *ptr=='\t')) ptr++;
2084 if (*ptr)
2085 target = (char*)ptr;
2086 }
2087
2088 if( target )
2089 ret = vfs_add_restricted( &mainConfig->vfs, vpath, ppath, target );
2090 else
2091 ret = vfs_add( &mainConfig->vfs, vpath, ppath );
2092
2093 if (ret==1)
2094 send_message_with_args(501,context,"site vfsadd |/home/vfsroot|/physical/path| [PERM]");
2095 else if (ret==2)
2096 {
2097 char tmp[80];
2098 snprintf( tmp, 80, "vfs %s already set", vpath );
2099 send_message_with_args(501,context,tmp);
2100 } else
2101 send_message_with_args(200,context,"VFSADD command okay");
2102
2103 free(vpath); free(ppath);
2104
2105 return 0;
2106 }
2107
2108 /********************* do_site_vfsdel **********************/
2109 /** vfsdel /home/vfsroot
2110 */
2111
do_site_vfsdel(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)2112 int do_site_vfsdel(UNUSED wzd_string_t * ignored, wzd_string_t * command_line, wzd_context_t * context)
2113 {
2114 int ret;
2115
2116 if (command_line && strlen(str_tochar(command_line))>0)
2117 ret = vfs_remove( &mainConfig->vfs, str_tochar(command_line) );
2118 else ret = 1;
2119
2120 if (ret==1)
2121 send_message_with_args(501,context,"site vfsdel /home/vfsroot");
2122 else if (ret==2)
2123 {
2124 char tmp[80];
2125 snprintf( tmp, 80, "vfs %s does not exist", str_tochar(command_line) );
2126 send_message_with_args(501,context,tmp);
2127 } else
2128 send_message_with_args(200,context,"VFSDEL command okay");
2129
2130 return 0;
2131 }
2132
2133 /* TODO XXX FIXME tests missing
2134 */
do_internal_wipe(const char * filename,wzd_context_t * context)2135 static int do_internal_wipe(const char *filename, wzd_context_t * context)
2136 {
2137 fs_filestat_t s;
2138 int ret;
2139 const char *dir_filename;
2140 char buffer[1024];
2141 char path[1024];
2142 char * ptr;
2143 fs_dir_t * dir;
2144 fs_fileinfo_t * finfo;
2145
2146 split_filename(filename,path,NULL,1024,0);
2147
2148 if (fs_file_lstat(filename,&s)) return -1;
2149
2150 if (S_ISREG(s.mode) || S_ISLNK(s.mode)) {
2151 ret = file_remove(filename,context);
2152 if (ret) return 1;
2153 }
2154 if (S_ISDIR(s.mode))
2155 {
2156 strncpy(buffer,filename,sizeof(buffer));
2157 ptr = buffer + strlen(buffer);
2158 *ptr++ = '/';
2159
2160 if ( fs_dir_open(filename,&dir) ) return -1;
2161
2162 while ( !fs_dir_read(dir,&finfo) ) {
2163 dir_filename = fs_fileinfo_getname(finfo);
2164
2165 if (strcmp(dir_filename,".")==0 || strcmp(dir_filename,"..")==0)
2166 continue;
2167 if (strlen(buffer)+strlen(dir_filename)>=1024) { fs_dir_close(dir); return 1; }
2168 strncpy(ptr,dir_filename,256);
2169
2170 /* if (fs_file_stat(buffer,&s)) { fs_dir_close(dir); return -1; }*/
2171 if (fs_file_lstat(buffer,&s)==0) {
2172 if (S_ISREG(s.mode) || S_ISLNK(s.mode)) {
2173 /* ret = file_remove(buffer,context);*/
2174 ret = unlink(buffer);
2175 if (ret) { fs_dir_close(dir); return 1; }
2176 }
2177 if (S_ISDIR(s.mode)) {
2178 ret = do_internal_wipe(buffer,context);
2179 if (ret) { fs_dir_close(dir); return 1; }
2180 }
2181 }
2182 }
2183
2184 fs_dir_close(dir);
2185 ret = rmdir(filename);
2186 if (ret) return 1;
2187 }
2188
2189 return 0;
2190 }
2191
2192 /********************* do_site_wipe ************************/
2193 /** wipe: [-r] file1 [file2 ...]
2194 */
2195
do_site_wipe(UNUSED wzd_string_t * ignored,wzd_string_t * command_line,wzd_context_t * context)2196 int do_site_wipe(UNUSED wzd_string_t *ignored, wzd_string_t *command_line, wzd_context_t * context)
2197 {
2198 char buffer[WZD_MAX_PATH+1];
2199 wzd_string_t * firstarg, *filename;
2200 int is_recursive;
2201 int ret;
2202 /* wzd_user_t user;*/
2203 /* int uid;*/
2204
2205 firstarg = str_read_token(command_line);
2206 if (!firstarg) {
2207 do_site_help("wipe",context);
2208 return E_PARAM_NULL;
2209 }
2210 /* check if wiping is recursive */
2211 if ( strcasecmp(str_tochar(firstarg),"-r")==0 ) {
2212 str_deallocate(firstarg);
2213 is_recursive=1;
2214 filename = str_read_token(command_line);
2215 if( !filename) {
2216 do_site_help("wipe",context);
2217 return E_PARAM_INVALID;
2218 }
2219 }
2220 else
2221 filename = firstarg;
2222
2223 do
2224 {
2225 /* convert file to absolute path, remember _setPerm wants ABSOLUTE paths ! */
2226 if (checkpath_new(str_tochar(filename),buffer,context) != 0)
2227 {
2228 ret = send_message_with_args(501,context,"File does not exist");
2229 str_deallocate(filename);
2230 return E_FILE_NOEXIST;
2231 }
2232
2233 {
2234 wzd_string_t * event_args = str_allocate();
2235 wzd_user_t * user = GetUserByID(context->userid);
2236 str_sprintf(event_args,"%s %s",user->username,str_tochar(filename));
2237 ret = event_send(mainConfig->event_mgr, EVENT_PREWIPE, 0, event_args, context);
2238 str_deallocate(event_args);
2239 }
2240 if (ret != EVENT_OK && ret != EVENT_BREAK) {
2241 out_log(LEVEL_NORMAL, "Wipe denied by hook (returned %d)\n", ret);
2242 ret = send_message_with_args(501,context,"WIPE denied");
2243 str_deallocate(filename);
2244 return E_COMMAND_FAILED;
2245 }
2246
2247 /* wipe file | if_recursive dir/file */
2248 ret = do_internal_wipe(buffer,context);
2249 if (ret) {
2250 ret = send_message_with_args(501,context,"WIPE failed");
2251 str_deallocate(filename);
2252 return E_COMMAND_FAILED;
2253 }
2254
2255 {
2256 wzd_string_t * event_args = str_allocate();
2257 wzd_user_t * user = GetUserByID(context->userid);
2258 str_sprintf(event_args,"%s %s",user->username,str_tochar(filename));
2259 event_send(mainConfig->event_mgr, EVENT_WIPE, 200, event_args, context);
2260 str_deallocate(event_args);
2261 }
2262
2263 str_deallocate(filename);
2264 }
2265 while ( (filename = str_read_token(command_line)) );
2266
2267 ret = send_message_with_args(200,context,"File(s) wiped");
2268
2269 return 0;
2270 }
2271
2272 /********************* do_site *****************************/
2273
do_site(wzd_string_t * command,wzd_string_t * command_line,wzd_context_t * context)2274 int do_site(wzd_string_t *command, wzd_string_t *command_line, wzd_context_t * context)
2275 {
2276 char buffer[4096];
2277 int ret=0;
2278 wzd_hook_reply_t hook_reply;
2279 int first_reply;
2280 const char *s_token;
2281
2282 if (!command || !command_line) {
2283 ret = send_message_with_args(501,context,"SITE command failed");
2284 return 1;
2285 }
2286
2287 /* check general site permission */
2288 #ifdef DEBUG
2289 if (strlen(str_tochar(command))>255) {
2290 out_err(LEVEL_HIGH,"*** WARNING *** permissions name too long > 255 - truncated : '%s'\n",str_tochar(command));
2291 }
2292 #endif
2293
2294 {
2295 wzd_command_t * command_real;
2296
2297 command_real = commands_find(mainConfig->commands_list,command);
2298 /* disabled because this breaks custom site commands */
2299 #if 0
2300 if (!command_real) {
2301 ret = send_message_with_args(501,context,"Permission not found for site command");
2302 return 1;
2303 }
2304 #endif
2305 if (command_real && commands_check_permission(command_real,context)) {
2306 ret = send_message_with_args(501,context,"Permission Denied");
2307 return 1;
2308 }
2309 }
2310
2311 s_token = str_tochar(command);
2312
2313 #if 0
2314 fct = site_find(s_token);
2315
2316 if (fct)
2317 {
2318 tok_command = str_tok(command_line,"\r\n");
2319 ret = (*fct)((char*)str_tochar(tok_command),context);
2320 str_deallocate(tok_command);
2321 return ret;
2322 }
2323 #endif
2324
2325 /******************** CLOSE *********************/
2326 if (strcmp(s_token,"site_close")==0) {
2327 mainConfig->site_closed = 1;
2328 ret = send_message_with_args(250,context,"SITE: ","server is now closed");
2329 return 0;
2330 } else
2331 /******************** REOPEN ********************/
2332 if (strcmp(s_token,"site_reopen")==0) {
2333 mainConfig->site_closed = 0;
2334 ret = send_message_with_args(250,context,"SITE: ","server is now opened");
2335 return 0;
2336 } else
2337 /******************* UPTIME *********************/
2338 if (strcmp(s_token,"site_uptime")==0) {
2339 time_t t;
2340 time(&t);
2341 t = t - mainConfig->server_start;
2342 snprintf(buffer,sizeof(buffer),"Uptime: %s",time_to_str(t));
2343 ret = send_message_with_args(200,context,buffer);
2344 return 0;
2345 }
2346 /******************* SHUTDOWN *******************/
2347 #ifndef WZD_MULTITHREAD
2348 else if (strcmp(s_token,"site_shutdown")==0) {
2349 mainConfig->serverstop = 1;
2350 ret = send_message_with_args(250,context,"SITE: ","server will shutdown after you logout");
2351 context->exitclient = 1;
2352 return 0;
2353 }
2354 #endif /* WZD_MULTIPROCESS */
2355 #ifdef WZD_MULTITHREAD
2356 else if (strcmp(s_token,"site_shutdown")==0) {
2357 ret = send_message_with_args(250,context,"SITE: ","server will shutdown NOW");
2358 mainConfig->serverstop = 1;
2359 return 0;
2360 }
2361 #endif /* WZD_MULTITHREAD */
2362
2363 hook_reply = EVENT_IGNORED;
2364 first_reply = 1;
2365
2366 #if 0
2367 FORALL_HOOKS(EVENT_SITE)
2368 typedef wzd_hook_reply_t (*site_hook)(unsigned long, wzd_context_t *, const char*,const char *);
2369 if (hook->hook) {
2370 hook_reply = (*(site_hook)hook->hook)(EVENT_SITE,context,s_token,str_tochar(command_line));
2371 /** \todo implement and use constants: HANDLED, NEXT, ERROR or something like .. */
2372 if (hook_reply != EVENT_IGNORED && hook_reply != EVENT_NEXT) break;
2373 }
2374 /* custom site commands */
2375 if (hook->opt && hook->external_command && strcasecmp(hook->opt,s_token)==0) {
2376 if (first_reply) { send_message_raw("200-\r\n",context); first_reply=0; }
2377 ret = hook_call_custom(context, hook, 200, (char*)str_tochar(command_line));
2378 if (!ret) {
2379 ret = send_message_with_args(200,context,"SITE command ok");
2380 } else {
2381 ret = send_message_with_args(200,context,"SITE command failed");
2382 }
2383 return 0; /* there can be only one site command ! */
2384 }
2385 END_FORALL_HOOKS
2386 #endif /* 0 */
2387
2388 switch (hook_reply) {
2389 case EVENT_ERR:
2390 /* we do not know how to reply .. trying 200 */
2391 out_log(LEVEL_INFO, "Someone reported errors for site command %s\n", s_token);
2392 ret = send_message_with_args(200,context,"SITE command failed");
2393 break;
2394 case EVENT_NEXT:
2395 /* we do not know how to reply .. trying 200 */
2396 out_log(LEVEL_INFO, "Received only EVENT_NEXT for site command %s\n", s_token);
2397 out_log(LEVEL_INFO, "The last handler should send EVENT_CATCHED\n");
2398 ret = send_message_with_args(200,context,"SITE command executed (with warnings)");
2399 break;
2400 case EVENT_IGNORED:
2401 ret = send_message_with_args(250,context,"SITE ","command unknown");
2402 break;
2403 case EVENT_HANDLED:
2404 break;
2405 }
2406
2407 return 0;
2408 }
2409
2410
2411