1 /*
2 * h_mff.c
3 *
4 * (C)2002-2011 by Marc Huber <Marc.Huber@web.de>
5 * All rights reserved.
6 *
7 * $Id: h_mff.c,v 1.13 2015/03/14 06:11:25 marc Exp marc $
8 *
9 */
10
11 #include "headers.h"
12
13 static const char rcsid[] __attribute__ ((used)) = "$Id: h_mff.c,v 1.13 2015/03/14 06:11:25 marc Exp marc $";
14
h_mff(struct context * ctx,char * arg)15 void h_mff(struct context *ctx, char *arg)
16 {
17 char *t;
18
19 DebugIn(DEBUG_COMMAND);
20
21 t = arg;
22
23 while (*arg && !isspace((int) *arg))
24 arg++;
25
26 if (!isspace((int) *arg)) {
27 reply(ctx, MSG_500_arguments_required);
28 DebugOut(DEBUG_COMMAND);
29 return;
30 }
31
32 *arg++ = 0;
33
34 if (*arg) {
35 char *u, *v;
36 int flags = 0;
37 #define flag_modify 1
38 #define flag_unix_mode 2
39 #define flag_unix_group 4
40 time_t modify = 0;
41 mode_t unix_mode = 0;
42 gid_t unix_group = 0;
43
44 for (; (u = strtok(t, ";")); t = NULL)
45 if (*u && (v = strchr(u, '='))) {
46 *v++ = 0;
47
48 if (!strcasecmp(u, "Modify")) {
49 struct tm tm;
50 memset(&tm, 0, sizeof(tm));
51
52 if (6 != sscanf(v, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec))
53 goto syntax_error;
54 tm.tm_year -= 1900;
55 tm.tm_mon--;
56 flags |= flag_modify;
57 modify = mktime(&tm);
58 } else if (!strcasecmp(u, "UNIX.mode")) {
59 u_int mode;
60 if (1 != sscanf(v, "%o", &mode))
61 goto syntax_error;
62 flags |= flag_unix_mode;
63 unix_mode = (mode_t) mode;
64
65 } else if (!strcasecmp(u, "UNIX.group")) {
66 int i = NGROUPS_MAX;
67 u_int ug;
68
69 if (1 == sscanf(v, "%u", &ug))
70 for (i = 0; i < ctx->gids_size && (gid_t) ug != ctx->gids[i]; i++);
71 else
72 for (i = 0; i < ctx->gids_size && strcmp(arg, lookup_gid(ctx, ctx->gids[i])); i++);
73
74 if (i < ctx->gids_size) {
75 flags |= flag_unix_group;
76 unix_group = (gid_t) i;
77 }
78 } else {
79 replyf(ctx, MSG_504_Parameter_not_implemented, u);
80 goto bye;
81 }
82 } else if (*u) {
83 syntax_error:
84 reply(ctx, MSG_501_Syntax_error);
85 goto bye;
86 }
87
88 if (flags) {
89 struct stat st;
90 if ((t = buildpath(ctx, arg)) && (!pickystat(ctx, &st, t))
91 && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
92 if ((flags & flag_modify) && st.st_uid == ctx->uid) {
93 struct utimbuf ut;
94 ut.actime = st.st_atime;
95 ut.modtime = modify;
96 utime(t, &ut);
97 }
98
99 if (flags & ~flag_modify) {
100 int fn = open(t, O_RDONLY | O_NOFOLLOW);
101 if (fn > -1) {
102 if (!fstat(fn, &st) && st.st_uid == ctx->uid) {
103 if (flags & flag_unix_group) {
104 seteuid(0);
105 if (fchown(fn, (uid_t) - 1, unix_group)) {
106 // FIXME
107 }
108 seteuid(ctx->uid);
109 }
110 if (flags & flag_unix_mode)
111 fchmod(fn, unix_mode | (S_ISDIR(st.st_mode)
112 ? ctx->chmod_dirmask : ctx->chmod_filemask));
113 fstat(fn, &st);
114
115 }
116 close(fn);
117 }
118 } else
119 stat(t, &st);
120
121 reply(ctx, "213 ");
122 if (flags & flag_modify) {
123 char s[30];
124 strftime(s, sizeof(s), "%Y%m%d%H%M%S", gmtime(&st.st_mtime));
125 replyf(ctx, "Modify=%s;", s);
126 }
127
128 if (flags & flag_unix_mode)
129 replyf(ctx, "UNIX.mode=0%o;", 0777 & (u_int) st.st_mode);
130
131 if (flags & flag_unix_group)
132 replyf(ctx, "UNIX.group=%s;", lookup_gid(ctx, st.st_gid));
133
134 replyf(ctx, " %s\r\n", arg);
135 } else
136 reply(ctx, MSG_550_Permission_denied);
137 } else
138 replyf(ctx, "213 %s\r\n", arg);
139 } else
140 reply(ctx, MSG_500_missing_filename);
141
142 bye:
143 DebugOut(DEBUG_COMMAND);
144 }
145