Codebase list fdm / 0a6441f
Get rid of from-headers. Framework for user lookups. passwd(5) only for now. Nicholas Marriott 15 years ago
29 changed file(s) with 548 addition(s) and 702 deletion(s). Raw diff Collapse all Expand all
0 26 June 2008
1
2 * Framework for changing user lookup method. At the moment only normal
3 Unix passwd (getpwnam(3)) is supported.
4 * Get rid of from-headers which was ugly and unreliable.
5
06 30 May 2008
17
28 * Make NNTP fetching save the cache file after each mail since some NNTP
4545 match-in-cache.c match-matched.c match-regexp.c match-size.c \
4646 match-string.c match-tagged.c match-unmatched.c match-account.c \
4747 parent-deliver.c parent-fetch.c \
48 lookup.c lookup-passwd.c \
4849 y.tab.c parse-fn.c lex.c
4950
5051 ifeq ($(shell uname),Darwin)
820820
821821 users { 1001 "nicholas" }
822822
823 - the keyword 'from-headers', that will attempt to ascertain a set of users
824 from the mail headers (see the 'domains' and 'headers' options in the
825 section on setting options).
826
827823 If users are specified, the action will be run once for each user, with fdm
828824 changing to that user before executing the action. Note that fdm will execute
829825 the action once for each user even when not started as root, but will not be
13971393
13981394 set lock-types fcntl dotlock
13991395
1400 - [domain|domains] <domains>
1401
1402 This specifies a domain or list of domains to use when searching for users in
1403 mail headers with the 'from-headers' keyword. Examples include:
1404
1405 set domain "xyz.ath.cx"
1406
1407 set domains { "abc.ca" "def.co.uk" }
1408
1409 The default is the hostname, FQDN and IP of the local machine.
1410
1411 - [header|headers] <headers>
1412
1413 This specifies a header or list of headers to search with the 'from-headers'
1414 keyword, such as:
1415
1416 set header { "to" "cc" }
1417
1418 set headers "x-envelope-to"
1419
1420 The default is "to" "cc".
1421
14221396 - proxy <url>
14231397
14241398 This specifies a URL to proxy outgoing connections through. See the section
2929 match-in-cache.c match-matched.c match-regexp.c match-size.c \
3030 match-string.c match-tagged.c match-unmatched.c match-account.c \
3131 parent-deliver.c parent-fetch.c \
32 lookup.c lookup-passwd.c \
3233 parse.y parse-fn.c lex.c
3334 HDRS= fdm.h array.h fetch.h match.h deliver.h
3435
4646 check pipe command user
4747 - when doing .netrc lookup, match the username if given as well to allow
4848 multiple users on the same server
49 - some way to limit number of accounts fetched in parallel, to avoid
50 hitting server per-IP limits
5149 - set secondary groups when changing user
5250 - from-headers stuff can probably go at some point
5351 - regress fails as root
5452 - rml could be stored as actual tags, then command0-9 could go... means
5553 copying... get rid of %0
5654 - document deliver imap
55 - add FAQ entry about no-apop since there are several servers out there
56 which claim to support it but do not
57 - lookup uid/gid/home in eg courier-authlib
58 document lookup-order
4747 setproctitle("%s[%lu]", data->name, (u_long) geteuid());
4848 #endif
4949
50 /* Refresh user and home and fix tags. */
51 fill_info(NULL);
52 update_tags(&m->tags);
53 log_debug2("%s: user is: %s, home is: %s", a->name, conf.info.user,
54 conf.info.home);
55
5650 /* Call the hook. */
5751 memset(&msg, 0, sizeof msg);
5852 data->hook(0, a, &msg, data, &msg.data.error);
110104 return;
111105 }
112106
107 dctx->udata = xmalloc(sizeof *dctx->udata);
108 dctx->udata->uid = data->uid;
109 dctx->udata->gid = data->gid;
110 dctx->udata->name = xstrdup(find_tag(m->tags, "user"));
111 dctx->udata->home = xstrdup(find_tag(m->tags, "home"));
112 log_debug2("%s: deliver user is: %s (%lu/%lu), home is: %s", a->name,
113 dctx->udata->name, (u_long) dctx->udata->uid,
114 (u_long) dctx->udata->gid, dctx->udata->home);
115
113116 /* This is the child. do the delivery. */
114117 *result = ti->deliver->deliver(dctx, ti);
115 if (ti->deliver->type != DELIVER_WRBACK || *result != DELIVER_SUCCESS)
118 if (ti->deliver->type != DELIVER_WRBACK || *result != DELIVER_SUCCESS) {
119 user_free(dctx->udata);
116120 return;
121 }
122 user_free(dctx->udata);
117123
118124 mail_send(md, msg);
119125 log_debug2("%s: using new mail, size %zu", a->name, md->size);
140146 }
141147
142148 /* Sort out the command. */
143 s = replacepath(&cmddata->cmd, m->tags, m, &m->rml);
149 s = replacepath(
150 &cmddata->cmd, m->tags, m, &m->rml, find_tag(m->tags, "home"));
144151 if (s == NULL || *s == '\0') {
145152 log_warnx("%s: empty command", a->name);
146153 goto error;
110110 setproctitle("child: %s", a->name);
111111 #endif
112112
113 fill_info(NULL);
114 log_debug2("%s: user is: %s, home is: %s", a->name, conf.info.user,
115 conf.info.home);
113 log_debug2("%s: user is %lu", a->name, (u_long) geteuid());
116114 tim = get_time();
117115
118116 /* Process fetch or poll. */
253251 while (!TAILQ_EMPTY(&mctx->dqueue)) {
254252 dctx = TAILQ_FIRST(&mctx->dqueue);
255253 TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
254 user_free(dctx->udata);
256255 xfree(dctx);
257256 }
258257
597596 if (!conf.no_received) {
598597 error = 1;
599598 if (rfc822time(time(NULL), rtime, sizeof rtime) != NULL) {
600 rhost = conf.info.fqdn;
599 rhost = conf.host_fqdn;
601600 if (rhost == NULL)
602 rhost = conf.info.host;
601 rhost = conf.host_name;
603602
604603 error = insert_header(m, "received", "Received: by "
605604 "%.450s (%s " BUILD ", account \"%.450s\");\n\t%s",
8989 }
9090
9191 struct child *
92 child_start(struct children *children, uid_t uid, int (*start)(struct child *,
93 struct io *), int (*msg)(struct child *, struct msg *, struct msgbuf *),
92 child_start(struct children *children, uid_t uid, gid_t gid,
93 int (*start)(struct child *, struct io *),
94 int (*msg)(struct child *, struct msg *, struct msgbuf *),
9495 void *data)
9596 {
9697 struct child *child, *childp;
116117 io_free(child->io);
117118
118119 if (geteuid() == 0)
119 dropto(uid);
120 dropto(uid, gid);
120121
121122 io = io_create(fds[1], NULL, IO_LF);
122123 n = start(child, io);
149149 name = NULL;
150150 fd = -1;
151151
152 path = replacepath(&data->path, m->tags, m, &m->rml);
152 path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home);
153153 if (path == NULL || *path == '\0') {
154154 log_warnx("%s: empty path", a->name);
155155 goto error;
8181 f = gzf = NULL;
8282 fd = -1;
8383
84 path = replacepath(&data->path, m->tags, m, &m->rml);
84 path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home);
8585 if (path == NULL || *path == '\0') {
8686 log_warnx("%s: empty path", a->name);
8787 goto error;
158158 fatal("sigprocmask failed");
159159
160160 /* Write the from line. */
161 from = make_from(m);
161 from = make_from(m, dctx->udata->name);
162162 if (deliver_mbox_write(f, gzf, from, strlen(from)) < 0) {
163163 xfree(from);
164164 goto error_unblock;
4848 char *lbuf;
4949 size_t llen;
5050
51 s = replacepath(&data->cmd, m->tags, m, &m->rml);
51 s = replacepath(&data->cmd, m->tags, m, &m->rml, dctx->udata->home);
5252 if (s == NULL || *s == '\0') {
5353 log_warnx("%s: empty command", a->name);
5454 goto error;
5151 char *lbuf;
5252 size_t llen;
5353
54 s = replacepath(&data->cmd, m->tags, m, &m->rml);
54 s = replacepath(&data->cmd, m->tags, m, &m->rml, dctx->udata->home);
5555 if (s == NULL || *s == '\0') {
5656 log_warnx("%s: empty command", a->name);
5757 goto error;
8686 llen = IO_LINESIZE;
8787 lbuf = xmalloc(llen);
8888
89 xasprintf(&ptr, "%s@%s", conf.info.user, conf.info.host);
89 if (conf.host_fqdn != NULL)
90 xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_fqdn);
91 else
92 xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_name);
9093 if (data->to.str == NULL)
9194 to = xstrdup(ptr);
9295 else {
128131 if (code != 220)
129132 goto error;
130133 state = SMTP_HELO;
131 io_writeline(io, "HELO %s", conf.info.host);
134 if (conf.host_fqdn != NULL)
135 io_writeline(io, "HELO %s", conf.host_fqdn);
136 else
137 io_writeline(io, "HELO %s", conf.host_name);
132138 break;
133139 case SMTP_HELO:
134140 if (code != 250)
4545 char *path;
4646 FILE *f;
4747
48 path = replacepath(&data->path, m->tags, m, &m->rml);
48 path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home);
4949 if (path == NULL || *path == '\0') {
5050 if (path != NULL)
5151 xfree(path);
3333 struct account *account;
3434 struct mail *mail;
3535
36 uid_t uid;
36 struct userdata *udata;
3737
3838 struct mail wr_mail;
3939
+73
-150
fdm.c less more
7979 }
8080
8181 void
82 fill_info(const char *home)
82 fill_host(void)
8383 {
84 struct passwd *pw;
85 uid_t uid;
86 char host[MAXHOSTNAMELEN];
87
88 uid = geteuid();
89 if (conf.info.valid && conf.info.last_uid == uid)
90 return;
91 conf.info.valid = 1;
92 conf.info.last_uid = uid;
93
94 if (conf.info.uid != NULL) {
95 xfree(conf.info.uid);
96 conf.info.uid = NULL;
97 }
98 if (conf.info.user != NULL) {
99 xfree(conf.info.user);
100 conf.info.user = NULL;
101 }
102 if (conf.info.home != NULL) {
103 xfree(conf.info.home);
104 conf.info.home = NULL;
105 }
106
107 if (conf.info.host == NULL) {
108 if (gethostname(host, sizeof host) != 0)
109 fatal("gethostname failed");
110 conf.info.host = xstrdup(host);
111
112 getaddrs(host, &conf.info.fqdn, &conf.info.addr);
113 }
114
115 if (home != NULL && *home != '\0')
116 conf.info.home = xstrdup(home);
117
118 xasprintf(&conf.info.uid, "%lu", (u_long) uid);
119 pw = getpwuid(uid);
120 if (pw != NULL) {
121 if (conf.info.home == NULL) {
122 if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
123 conf.info.home = xstrdup(pw->pw_dir);
124 else
125 conf.info.home = xstrdup(".");
126 }
127 if (pw->pw_name != NULL && *pw->pw_name != '\0')
128 conf.info.user = xstrdup(pw->pw_name);
129 }
130 endpwent();
131 if (conf.info.user == NULL) {
132 conf.info.user = xstrdup(conf.info.uid);
133 log_warnx("can't find name for user %lu", (u_long) uid);
134 }
84 char host[MAXHOSTNAMELEN];
85
86 if (gethostname(host, sizeof host) != 0)
87 fatal("gethostname failed");
88 conf.host_name = xstrdup(host);
89 getaddrs(host, &conf.host_fqdn, &conf.host_address);
13590 }
13691
13792 void
138 dropto(uid_t uid)
93 dropto(uid_t uid, gid_t gid)
13994 {
140 struct passwd *pw;
141 gid_t gid;
142
14395 if (uid == (uid_t) -1 || uid == 0)
14496 return;
145
146 pw = getpwuid(uid);
147 if (pw == NULL) {
148 errno = ESRCH;
149 fatal("getpwuid failed");
150 }
151 gid = pw->pw_gid;
152 endpwent();
97 if (gid == (gid_t) -1 || gid == 0)
98 return;
15399
154100 if (setgroups(1, &gid) != 0)
155101 fatal("setgroups failed");
234180 int opt, lockfd, status, res;
235181 u_int i;
236182 enum fdmop op = FDMOP_NONE;
237 const char *errstr, *proxy = NULL, *s;
238 char tmp[BUFSIZ], *ptr, *strs, *user = NULL, *lock = NULL;
183 const char *proxy = NULL, *s;
184 char tmp[BUFSIZ], *ptr, *lock = NULL;
239185 long n;
240186 struct utsname un;
241187 struct passwd *pw;
255201 size_t off;
256202 struct strings macros;
257203 struct child_fetch_data *cfd;
204 struct userdata *ud;
258205 #ifdef DEBUG
259206 struct rule *r;
260207 struct action *t;
277224 conf.file_group = -1;
278225 conf.queue_high = -1;
279226 conf.queue_low = -1;
280 conf.def_user = -1;
281 conf.cmd_user = -1;
227 conf.def_user = NULL;
228 conf.cmd_user = NULL;
282229 conf.max_accts = -1;
283230 conf.strip_chars = xstrdup(DEFSTRIPCHARS);
231
232 conf.user_order = xmalloc(sizeof *conf.user_order);
233 ARRAY_INIT(conf.user_order);
234 ARRAY_ADD(conf.user_order, passwd_lookup);
284235
285236 ARRAY_INIT(&conf.incl);
286237 ARRAY_INIT(&conf.excl);
295246 ARRAY_ADD(&macros, optarg);
296247 break;
297248 case 'f':
298 conf.conf_file = xstrdup(optarg);
249 if (conf.conf_file == NULL)
250 conf.conf_file = xstrdup(optarg);
299251 break;
300252 case 'k':
301253 conf.keep_all = 1;
310262 conf.check_only = 1;
311263 break;
312264 case 'u':
313 user = optarg;
265 if (conf.def_user == NULL)
266 conf.def_user = xstrdup(optarg);
314267 break;
315268 case 'v':
316269 if (conf.debug != -1)
348301 usage();
349302 }
350303
351 /* Check the user. */
352 if (user != NULL) {
353 pw = getpwnam(user);
354 if (pw == NULL) {
355 endpwent();
356 n = strtonum(user, 0, UID_MAX, &errstr);
357 if (errstr != NULL) {
358 if (errno == ERANGE) {
359 log_warnx("invalid uid: %s", user);
360 exit(1);
361 }
362 } else
363 pw = getpwuid((uid_t) n);
364 if (pw == NULL) {
365 log_warnx("unknown user: %s", user);
366 exit(1);
367 }
368 }
369 conf.def_user = pw->pw_uid;
370 endpwent();
371 }
372
373304 /* Set debug level and start logging to syslog if necessary. */
374305 if (conf.syslog)
375306 log_open(NULL, LOG_MAIL, conf.debug);
386317 } else
387318 log_debug2("uname: %s", strerror(errno));
388319
389 /* Save the home dir and misc user info. */
390 fill_info(getenv("HOME"));
391 log_debug2("user is: %s, home is: %s", conf.info.user, conf.info.home);
320 /* Fill the hostname. */
321 fill_host();
322 log_debug2("host is: %s %s %s",
323 conf.host_name, conf.host_fqdn, conf.host_address);
324
325 /* Find invoking user's details. */
326 if ((pw = getpwuid(geteuid())) == NULL) {
327 log_warnx("unknown user: %lu", (u_long) geteuid());
328 exit(1);
329 }
330 if (conf.def_user == NULL)
331 conf.def_user = xstrdup(pw->pw_name);
332 if (conf.cmd_user == NULL)
333 conf.cmd_user = xstrdup(pw->pw_name);
334 conf.user_home = xstrdup(pw->pw_dir);
335 log_debug2("home is: %s", conf.user_home);
336 endpwent();
392337
393338 /* Find the config file. */
394339 if (conf.conf_file == NULL) {
395340 /* If no file specified, try ~ then /etc. */
396 xasprintf(&conf.conf_file, "%s/%s", conf.info.home, CONFFILE);
341 xasprintf(&conf.conf_file, "%s/%s", conf.user_home, CONFFILE);
397342 if (access(conf.conf_file, R_OK) != 0) {
398343 xfree(conf.conf_file);
399344 conf.conf_file = xstrdup(SYSCONFFILE);
425370 /* Set the umask. */
426371 umask(conf.file_umask);
427372
428 /* Figure out default and command users. */
429 if (conf.def_user == (uid_t) -1) {
430 conf.def_user = geteuid();
431 if (conf.def_user == 0) {
432 log_warnx("no default user specified");
433 exit(1);
434 }
435 }
436 if (conf.cmd_user == (uid_t) -1)
437 conf.cmd_user = geteuid();
373 /* Check default and command users. */
374 if (conf.def_user == NULL) {
375 ud = user_lookup(conf.def_user, conf.user_order);
376 if (ud == NULL) {
377 log_warnx("unknown user: %s", conf.def_user);
378 exit(1);
379 }
380 user_free(ud);
381 }
382 if (conf.cmd_user == NULL) {
383 ud = user_lookup(conf.cmd_user, conf.user_order);
384 if (ud == NULL) {
385 log_warnx("unknown user: %s", conf.cmd_user);
386 exit(1);
387 }
388 user_free(ud);
389 }
438390
439391 /* Print proxy info. */
440392 if (conf.proxy != NULL) {
466418 strlcat(tmp, "dotlock ", sizeof tmp);
467419 }
468420 log_debug2("locking using: %s", tmp);
469
470 /* Initialise and print headers and domains. */
471 if (conf.headers == NULL) {
472 conf.headers = xmalloc(sizeof *conf.headers);
473 ARRAY_INIT(conf.headers);
474 ARRAY_ADD(conf.headers, xstrdup("to"));
475 ARRAY_ADD(conf.headers, xstrdup("cc"));
476 }
477 strs = fmt_strings("", conf.headers);
478 log_debug2("headers are: %s", strs);
479 xfree(strs);
480 if (conf.domains == NULL) {
481 conf.domains = xmalloc(sizeof *conf.domains);
482 ARRAY_INIT(conf.domains);
483 ARRAY_ADD(conf.domains, xstrdup(conf.info.host));
484 if (conf.info.fqdn != NULL) {
485 ptr = xstrdup(conf.info.fqdn);
486 ARRAY_ADD(conf.domains, ptr);
487 }
488 if (conf.info.addr != NULL) {
489 xasprintf(&ptr, "\\[%s\\]", conf.info.addr);
490 ARRAY_ADD(conf.domains, ptr);
491 }
492 }
493 strs = fmt_strings("", conf.domains);
494 log_debug2("domains are: %s", strs);
495 xfree(strs);
496421
497422 /* Print the other settings. */
498423 *tmp = '\0';
521446 }
522447 if (sizeof tmp > off) {
523448 off += xsnprintf(tmp + off, (sizeof tmp) - off,
524 "default-user=%lu, ", (u_long) conf.def_user);
449 "default-user=\"%s\", ", conf.def_user);
525450 }
526451 if (sizeof tmp > off) {
527452 off += xsnprintf(tmp + off, (sizeof tmp) - off,
528 "command-user=%lu, ", (u_long) conf.cmd_user);
453 "command-user=\"%s\", ", conf.cmd_user);
529454 }
530455 if (sizeof tmp > off && conf.impl_act != DECISION_NONE) {
531456 if (conf.impl_act == DECISION_DROP)
653578 if (geteuid() == 0)
654579 lock = xstrdup(SYSLOCKFILE);
655580 else
656 xasprintf(&lock, "%s/%s", conf.info.home, LOCKFILE);
581 xasprintf(&lock, "%s/%s", conf.user_home, LOCKFILE);
657582 }
658583 if (*lock != '\0' && !conf.allow_many) {
659584 lockfd = xcreate(lock, O_WRONLY, -1, -1, S_IRUSR|S_IWUSR);
717642 cfd->account = a;
718643 cfd->op = op;
719644 cfd->children = &children;
720 child = child_start(&children,
721 conf.child_uid, child_fetch, parent_fetch, cfd);
645 child = child_start(&children,
646 conf.child_uid, conf.child_gid,
647 child_fetch, parent_fetch, cfd);
722648 log_debug2("parent: child %ld (%s) started",
723649 (long) child->pid, a->name);
724650 }
878804 TAILQ_REMOVE(&conf.actions, t, entry);
879805 free_action(t);
880806 }
881 xfree(conf.info.home);
882 xfree(conf.info.user);
883 xfree(conf.info.uid);
884 xfree(conf.info.host);
885 if (conf.info.fqdn != NULL)
886 xfree(conf.info.fqdn);
887 if (conf.info.addr != NULL)
888 xfree(conf.info.addr);
807 xfree(conf.def_user);
808 xfree(conf.cmd_user);
809 xfree(conf.user_home);
810 ARRAY_FREEALL(conf.user_order);
811 xfree(conf.host_name);
812 if (conf.host_fqdn != NULL)
813 xfree(conf.host_fqdn);
814 if (conf.host_address != NULL)
815 xfree(conf.host_address);
889816 xfree(conf.conf_file);
890817 xfree(conf.lock_file);
891818 xfree(conf.tmp_dir);
892819 xfree(conf.strip_chars);
893 free_strings(conf.domains);
894 ARRAY_FREEALL(conf.domains);
895 free_strings(conf.headers);
896 ARRAY_FREEALL(conf.headers);
897820 free_strings(&conf.incl);
898821 free_strings(&conf.excl);
899822
147147 types are mutually exclusive.
148148 The default is
149149 .Em flock .
150 .It Xo Ic domain Ar domain | Ic domains
151 .Li {
152 .Ar domain Ar ...
153 .Li }
154 .Xc
155 This specifies the domains to be used when looking for users with the
156 .Ic from-headers
157 keyword.
158 The default is the computer's hostname.
159 .It Xo Ic header Ar header | Ic headers
160 .Li {
161 .Ar header Ar ...
162 .Li }
163 .Xc
164 This allows the headers to be examined when looking for users to be set.
165 The default is to look only at the "From" and "Cc" headers.
166 The headers are case-insensitive.
167150 .It Ic proxy Ar url
168151 This instructs
169152 .Xr fdm 1
310293 .Li {
311294 .Ar user ...
312295 .Li } |
313 .Ic user Ic from-headers
314 .Xc
315 .El
316296 .Pp
317297 The first two options specify a user or list of users as which the mail should
318298 be delivered when an action is executed.
319 If
320 .Ic user Ic from-headers
321 is specified,
322 .Xr fdm 1
323 attempts to find the users from the mail headers, using the values of the
324 .Ic headers
325 and
326 .Ic domains
327 options.
328 If no headers are specified, or
329 .Xr fdm 1
330 fails to find any valid users in the headers, the default user (set with
299 If no users are specified, the default user (set with
331300 .Ic set Ic default-user )
332301 is used.
333302 Users specified as part of the account definition may be overridden by similar
+50
-37
fdm.h less more
6666 #define DEFUMASK (S_IRWXG|S_IRWXO)
6767 #define FILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
6868 #define DIRMODE (S_IRWXU|S_IRWXG|S_IRWXO)
69 #define MAXUSERLEN 256
6970
7071 extern char *__progname;
7172
425426 struct actitem *actitem;
426427 struct match_command_data *cmddata;
427428
428 uid_t uid;
429 uid_t uid;
430 gid_t gid;
429431 };
430432
431433 /* Privsep message buffer. */
472474
473475 struct child *child; /* the source of the request */
474476
477 uid_t uid;
478 gid_t gid;
479
475480 u_int msgid;
476481 const char *name;
477482
485490 struct match_command_data *cmddata;
486491 };
487492
488 /* Users list. */
489 ARRAY_DECL(users, uid_t);
490
491493 /* Account entry. */
492494 struct account {
493495 u_int idx;
494496
495497 char name[MAXNAMESIZE];
496498
497 struct users *users;
498 int find_uid;
499 struct replstrs *users;
499500
500501 int disabled;
501502 int keep;
524525 struct action {
525526 char name[MAXNAMESIZE];
526527
527 struct users *users;
528 int find_uid;
528 struct replstrs *users;
529529
530530 struct actlist *list;
531531
572572
573573 struct expr *expr;
574574
575 struct users *users;
576 int find_uid; /* find uids from headers */
575 struct replstrs *users;
577576
578577 int stop; /* stop matching at this rule */
579578
589588 #define LOCK_FLOCK 0x2
590589 #define LOCK_DOTLOCK 0x4
591590
591 /* User info settings. */
592 struct userdata {
593 char *name;
594 char *home;
595
596 uid_t uid;
597 gid_t gid;
598 };
599
600 /* User lookup order. */
601 typedef struct userdata *(*userfunction)(const char *);
602 ARRAY_DECL(userfunctions, userfunction);
603
592604 /* Configuration settings. */
593605 struct conf {
594606 int debug;
603615
604616 struct proxy *proxy;
605617
606 struct strings *domains; /* domains to look for with users */
607 struct strings *headers; /* headers to search for users */
608
609 struct {
610 int valid;
611 uid_t last_uid;
612
613 char *home;
614 char *user;
615 char *uid;
616 char *host;
617 char *fqdn;
618 char *addr;
619 } info;
618 char *user_home;
619 struct userfunctions *user_order;
620
621 char *host_name;
622 char *host_fqdn;
623 char *host_address;
620624
621625 char *conf_file;
622626 char *lock_file;
641645 int timeout;
642646 int del_big;
643647 u_int lock_types;
644 uid_t def_user;
645 uid_t cmd_user;
648
649 char *def_user;
650 char *cmd_user;
646651
647652 TAILQ_HEAD(, cache) caches;
648653 TAILQ_HEAD(, account) accounts;
730735 __dead printflike1 void yyerror(const char *, ...);
731736
732737 /* parse-fn.c */
733 char *expand_path(const char *);
738 char *expand_path(const char *, const char *);
734739 char *run_command(const char *, const char *);
735740 char *fmt_replstrs(const char *, struct replstrs *);
736741 char *fmt_strings(const char *, struct strings *);
737 char *fmt_users(const char *, struct users *);
738742 int have_accounts(char *);
739743 struct account *find_account(char *);
740744 struct action *find_action(char *);
763767 extern volatile sig_atomic_t sigint;
764768 extern volatile sig_atomic_t sigterm;
765769 double get_time(void);
766 void dropto(uid_t);
770 void dropto(uid_t, gid_t);
767771 int check_incl(const char *);
768772 int check_excl(const char *);
769773 int use_account(struct account *, char **);
770 void fill_info(const char *);
774 void fill_host(void);
771775 __dead void usage(void);
772776
773777 /* cache-op.c */
786790 struct attach *attach_build(struct mail *);
787791 void attach_free(struct attach *);
788792
793 /* lookup.c */
794 struct userdata *user_lookup(const char *, struct userfunctions *);
795 void user_free(struct userdata *);
796 struct userdata *user_copy(struct userdata *);
797
798 /* lookup-passwd.c */
799 struct userdata *passwd_lookup(const char *);
800
789801 /* privsep.c */
790802 int privsep_send(struct io *, struct msg *, struct msgbuf *);
791803 int privsep_check(struct io *);
800812 /* child.c */
801813 int child_fork(void);
802814 __dead void child_exit(int);
803 struct child *child_start(struct children *, uid_t, int (*)(struct child *,
804 struct io *), int (*)(struct child *, struct msg *,
805 struct msgbuf *), void *);
815 struct child *child_start(struct children *, uid_t, gid_t,
816 int (*)(struct child *, struct io *),
817 int (*)(struct child *, struct msg *, struct msgbuf *),
818 void *);
806819
807820 /* child-fetch.c */
808821 int open_cache(struct account *, struct cache *);
865878 size_t find_body(struct mail *);
866879 void count_lines(struct mail *, u_int *, u_int *);
867880 int append_line(struct mail *, const char *, size_t);
868 struct users *find_users(struct mail *);
869881 char *find_address(char *, size_t, size_t *);
870882 void trim_from(struct mail *);
871 char *make_from(struct mail *);
883 char *make_from(struct mail *, char *);
872884 u_int fill_wrapped(struct mail *);
873885 void set_wrapped(struct mail *, char);
874886
914926 const char *find_tag(struct strb *, const char *);
915927 const char *match_tag(struct strb *, const char *);
916928 void default_tags(struct strb **, const char *);
917 void update_tags(struct strb **);
929 void update_tags(struct strb **, struct userdata *);
930 void reset_tags(struct strb **);
918931 char *replacestr(struct replstr *, struct strb *, struct mail *,
919932 struct rmlist *);
920933 char *replacepath(struct replpath *, struct strb *, struct mail *,
921 struct rmlist *);
934 struct rmlist *, const char *);
922935
923936 /* log.c */
924937 void log_open(FILE *, int, int);
8989 { "delete-oversized", TOKDELTOOBIG },
9090 { "disabled", TOKDISABLED },
9191 { "domain", TOKDOMAIN },
92 { "domains", TOKDOMAINS },
9392 { "dotlock", TOKDOTLOCK },
9493 { "drop", TOKDROP },
9594 { "exec", TOKEXEC },
101100 { "folder", TOKFOLDER },
102101 { "folders", TOKFOLDERS },
103102 { "from", TOKFROM },
104 { "from-headers", TOKFROMHEADERS },
105103 { "g", TOKGIGABYTES },
106104 { "gb", TOKGIGABYTES },
107105 { "gigabyte", TOKGIGABYTES },
126124 { "lock-file", TOKLOCKFILE },
127125 { "lock-type", TOKLOCKTYPES },
128126 { "lock-types", TOKLOCKTYPES },
127 { "lookup-order", TOKLOOKUPORDER },
129128 { "m", TOKMEGABYTES },
130129 { "maildir", TOKMAILDIR },
131130 { "maildirs", TOKMAILDIRS },
156155 { "or", TOKOR },
157156 { "parallel-accounts", TOKPARALLELACCOUNTS },
158157 { "pass", TOKPASS },
158 { "passwd", TOKPASSWD },
159159 { "pipe", TOKPIPE },
160160 { "pop3", TOKPOP3 },
161161 { "pop3s", TOKPOP3S },
216216 rp.str = read_string('"', 1);
217217 else
218218 rp.str = read_string('\'', 0);
219 path = replacepath(&rp, parse_tags, NULL, NULL);
219 path = replacepath(&rp, parse_tags, NULL, NULL, conf.user_home);
220220 xfree(rp.str);
221221 include_start(path);
222222 lex_include = 0;
0 /* $Id$ */
1
2 /*
3 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
14 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
15 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/types.h>
19
20 #include <pwd.h>
21
22 #include "fdm.h"
23
24 struct userdata *
25 passwd_lookup(const char *user)
26 {
27 struct passwd *pw;
28 struct userdata *ud;
29 uid_t uid;
30 const char *errstr;
31
32 if ((pw = getpwnam(user)) == NULL) {
33 endpwent();
34 uid = strtonum(user, 0, UID_MAX, &errstr);
35 if (errstr != NULL)
36 return (NULL);
37 if ((pw = getpwuid(uid)) == NULL) {
38 endpwent();
39 return (NULL);
40 }
41 }
42
43 ud = xmalloc(sizeof *ud);
44
45 ud->name = xstrdup(pw->pw_name);
46 ud->home = xstrdup(pw->pw_dir);
47
48 ud->uid = pw->pw_uid;
49 ud->gid = pw->pw_gid;
50
51 endpwent();
52 return (ud);
53 }
0 /* $Id$ */
1
2 /*
3 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
14 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
15 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/types.h>
19
20 #include <unistd.h>
21
22 #include "fdm.h"
23
24 struct userdata *
25 user_lookup(const char *user, struct userfunctions *order)
26 {
27 struct userdata *ud;
28 u_int i;
29
30 for (i = 0; i < ARRAY_LENGTH(order); i++) {
31 if ((ud = ARRAY_ITEM(order, i)(user)) != NULL)
32 return (ud);
33 }
34 return (NULL);
35 }
36
37 void
38 user_free(struct userdata *ud)
39 {
40 xfree(ud->name);
41 xfree(ud->home);
42 xfree(ud);
43
44 }
45
46 struct userdata *
47 user_copy(struct userdata *ud)
48 {
49 struct userdata *ue;
50
51 ue = xmalloc(sizeof *ue);
52 ue->uid = ud->uid;
53 ue->gid = ud->gid;
54 ue->name = xstrdup(ud->name);
55 ue->home = xstrdup(ud->home);
56
57 return (ue);
58 }
2525 #include "fetch.h"
2626 #include "match.h"
2727
28 void apply_result(struct expritem *, int *, int);
29
30 struct users *find_delivery_users(struct mail_ctx *, struct action *, int *);
31 int fill_from_strings(struct mail_ctx *, struct rule *,
32 struct replstrs *);
33 int fill_from_string(struct mail_ctx *, struct rule *,
34 struct replstr *);
35 int fill_from_action(struct mail_ctx *, struct rule *,
36 struct action *, struct users *);
37
38 int start_action(struct mail_ctx *, struct deliver_ctx *);
39 int finish_action(struct deliver_ctx *, struct msg *,
28 void apply_result(struct expritem *, int *, int);
29
30 struct replstrs *find_delivery_users(struct mail_ctx *, struct action *, int *);
31 int fill_from_strings(struct mail_ctx *, struct rule *,
32 struct replstrs *);
33 int fill_from_string(struct mail_ctx *, struct rule *,
34 struct replstr *);
35 int fill_from_action(struct mail_ctx *, struct rule *,
36 struct action *, struct replstrs *);
37
38 int start_action(struct mail_ctx *, struct deliver_ctx *);
39 int finish_action(struct deliver_ctx *, struct msg *,
4040 struct msgbuf *);
4141
4242 #define ACTION_DONE 0
5757 struct account *a = mctx->account;
5858 struct mail *m = mctx->mail;
5959 struct expritem *ei;
60 struct users *users;
60 struct replstrs *users;
6161 int should_free, this = -1, error = MAIL_CONTINUE;
6262 char desc[DESCBUFSIZE];
6363
7474 if (msgbuf->buf != NULL && msgbuf->len != 0) {
7575 strb_destroy(&m->tags);
7676 m->tags = msgbuf->buf;
77 update_tags(&m->tags);
77 update_tags(&m->tags, NULL);
7878 }
7979
8080 ei = mctx->expritem;
306306 log_debug("%s: message %u delivered (rule %u, %s) in %.3f seconds",
307307 a->name, m->idx, dctx->rule->idx,
308308 dctx->actitem->deliver->name, get_time() - dctx->tim);
309 user_free(dctx->udata);
309310 xfree(dctx);
310311 return (MAIL_CONTINUE);
311312 }
312313
313 struct users *
314 struct replstrs *
314315 find_delivery_users(struct mail_ctx *mctx, struct action *t, int *should_free)
315316 {
316317 struct account *a = mctx->account;
317 struct mail *m = mctx->mail;
318318 struct rule *r = mctx->rule;
319 struct users *users;
319 struct replstrs *users;
320320
321321 *should_free = 0;
322322 users = NULL;
323 if (r->find_uid) { /* rule comes first */
324 *should_free = 1;
325 users = find_users(m);
326 } else if (r->users != NULL) {
327 *should_free = 0;
323 if (r->users != NULL) /* rule comes first */
328324 users = r->users;
329 } else if (t != NULL && t->find_uid) { /* then action */
330 *should_free = 1;
331 users = find_users(m);
332 } else if (t != NULL && t->users != NULL) {
333 *should_free = 0;
325 else if (t != NULL && t->users != NULL) /* then action */
334326 users = t->users;
335 } else if (a->find_uid) { /* then account */
336 *should_free = 1;
337 users = find_users(m);
338 } else if (a->users != NULL) {
339 *should_free = 0;
327 else if (a->users != NULL) /* then account */
340328 users = a->users;
341 }
342329 if (users == NULL) {
343330 *should_free = 1;
344331 users = xmalloc(sizeof *users);
345332 ARRAY_INIT(users);
346 ARRAY_ADD(users, conf.def_user);
333 ARRAY_EXPAND(users, 1);
334 ARRAY_LAST(users).str = conf.def_user;
347335 }
348336
349337 return (users);
380368 struct actions *ta;
381369 u_int i;
382370 char *s;
383 struct users *users;
371 struct replstrs *users;
384372 int should_free;
385373
386374 s = replacestr(rs, m->tags, m, &m->rml);
419407
420408 int
421409 fill_from_action(struct mail_ctx *mctx, struct rule *r, struct action *t,
422 struct users *users)
410 struct replstrs *users)
423411 {
424412 struct account *a = mctx->account;
425413 struct mail *m = mctx->mail;
427415 struct actitem *ti;
428416 struct deliver_ctx *dctx;
429417 u_int i;
418 const char *user;
419 struct userdata *udata;
430420
431421 for (i = 0; i < ARRAY_LENGTH(users); i++) {
422 user = replacestr(&ARRAY_ITEM(users, i), m->tags, m, &m->rml);
423 if (user == NULL || *user == '\0') {
424 log_warnx("%s: empty user", a->name);
425 return (-1);
426 }
427 if ((udata = user_lookup(user, conf.user_order)) == NULL) {
428 log_warnx("%s: bad user: %s", a->name, user);
429 return (-1);
430 }
431
432432 TAILQ_FOREACH(ti, t->list, entry) {
433433 if (ti->deliver == NULL) {
434434 data = ti->data;
435435 if (fill_from_strings(
436 mctx, r, data->actions) != 0)
436 mctx, r, data->actions) != 0) {
437 user_free(udata);
437438 return (-1);
439 }
438440 continue;
439441 }
440442
444446 dctx->account = a;
445447 dctx->rule = r;
446448 dctx->mail = m;
447 dctx->uid = ARRAY_ITEM(users, i);
448
449 log_debug3("%s: action %s:%u (%s), uid %lu", a->name,
449
450 dctx->udata = user_copy(udata);
451
452 log_debug3("%s: action %s:%u (%s), user %s", a->name,
450453 t->name, ti->idx, ti->deliver->name,
451 (u_long) dctx->uid);
454 ARRAY_ITEM(users, i).str);
452455 TAILQ_INSERT_TAIL(&mctx->dqueue, dctx, entry);
453456 }
457
458 user_free(udata);
454459 }
455460
456461 return (0);
467472 struct msgbuf msgbuf;
468473
469474 dctx->tim = get_time();
470 log_debug2("%s: message %u, running action %s:%u (%s) as user %lu",
475 log_debug2("%s: message %u, running action %s:%u (%s) as user %s",
471476 a->name, m->idx, t->name, ti->idx, ti->deliver->name,
472 (u_long) dctx->uid);
477 dctx->udata->name);
473478 add_tag(&m->tags, "action", "%s", t->name);
479
480 update_tags(&m->tags, dctx->udata);
474481
475482 /* Just deliver now for in-child delivery. */
476483 if (ti->deliver->type == DELIVER_INCHILD) {
477 if (ti->deliver->deliver(dctx, ti) != DELIVER_SUCCESS)
484 if (ti->deliver->deliver(dctx, ti) != DELIVER_SUCCESS) {
485 reset_tags(&m->tags);
478486 return (ACTION_ERROR);
487 }
488
489 reset_tags(&m->tags);
479490 return (ACTION_DONE);
480491 }
481492
485496
486497 msg.data.account = a;
487498 msg.data.actitem = ti;
488 msg.data.uid = dctx->uid;
499
500 msg.data.uid = dctx->udata->uid;
501 msg.data.gid = dctx->udata->gid;
489502
490503 msgbuf.buf = m->tags;
491504 msgbuf.len = STRB_SIZE(m->tags);
497510 fatalx("privsep_send error");
498511
499512 mctx->msgid = msg.id;
513
514 reset_tags(&m->tags);
500515 return (ACTION_PARENT);
501516 }
502517
511526 if (msgbuf->buf != NULL && msgbuf->len != 0) {
512527 strb_destroy(&m->tags);
513528 m->tags = msgbuf->buf;
514 update_tags(&m->tags);
529 reset_tags(&m->tags);
515530 }
516531
517532 if (msg->data.error != 0)
418418 return (0);
419419 }
420420
421 /* Fill array of users from headers. */
422 struct users *
423 find_users(struct mail *m)
424 {
425 struct passwd *pw;
426 struct users *users;
427 char *ptr, *last, *data, *hdr, *dom, *aptr, *dptr, *line;
428 u_int i, j;
429 size_t len, alen;
430
431 users = xmalloc(sizeof *users);
432 ARRAY_INIT(users);
433
434 line = NULL;
435 line_init(m, &ptr, &len);
436 while (ptr != NULL) {
437 if (ptr >= m->data + m->body)
438 break;
439 line = xmemstrdup(ptr, len);
440
441 /* Find separator. */
442 data = strchr(line, ':');
443 if (data == NULL)
444 goto next;
445 *data++ = '\0';
446 while (isspace((u_char) *data))
447 data++;
448 while ((last = strrchr(data, '\n')) != NULL)
449 *last = '\0';
450
451 /* Is this in the list of headers? */
452 for (i = 0; i < ARRAY_LENGTH(conf.headers); i++) {
453 hdr = ARRAY_ITEM(conf.headers, i);
454 if (*hdr == '\0')
455 continue;
456 if (fnmatch(hdr, line, FNM_CASEFOLD) == 0)
457 break;
458 }
459 if (i == ARRAY_LENGTH(conf.headers))
460 goto next;
461
462 /* Yes, try to find addresses. */
463 while (*data != '\0') {
464 aptr = find_address(data, strlen(data), &alen);
465 if (aptr == NULL)
466 break;
467 data = aptr + alen;
468
469 aptr = xmemstrdup(aptr, alen);
470 dptr = memchr(aptr, '@', alen);
471 *dptr++ = '\0';
472
473 for (j = 0; j < ARRAY_LENGTH(conf.domains); j++) {
474 dom = ARRAY_ITEM(conf.domains, j);
475 if (fnmatch(dom, dptr, FNM_CASEFOLD) != 0)
476 continue;
477
478 pw = getpwnam(aptr);
479 if (pw != NULL)
480 ARRAY_ADD(users, pw->pw_uid);
481 endpwent();
482 break;
483 }
484
485 xfree(aptr);
486 }
487
488 next:
489 if (line != NULL)
490 xfree(line);
491 line = NULL;
492
493 line_next(m, &ptr, &len);
494 }
495
496 if (ARRAY_EMPTY(users)) {
497 ARRAY_FREE(users);
498 xfree(users);
499 return (NULL);
500 }
501 return (users);
502 }
503
504421 char *
505422 find_address(char *buf, size_t len, size_t *alen)
506423 {
608525 }
609526
610527 char *
611 make_from(struct mail *m)
612 {
613 time_t t;
614 char *s, *from = NULL;
615 size_t fromlen = 0;
528 make_from(struct mail *m, char *user)
529 {
530 time_t t;
531 char *s, *from = NULL;
532 size_t fromlen = 0;
616533
617534 from = find_header(m, "from", &fromlen, 1);
618535 if (from != NULL && fromlen > 0)
620537 if (fromlen > INT_MAX)
621538 from = NULL;
622539 if (from == NULL) {
623 from = conf.info.user;
540 from = user;
624541 fromlen = strlen(from);
625542 }
626543
4040 struct io *io = mctx->io;
4141 struct msg msg;
4242 struct msgbuf msgbuf;
43 struct userdata *ud;
44 const char *user;
4345
4446 set_wrapped(m, '\n');
4547
5355
5456 msg.data.account = a;
5557 msg.data.cmddata = data;
56 msg.data.uid = data->uid;
57 if (msg.data.uid == (uid_t) -1)
58 msg.data.uid = conf.cmd_user;
58
59 user = conf.cmd_user;
60 if (data->user != NULL)
61 user = data->user;
62 if ((ud = user_lookup(user, conf.user_order)) == NULL) {
63 log_warnx("%s: bad user: %s", a->name, user);
64 return (MATCH_ERROR);
65 }
66 msg.data.uid = ud->uid;
67 msg.data.gid = ud->gid;
68 update_tags(&m->tags, ud);
69 user_free(ud);
5970
6071 msgbuf.buf = m->tags;
6172 msgbuf.len = STRB_SIZE(m->tags);
6475
6576 if (privsep_send(io, &msg, &msgbuf) != 0)
6677 fatalx("privsep_send error");
78
79 reset_tags(&m->tags);
6780
6881 mctx->msgid = msg.id;
6982 return (MATCH_PARENT);
8295 type = data->pipe ? "pipe" : "exec";
8396
8497 if (data->re.str == NULL) {
85 if (data->uid != (uid_t) -1) {
86 xsnprintf(buf, len, "%s \"%s\" user %lu returns (%s, )",
87 type, data->cmd.str, (u_long) data->uid, ret);
98 if (data->user != NULL) {
99 xsnprintf(buf, len,
100 "%s \"%s\" user \"%s\" returns (%s, )",
101 type, data->cmd.str, data->user, ret);
88102 } else {
89103 xsnprintf(buf, len, "%s \"%s\" returns (%s, )", type,
90104 data->cmd.str, ret);
91105 }
92106 } else {
93 if (data->uid != (uid_t) -1) {
107 if (data->user != NULL) {
94108 xsnprintf(buf, len,
95 "%s \"%s\" user %lu returns (%s, \"%s\")",
96 type, data->cmd.str, (u_long) data->uid, ret,
109 "%s \"%s\" user \"%s\" returns (%s, \"%s\")",
110 type, data->cmd.str, data->user, ret,
97111 data->re.str);
98112 } else {
99113 xsnprintf(buf, len,
9191 /* Match command data. */
9292 struct match_command_data {
9393 struct replpath cmd;
94 uid_t uid;
94 char *user;
9595 int pipe; /* pipe mail to command */
9696
9797 struct re re; /* re->str NULL to not check */
4242 struct deliver_ctx *dctx;
4343 struct mail_ctx *mctx;
4444 struct mail *m;
45
45
4646 switch (msg->type) {
4747 case MSG_ACTION:
4848 if (msgbuf->buf == NULL || msgbuf->len == 0)
7575 mctx = xcalloc(1, sizeof *mctx);
7676 mctx->account = msg->data.account;
7777 mctx->mail = m;
78
78
7979 parent_fetch_cmd(child, children, mctx, msg);
8080 break;
8181 case MSG_DONE:
101101 struct deliver_ctx *dctx, struct msg *msg)
102102 {
103103 struct actitem *ti = msg->data.actitem;
104 uid_t uid = msg->data.uid;
105104 struct mail *m = dctx->mail;
106105 struct mail *md = &dctx->wr_mail;
107106 struct child_deliver_data *data;
107 uid_t uid = msg->data.uid;
108 gid_t gid = msg->data.gid;
108109
109110 memset(md, 0, sizeof *md);
110111 /*
136137 data->dctx = dctx;
137138 data->mail = m;
138139 data->name = "deliver";
139 child = child_start(children, uid, child_deliver, parent_deliver, data);
140 data->uid = uid;
141 data->gid = gid;
142 child = child_start(
143 children, uid, gid, child_deliver, parent_deliver, data);
140144 log_debug3("parent: deliver "
141145 "child %ld started (uid %lu)", (long) child->pid, (u_long) uid);
142146 }
145149 parent_fetch_cmd(struct child *child, struct children *children,
146150 struct mail_ctx *mctx, struct msg *msg)
147151 {
148 uid_t uid = msg->data.uid;
149152 struct mail *m = mctx->mail;
150153 struct child_deliver_data *data;
154 uid_t uid = msg->data.uid;
155 gid_t gid = msg->data.gid;
151156
152157 data = xmalloc(sizeof *data);
153158 data->child = child;
158163 data->cmddata = msg->data.cmddata;
159164 data->mail = m;
160165 data->name = "command";
161 child = child_start(children, uid, child_deliver, parent_deliver, data);
166 data->uid = uid;
167 data->gid = gid;
168 child = child_start(
169 children, uid, gid, child_deliver, parent_deliver, data);
162170 log_debug3("parent: command "
163171 "child %ld started (uid %lu)", (long) child->pid, (u_long) uid);
164172 }
6969 s = ARRAY_ITEM(sp, i);
7070 ENSURE_SIZE(buf, len, off + strlen(s) + 4);
7171 off += xsnprintf(buf + off, len - off, "\"%s\" ", s);
72 }
73
74 if (off == 0) {
75 ENSURE_SIZE(buf, len, off + 1);
76 buf[off] = '\0';
77 } else
78 buf[off - 1] = '\0';
79 return (buf);
80 }
81
82 char *
83 fmt_users(const char *prefix, struct users *up)
84 {
85 char *buf;
86 size_t len;
87 uid_t uid;
88 ssize_t off, uidlen;
89 u_int i;
90
91 len = BUFSIZ;
92 buf = xmalloc(len);
93
94 ENSURE_SIZE(buf, len, strlen(prefix) + 1);
95 off = xsnprintf(buf, len, "%s", prefix);
96
97 for (i = 0; i < ARRAY_LENGTH(up); i++) {
98 uid = ARRAY_ITEM(up, i);
99 uidlen = xsnprintf(NULL, 0, "%lu ", (u_long) uid);
100 ENSURE_SIZE(buf, len, off + uidlen + 1);
101 off += xsnprintf(buf + off, len - off, "%lu ", (u_long) uid);
10272 }
10373
10474 if (off == 0) {
242212 strlcat(s, " ", sizeof s);
243213 }
244214 if (r->users != NULL)
245 su = fmt_users(" users=", r->users);
215 su = fmt_replstrs(" users=", r->users);
246216 else
247217 su = xstrdup("");
248218 if (r->lambda != NULL) {
266236 size_t off;
267237
268238 if (t->users != NULL)
269 su = fmt_users(" users=", t->users);
239 su = fmt_replstrs(" users=", t->users);
270240 else
271241 su = xstrdup("");
272242 off = xsnprintf(s, sizeof s, "added action \"%s\":%s deliver=",
306276 {
307277 struct actitem *ti;
308278
309 if (t->users != NULL)
279 if (t->users != NULL) {
280 free_replstrs(t->users);
310281 ARRAY_FREEALL(t->users);
282 }
311283
312284 while (!TAILQ_EMPTY(t->list)) {
313285 ti = TAILQ_FIRST(t->list);
397369 struct rule *rr;
398370 struct expritem *ei;
399371
400 if (r->users != NULL)
372 if (r->users != NULL) {
373 free_replstrs(r->users);
401374 ARRAY_FREEALL(r->users);
375 }
402376 if (r->actions != NULL) {
403377 free_replstrs(r->actions);
404378 ARRAY_FREEALL(r->actions);
470444 void
471445 free_account(struct account *a)
472446 {
473 if (a->users != NULL)
447 if (a->users != NULL) {
448 free_replstrs(a->users);
474449 ARRAY_FREEALL(a->users);
450 }
475451
476452 if (a->fetch == &fetch_pop3) {
477453 struct fetch_pop3_data *data = a->data;
534510 }
535511
536512 char *
537 expand_path(const char *path)
513 expand_path(const char *path, const char *home)
538514 {
539515 const char *src;
540516 char *ptr;
548524
549525 /* ~ */
550526 if (src[1] == '\0')
551 return (xstrdup(conf.info.home));
527 return (xstrdup(home));
552528
553529 /* ~/ */
554530 if (src[1] == '/') {
555 xasprintf(&ptr, "%s/%s", conf.info.home, src + 2);
531 xasprintf(&ptr, "%s/%s", home, src + 2);
556532 return (ptr);
557533 }
558534
583559 FILE *f;
584560 char *cause;
585561
586 if ((f = netrc_open(conf.info.home, &cause)) == NULL)
562 if ((f = netrc_open(conf.user_home, &cause)) == NULL)
587563 yyerror("%s", cause);
588564
589565 if (netrc_lookup(f, host, user, pass) != 0)
+115
-220
parse.y less more
6969
7070 strb_create(&parse_tags);
7171 default_tags(&parse_tags, NULL);
72 add_tag(&parse_tags, "home", "%s", conf.user_home);
7273
7374 TAILQ_INIT(&parse_macros);
7475 parse_last = NULL;
147148 %token TOKDELTOOBIG
148149 %token TOKDISABLED
149150 %token TOKDOMAIN
150 %token TOKDOMAINS
151151 %token TOKDOTLOCK
152152 %token TOKDROP
153153 %token TOKEQ
160160 %token TOKFOLDER
161161 %token TOKFOLDERS
162162 %token TOKFROM
163 %token TOKFROMHEADERS
164163 %token TOKGIGABYTES
165164 %token TOKGROUP
166165 %token TOKGROUPS
178177 %token TOKKILOBYTES
179178 %token TOKLOCKFILE
180179 %token TOKLOCKTYPES
180 %token TOKLOOKUPORDER
181181 %token TOKMAILDIR
182182 %token TOKMAILDIRS
183183 %token TOKMATCH
204204 %token TOKOR
205205 %token TOKPARALLELACCOUNTS
206206 %token TOKPASS
207 %token TOKPASSWD
207208 %token TOKPIPE
208209 %token TOKPOP3
209210 %token TOKPOP3S
271272 int flags;
272273 char *str;
273274 } re;
274 uid_t uid;
275 gid_t gid;
276 struct {
277 struct users *users;
278 int find_uid;
279 } users;
275 gid_t localgid;
280276 enum cmp cmp;
281277 struct rule *rule;
282278 struct {
285281 char *pass;
286282 int pass_netrc;
287283 } userpass;
284 userfunction ufn;
285 struct userfunctions *ufns;
288286 }
289287
290288 %token NONE
302300 %type <fetch> fetchtype
303301 %type <flag> cont not disabled keep execpipe writeappend compress verify
304302 %type <flag> apop poptype imaptype nntptype nocrammd5 nologin
305 %type <gid> gid
303 %type <localgid> localgid
306304 %type <locks> lock locklist
307305 %type <number> size time numv retrc expire
308306 %type <only> only imaponly
309307 %type <poponly> poponly
310 %type <replstrs> replstrslist actions rmheaders accounts
308 %type <replstrs> replstrslist actions rmheaders accounts users
311309 %type <re> casere retre
312310 %type <rule> perform
313311 %type <server> server
314312 %type <string> port to from xstrv strv replstrv replpathv val optval folder1
315 %type <strings> stringslist pathslist
316 %type <strings> domains headers maildirs mboxes groups folders folderlist
317 %type <users> users userslist
313 %type <strings> stringslist pathslist maildirs mboxes groups folders folderlist
318314 %type <userpass> userpass userpassreqd userpassnetrc
319 %type <uid> uid user
315 %type <ufn> ufn
316 %type <ufns> ufns ufnslist
320317
321318 %%
322319
358355 /** RMHEADERP */
359356 rmheaderp: TOKREMOVEHEADER
360357 | TOKREMOVEHEADERS
361 /** HEADERP */
362 headerp: TOKHEADER
363 | TOKHEADERS
364 /** DOMAINP */
365 domainp: TOKDOMAIN
366 | TOKDOMAINS
367358
368359 /** VAL: <string> (char *) */
369360 val: TOKVALUE strv
487478 struct replpath rp;
488479
489480 rp.str = $1;
490 $$ = replacepath(&rp, parse_tags, NULL, NULL);
481 $$ = replacepath(&rp, parse_tags, NULL, NULL, conf.user_home);
491482 xfree($1);
492483 }
493484
646637 {
647638 conf.allow_many = 1;
648639 }
649 | TOKSET TOKDEFUSER uid
650 /** [$3: uid (uid_t)] */
640 | TOKSET TOKDEFUSER strv
641 /** [$3: strv (char *)] */
651642 {
652643 conf.def_user = $3;
653644 }
654 | TOKSET TOKCMDUSER uid
655 /** [$3: uid (uid_t)] */
645 | TOKSET TOKCMDUSER strv
646 /** [$3: strv (char *)] */
656647 {
657648 conf.cmd_user = $3;
658649 }
701692 if ($3 == 0)
702693 yyerror("parallel-accounts cannot be zero");
703694 conf.max_accts = $3;
704 }
705 | TOKSET domains
706 /** [$2: domains (struct strings *)] */
707 {
708 u_int i;
709
710 if (conf.domains != NULL) {
711 for (i = 0; i < ARRAY_LENGTH(conf.domains); i++)
712 xfree(ARRAY_ITEM(conf.domains, i));
713 ARRAY_FREE(conf.domains);
714 xfree(conf.domains);
715 }
716
717 conf.domains = $2;
718 }
719 | TOKSET headers
720 /** [$2: headers (struct strings *)] */
721 {
722 u_int i;
723
724 if (conf.headers != NULL) {
725 for (i = 0; i < ARRAY_LENGTH(conf.headers); i++)
726 xfree(ARRAY_ITEM(conf.headers, i));
727 ARRAY_FREE(conf.headers);
728 xfree(conf.headers);
729 }
730
731 conf.headers = $2;
732695 }
733696 | TOKSET TOKPROXY replstrv
734697 /** [$3: replstrv (char *)] */
783746 {
784747 conf.file_group = -1;
785748 }
786 | TOKSET TOKFILEGROUP gid
787 /** [$3: gid (gid_t)] */
749 | TOKSET TOKFILEGROUP localgid
750 /** [$3: localgid (gid_t)] */
788751 {
789752 conf.file_group = $3;
790753 }
792755 {
793756 conf.file_umask = umask(0);
794757 umask(conf.file_umask);
758 }
759 | TOKSET TOKLOOKUPORDER ufns
760 /** [$3: ufns (struct userfunctions *)] */
761 {
762 ARRAY_FREEALL(conf.user_order);
763 conf.user_order = $3;
795764 }
796765 | TOKSET TOKFILEUMASK numv
797766 /** [$3: numv (long long)] */
930899 ARRAY_ADD($$, $1);
931900 }
932901
933 /** USERSLIST: <users> (struct { ... } users) */
934 userslist: userslist uid
935 /** [$1: userslist (struct { ... } users)] [$2: uid (uid_t)] */
936 {
937 $$ = $1;
938 ARRAY_ADD($$.users, $2);
939 }
940 | uid
941 /** [$1: uid (uid_t)] */
942 {
943 $$.users = xmalloc(sizeof *$$.users);
944 ARRAY_INIT($$.users);
945 ARRAY_ADD($$.users, $1);
946 }
947
948 /** DOMAINS: <strings> (struct strings *) */
949 domains: domainp replstrv
950 /** [$2: replstrv (char *)] */
951 {
952 if (*$2 == '\0')
953 yyerror("invalid domain");
954
955 $$ = xmalloc(sizeof *$$);
956 ARRAY_INIT($$);
957 ARRAY_ADD($$, $2);
958 }
959 | domainp '{' stringslist '}'
960 /** [$3: stringslist (struct strings *)] */
961 {
962 $$ = $3;
963 }
964
965 /** HEADERS: <strings> (struct strings *) */
966 headers: headerp replstrv
967 /** [$2: replstrv (char *)] */
968 {
969 if (*$2 == '\0')
970 yyerror("invalid header");
971
972 $$ = xmalloc(sizeof *$$);
973 ARRAY_INIT($$);
974 ARRAY_ADD($$, $2);
975 }
976 | headerp '{' stringslist '}'
977 /** [$3: stringslist (struct strings *)] */
978 {
979 $$ = $3;
980 }
902 /** UFN: <ufn> (userfunction) */
903 ufn: TOKPASSWD
904 {
905 $$ = &passwd_lookup;
906 }
907
908 /** UFNS: <ufns> (struct userfunctions *) */
909 ufns: ufn
910 /** [$1: ufn (userfunction)] */
911 {
912 $$ = xmalloc(sizeof *$$);
913 ARRAY_INIT($$);
914 ARRAY_ADD($$, $1);
915 }
916 | '{' ufnslist '}'
917 /** [$2: ufnslist (struct userfunctions *)] */
918 {
919 $$ = $2;
920 }
921
922 /** UFNSLIST: <ufns> (struct userfunctions *) */
923 ufnslist: ufnslist ufn
924 /** [$1: ufnslist (struct userfunctions *)] [$2: ufn (userfunction)] */
925 {
926 $$ = $1;
927 ARRAY_ADD($$, $2);
928 }
929 | ufn
930 /** [$1: ufn (userfunction)] */
931 {
932 $$ = xmalloc(sizeof *$$);
933 ARRAY_INIT($$);
934 ARRAY_ADD($$, $1);
935 }
981936
982937 /** RMHEADERS: <replstrs> (struct replstrs *) */
983938 rmheaders: rmheaderp strv
10781033 $$ = 0;
10791034 }
10801035
1081 /** UID: <uid> (uid_t) */
1082 uid: replstrv
1083 /** [$1: replstrv (char *)] */
1084 {
1085 struct passwd *pw;
1086
1087 if (*$1 == '\0')
1088 yyerror("invalid user");
1089
1090 pw = getpwnam($1);
1091 if (pw == NULL)
1092 yyerror("unknown user: %s", $1);
1093 $$ = pw->pw_uid;
1094 endpwent();
1095
1096 xfree($1);
1097 }
1098 | numv
1099 /** [$1: numv (long long)] */
1100 {
1101 struct passwd *pw;
1102
1103 if ($1 > UID_MAX)
1104 yyerror("invalid uid: %llu", $1);
1105 pw = getpwuid($1);
1106 if (pw == NULL)
1107 yyerror("unknown uid: %llu", $1);
1108 $$ = pw->pw_uid;
1109 endpwent();
1110 }
1111
1112 /** GID: <gid> (gid_t) */
1113 gid: replstrv
1114 /** [$1: replstrv (char *)] */
1115 {
1116 struct group *gr;
1117
1118 if (*$1 == '\0')
1119 yyerror("invalid group");
1120
1121 gr = getgrnam($1);
1122 if (gr == NULL)
1123 yyerror("unknown group: %s", $1);
1124 $$ = gr->gr_gid;
1125 endgrent();
1126
1127 xfree($1);
1128 }
1129 | numv
1130 /** [$1: numv (long long)] */
1131 {
1132 struct group *gr;
1133
1134 if ($1 > GID_MAX)
1135 yyerror("invalid gid: %llu", $1);
1136 gr = getgrgid($1);
1137 if (gr == NULL)
1138 yyerror("unknown gid: %llu", $1);
1139 $$ = gr->gr_gid;
1140 endgrent();
1141 }
1142
1143 /** USER: <uid> (uid_t) */
1144 user: /* empty */
1145 {
1146 $$ = -1;
1147 }
1148 | TOKUSER uid
1149 /** [$2: uid (uid_t)] */
1150 {
1151 $$ = $2;
1152 }
1153
1154
1155 /** USERS: <users> (struct { ... } users) */
1036 /** LOCALGID: <localgid> (gid_t) */
1037 localgid: replstrv
1038 /** [$1: replstrv (char *)] */
1039 {
1040 struct group *gr;
1041
1042 if (*$1 == '\0')
1043 yyerror("invalid group");
1044
1045 gr = getgrnam($1);
1046 if (gr == NULL)
1047 yyerror("unknown group: %s", $1);
1048 $$ = gr->gr_gid;
1049 endgrent();
1050
1051 xfree($1);
1052 }
1053 | numv
1054 /** [$1: numv (long long)] */
1055 {
1056 struct group *gr;
1057
1058 if ($1 > GID_MAX)
1059 yyerror("invalid gid: %llu", $1);
1060 gr = getgrgid($1);
1061 if (gr == NULL)
1062 yyerror("unknown gid: %llu", $1);
1063 $$ = gr->gr_gid;
1064 endgrent();
1065 }
1066
1067 /** USERS: <replstrs> (struct replstrs *) */
11561068 users: /* empty */
11571069 {
1158 $$.users = NULL;
1159 $$.find_uid = 0;
1070 $$ = NULL;
11601071 }
1161 | userp TOKFROMHEADERS
1072 | userp strv
1073 /** [$2: strv (char *)] */
11621074 {
1163 $$.users = NULL;
1164 $$.find_uid = 1;
1075 $$ = xmalloc(sizeof *$$);
1076 ARRAY_INIT($$);
1077 ARRAY_EXPAND($$, 1);
1078 ARRAY_LAST($$).str = $2;
11651079 }
1166 | userp uid
1167 /** [$2: uid (uid_t)] */
1168 {
1169 $$.users = xmalloc(sizeof *$$.users);
1170 ARRAY_INIT($$.users);
1171 ARRAY_ADD($$.users, $2);
1172 $$.find_uid = 0;
1173 }
1174 | userp '{' userslist '}'
1175 /** [$3: userslist (struct { ... } users)] */
1080 | userp '{' replstrslist '}'
1081 /** [$3: replstrslist (struct replstrs *)] */
11761082 {
11771083 $$ = $3;
1178 $$.users = $$.users;
1179 $$.find_uid = 0;
11801084 }
11811085
11821086 /** CASERE: <re> (struct { ... } re) */
15821486
15831487 /** DEFACTION */
15841488 defaction: TOKACTION replstrv users actitem
1585 /** [$2: replstrv (char *)] [$3: users (struct { ... } users)] */
1489 /** [$2: replstrv (char *)] [$3: users (struct replstrs *)] */
15861490 /** [$4: actitem (struct actitem *)] */
15871491 {
15881492 struct action *t;
16021506 TAILQ_INSERT_HEAD(t->list, $4, entry);
16031507 $4->idx = 0;
16041508
1605 t->users = $3.users;
1606 t->find_uid = $3.find_uid;
1509 t->users = $3;
16071510 TAILQ_INSERT_TAIL(&conf.actions, t, entry);
16081511
16091512 print_action(t);
16111514 xfree($2);
16121515 }
16131516 | TOKACTION replstrv users '{' actlist '}'
1614 /** [$2: replstrv (char *)] [$3: users (struct { ... } users)] */
1517 /** [$2: replstrv (char *)] [$3: users (struct replstrs *)] */
16151518 /** [$5: actlist (struct actlist *)] */
16161519 {
16171520 struct action *t;
16281531
16291532 t->list = $5;
16301533
1631 t->users = $3.users;
1632 t->find_uid = $3.find_uid;
1534 t->users = $3;
16331535 TAILQ_INSERT_TAIL(&conf.actions, t, entry);
16341536
16351537 print_action(t);
18321734
18331735 data->accounts = $2;
18341736 }
1835 | not execpipe strv user TOKRETURNS '(' retrc ',' retre ')'
1737 | not execpipe strv strv TOKRETURNS '(' retrc ',' retre ')'
18361738 /** [$1: not (int)] [$2: execpipe (int)] [$3: strv (char *)] */
1837 /** [$4: user (uid_t)] [$7: retrc (long long)] */
1739 /** [$4: strv (char *)] [$7: retrc (long long)] */
18381740 /** [$9: retre (struct { ... } re)] */
18391741 {
18401742 struct match_command_data *data;
18521754 data = xcalloc(1, sizeof *data);
18531755 $$->data = data;
18541756
1855 data->uid = $4;
1757 data->user = $4;
18561758 data->pipe = $2;
18571759 data->cmd.str = $3;
18581760
21392041
21402042 /** PERFORM: <rule> (struct rule *) */
21412043 perform: users actionp actitem cont
2142 /** [$1: users (struct { ... } users)] [$3: actitem (struct actitem *)] */
2044 /** [$1: users (struct replstrs *)] [$3: actitem (struct actitem *)] */
21432045 /** [$4: cont (int)] */
21442046 {
21452047 struct action *t;
21492051 $$->actions = NULL;
21502052 TAILQ_INIT(&$$->rules);
21512053 $$->stop = !$4;
2152 $$->users = $1.users;
2153 $$->find_uid = $1.find_uid;
2054 $$->users = $1;
21542055
21552056 t = $$->lambda = xcalloc(1, sizeof *$$->lambda);
21562057 xsnprintf(t->name, sizeof t->name, "<rule %u>", $$->idx);
21572058 t->users = NULL;
2158 t->find_uid = 0;
21592059 t->list = xmalloc(sizeof *t->list);
21602060 TAILQ_INIT(t->list);
21612061 TAILQ_INSERT_HEAD(t->list, $3, entry);
21672067 TAILQ_INSERT_TAIL(&parse_rule->rules, $$, entry);
21682068 }
21692069 | users actionp '{' actlist '}' cont
2170 /** [$1: users (struct { ... } users)] */
2070 /** [$1: users (struct replstrs *)] */
21712071 /** [$4: actlist (struct actlist *)] [$6: cont (int)] */
21722072 {
21732073 struct action *t;
21772077 $$->actions = NULL;
21782078 TAILQ_INIT(&$$->rules);
21792079 $$->stop = !$6;
2180 $$->users = $1.users;
2181 $$->find_uid = $1.find_uid;
2080 $$->users = $1;
21822081
21832082 t = $$->lambda = xcalloc(1, sizeof *$$->lambda);
21842083 xsnprintf(t->name, sizeof t->name, "<rule %u>", $$->idx);
21852084 t->users = NULL;
2186 t->find_uid = 0;
21872085 t->list = $4;
21882086
21892087 if (parse_rule == NULL)
21922090 TAILQ_INSERT_TAIL(&parse_rule->rules, $$, entry);
21932091 }
21942092 | users actions cont
2195 /** [$1: users (struct { ... } users)] */
2093 /** [$1: users (struct replstrs *)] */
21962094 /** [$2: actions (struct replstrs *)] [$3: cont (int)] */
21972095 {
21982096 $$ = xcalloc(1, sizeof *$$);
22012099 $$->actions = $2;
22022100 TAILQ_INIT(&$$->rules);
22032101 $$->stop = !$3;
2204 $$->users = $1.users;
2205 $$->find_uid = $1.find_uid;
2102 $$->users = $1;
22062103
22072104 if (parse_rule == NULL)
22082105 TAILQ_INSERT_TAIL(&conf.rules, $$, entry);
22182115 TAILQ_INIT(&$$->rules);
22192116 $$->stop = 0;
22202117 $$->users = NULL;
2221 $$->find_uid = 0;
22222118
22232119 if (parse_rule == NULL)
22242120 TAILQ_INSERT_TAIL(&conf.rules, $$, entry);
26492545 /** ACCOUNT */
26502546 account: TOKACCOUNT replstrv disabled users fetchtype keep
26512547 /** [$2: replstrv (char *)] [$3: disabled (int)] */
2652 /** [$4: users (struct { ... } users)] [$5: fetchtype (struct { ... } fetch)] */
2548 /** [$4: users (struct replstrs *)] [$5: fetchtype (struct { ... } fetch)] */
26532549 /** [$6: keep (int)] */
26542550 {
26552551 struct account *a;
26662562 strlcpy(a->name, $2, sizeof a->name);
26672563 a->keep = $6;
26682564 a->disabled = $3;
2669 a->users = $4.users;
2670 a->find_uid = $4.find_uid;
2565 a->users = $4;
26712566 a->fetch = $5.fetch;
26722567 a->data = $5.data;
26732568 TAILQ_INSERT_TAIL(&conf.accounts, a, entry);
26742569
26752570 if (a->users != NULL)
2676 su = fmt_users(" users=", a->users);
2571 su = fmt_replstrs(" users=", a->users);
26772572 else
26782573 su = xstrdup("");
26792574 a->fetch->desc(a, desc, sizeof desc);
128128 struct tm *tm;
129129 time_t t;
130130
131 strb_clear(tags);
132 add_tag(tags, "home", "%s", conf.info.home);
133 add_tag(tags, "uid", "%s", conf.info.uid);
134 add_tag(tags, "user", "%s", conf.info.user);
131 strb_clear(tags);
135132
136133 if (src != NULL)
137134 add_tag(tags, "source", "%s", src);
138135
139 if (conf.info.host != NULL)
140 add_tag(tags, "hostname", "%s", conf.info.host);
136 if (conf.host_name != NULL)
137 add_tag(tags, "hostname", "%s", conf.host_name);
141138
142139 t = time(NULL);
143140 if ((tm = localtime(&t)) != NULL) {
167164 }
168165
169166 void
170 update_tags(struct strb **tags)
171 {
172 add_tag(tags, "home", "%s", conf.info.home);
173 add_tag(tags, "uid", "%s", conf.info.uid);
174 add_tag(tags, "user", "%s", conf.info.user);
167 update_tags(struct strb **tags, struct userdata *ud)
168 {
169 add_tag(tags, "user", "%s", ud->name);
170 add_tag(tags, "home", "%s", ud->home);
171 add_tag(tags, "uid", "%lu", (u_long) ud->uid);
172 add_tag(tags, "gid", "%lu", (u_long) ud->gid);
173 }
174
175 void
176 reset_tags(struct strb **tags)
177 {
178 add_tag(tags, "user", "%s", "");
179 add_tag(tags, "home", "%s", "");
180 add_tag(tags, "uid", "%s", "");
181 add_tag(tags, "gid", "%s", "");
175182 }
176183
177184 char *
183190
184191 char *
185192 replacepath(struct replpath *rp, struct strb *tags, struct mail *m,
186 struct rmlist *rml)
187 {
188 char *s, *ss;
193 struct rmlist *rml, const char *home)
194 {
195 char *s, *t;
189196
190197 s = replace(rp->str, tags, m, rml);
191 ss = expand_path(s);
192 if (ss == NULL)
198 if ((t = expand_path(s, home)) == NULL)
193199 return (s);
194200 xfree(s);
195 return (ss);
201 return (t);
196202 }
197203
198204 const char *