1 /*	$NetBSD: master_listen.c,v 1.1.1.1 2009/06/23 10:08:49 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	master_listen 3
6 /* SUMMARY
7 /*	Postfix master - start/stop listeners
8 /* SYNOPSIS
9 /*	#include "master.h"
10 /*
11 /*	void	master_listen_init(serv)
12 /*	MASTER_SERV *serv;
13 /*
14 /*	void	master_listen_cleanup(serv)
15 /*	MASTER_SERV *serv;
16 /* DESCRIPTION
17 /*	master_listen_init() turns on the listener implemented by the
18 /*	named process. FIFOs and UNIX-domain sockets are created with
19 /*	mode 0622 and with ownership mail_owner.
20 /*
21 /*	master_listen_cleanup() turns off the listener implemented by the
22 /*	named process.
23 /* DIAGNOSTICS
24 /* BUGS
25 /* SEE ALSO
26 /*	inet_listen(3), internet-domain listener
27 /*	unix_listen(3), unix-domain listener
28 /*	fifo_listen(3), named-pipe listener
29 /*	upass_listen(3), file descriptor passing listener
30 /*	set_eugid(3), set effective user/group attributes
31 /* LICENSE
32 /* .ad
33 /* .fi
34 /*	The Secure Mailer license must be distributed with this software.
35 /* AUTHOR(S)
36 /*	Wietse Venema
37 /*	IBM T.J. Watson Research
38 /*	P.O. Box 704
39 /*	Yorktown Heights, NY 10598, USA
40 /*--*/
41 
42 /* System library. */
43 
44 #include <sys_defs.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <unistd.h>
49 #include <string.h>
50 
51 /* Utility library. */
52 
53 #include <msg.h>
54 #include <listen.h>
55 #include <mymalloc.h>
56 #include <stringops.h>
57 #include <inet_addr_list.h>
58 #include <set_eugid.h>
59 #include <set_ugid.h>
60 #include <iostuff.h>
61 #include <myaddrinfo.h>
62 #include <sock_addr.h>
63 
64 /* Global library. */
65 
66 #include <mail_params.h>
67 
68 /* Application-specific. */
69 
70 #include "master.h"
71 
72 /* master_listen_init - enable connection requests */
73 
74 void    master_listen_init(MASTER_SERV *serv)
75 {
76     const char *myname = "master_listen_init";
77     char   *end_point;
78     int     n;
79     MAI_HOSTADDR_STR hostaddr;
80     struct sockaddr *sa;
81 
82     /*
83      * Find out what transport we should use, then create one or more
84      * listener sockets. Make the listener sockets non-blocking, so that
85      * child processes don't block in accept() when multiple processes are
86      * selecting on the same socket and only one of them gets the connection.
87      */
88     switch (serv->type) {
89 
90 	/*
91 	 * UNIX-domain or stream listener endpoints always come as singlets.
92 	 */
93     case MASTER_SERV_TYPE_UNIX:
94 	set_eugid(var_owner_uid, var_owner_gid);
95 	serv->listen_fd[0] =
96 	    LOCAL_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
97 			 serv->max_proc : var_proc_limit, NON_BLOCKING);
98 	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
99 	set_ugid(getuid(), getgid());
100 	break;
101 
102 	/*
103 	 * FIFO listener endpoints always come as singlets.
104 	 */
105     case MASTER_SERV_TYPE_FIFO:
106 	set_eugid(var_owner_uid, var_owner_gid);
107 	serv->listen_fd[0] = fifo_listen(serv->name, 0622, NON_BLOCKING);
108 	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
109 	set_ugid(getuid(), getgid());
110 	break;
111 
112 	/*
113 	 * INET-domain listener endpoints can be wildcarded (the default) or
114 	 * bound to specific interface addresses.
115 	 *
116 	 * With dual-stack IPv4/6 systems it does not matter, we have to specify
117 	 * the addresses anyway, either explicit or wild-card.
118 	 */
119     case MASTER_SERV_TYPE_INET:
120 	for (n = 0; n < serv->listen_fd_count; n++) {
121 	    sa = SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv)->addrs + n);
122 	    SOCKADDR_TO_HOSTADDR(sa, SOCK_ADDR_LEN(sa), &hostaddr,
123 				 (MAI_SERVPORT_STR *) 0, 0);
124 	    end_point = concatenate(hostaddr.buf,
125 				    ":", MASTER_INET_PORT(serv), (char *) 0);
126 	    serv->listen_fd[n]
127 		= inet_listen(end_point, serv->max_proc > var_proc_limit ?
128 			      serv->max_proc : var_proc_limit, NON_BLOCKING);
129 	    close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC);
130 	    myfree(end_point);
131 	}
132 	break;
133 
134 	/*
135 	 * Descriptor passing endpoints always come as singlets.
136 	 */
137 #ifdef MASTER_SERV_TYPE_PASS
138     case MASTER_SERV_TYPE_PASS:
139 	set_eugid(var_owner_uid, var_owner_gid);
140 	serv->listen_fd[0] =
141 	    PASS_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
142 			serv->max_proc : var_proc_limit, NON_BLOCKING);
143 	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
144 	set_ugid(getuid(), getgid());
145 	break;
146 #endif
147     default:
148 	msg_panic("%s: unknown service type: %d", myname, serv->type);
149     }
150 }
151 
152 /* master_listen_cleanup - disable connection requests */
153 
154 void    master_listen_cleanup(MASTER_SERV *serv)
155 {
156     const char *myname = "master_listen_cleanup";
157     int     n;
158 
159     /*
160      * XXX The listen socket is shared with child processes. Closing the
161      * socket in the master process does not really disable listeners in
162      * child processes. There seems to be no documented way to turn off a
163      * listener. The 4.4BSD shutdown(2) man page promises an ENOTCONN error
164      * when shutdown(2) is applied to a socket that is not connected.
165      */
166     for (n = 0; n < serv->listen_fd_count; n++) {
167 	if (close(serv->listen_fd[n]) < 0)
168 	    msg_warn("%s: close listener socket %d: %m",
169 		     myname, serv->listen_fd[n]);
170 	serv->listen_fd[n] = -1;
171     }
172 }
173