initial load of upstream version 1.06.32
[xmlrpc-c] / lib / abyss / src / conf.c
1 /******************************************************************************
2 **
3 ** conf.c
4 **
5 ** This file is part of the ABYSS Web server project.
6 **
7 ** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
8 ** All rights reserved.
9 **
10 ** Redistribution and use in source and binary forms, with or without
11 ** modification, are permitted provided that the following conditions
12 ** are met:
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 ** 
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 ** SUCH DAMAGE.
32 **
33 ******************************************************************************/
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38
39 #if defined(WIN32) && !defined(__BORLANDC__)
40 #include <direct.h>
41 #endif
42
43 #ifdef _UNIX
44 #include <pwd.h>
45 #endif
46
47 #include "xmlrpc_config.h"
48 #include "xmlrpc-c/string_int.h"
49 #include "xmlrpc-c/abyss.h"
50 #include "trace.h"
51 #include "server.h"
52 #include "http.h"
53
54 /*********************************************************************
55 ** Configuration Files Parsing Functions
56 *********************************************************************/
57
58
59
60 static abyss_bool
61 ConfReadLine(TFile *f,char *buffer,uint32_t len) {
62     abyss_bool r=TRUE;
63     char c,*p,*z=buffer;
64
65     while ((--len)>0)
66     {
67         if (FileRead(f,buffer,1)<1)
68         {
69             if (z==buffer)
70                 r=FALSE;
71             break;
72         };
73
74         if ((*buffer==CR) || (*buffer==LF) )
75             break;
76
77         buffer++;
78     };
79
80     if (len==0)
81         while (FileRead(f,&c,1)==1)
82             if ((c==CR) || (c==LF))
83                 break;
84
85     *buffer='\0';
86
87     /* Discard comments */
88     p=strchr(z,'#');
89     if (p)
90         *p='\0';
91
92     return r;
93 }
94
95 static abyss_bool
96 ConfNextToken(char **p) {
97     while (1)
98         switch (**p)
99         {
100         case '\t':
101         case ' ':
102             (*p)++;
103             break;
104         case '\0':
105             return FALSE;
106         default:
107             return TRUE;
108         };
109 }
110
111 static char *
112 ConfGetToken(char **p) {
113     char *p0=*p;
114
115     while (1)
116         switch (**p)
117         {
118         case '\t':
119         case ' ':
120         case CR:
121         case LF:
122         case '\0':
123             if (p0==*p)
124                 return NULL;
125
126             if (**p)
127             {
128                 **p='\0';
129                 (*p)++;
130             };
131             return p0;
132
133         default:
134             (*p)++;
135         };
136 }
137
138 static abyss_bool
139 ConfReadInt(const char * const p,
140             int32_t *    const n,
141             int32_t      const min,
142             int32_t      const max) {
143 /*----------------------------------------------------------------------------
144    Convert string 'p' to integer *n.
145
146    If it isn't a valid integer or is not with the bounds [min, max],
147    return FALSE.  Otherwise, return TRUE.
148 -----------------------------------------------------------------------------*/
149     char * e;
150
151     *n = strtol(p, &e, 10);
152
153     if (min != max)
154         return ((e != p) && (*n >= min) && (*n <= max));
155     else
156         return (e != p);
157 }
158
159
160
161 static abyss_bool
162 ConfReadBool(char *p, abyss_bool *b) {
163     if (strcasecmp(p,"yes")==0)
164     {
165         *b=TRUE;
166         return TRUE;
167     };
168
169     if (strcasecmp(p,"no")==0)
170     {
171         *b=FALSE;
172         return TRUE;
173     };
174
175     return FALSE;
176 }
177
178 /*********************************************************************
179 ** MIME Types File
180 *********************************************************************/
181
182 static void
183 readMIMETypesFile(const char * const filename,
184                   MIMEType **  const MIMETypePP) {
185
186     abyss_bool success;
187     MIMEType * MIMETypeP;
188
189     MIMETypeP = MIMETypeCreate();
190     if (MIMETypeP) {
191         TFile file;
192         abyss_bool fileOpened;
193
194         fileOpened = FileOpen(&file, filename, O_RDONLY);
195         if (fileOpened) {
196             char z[512];
197             while (ConfReadLine(&file, z, 512)) {
198                 char * p;
199                 p = &z[0];
200             
201                 if (ConfNextToken(&p)) {
202                     const char * mimetype = ConfGetToken(&p);
203                     if (mimetype) {
204                         while (ConfNextToken(&p)) {
205                             const char * const ext = ConfGetToken(&p);
206                             if (ext)
207                                 MIMETypeAdd2(MIMETypeP, mimetype, ext);
208                             else
209                                 break;
210                         }
211                     }
212                 }
213             }
214             FileClose(&file);
215             success = TRUE;
216         } else
217             success = FALSE;
218         if (!success)
219             MIMETypeDestroy(MIMETypeP);
220     } else
221         success = FALSE;
222
223     if (success)
224         *MIMETypePP = MIMETypeP;
225     else
226         *MIMETypePP = NULL;
227 }
228
229 /*********************************************************************
230 ** Server Configuration File
231 *********************************************************************/
232
233 static void
234 chdirx(const char * const newdir,
235        abyss_bool * const successP) {
236     
237 #if defined(WIN32) && !defined(__BORLANDC__)
238     *successP = _chdir(newdir) == 0;
239 #else
240     *successP = chdir(newdir) == 0;
241 #endif
242 }
243
244
245
246 static void
247 parseUser(const char *      const p, 
248           struct _TServer * const srvP) {
249 #ifdef _UNIX
250     if (p[0] == '#') {
251         int32_t n;
252         
253         if (!ConfReadInt(&p[1], &n, 0, 0))
254             TraceExit("Bad user number '%s'", p);
255         else
256             srvP->uid = n;
257     } else {
258         struct passwd * pwd;
259
260         if (!(pwd = getpwnam(p)))
261             TraceExit("Unknown user '%s'", p);
262         
263         srvP->uid = pwd->pw_uid;
264         if ((int)srvP->gid==(-1))
265             srvP->gid = pwd->pw_gid;
266     };
267 #else
268     TraceMsg("User option ignored");
269 #endif  /* _UNIX */ 
270 }
271
272
273
274 static void
275 parsePidfile(const char *      const p,
276              struct _TServer * const srvP) {
277 #ifdef _UNIX
278     if (!FileOpenCreate(&srvP->pidfile, p, O_TRUNC | O_WRONLY)) {
279         srvP->pidfile = -1;
280         TraceMsg("Bad PidFile value '%s'", p);
281     };
282 #else
283     TraceMsg("PidFile option ignored");
284 #endif  /* _UNIX */ 
285 }
286
287
288
289 abyss_bool
290 ConfReadServerFile(const char * const filename,
291                    TServer *    const serverP) {
292
293     struct _TServer * const srvP = serverP->srvP;
294
295     TFile f;
296     char z[512];
297     char * p;
298     unsigned int lineNum;
299     TFileStat fs;
300
301     if (!FileOpen(&f, filename, O_RDONLY))
302         return FALSE;
303
304     lineNum = 0;
305
306     while (ConfReadLine(&f, z, 512)) {
307         ++lineNum;
308         p = z;
309
310         if (ConfNextToken(&p)) {
311             const char * const option = ConfGetToken(&p);
312             if (option) {
313                 ConfNextToken(&p);
314
315                 if (strcasecmp(option, "port") == 0) {
316                     int32_t n;
317                     if (ConfReadInt(p, &n, 1, 65535))
318                         srvP->port = n;
319                     else
320                         TraceExit("Invalid port '%s'", p);
321                 } else if (strcasecmp(option, "serverroot") == 0) {
322                     abyss_bool success;
323                     chdirx(p, &success);
324                     if (!success)
325                         TraceExit("Invalid server root '%s'",p);
326                 } else if (strcasecmp(option, "path") == 0) {
327                     if (FileStat(p, &fs))
328                         if (fs.st_mode & S_IFDIR) {
329                             xmlrpc_strfree(srvP->filespath);
330                             srvP->filespath = strdup(p);
331                             continue;
332                         }
333                     TraceExit("Invalid path '%s'", p);
334                 } else if (strcasecmp(option, "default") == 0) {
335                     const char * filename;
336                     
337                     while ((filename = ConfGetToken(&p))) {
338                         ListAdd(&srvP->defaultfilenames, strdup(filename));
339                         if (!ConfNextToken(&p))
340                             break;
341                     }
342                 } else if (strcasecmp(option, "keepalive") == 0) {
343                     int32_t n;
344                     if (ConfReadInt(p, &n, 1, 65535))
345                         srvP->keepalivemaxconn = n;
346                     else
347                         TraceExit("Invalid KeepAlive value '%s'", p);
348                 } else if (strcasecmp(option, "timeout") == 0) {
349                     int32_t n;
350                     if (ConfReadInt(p, &n, 1, 3600)) {
351                         srvP->keepalivetimeout = n;
352                         /* Must see what to do with that */
353                         srvP->timeout = n;
354                     } else
355                         TraceExit("Invalid TimeOut value '%s'", p);
356                 } else if (strcasecmp(option, "mimetypes") == 0) {
357                     readMIMETypesFile(p, &srvP->mimeTypeP);
358                     if (!srvP->mimeTypeP)
359                         TraceExit("Can't read MIME Types file '%s'", p);
360                 } else if (strcasecmp(option,"logfile") == 0) {
361                     srvP->logfilename = strdup(p);
362                 } else if (strcasecmp(option,"user") == 0) {
363                     parseUser(p, srvP);
364                 } else if (strcasecmp(option, "pidfile")==0) {
365                     parsePidfile(p, srvP);
366                 } else if (strcasecmp(option, "advertiseserver") == 0) {
367                     if (!ConfReadBool(p, &srvP->advertise))
368                         TraceExit("Invalid boolean value "
369                                   "for AdvertiseServer option");
370                 } else
371                     TraceExit("Invalid option '%s' at line %u",
372                               option, lineNum);
373             }
374         }
375     }
376
377     FileClose(&f);
378     return TRUE;
379 }