1 /*                      _             _
2 **  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
3 ** | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| |   \__ \__ \ |  www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_|  ftp.modssl.org
6 **                      |_____|
7 **  ssl_engine_mutex.c
8 **  Semaphore for Mutual Exclusion
9 */
10 
11 /* ====================================================================
12  * Copyright (c) 1998-2003 Ralf S. Engelschall. All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  *
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  *
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following
23  *    disclaimer in the documentation and/or other materials
24  *    provided with the distribution.
25  *
26  * 3. All advertising materials mentioning features or use of this
27  *    software must display the following acknowledgment:
28  *    "This product includes software developed by
29  *     Ralf S. Engelschall <rse@engelschall.com> for use in the
30  *     mod_ssl project (http://www.modssl.org/)."
31  *
32  * 4. The names "mod_ssl" must not be used to endorse or promote
33  *    products derived from this software without prior written
34  *    permission. For written permission, please contact
35  *    rse@engelschall.com.
36  *
37  * 5. Products derived from this software may not be called "mod_ssl"
38  *    nor may "mod_ssl" appear in their names without prior
39  *    written permission of Ralf S. Engelschall.
40  *
41  * 6. Redistributions of any form whatsoever must retain the following
42  *    acknowledgment:
43  *    "This product includes software developed by
44  *     Ralf S. Engelschall <rse@engelschall.com> for use in the
45  *     mod_ssl project (http://www.modssl.org/)."
46  *
47  * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
48  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL RALF S. ENGELSCHALL OR
51  * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
56  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
58  * OF THE POSSIBILITY OF SUCH DAMAGE.
59  * ====================================================================
60  */
61                              /* ``Real programmers confuse
62                                   Christmas and Halloween
63                                   because DEC 25 = OCT 31.''
64                                              -- Unknown     */
65 #include "mod_ssl.h"
66 
67 
68 /*  _________________________________________________________________
69 **
70 **  Mutex Support (Common)
71 **  _________________________________________________________________
72 */
73 
ssl_mutex_init(server_rec * s,pool * p)74 void ssl_mutex_init(server_rec *s, pool *p)
75 {
76     SSLModConfigRec *mc = myModConfig();
77 
78     if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
79         ssl_mutex_file_create(s, p);
80     else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
81         ssl_mutex_sem_create(s, p);
82     return;
83 }
84 
ssl_mutex_reinit(server_rec * s,pool * p)85 void ssl_mutex_reinit(server_rec *s, pool *p)
86 {
87     SSLModConfigRec *mc = myModConfig();
88 
89     if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
90         ssl_mutex_file_open(s, p);
91     else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
92         ssl_mutex_sem_open(s, p);
93     return;
94 }
95 
ssl_mutex_on(server_rec * s)96 void ssl_mutex_on(server_rec *s)
97 {
98     SSLModConfigRec *mc = myModConfig();
99     BOOL ok = TRUE;
100 
101     if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
102         ok = ssl_mutex_file_acquire();
103     else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
104         ok = ssl_mutex_sem_acquire();
105     if (!ok)
106         ssl_log(s, SSL_LOG_WARN, "Failed to acquire global mutex lock");
107     return;
108 }
109 
ssl_mutex_off(server_rec * s)110 void ssl_mutex_off(server_rec *s)
111 {
112     SSLModConfigRec *mc = myModConfig();
113     BOOL ok = TRUE;
114 
115     if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
116         ok = ssl_mutex_file_release();
117     else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
118         ok = ssl_mutex_sem_release();
119     if (!ok)
120         ssl_log(s, SSL_LOG_WARN, "Failed to release global mutex lock");
121     return;
122 }
123 
ssl_mutex_kill(server_rec * s)124 void ssl_mutex_kill(server_rec *s)
125 {
126     SSLModConfigRec *mc = myModConfig();
127 
128     if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
129         ssl_mutex_file_remove(s);
130     else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
131         ssl_mutex_sem_remove(s);
132     return;
133 }
134 
135 
136 /*  _________________________________________________________________
137 **
138 **  Mutex Support (Lockfile)
139 **  _________________________________________________________________
140 */
141 
ssl_mutex_file_create(server_rec * s,pool * p)142 void ssl_mutex_file_create(server_rec *s, pool *p)
143 {
144     SSLModConfigRec *mc = myModConfig();
145     char mutexfile[MAXPATHLEN];
146 
147     /* create the lockfile */
148     strlcpy(mutexfile, mc->szMutexFile, sizeof(mutexfile));
149     ap_server_strip_chroot(mutexfile, 0);
150     unlink(mutexfile);
151     if ((mc->nMutexFD = ap_popenf(p, mutexfile,
152                                   O_WRONLY|O_CREAT, SSL_MUTEX_LOCK_MODE)) < 0) {
153         ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
154                 "Parent process could not create SSLMutex lockfile %s",
155                 mutexfile);
156         ssl_die();
157     }
158     ap_pclosef(p, mc->nMutexFD);
159 
160     /* make sure the childs have access to this file */
161     if (geteuid() == 0 /* is superuser */)
162         chown(mutexfile, ap_user_id, -1 /* no gid change */);
163 
164     /* open the lockfile for real */
165     if ((mc->nMutexFD = ap_popenf(p, mutexfile,
166                                   O_WRONLY, SSL_MUTEX_LOCK_MODE)) < 0) {
167         ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
168                 "Parent could not open SSLMutex lockfile %s",
169                 mutexfile);
170         ssl_die();
171     }
172     return;
173 }
174 
ssl_mutex_file_open(server_rec * s,pool * p)175 void ssl_mutex_file_open(server_rec *s, pool *p)
176 {
177     SSLModConfigRec *mc = myModConfig();
178     char mutexfile[MAXPATHLEN];
179 
180     strlcpy(mutexfile, mc->szMutexFile, sizeof(mutexfile));
181     ap_server_strip_chroot(mutexfile, 0);
182 
183     /* open the lockfile (once per child) to get a unique fd */
184     if ((mc->nMutexFD = ap_popenf(p, mutexfile,
185                                   O_WRONLY, SSL_MUTEX_LOCK_MODE)) < 0) {
186         ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
187                 "Child could not open SSLMutex lockfile %s",
188                 mutexfile);
189         ssl_die();
190     }
191     return;
192 }
193 
ssl_mutex_file_remove(void * data)194 void ssl_mutex_file_remove(void *data)
195 {
196     SSLModConfigRec *mc = myModConfig();
197     char mutexfile[MAXPATHLEN];
198     strlcpy(mutexfile, mc->szMutexFile, sizeof(mutexfile));
199     ap_server_strip_chroot(mutexfile, 0);
200 
201     /* remove the mutex lockfile */
202     unlink(mutexfile);
203     return;
204 }
205 
206 #ifdef SSL_USE_FCNTL
207 static struct flock   lock_it;
208 static struct flock unlock_it;
209 #endif
210 
ssl_mutex_file_acquire(void)211 BOOL ssl_mutex_file_acquire(void)
212 {
213     int rc = -1;
214     SSLModConfigRec *mc = myModConfig();
215 
216 #ifdef SSL_USE_FCNTL
217     lock_it.l_whence = SEEK_SET; /* from current point */
218     lock_it.l_start  = 0;        /* -"- */
219     lock_it.l_len    = 0;        /* until end of file */
220     lock_it.l_type   = F_WRLCK;  /* set exclusive/write lock */
221     lock_it.l_pid    = 0;        /* pid not actually interesting */
222 
223     while (   ((rc = fcntl(mc->nMutexFD, F_SETLKW, &lock_it)) < 0)
224            && (errno == EINTR)                                    )
225         ;
226 #endif
227 #ifdef SSL_USE_FLOCK
228     while (   ((rc = flock(mc->nMutexFD, LOCK_EX)) < 0)
229            && (errno == EINTR)                         )
230         ;
231 #endif
232 
233     if (rc < 0)
234         return FALSE;
235     else
236         return TRUE;
237 }
238 
ssl_mutex_file_release(void)239 BOOL ssl_mutex_file_release(void)
240 {
241     int rc = -1;
242     SSLModConfigRec *mc = myModConfig();
243 
244 #ifdef SSL_USE_FCNTL
245     unlock_it.l_whence = SEEK_SET; /* from current point */
246     unlock_it.l_start  = 0;        /* -"- */
247     unlock_it.l_len    = 0;        /* until end of file */
248     unlock_it.l_type   = F_UNLCK;  /* unlock */
249     unlock_it.l_pid    = 0;        /* pid not actually interesting */
250 
251     while (   (rc = fcntl(mc->nMutexFD, F_SETLKW, &unlock_it)) < 0
252            && (errno == EINTR)                                    )
253         ;
254 #endif
255 #ifdef SSL_USE_FLOCK
256     while (   (rc = flock(mc->nMutexFD, LOCK_UN)) < 0
257            && (errno == EINTR)                       )
258         ;
259 #endif
260 
261     if (rc < 0)
262         return FALSE;
263     else
264         return TRUE;
265 }
266 
267 /*  _________________________________________________________________
268 **
269 **  Mutex Support (Process Semaphore)
270 **  _________________________________________________________________
271 */
272 
ssl_mutex_sem_create(server_rec * s,pool * p)273 void ssl_mutex_sem_create(server_rec *s, pool *p)
274 {
275     int semid;
276     SSLModConfigRec *mc = myModConfig();
277     union ssl_ipc_semun semctlarg;
278     struct semid_ds semctlbuf;
279 
280     semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
281     if (semid == -1 && errno == EEXIST)
282         semid = semget(IPC_PRIVATE, 1, IPC_EXCL|S_IRUSR|S_IWUSR);
283     if (semid == -1) {
284         ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
285                 "Parent process could not create private SSLMutex semaphore");
286         ssl_die();
287     }
288     semctlarg.val = 0;
289     if (semctl(semid, 0, SETVAL, semctlarg) < 0) {
290         ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
291                 "Parent process could not initialize SSLMutex semaphore value");
292         ssl_die();
293     }
294     semctlbuf.sem_perm.uid  = ap_user_id;
295     semctlbuf.sem_perm.gid  = ap_group_id;
296     semctlbuf.sem_perm.mode = 0600;
297     semctlarg.buf = &semctlbuf;
298     if (semctl(semid, 0, IPC_SET, semctlarg) < 0) {
299         ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
300                 "Parent process could not set permissions for SSLMutex semaphore");
301         ssl_die();
302     }
303     mc->nMutexSEMID = semid;
304     return;
305 }
306 
ssl_mutex_sem_open(server_rec * s,pool * p)307 void ssl_mutex_sem_open(server_rec *s, pool *p)
308 {
309     return;
310 }
311 
ssl_mutex_sem_remove(void * data)312 void ssl_mutex_sem_remove(void *data)
313 {
314     SSLModConfigRec *mc = myModConfig();
315 
316     semctl(mc->nMutexSEMID, 0, IPC_RMID, 0);
317     return;
318 }
319 
ssl_mutex_sem_acquire(void)320 BOOL ssl_mutex_sem_acquire(void)
321 {
322     int rc = 0;
323     SSLModConfigRec *mc = myModConfig();
324 
325     struct sembuf sb[] = {
326         { 0, 0, 0 },       /* wait for semaphore */
327         { 0, 1, SEM_UNDO } /* increment semaphore */
328     };
329 
330     while (   (rc = semop(mc->nMutexSEMID, sb, 2)) < 0
331            && (errno == EINTR)                        )
332         ;
333     if (rc != 0)
334         return FALSE;
335     else
336         return TRUE;
337 }
338 
ssl_mutex_sem_release(void)339 BOOL ssl_mutex_sem_release(void)
340 {
341     int rc = 0;
342     SSLModConfigRec *mc = myModConfig();
343 
344     struct sembuf sb[] = {
345         { 0, -1, SEM_UNDO } /* decrements semaphore */
346     };
347 
348     while (   (rc = semop(mc->nMutexSEMID, sb, 1)) < 0
349            && (errno == EINTR)                        )
350         ;
351     if (rc != 0)
352         return FALSE;
353     else
354         return TRUE;
355 }
356 
357