1 /*	$NetBSD: master_wakeup.c,v 1.3 2020/03/18 19:05:16 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	master_wakeup 3
6 /* SUMMARY
7 /*	Postfix master - start/stop service wakeup timers
8 /* SYNOPSIS
9 /*	#include "master.h"
10 /*
11 /*	void	master_wakeup_init(serv)
12 /*	MASTER_SERV *serv;
13 /*
14 /*	void	master_wakeup_cleanup(serv)
15 /*	MASTER_SERV *serv;
16 /* DESCRIPTION
17 /*	This module implements automatic service wakeup. In order to
18 /*	wakeup a service, a wakeup trigger is sent to the corresponding
19 /*	service port or FIFO, and a timer is started to repeat this sequence
20 /*	after a configurable amount of time.
21 /*
22 /*	master_wakeup_init() wakes up the named service. No wakeup
23 /*	is done or scheduled when a zero wakeup time is given, or when
24 /*	the service has been throttled in the mean time.
25 /*	It is OK to call master_wakeup_init() while a timer is already
26 /*	running for the named service. The effect is to restart the
27 /*	wakeup timer.
28 /*
29 /*	master_wakeup_cleanup() cancels the wakeup timer for the named
30 /*	service. It is an error to disable a service while it still has
31 /*	an active wakeup timer (doing so would cause a dangling reference
32 /*	to a non-existent service).
33 /*	It is OK to call master_wakeup_cleanup() even when no timer is
34 /*	active for the named service.
35 /* DIAGNOSTICS
36 /* BUGS
37 /* SEE ALSO
38 /*	inet_trigger(3), internet-domain client
39 /*	unix_trigger(3), unix-domain client
40 /*	fifo_trigger(3), fifo client
41 /*	upass_trigger(3), file descriptor passing client
42 /* LICENSE
43 /* .ad
44 /* .fi
45 /*	The Secure Mailer license must be distributed with this software.
46 /* AUTHOR(S)
47 /*	Wietse Venema
48 /*	IBM T.J. Watson Research
49 /*	P.O. Box 704
50 /*	Yorktown Heights, NY 10598, USA
51 /*
52 /*	Wietse Venema
53 /*	Google, Inc.
54 /*	111 8th Avenue
55 /*	New York, NY 10011, USA
56 /*--*/
57 
58 /* System library. */
59 
60 #include <sys_defs.h>
61 #include <unistd.h>
62 #include <string.h>
63 #include <errno.h>
64 
65 /* Utility library. */
66 
67 #include <msg.h>
68 #include <trigger.h>
69 #include <events.h>
70 #include <set_eugid.h>
71 #include <set_ugid.h>
72 
73 /* Global library. */
74 
75 #include <mail_proto.h>			/* triggers */
76 #include <mail_params.h>
77 
78 /* Application-specific. */
79 
80 #include "mail_server.h"
81 #include "master.h"
82 
83 /* master_wakeup_timer_event - wakeup event handler */
84 
master_wakeup_timer_event(int unused_event,void * context)85 static void master_wakeup_timer_event(int unused_event, void *context)
86 {
87     const char *myname = "master_wakeup_timer_event";
88     MASTER_SERV *serv = (MASTER_SERV *) context;
89     int     status;
90     static char wakeup = TRIGGER_REQ_WAKEUP;
91 
92     /*
93      * Don't wakeup services whose automatic wakeup feature was turned off in
94      * the mean time.
95      */
96     if (serv->wakeup_time == 0)
97 	return;
98 
99     /*
100      * Don't wake up services that are throttled. Find out what transport to
101      * use. We can't block here so we choose a short timeout.
102      */
103 #define BRIEFLY	1
104 
105     if (MASTER_THROTTLED(serv) == 0) {
106 	if (msg_verbose)
107 	    msg_info("%s: service %s", myname, serv->name);
108 
109 	switch (serv->type) {
110 	case MASTER_SERV_TYPE_INET:
111 	    status = inet_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
112 	    break;
113 	case MASTER_SERV_TYPE_UNIX:
114 	    status = LOCAL_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
115 	    break;
116 	case MASTER_SERV_TYPE_UXDG:
117 	    status = -1;
118 	    errno = EOPNOTSUPP;
119 	    break;
120 #ifdef MASTER_SERV_TYPE_PASS
121 	case MASTER_SERV_TYPE_PASS:
122 	    status = pass_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
123 	    break;
124 #endif
125 
126 	    /*
127 	     * If someone compromises the postfix account then this must not
128 	     * overwrite files outside the chroot jail. Countermeasures:
129 	     *
130 	     * - Limit the damage by accessing the FIFO as postfix not root.
131 	     *
132 	     * - Have fifo_trigger() call safe_open() so we won't follow
133 	     * arbitrary hard/symlinks to files in/outside the chroot jail.
134 	     *
135 	     * - All non-chroot postfix-related files must be root owned (or
136 	     * postfix check complains).
137 	     *
138 	     * - The postfix user and group ID must not be shared with other
139 	     * applications (says the INSTALL documentation).
140 	     *
141 	     * Result of a discussion with Michael Tokarev, who received his
142 	     * insights from Solar Designer, who tested Postfix with a kernel
143 	     * module that is paranoid about open() calls.
144 	     */
145 	case MASTER_SERV_TYPE_FIFO:
146 	    set_eugid(var_owner_uid, var_owner_gid);
147 	    status = fifo_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
148 	    set_ugid(getuid(), getgid());
149 	    break;
150 	default:
151 	    msg_panic("%s: unknown service type: %d", myname, serv->type);
152 	}
153 	if (status < 0)
154 	    msg_warn("%s: service %s(%s): %m",
155 		     myname, serv->ext_name, serv->name);
156     }
157 
158     /*
159      * Schedule another wakeup event.
160      */
161     event_request_timer(master_wakeup_timer_event, (void *) serv,
162 			serv->wakeup_time);
163 }
164 
165 /* master_wakeup_init - start automatic service wakeup */
166 
master_wakeup_init(MASTER_SERV * serv)167 void    master_wakeup_init(MASTER_SERV *serv)
168 {
169     const char *myname = "master_wakeup_init";
170 
171     if (serv->wakeup_time == 0 || (serv->flags & MASTER_FLAG_CONDWAKE))
172 	return;
173     if (msg_verbose)
174 	msg_info("%s: service %s time %d",
175 		 myname, serv->name, serv->wakeup_time);
176     master_wakeup_timer_event(0, (void *) serv);
177 }
178 
179 /* master_wakeup_cleanup - cancel wakeup timer */
180 
master_wakeup_cleanup(MASTER_SERV * serv)181 void    master_wakeup_cleanup(MASTER_SERV *serv)
182 {
183     const char *myname = "master_wakeup_cleanup";
184 
185     /*
186      * Cleanup, even when the wakeup feature has been turned off. There might
187      * still be a pending timer. Don't depend on the code that reloads the
188      * config file to reset the wakeup timer when things change.
189      */
190     if (msg_verbose)
191 	msg_info("%s: service %s", myname, serv->name);
192 
193     event_cancel_timer(master_wakeup_timer_event, (void *) serv);
194 }
195