1 /*
2  * Server listening routines for the CUPS scheduler.
3  *
4  * Copyright 2007-2016 by Apple Inc.
5  * Copyright 1997-2006 by Easy Software Products, all rights reserved.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
8  */
9 
10 /*
11  * Include necessary headers...
12  */
13 
14 #include "cupsd.h"
15 
16 
17 /*
18  * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
19  * glibc don't define it even if the kernel supports it...
20  */
21 
22 #if defined(__linux) && !defined(IPV6_V6ONLY)
23 #  define IPV6_V6ONLY 26
24 #endif /* __linux && !IPV6_V6ONLY */
25 
26 
27 /*
28  * 'cupsdDeleteAllListeners()' - Delete all listeners.
29  */
30 
31 void
cupsdDeleteAllListeners(void)32 cupsdDeleteAllListeners(void)
33 {
34   cupsd_listener_t	*lis;		/* Current listening socket */
35 
36 
37   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
38        lis;
39        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
40 #ifdef HAVE_ONDEMAND
41     if (!lis->on_demand)
42 #endif /* HAVE_ONDEMAND */
43     {
44       cupsArrayRemove(Listeners, lis);
45       free(lis);
46     }
47 
48   if (cupsArrayCount(Listeners) == 0)
49   {
50     cupsArrayDelete(Listeners);
51     Listeners = NULL;
52   }
53 }
54 
55 
56 /*
57  * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
58  */
59 
60 void
cupsdPauseListening(void)61 cupsdPauseListening(void)
62 {
63   cupsd_listener_t	*lis;		/* Current listening socket */
64 
65 
66   if (cupsArrayCount(Listeners) < 1)
67     return;
68 
69   if (cupsArrayCount(Clients) == MaxClients)
70     cupsdLogMessage(CUPSD_LOG_WARN,
71                     "Max clients reached, holding new connections...");
72   else if (errno == ENFILE || errno == EMFILE)
73     cupsdLogMessage(CUPSD_LOG_WARN,
74                     "Too many open files, holding new connections for "
75 		    "30 seconds...");
76 
77   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
78 
79   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
80        lis;
81        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
82     cupsdRemoveSelect(lis->fd);
83 
84   ListeningPaused = time(NULL) + 30;
85 }
86 
87 
88 /*
89  * 'cupsdResumeListening()' - Set input polling on all listening sockets...
90  */
91 
92 void
cupsdResumeListening(void)93 cupsdResumeListening(void)
94 {
95   cupsd_listener_t	*lis;		/* Current listening socket */
96 
97 
98   if (cupsArrayCount(Listeners) < 1)
99     return;
100 
101   cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
102   cupsdLogMessage(CUPSD_LOG_DEBUG2,
103                   "cupsdResumeListening: Setting input bits...");
104 
105   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
106        lis;
107        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
108     cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
109 
110   ListeningPaused = 0;
111 }
112 
113 
114 /*
115  * 'cupsdStartListening()' - Create all listening sockets...
116  */
117 
118 void
cupsdStartListening(void)119 cupsdStartListening(void)
120 {
121   int			p;		/* Port number */
122   cupsd_listener_t	*lis;		/* Current listening socket */
123   char			s[256];		/* String addresss */
124   const char		*have_domain;	/* Have a domain socket? */
125   static const char * const encryptions[] =
126 		{			/* Encryption values */
127 		  "IfRequested",
128 		  "Never",
129 		  "Required",
130 		  "Always"
131 		};
132 
133 
134   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
135                   cupsArrayCount(Listeners));
136 
137  /*
138   * Setup socket listeners...
139   */
140 
141   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
142            have_domain = NULL;
143        lis;
144        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
145   {
146     httpAddrString(&(lis->address), s, sizeof(s));
147     p = httpAddrPort(&(lis->address));
148 
149    /*
150     * If needed, create a socket for listening...
151     */
152 
153     if (lis->fd == -1)
154     {
155      /*
156       * Create a socket for listening...
157       */
158 
159       lis->fd = httpAddrListen(&(lis->address), p);
160 
161       if (lis->fd == -1)
162       {
163 	cupsdLogMessage(CUPSD_LOG_ERROR,
164 			"Unable to open listen socket for address %s:%d - %s.",
165 			s, p, strerror(errno));
166 
167 #ifdef AF_INET6
168        /*
169         * IPv6 is often disabled while DNS returns IPv6 addresses...
170 	*/
171 
172 	if (lis->address.addr.sa_family != AF_INET6 &&
173 	    (FatalErrors & CUPSD_FATAL_LISTEN))
174 	  cupsdEndProcess(getpid(), 0);
175 #else
176 	if (FatalErrors & CUPSD_FATAL_LISTEN)
177 	  cupsdEndProcess(getpid(), 0);
178 #endif /* AF_INET6 */
179 
180 	continue;
181       }
182     }
183 
184     if (p)
185       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
186         	      s, p, lis->fd);
187     else
188       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
189         	      s, lis->fd);
190 
191    /*
192     * Save the first port that is bound to the local loopback or
193     * "any" address...
194     */
195 
196     if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
197         (httpAddrLocalhost(&(lis->address)) ||
198          httpAddrAny(&(lis->address))))
199     {
200       LocalPort       = p;
201       LocalEncryption = lis->encryption;
202     }
203 
204 #ifdef AF_LOCAL
205     if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
206       have_domain = lis->address.un.sun_path;
207 #endif /* AF_LOCAL */
208   }
209 
210  /*
211   * Make sure that we are listening on localhost!
212   */
213 
214   if (!LocalPort && !have_domain)
215   {
216     cupsdLogMessage(CUPSD_LOG_EMERG,
217                     "No Listen or Port lines were found to allow access via "
218 		    "localhost.");
219 
220     if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
221       cupsdEndProcess(getpid(), 0);
222   }
223 
224  /*
225   * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
226   * the listeners...
227   */
228 
229   if (have_domain)
230   {
231    /*
232     * Use domain sockets for the local connection...
233     */
234 
235     cupsdSetEnv("CUPS_SERVER", have_domain);
236 
237     LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
238   }
239   else
240   {
241    /*
242     * Use the default local loopback address for the server...
243     */
244 
245     cupsdSetEnv("CUPS_SERVER", "localhost");
246   }
247 
248   cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
249 
250   if (LocalPort)
251     cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
252 
253  /*
254   * Resume listening for connections...
255   */
256 
257   cupsdResumeListening();
258 }
259 
260 
261 /*
262  * 'cupsdStopListening()' - Close all listening sockets...
263  */
264 
265 void
cupsdStopListening(void)266 cupsdStopListening(void)
267 {
268   cupsd_listener_t	*lis;		/* Current listening socket */
269 
270 
271   cupsdLogMessage(CUPSD_LOG_DEBUG2,
272                   "cupsdStopListening: closing all listen sockets.");
273 
274   cupsdPauseListening();
275 
276   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
277        lis;
278        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
279   {
280 #ifdef HAVE_ONDEMAND
281     if (!lis->on_demand && lis->fd != -1)
282     {
283       httpAddrClose(&(lis->address), lis->fd);
284       lis->fd = -1;
285     }
286 
287 #else
288     if (lis->fd != -1)
289     {
290       httpAddrClose(&(lis->address), lis->fd);
291       lis->fd = -1;
292     }
293 #endif /* HAVE_ONDEMAND */
294   }
295 }
296