~ubuntu-branches/ubuntu/trusty/proftpd-dfsg/trusty

« back to all changes in this revision

Viewing changes to contrib/mod_site_misc.c

  • Committer: Bazaar Package Importer
  • Author(s): Francesco Paolo Lovergine
  • Date: 2011-10-06 12:57:29 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20111006125729-wiq6d3yzf2ensafj
Tags: 1.3.4~rc3-1
* New upstream pre-release.
* Refreshed all patches.
* Changed patch xferstats.holger-preiss to fix a few warnings and use
  Getopt::Std instead of the old getopts.pl which will be removed soon or
  later in perl5. Thanks lintian.
* Policy bumped to 3.9.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * ProFTPD: mod_site_misc -- a module implementing miscellaneous SITE commands
3
3
 *
4
 
 * Copyright (c) 2004-2010 The ProFTPD Project
 
4
 * Copyright (c) 2004-2011 The ProFTPD Project
5
5
 *
6
6
 * This program is free software; you can redistribute it and/or modify
7
7
 * it under the terms of the GNU General Public License as published by
15
15
 *
16
16
 * You should have received a copy of the GNU General Public License
17
17
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
 
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
19
19
 *
20
20
 * As a special exemption, The ProFTPD Project team and other respective
21
21
 * copyright holders give permission to link this program with OpenSSL, and
22
22
 * distribute the resulting executable, without including the source code for
23
23
 * OpenSSL in the source distribution.
24
24
 *
25
 
 * $Id: mod_site_misc.c,v 1.18 2011/03/03 21:38:54 castaglia Exp $
 
25
 * $Id: mod_site_misc.c,v 1.20 2011/05/26 23:14:01 castaglia Exp $
26
26
 */
27
27
 
28
28
#include "conf.h"
29
29
 
30
 
#define MOD_SITE_MISC_VERSION           "mod_site_misc/1.4"
 
30
#define MOD_SITE_MISC_VERSION           "mod_site_misc/1.5"
 
31
 
 
32
extern pr_response_t *resp_list, *resp_err_list;
31
33
 
32
34
static unsigned int site_misc_engine = TRUE;
33
35
 
60
62
  pr_fs_clear_cache();
61
63
 
62
64
  res = pr_fsio_stat(dir, &st);
63
 
  if (res == -1 &&
 
65
  if (res < 0 &&
64
66
      errno != ENOENT) {
 
67
    int xerrno = errno;
 
68
 
65
69
    pr_log_debug(DEBUG2, MOD_SITE_MISC_VERSION ": error checking '%s': %s",
66
 
      dir, strerror(errno));
 
70
      dir, strerror(xerrno));
 
71
 
 
72
    errno = xerrno;
67
73
    return -1;
68
74
  }
69
75
 
70
 
  if (res == 0)
71
 
    return 0;
 
76
  if (res == 0) {
 
77
    /* Directory already exists */
 
78
    return 1;
 
79
  }
72
80
 
73
81
  if (pr_fsio_mkdir(dir, 0777) < 0) {
 
82
    int xerrno = errno;
 
83
 
74
84
    pr_log_debug(DEBUG2, MOD_SITE_MISC_VERSION ": error creating '%s': %s",
75
 
      dir, strerror(errno));
 
85
      dir, strerror(xerrno));
 
86
 
 
87
    errno = xerrno;
76
88
    return -1;
77
89
  }
78
90
 
98
110
  while (tmp_path &&
99
111
         *tmp_path) {
100
112
    char *curr_dir;
 
113
    int res;
 
114
    cmd_rec *cmd;
 
115
    pool *sub_pool;
101
116
 
102
117
    pr_signals_handle();
103
118
 
104
119
    curr_dir = strsep(&tmp_path, "/");
105
120
    curr_path = pdircat(p, curr_path, curr_dir, NULL);
106
121
 
107
 
    if (site_misc_create_dir(curr_path) < 0) {
108
 
      return -1;
109
 
    }
 
122
    /* Dispatch the fake C_MKD command, e.g. for mod_quotatab. */
 
123
    sub_pool = pr_pool_create_sz(p, 64);
 
124
    cmd = pr_cmd_alloc(sub_pool, 2, pstrdup(sub_pool, C_MKD),
 
125
      pstrdup(sub_pool, curr_path));
 
126
    cmd->arg = pstrdup(cmd->pool, curr_path);
 
127
    cmd->class = CL_DIRS|CL_WRITE;
 
128
 
 
129
    res = pr_cmd_dispatch_phase(cmd, PRE_CMD, 0);
 
130
    if (res < 0) {
 
131
      int xerrno = errno;
 
132
 
 
133
      pr_log_debug(DEBUG3, MOD_SITE_MISC_VERSION
 
134
        ": creating directory '%s' blocked by MKD handler: %s", curr_path,
 
135
        strerror(xerrno));
 
136
 
 
137
      pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
 
138
      pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
 
139
      pr_response_clear(&resp_err_list);
 
140
 
 
141
      destroy_pool(sub_pool);
 
142
      sub_pool = NULL;
 
143
      cmd = NULL;
 
144
 
 
145
      errno = xerrno;
 
146
      return -1;
 
147
    }
 
148
 
 
149
    res = site_misc_create_dir(curr_path);
 
150
    if (res < 0) {
 
151
      int xerrno = errno;
 
152
 
 
153
      pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
 
154
      pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
 
155
      pr_response_clear(&resp_err_list);
 
156
 
 
157
      destroy_pool(sub_pool);
 
158
      sub_pool = NULL;
 
159
      cmd = NULL;
 
160
 
 
161
      errno = xerrno;
 
162
      return -1;
 
163
    }
 
164
 
 
165
    pr_cmd_dispatch_phase(cmd, POST_CMD, 0);
 
166
    pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
 
167
    pr_response_clear(&resp_list);
 
168
 
 
169
    destroy_pool(sub_pool);
 
170
    sub_pool = NULL;
 
171
    cmd = NULL;
110
172
  }
111
173
 
112
174
  return 0;
115
177
static int site_misc_delete_dir(pool *p, const char *dir) {
116
178
  void *dirh;
117
179
  struct dirent *dent;
 
180
  int res;
 
181
  cmd_rec *cmd;
 
182
  pool *sub_pool;
118
183
 
119
184
  dirh = pr_fsio_opendir(dir);
120
 
  if (!dirh)
 
185
  if (dirh == NULL)
121
186
    return -1;
122
187
 
123
188
  while ((dent = pr_fsio_readdir(dirh)) != NULL) {
126
191
 
127
192
    pr_signals_handle();
128
193
 
129
 
    if (strcmp(dent->d_name, ".") == 0 ||
130
 
        strcmp(dent->d_name, "..") == 0)
 
194
    if (strncmp(dent->d_name, ".", 2) == 0 ||
 
195
        strncmp(dent->d_name, "..", 3) == 0)
131
196
      continue;
132
197
 
133
198
    file = pdircat(p, dir, dent->d_name, NULL);
136
201
      continue;
137
202
    
138
203
    if (S_ISDIR(st.st_mode)) {
139
 
      if (site_misc_delete_dir(p, file) < 0) {
140
 
        int xerrno = errno;
141
 
 
142
 
        pr_fsio_closedir(dirh);
143
 
 
144
 
        errno = xerrno;
145
 
        return -1;
146
 
      }
147
 
 
148
 
    } else if (pr_fsio_unlink(file) < 0) {
149
 
      int xerrno = errno;
150
 
 
151
 
      pr_fsio_closedir(dirh);
152
 
 
153
 
      errno = xerrno;
154
 
      return -1;
 
204
      res = site_misc_delete_dir(p, file);
 
205
      if (res < 0) {
 
206
        int xerrno = errno;
 
207
 
 
208
        pr_fsio_closedir(dirh);
 
209
 
 
210
        errno = xerrno;
 
211
        return -1;
 
212
      }
 
213
 
 
214
    } else {
 
215
 
 
216
      /* Dispatch fake C_DELE command, e.g. for mod_quotatab */
 
217
      sub_pool = pr_pool_create_sz(p, 64);
 
218
      cmd = pr_cmd_alloc(sub_pool, 2, pstrdup(sub_pool, C_DELE),
 
219
        pstrdup(sub_pool, file));
 
220
      cmd->arg = pstrdup(cmd->pool, file);
 
221
      cmd->class = CL_WRITE;
 
222
 
 
223
      res = pr_cmd_dispatch_phase(cmd, PRE_CMD, 0);
 
224
      if (res < 0) {
 
225
        int xerrno = errno;
 
226
 
 
227
        pr_log_debug(DEBUG3, MOD_SITE_MISC_VERSION
 
228
          ": deleting file '%s' blocked by DELE handler: %s", file,
 
229
          strerror(xerrno));
 
230
 
 
231
        pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
 
232
        pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
 
233
        pr_response_clear(&resp_err_list);
 
234
 
 
235
        destroy_pool(sub_pool);
 
236
        pr_fsio_closedir(dirh);
 
237
 
 
238
        errno = xerrno;
 
239
        return -1;
 
240
      }
 
241
 
 
242
      res = pr_fsio_unlink(file);
 
243
      if (res < 0) {
 
244
        int xerrno = errno;
 
245
 
 
246
        pr_fsio_closedir(dirh);
 
247
 
 
248
        pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
 
249
        pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
 
250
        pr_response_clear(&resp_err_list);
 
251
 
 
252
        destroy_pool(sub_pool);
 
253
        pr_fsio_closedir(dirh);
 
254
 
 
255
        errno = xerrno;
 
256
        return -1;
 
257
      }
 
258
 
 
259
      pr_cmd_dispatch_phase(cmd, POST_CMD, 0);
 
260
      pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
 
261
      pr_response_clear(&resp_list);
 
262
      destroy_pool(sub_pool);
155
263
    }
156
264
  }
157
265
 
158
266
  pr_fsio_closedir(dirh);
159
267
 
160
 
  if (pr_fsio_rmdir(dir) < 0)
161
 
    return -1;
 
268
  /* Dispatch fake C_RMD command, e.g. for mod_quotatab */
 
269
  sub_pool = pr_pool_create_sz(p, 64);
 
270
  cmd = pr_cmd_alloc(sub_pool, 2, pstrdup(sub_pool, C_RMD),
 
271
    pstrdup(sub_pool, dir));
 
272
  cmd->arg = pstrdup(cmd->pool, dir);
 
273
  cmd->class = CL_DIRS|CL_WRITE;
 
274
 
 
275
  res = pr_cmd_dispatch_phase(cmd, PRE_CMD, 0);
 
276
  if (res < 0) {
 
277
    int xerrno = errno;
 
278
 
 
279
    pr_log_debug(DEBUG3, MOD_SITE_MISC_VERSION
 
280
      ": removing directory '%s' blocked by RMD handler: %s", dir,
 
281
      strerror(xerrno));
 
282
 
 
283
    pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
 
284
    pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
 
285
    pr_response_clear(&resp_err_list);
 
286
 
 
287
    destroy_pool(sub_pool);
 
288
 
 
289
    errno = xerrno;
 
290
    return -1;
 
291
  }
 
292
 
 
293
  res = pr_fsio_rmdir(dir);
 
294
  if (res < 0) {
 
295
    int xerrno = errno;
 
296
 
 
297
    pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
 
298
    pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
 
299
    pr_response_clear(&resp_err_list);
 
300
 
 
301
    destroy_pool(sub_pool);
 
302
    errno = xerrno;
 
303
    return -1;
 
304
  }
 
305
 
 
306
  pr_cmd_dispatch_phase(cmd, POST_CMD, 0);
 
307
  pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
 
308
  pr_response_clear(&resp_list);
 
309
  destroy_pool(sub_pool);
162
310
 
163
311
  return 0;
164
312
}
286
434
    return PR_DECLINED(cmd);
287
435
  }
288
436
 
289
 
  if (strcasecmp(cmd->argv[1], "MKDIR") == 0) {
 
437
  if (strncasecmp(cmd->argv[1], "MKDIR", 6) == 0) {
290
438
    register unsigned int i;
291
439
    char *cmd_name, *path = "";
292
440
    unsigned char *authenticated;
296
444
 
297
445
    authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
298
446
 
299
 
    if (!authenticated || *authenticated == FALSE) {
 
447
    if (!authenticated ||
 
448
        *authenticated == FALSE) {
300
449
      pr_response_add_err(R_530, _("Please login with USER and PASS"));
 
450
      errno = EACCES;
301
451
      return PR_ERROR(cmd);
302
452
    }
303
453
 
307
457
    path = pr_fs_decode_path(cmd->tmp_pool, path);
308
458
 
309
459
    if (site_misc_check_filters(cmd, path) < 0) {
310
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM));
 
460
      int xerrno = EPERM;
 
461
 
 
462
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
463
 
 
464
      errno = xerrno;
311
465
      return PR_ERROR(cmd);
312
466
    }
313
467
 
314
468
    path = dir_canonical_path(cmd->tmp_pool, path);
315
469
    if (path == NULL) {
316
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EINVAL));
 
470
      int xerrno = EINVAL;
 
471
 
 
472
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
473
 
 
474
      errno = xerrno;
317
475
      return PR_ERROR(cmd);
318
476
    }
319
477
 
320
478
    cmd_name = cmd->argv[0];
321
479
    cmd->argv[0] = "SITE_MKDIR";
322
480
    if (!dir_check_canon(cmd->tmp_pool, cmd, G_WRITE, path, NULL)) {
 
481
      int xerrno = EPERM;
 
482
 
323
483
      cmd->argv[0] = cmd_name;
324
484
 
325
485
      pr_log_debug(DEBUG4, MOD_SITE_MISC_VERSION
326
486
        ": %s command denied by <Limit>", cmd->argv[0]);
327
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM));
 
487
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
488
 
 
489
      errno = xerrno;
328
490
      return PR_ERROR(cmd);
329
491
    }
330
492
    cmd->argv[0] = cmd_name;
331
493
 
332
494
    if (site_misc_create_path(cmd->tmp_pool, path) < 0) {
333
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno));
 
495
      int xerrno = errno;
 
496
 
 
497
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
498
 
 
499
      errno = xerrno;
334
500
      return PR_ERROR(cmd);
335
501
    }
336
502
 
338
504
    return PR_HANDLED(cmd);
339
505
  }
340
506
 
341
 
  if (strcasecmp(cmd->argv[1], "HELP") == 0)
 
507
  if (strncasecmp(cmd->argv[1], "HELP", 5) == 0) {
342
508
    pr_response_add(R_214, "MKDIR <sp> path");
 
509
  }
343
510
 
344
511
  return PR_DECLINED(cmd);
345
512
}
355
522
    return PR_DECLINED(cmd);
356
523
  }
357
524
 
358
 
  if (strcasecmp(cmd->argv[1], "RMDIR") == 0) {
 
525
  if (strncasecmp(cmd->argv[1], "RMDIR", 6) == 0) {
359
526
    register unsigned int i;
360
527
    char *cmd_name, *path = "";
361
528
    unsigned char *authenticated;
365
532
 
366
533
    authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
367
534
 
368
 
    if (!authenticated || *authenticated == FALSE) {
 
535
    if (!authenticated ||
 
536
        *authenticated == FALSE) {
369
537
      pr_response_add_err(R_530, _("Please login with USER and PASS"));
 
538
      errno = EACCES;
370
539
      return PR_ERROR(cmd);
371
540
    }
372
541
 
377
546
 
378
547
    path = dir_canonical_path(cmd->tmp_pool, path);
379
548
    if (path == NULL) {
380
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EINVAL));
 
549
      int xerrno = EINVAL;
 
550
 
 
551
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
552
 
 
553
      errno = xerrno;
381
554
      return PR_ERROR(cmd);
382
555
    }
383
556
 
384
557
    cmd_name = cmd->argv[0];
385
558
    cmd->argv[0] = "SITE_RMDIR";
386
559
    if (!dir_check_canon(cmd->tmp_pool, cmd, G_WRITE, path, NULL)) {
 
560
      int xerrno = EPERM;
 
561
 
387
562
      cmd->argv[0] = cmd_name;
388
563
 
389
564
      pr_log_debug(DEBUG4, MOD_SITE_MISC_VERSION
390
565
        ": %s command denied by <Limit>", cmd->argv[0]);
391
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM));
 
566
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
567
 
 
568
      errno = xerrno;
392
569
      return PR_ERROR(cmd);
393
570
    }
394
571
    cmd->argv[0] = cmd_name;
395
572
 
396
573
    if (site_misc_delete_path(cmd->tmp_pool, path) < 0) {
397
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno));
 
574
      int xerrno = errno;
 
575
 
 
576
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
577
 
 
578
      errno = xerrno;
398
579
      return PR_ERROR(cmd);
399
580
    }
400
581
 
402
583
    return PR_HANDLED(cmd);
403
584
  } 
404
585
 
405
 
  if (strcasecmp(cmd->argv[1], "HELP") == 0)
 
586
  if (strncasecmp(cmd->argv[1], "HELP", 5) == 0) {
406
587
    pr_response_add(R_214, "RMDIR <sp> path");
 
588
  }
407
589
 
408
590
  return PR_DECLINED(cmd);
409
591
}
419
601
    return PR_DECLINED(cmd);
420
602
  }
421
603
 
422
 
  if (strcasecmp(cmd->argv[1], "SYMLINK") == 0) {
 
604
  if (strncasecmp(cmd->argv[1], "SYMLINK", 8) == 0) {
423
605
    struct stat st;
424
606
    int res;
425
607
    char *cmd_name, *src, *dst;
430
612
 
431
613
    authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
432
614
 
433
 
    if (!authenticated || *authenticated == FALSE) {
 
615
    if (!authenticated ||
 
616
        *authenticated == FALSE) {
434
617
      pr_response_add_err(R_530, _("Please login with USER and PASS"));
 
618
      errno = EACCES;
435
619
      return PR_ERROR(cmd);
436
620
    }
437
621
 
438
622
    src = pr_fs_decode_path(cmd->tmp_pool, cmd->argv[2]);
439
623
    src = dir_canonical_path(cmd->tmp_pool, src);
440
624
    if (src == NULL) {
441
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EINVAL));
 
625
      int xerrno = EINVAL;
 
626
 
 
627
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
628
 
 
629
      errno = xerrno;
442
630
      return PR_ERROR(cmd);
443
631
    }
444
632
 
445
633
    cmd_name = cmd->argv[0];
446
634
    cmd->argv[0] = "SITE_SYMLINK";
447
635
    if (!dir_check_canon(cmd->tmp_pool, cmd, G_READ, src, NULL)) {
 
636
      int xerrno = EPERM;
 
637
 
448
638
      cmd->argv[0] = cmd_name;
449
639
 
450
640
      pr_log_debug(DEBUG4, MOD_SITE_MISC_VERSION
451
641
        ": %s command denied by <Limit>", cmd->argv[0]);
452
 
      pr_response_add_err(R_550, "%s: %s", cmd->argv[2], strerror(EPERM));
 
642
      pr_response_add_err(R_550, "%s: %s", cmd->argv[2], strerror(xerrno));
 
643
 
 
644
      errno = xerrno;
453
645
      return PR_ERROR(cmd);
454
646
    }
455
647
 
456
648
    dst = pr_fs_decode_path(cmd->tmp_pool, cmd->argv[3]);
457
649
    dst = dir_canonical_path(cmd->tmp_pool, dst);
458
650
    if (dst == NULL) {
459
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EINVAL));
 
651
      int xerrno = EINVAL;
 
652
 
 
653
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
654
 
 
655
      errno = xerrno;
460
656
      return PR_ERROR(cmd);
461
657
    }
462
658
 
463
659
    if (!dir_check_canon(cmd->tmp_pool, cmd, G_WRITE, dst, NULL)) {
 
660
      int xerrno = EPERM;
 
661
 
464
662
      cmd->argv[0] = cmd_name;
465
663
 
466
664
      pr_log_debug(DEBUG4, MOD_SITE_MISC_VERSION
467
665
        ": %s command denied by <Limit>", cmd->argv[0]);
468
 
      pr_response_add_err(R_550, "%s: %s", cmd->argv[3], strerror(EPERM));
 
666
      pr_response_add_err(R_550, "%s: %s", cmd->argv[3], strerror(xerrno));
 
667
 
 
668
      errno = xerrno;
469
669
      return PR_ERROR(cmd);
470
670
    }
471
671
    cmd->argv[0] = cmd_name;
472
672
 
473
673
    if (site_misc_check_filters(cmd, dst) < 0) {
474
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM));
 
674
      int xerrno = EPERM;
 
675
 
 
676
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
677
 
 
678
      errno = xerrno;
475
679
      return PR_ERROR(cmd);
476
680
    }
477
681
 
484
688
    pr_fs_clear_cache();
485
689
    res = pr_fsio_stat(src, &st);
486
690
    if (res < 0) {
487
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno));
 
691
      int xerrno = errno;
 
692
 
 
693
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
694
 
 
695
      errno = xerrno;
488
696
      return PR_ERROR(cmd);
489
697
    }
490
698
 
491
699
    if (pr_fsio_symlink(src, dst) < 0) {
492
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno));
 
700
      int xerrno = errno;
 
701
 
 
702
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
703
 
 
704
      errno = xerrno;
493
705
      return PR_ERROR(cmd);
494
706
    }
495
707
 
497
709
    return PR_HANDLED(cmd);
498
710
  } 
499
711
 
500
 
  if (strcasecmp(cmd->argv[1], "HELP") == 0)
 
712
  if (strncasecmp(cmd->argv[1], "HELP", 5) == 0) {
501
713
    pr_response_add(R_214, "SYMLINK <sp> source <sp> destination");
 
714
  }
502
715
 
503
716
  return PR_DECLINED(cmd);
504
717
}
514
727
    return PR_DECLINED(cmd);
515
728
  }
516
729
 
517
 
  if (strcasecmp(cmd->argv[1], "UTIME") == 0) {
 
730
  if (strncasecmp(cmd->argv[1], "UTIME", 6) == 0) {
518
731
    register unsigned int i;
519
732
    char c, *cmd_name, *p, *path = "";
520
733
    unsigned int year, month, day, hour, min, sec = 0;
530
743
    if (!authenticated ||
531
744
        *authenticated == FALSE) {
532
745
      pr_response_add_err(R_530, _("Please login with USER and PASS"));
 
746
      errno = EACCES;
533
747
      return PR_ERROR(cmd);
534
748
    }
535
749
 
536
750
    /* Accept both 'YYYYMMDDhhmm' and 'YYYYMMDDhhmmss' formats. */
537
751
    if (strlen(cmd->argv[2]) != 12 &&
538
752
        strlen(cmd->argv[2]) != 14) {
 
753
      int xerrno = EINVAL;
 
754
 
539
755
      pr_log_debug(DEBUG7, MOD_SITE_MISC_VERSION
540
756
        ": wrong number of digits in timestamp argument '%s' (%lu)",
541
757
        cmd->argv[2], (unsigned long) strlen(cmd->argv[2]));
542
 
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(EINVAL));
 
758
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(xerrno));
 
759
 
 
760
      errno = xerrno;
543
761
      return PR_ERROR(cmd);
544
762
    }
545
763
 
554
772
 
555
773
    path = dir_canonical_path(cmd->tmp_pool, path);
556
774
    if (path == NULL) {
557
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EINVAL));
 
775
      int xerrno = EINVAL;
 
776
 
 
777
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
778
 
 
779
      errno = xerrno;
558
780
      return PR_ERROR(cmd);
559
781
    }
560
782
 
561
783
    cmd_name = cmd->argv[0];
562
784
    cmd->argv[0] = "SITE_UTIME";
563
785
    if (!dir_check_canon(cmd->tmp_pool, cmd, G_WRITE, path, NULL)) {
 
786
      int xerrno = EPERM;
 
787
 
564
788
      cmd->argv[0] = cmd_name;
565
789
 
566
790
      pr_log_debug(DEBUG4, MOD_SITE_MISC_VERSION
567
791
        ": %s command denied by <Limit>", cmd->argv[0]);
568
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM));
 
792
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
793
 
 
794
      errno = xerrno;
569
795
      return PR_ERROR(cmd);
570
796
    }
571
797
    cmd->argv[0] = cmd_name;
572
798
 
573
799
    if (site_misc_check_filters(cmd, path) < 0) {
574
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM));
 
800
      int xerrno = EPERM;
 
801
 
 
802
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
803
 
 
804
      errno = xerrno;
575
805
      return PR_ERROR(cmd);
576
806
    }
577
807
 
587
817
    month = atoi(p);
588
818
 
589
819
    if (month > 12) {
 
820
      int xerrno = EINVAL;
 
821
 
590
822
      pr_log_debug(DEBUG7, MOD_SITE_MISC_VERSION
591
823
        ": bad number of months in '%s' (%d)", cmd->argv[2], month);
592
 
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(EINVAL));
 
824
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(xerrno));
 
825
 
 
826
      errno = xerrno;
593
827
      return PR_ERROR(cmd);
594
828
    }
595
829
 
600
834
    day = atoi(p);
601
835
 
602
836
    if (day > 31) {
 
837
      int xerrno = EINVAL;
 
838
 
603
839
      pr_log_debug(DEBUG7, MOD_SITE_MISC_VERSION
604
840
        ": bad number of days in '%s' (%d)", cmd->argv[2], day);
605
 
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(EINVAL));
 
841
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(xerrno));
 
842
 
 
843
      errno = xerrno;
606
844
      return PR_ERROR(cmd);
607
845
    }
608
846
 
613
851
    hour = atoi(p);
614
852
 
615
853
    if (hour > 24) {
 
854
      int xerrno = EINVAL;
 
855
 
616
856
      pr_log_debug(DEBUG7, MOD_SITE_MISC_VERSION
617
857
        ": bad number of hours in '%s' (%d)", cmd->argv[2], hour);
618
 
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(EINVAL));
 
858
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(xerrno));
 
859
 
 
860
      errno = xerrno;
619
861
      return PR_ERROR(cmd);
620
862
    }
621
863
 
631
873
    min = atoi(p);
632
874
 
633
875
    if (min > 60) {
 
876
      int xerrno = EINVAL;
 
877
 
634
878
      pr_log_debug(DEBUG7, MOD_SITE_MISC_VERSION
635
879
        ": bad number of minutes in '%s' (%d)", cmd->argv[2], min);
636
 
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(EINVAL));
 
880
      pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(xerrno));
 
881
 
 
882
      errno = xerrno;
637
883
      return PR_ERROR(cmd);
638
884
    }
639
885
 
643
889
      sec = atoi(p);
644
890
 
645
891
      if (sec > 60) {
 
892
        int xerrno = EINVAL;
 
893
 
646
894
        pr_log_debug(DEBUG7, MOD_SITE_MISC_VERSION
647
895
          ": bad number of seconds in '%s' (%d)", cmd->argv[2], sec);
648
 
        pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(EINVAL));
 
896
        pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(xerrno));
 
897
 
 
898
        errno = xerrno;
649
899
        return PR_ERROR(cmd);
650
900
      }
651
901
    }
655
905
      min, sec);
656
906
 
657
907
    if (pr_fsio_utimes(path, tvs) < 0) {
658
 
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno));
 
908
      int xerrno = errno;
 
909
 
 
910
      pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(xerrno));
 
911
 
 
912
      errno = xerrno;
659
913
      return PR_ERROR(cmd);
660
914
    }
661
915
 
663
917
    return PR_HANDLED(cmd);
664
918
  }
665
919
 
666
 
  if (strcasecmp(cmd->argv[1], "HELP") == 0)
 
920
  if (strncasecmp(cmd->argv[1], "HELP", 5) == 0) {
667
921
    pr_response_add(R_214, "UTIME <sp> YYYYMMDDhhmm[ss] <sp> path");
 
922
  }
668
923
 
669
924
  return PR_DECLINED(cmd);
670
925
}