Rev 55 | Rev 63 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 55 | Rev 61 | ||
---|---|---|---|
Line 101... | Line 101... | ||
101 | }
|
101 | }
|
102 | 102 | ||
103 | /// Program arguments
|
103 | /// Program arguments
|
104 | static struct argp argp = { options, parse_opt, args_doc, doc }; |
104 | static struct argp argp = { options, parse_opt, args_doc, doc }; |
105 | 105 | ||
106 | /// Unlink a file with temporarily changed UID.
|
- | |
107 | /**
|
- | |
108 | * \param[in] file file to unlink
|
- | |
109 | * \param[in] uid UID for unlink processing
|
- | |
110 | *
|
- | |
111 | * \attention No error checking is done!
|
- | |
112 | */
|
- | |
113 | void unlink_suid(const char* file, uid_t uid) |
- | |
114 | {
|
106 | |
115 | uid_t iu = geteuid(); |
- | |
116 | seteuid(uid); |
- | |
117 | if (unlink(file) != 0) |
- | |
118 | perror("cannot remove temporary file"); |
- | |
119 | seteuid(iu); |
- | |
120 | }
|
- | |
121 | 107 | ||
122 | /// Copies a file to an user table.
|
108 | /// Copies a file to an user table.
|
123 | /**
|
109 | /**
|
124 | * \param[in] path path to file
|
110 | * \param[in] path path to file
|
125 | * \param[in] user user name
|
111 | * \param[in] user user name
|
Line 205... | Line 191... | ||
205 | struct passwd* ppwd = getpwnam(user); |
191 | struct passwd* ppwd = getpwnam(user); |
206 | if (ppwd == NULL) { |
192 | if (ppwd == NULL) { |
207 | fprintf(stderr, "cannot find user %s: %s\n", user, strerror(errno)); |
193 | fprintf(stderr, "cannot find user %s: %s\n", user, strerror(errno)); |
208 | return false; |
194 | return false; |
209 | }
|
195 | }
|
- | 196 | ||
210 | uid_t uid = ppwd->pw_uid; |
197 | uid_t uid = ppwd->pw_uid; |
- | 198 | uid_t gid = ppwd->pw_gid; |
|
211 | 199 | ||
212 | char s[NAME_MAX]; |
200 | char s[NAME_MAX]; |
213 | strcpy(s, "/tmp/incron.table-XXXXXX"); |
201 | strcpy(s, "/tmp/incron.table-XXXXXX"); |
214 | 202 | ||
215 | uid_t iu = geteuid(); |
203 | uid_t iu = geteuid(); |
- | 204 | uid_t ig = getegid(); |
|
216 | 205 | ||
217 | if (seteuid(uid) != 0) { |
206 | if (seteuid(uid) != 0 || setegid(gid) != 0) { |
218 | fprintf(stderr, "cannot change effective UID to %i: %s\n", (int) uid, strerror(errno)); |
207 | fprintf(stderr, "cannot change effective UID/GID for user %s: %s\n", user, strerror(errno)); |
219 | return false; |
208 | return false; |
220 | }
|
209 | }
|
221 | 210 | ||
222 | int fd = mkstemp(s); |
211 | int fd = mkstemp(s); |
223 | if (fd == -1) { |
212 | if (fd == -1) { |
224 | fprintf(stderr, "cannot create temporary file: %s\n", strerror(errno)); |
213 | fprintf(stderr, "cannot create temporary file: %s\n", strerror(errno)); |
225 | return false; |
214 | return false; |
226 | }
|
215 | }
|
227 | 216 | ||
- | 217 | bool ok = false; |
|
- | 218 | FILE* out = NULL; |
|
- | 219 | FILE* in = NULL; |
|
- | 220 | time_t mt = (time_t) 0; |
|
- | 221 | const char* e = NULL; |
|
- | 222 | ||
228 | if (fchmod(fd, 0644) != 0) { |
223 | if (fchmod(fd, 0644) != 0) { |
229 | fprintf(stderr, "cannot change mode of temporary file: %s\n", strerror(errno)); |
224 | fprintf(stderr, "cannot change mode of temporary file: %s\n", strerror(errno)); |
230 | close(fd); |
225 | close(fd); |
231 | unlink_suid(s, uid); |
- | |
232 | return false; |
226 | goto end; |
233 | }
|
227 | }
|
234 | 228 | ||
235 | if (seteuid(iu) != 0) { |
229 | if (seteuid(iu) != 0 || setegid(ig) != 0) { |
236 | fprintf(stderr, "cannot change effective UID: %s\n", strerror(errno)); |
230 | fprintf(stderr, "cannot change effective UID/GID: %s\n", strerror(errno)); |
237 | close(fd); |
231 | close(fd); |
238 | unlink_suid(s, uid); |
- | |
239 | return false; |
232 | goto end; |
240 | }
|
233 | }
|
241 | 234 | ||
242 | FILE* out = fdopen(fd, "w"); |
235 | out = fdopen(fd, "w"); |
243 | if (out == NULL) { |
236 | if (out == NULL) { |
244 | fprintf(stderr, "cannot write to temporary file: %s\n", strerror(errno)); |
237 | fprintf(stderr, "cannot write to temporary file: %s\n", strerror(errno)); |
245 | close(fd); |
238 | close(fd); |
246 | unlink_suid(s, uid); |
- | |
247 | return false; |
239 | goto end; |
248 | }
|
240 | }
|
249 | 241 | ||
250 | FILE* in = fopen(tp.c_str(), "r"); |
242 | in = fopen(tp.c_str(), "r"); |
251 | if (in == NULL) { |
243 | if (in == NULL) { |
252 | if (errno == ENOENT) { |
244 | if (errno == ENOENT) { |
253 | in = fopen("/dev/null", "r"); |
245 | in = fopen("/dev/null", "r"); |
254 | if (in == NULL) { |
246 | if (in == NULL) { |
255 | fprintf(stderr, "cannot get empty table for %s: %s\n", user, strerror(errno)); |
247 | fprintf(stderr, "cannot get empty table for %s: %s\n", user, strerror(errno)); |
256 | fclose(out); |
248 | fclose(out); |
257 | unlink_suid(s, uid); |
- | |
258 | return false; |
249 | goto end; |
259 | }
|
250 | }
|
260 | }
|
251 | }
|
261 | else { |
252 | else { |
262 | fprintf(stderr, "cannot read old table for %s: %s\n", user, strerror(errno)); |
253 | fprintf(stderr, "cannot read old table for %s: %s\n", user, strerror(errno)); |
263 | fclose(out); |
254 | fclose(out); |
264 | unlink_suid(s, uid); |
- | |
265 | return false; |
255 | goto end; |
266 | }
|
256 | }
|
267 | }
|
257 | }
|
268 | 258 | ||
269 | char buf[1024]; |
259 | char buf[1024]; |
270 | while (fgets(buf, 1024, in) != NULL) { |
260 | while (fgets(buf, 1024, in) != NULL) { |
Line 274... | Line 264... | ||
274 | fclose(out); |
264 | fclose(out); |
275 | 265 | ||
276 | struct stat st; |
266 | struct stat st; |
277 | if (stat(s, &st) != 0) { |
267 | if (stat(s, &st) != 0) { |
278 | fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); |
268 | fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); |
279 | unlink_suid(s, uid); |
- | |
280 | return false; |
269 | goto end; |
281 | }
|
270 | }
|
282 | 271 | ||
283 | time_t mt = st.st_mtime; |
272 | mt = st.st_mtime; |
284 | 273 | ||
285 | const char* e = getenv("EDITOR"); |
274 | e = getenv("EDITOR"); |
286 | if (e == NULL) |
275 | if (e == NULL) |
287 | e = INCRON_DEFAULT_EDITOR; |
276 | e = INCRON_DEFAULT_EDITOR; |
288 | 277 | ||
- | 278 | {
|
|
289 | pid_t pid = fork(); |
279 | pid_t pid = fork(); |
290 | if (pid == 0) { |
280 | if (pid == 0) { |
291 | if (setuid(uid) != 0) { |
281 | if (setuid(uid) != 0 || setgid(gid) != 0) { |
292 | fprintf(stderr, "cannot set user %s: %s\n", user, strerror(errno)); |
282 | fprintf(stderr, "cannot set user %s: %s\n", user, strerror(errno)); |
293 | return false; |
283 | goto end; |
294 | }
|
284 | }
|
295 | 285 | ||
296 | execlp(e, e, s, NULL); |
286 | execlp(e, e, s, NULL); |
297 | _exit(1); |
287 | _exit(1); |
298 | }
|
288 | }
|
299 | else if (pid > 0) { |
289 | else if (pid > 0) { |
300 | int status; |
290 | int status; |
301 | if (wait(&status) != pid) { |
291 | if (wait(&status) != pid) { |
302 | perror("error while waiting for editor"); |
292 | perror("error while waiting for editor"); |
303 | unlink_suid(s, uid); |
293 | goto end; |
- | 294 | }
|
|
- | 295 | if (!(WIFEXITED(status)) || WEXITSTATUS(status) != 0) { |
|
- | 296 | perror("editor finished with error"); |
|
304 | return false; |
297 | goto end; |
- | 298 | }
|
|
305 | }
|
299 | }
|
306 | if (!(WIFEXITED(status)) || WEXITSTATUS(status) != 0) { |
300 | else { |
307 | perror("editor finished with error"); |
301 | perror("cannot start editor"); |
308 | unlink_suid(s, uid); |
- | |
309 | return false; |
302 | goto end; |
310 | }
|
303 | }
|
311 | }
|
304 | }
|
312 | else { |
- | |
313 | perror("cannot start editor"); |
- | |
314 | unlink_suid(s, uid); |
- | |
315 | return false; |
- | |
316 | }
|
- | |
317 | 305 | ||
318 | if (stat(s, &st) != 0) { |
306 | if (stat(s, &st) != 0) { |
319 | fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); |
307 | fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); |
320 | unlink_suid(s, uid); |
- | |
321 | return false; |
308 | goto end; |
322 | }
|
309 | }
|
323 | 310 | ||
324 | if (st.st_mtime == mt) { |
311 | if (st.st_mtime == mt) { |
325 | fprintf(stderr, "table unchanged\n"); |
312 | fprintf(stderr, "table unchanged\n"); |
326 | unlink_suid(s, uid); |
313 | ok = true; |
327 | return true; |
314 | goto end; |
328 | }
|
315 | }
|
329 | 316 | ||
- | 317 | {
|
|
330 | InCronTab ict;
|
318 | InCronTab ict;
|
331 | if (!ict.Load(s) || !ict.Save(tp)) { |
319 | if (!ict.Load(s) || !ict.Save(tp)) { |
332 | fprintf(stderr, "cannot move temporary table: %s\n", strerror(errno)); |
320 | fprintf(stderr, "cannot move temporary table: %s\n", strerror(errno)); |
333 | unlink(s); |
321 | goto end; |
334 | return false; |
322 | }
|
335 | }
|
323 | }
|
336 | 324 | ||
- | 325 | ok = true; |
|
337 | fprintf(stderr, "table updated\n"); |
326 | fprintf(stderr, "table updated\n"); |
338 | 327 | ||
- | 328 | end:
|
|
- | 329 | ||
339 | unlink_suid(s, uid); |
330 | unlink(s); |
340 | return true; |
331 | return ok; |
341 | }
|
332 | }
|
342 | 333 | ||
343 | 334 | ||
344 | int main(int argc, char** argv) |
335 | int main(int argc, char** argv) |
345 | {
|
336 | {
|