2003-10-13 11:03:14 -04:00
|
|
|
/*
|
|
|
|
* $Id$
|
|
|
|
* Functions for reading and writing the config file
|
|
|
|
*
|
|
|
|
* Copyright (C) 2003 Ron Pedde (ron@corbey.com)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2003-10-19 16:03:54 -04:00
|
|
|
#include <errno.h>
|
2003-11-12 01:23:01 -05:00
|
|
|
#include <fcntl.h>
|
2003-11-10 11:14:20 -05:00
|
|
|
#include <limits.h>
|
2003-10-13 11:03:14 -04:00
|
|
|
#include <stdio.h>
|
2003-10-19 16:03:54 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2003-11-12 01:23:01 -05:00
|
|
|
#include <sys/stat.h>
|
2003-10-13 11:03:14 -04:00
|
|
|
|
|
|
|
#include "configfile.h"
|
2003-10-19 16:03:54 -04:00
|
|
|
#include "err.h"
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Forwards
|
|
|
|
*/
|
2003-11-12 02:08:18 -05:00
|
|
|
void config_emit_string(WS_CONNINFO *pwsc, void *value);
|
|
|
|
void config_emit_literal(WS_CONNINFO *pwsc, void *value);
|
|
|
|
void config_emit_int(WS_CONNINFO *pwsc, void *value);
|
2003-11-12 01:23:01 -05:00
|
|
|
|
2003-10-19 16:03:54 -04:00
|
|
|
/*
|
|
|
|
* Defines
|
|
|
|
*/
|
2003-11-12 01:23:01 -05:00
|
|
|
#define CONFIG_TYPE_INT 0
|
|
|
|
#define CONFIG_TYPE_STRING 1
|
|
|
|
|
|
|
|
typedef struct tag_configelement {
|
|
|
|
int config_element;
|
|
|
|
int required;
|
|
|
|
int changed;
|
|
|
|
int type;
|
|
|
|
char *name;
|
|
|
|
void *var;
|
2003-11-12 02:08:18 -05:00
|
|
|
void (*emit)(WS_CONNINFO *, void *);
|
2003-11-12 01:23:01 -05:00
|
|
|
} CONFIGELEMENT;
|
|
|
|
|
|
|
|
CONFIGELEMENT config_elements[] = {
|
|
|
|
{ 1,1,0,CONFIG_TYPE_STRING,"web_root",(void*)&config.web_root,config_emit_string },
|
|
|
|
{ 1,1,0,CONFIG_TYPE_INT,"port",(void*)&config.port,config_emit_int },
|
|
|
|
{ 1,1,0,CONFIG_TYPE_STRING,"admin_pw",(void*)&config.adminpassword,config_emit_string },
|
|
|
|
{ 1,1,0,CONFIG_TYPE_STRING,"mp3_dir",(void*)&config.mp3dir,config_emit_string },
|
2003-11-12 02:08:18 -05:00
|
|
|
{ 0,0,0,CONFIG_TYPE_STRING,"release",(void*)VERSION,config_emit_literal },
|
|
|
|
{ 0,0,0,CONFIG_TYPE_STRING,"package",(void*)PACKAGE,config_emit_literal },
|
2003-11-12 01:23:01 -05:00
|
|
|
{ -1,1,0,CONFIG_TYPE_STRING,NULL,NULL,NULL }
|
|
|
|
};
|
|
|
|
|
2003-10-19 16:03:54 -04:00
|
|
|
|
|
|
|
#define MAX_LINE 1024
|
|
|
|
|
2003-10-13 11:03:14 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* config_read
|
|
|
|
*
|
2003-10-19 16:03:54 -04:00
|
|
|
* Read the specified config file, padding the config structure
|
|
|
|
* appropriately.
|
2003-10-13 11:03:14 -04:00
|
|
|
*
|
|
|
|
* This function returns 0 on success, errorcode on failure
|
|
|
|
*/
|
2003-11-12 01:23:01 -05:00
|
|
|
int config_read(char *file) {
|
2003-10-19 16:03:54 -04:00
|
|
|
FILE *fin;
|
|
|
|
char *buffer;
|
|
|
|
int err;
|
|
|
|
char *value;
|
|
|
|
char *comment;
|
2003-11-10 11:14:20 -05:00
|
|
|
char path_buffer[PATH_MAX];
|
2003-10-19 16:03:54 -04:00
|
|
|
err=0;
|
2003-11-12 01:23:01 -05:00
|
|
|
CONFIGELEMENT *pce;
|
|
|
|
int handled;
|
2003-10-19 16:03:54 -04:00
|
|
|
|
|
|
|
buffer=(char*)malloc(MAX_LINE);
|
|
|
|
if(!buffer)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if((fin=fopen(file,"r")) == NULL) {
|
|
|
|
err=errno;
|
|
|
|
free(buffer);
|
|
|
|
errno=err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
memset((void*)&config,0,sizeof(CONFIG));
|
2003-10-19 16:03:54 -04:00
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
config.configfile=strdup(file);
|
2003-10-19 16:03:54 -04:00
|
|
|
|
|
|
|
while(fgets(buffer,MAX_LINE,fin)) {
|
|
|
|
if(*buffer != '#') {
|
|
|
|
value=buffer;
|
|
|
|
strsep(&value,"\t ");
|
|
|
|
if(value) {
|
|
|
|
while((*value==' ')||(*value=='\t'))
|
|
|
|
value++;
|
|
|
|
|
|
|
|
comment=value;
|
|
|
|
strsep(&comment,"#");
|
|
|
|
|
|
|
|
if(value[strlen(value)-1] == '\n')
|
|
|
|
value[strlen(value)-1] = '\0';
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
pce=config_elements;
|
|
|
|
handled=0;
|
|
|
|
while((!handled) && (pce->config_element != -1)) {
|
|
|
|
if((strcasecmp(buffer,pce->name)==0) && (pce->config_element)) {
|
|
|
|
/* valid config directive */
|
|
|
|
handled=1;
|
|
|
|
pce->changed=1;
|
|
|
|
|
|
|
|
switch(pce->type) {
|
|
|
|
case CONFIG_TYPE_STRING:
|
2003-11-12 02:08:18 -05:00
|
|
|
*((char **)(pce->var)) = (void*)strdup(value);
|
2003-11-12 01:23:01 -05:00
|
|
|
break;
|
|
|
|
case CONFIG_TYPE_INT:
|
|
|
|
*((int*)(pce->var)) = atoi(value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pce++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!handled) {
|
|
|
|
fprintf(stderr,"Invalid config directive: %s\n",buffer);
|
|
|
|
fclose(fin);
|
|
|
|
return -1;
|
2003-10-19 16:03:54 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fin);
|
|
|
|
|
2003-11-12 02:08:18 -05:00
|
|
|
/* fix the fullpath of the web root */
|
|
|
|
realpath(config.web_root,path_buffer);
|
|
|
|
free(config.web_root);
|
|
|
|
config.web_root=strdup(path_buffer);
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
/* check to see if all required elements are satisfied */
|
|
|
|
pce=config_elements;
|
|
|
|
err=0;
|
|
|
|
while((pce->config_element != -1)) {
|
|
|
|
if(pce->required && pce->config_element && !pce->changed) {
|
|
|
|
fprintf(stderr,"Required config entry '%s' not specified\n",pce->name);
|
|
|
|
err=-1;
|
|
|
|
}
|
2003-11-12 02:08:18 -05:00
|
|
|
if((pce->config_element) && (pce->changed)) {
|
|
|
|
switch(pce->type) {
|
|
|
|
case CONFIG_TYPE_STRING:
|
|
|
|
DPRINTF(ERR_INFO,"%s: %s\n",pce->name,*((char**)pce->var));
|
|
|
|
break;
|
|
|
|
case CONFIG_TYPE_INT:
|
|
|
|
DPRINTF(ERR_INFO,"%s: %d\n",pce->name,*((int*)pce->var));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
pce->changed=0;
|
|
|
|
pce++;
|
2003-10-19 16:03:54 -04:00
|
|
|
}
|
2003-11-12 01:23:01 -05:00
|
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* config_write
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int config_write(CONFIG *pconfig) {
|
|
|
|
return 0;
|
|
|
|
}
|
2003-10-19 16:03:54 -04:00
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
/*
|
|
|
|
* config_handler
|
|
|
|
*
|
|
|
|
* Handle serving pages from the admin-root
|
|
|
|
*/
|
|
|
|
void config_handler(WS_CONNINFO *pwsc) {
|
|
|
|
char path[PATH_MAX];
|
|
|
|
char resolved_path[PATH_MAX];
|
|
|
|
int file_fd;
|
|
|
|
struct stat sb;
|
|
|
|
char argbuffer[30];
|
|
|
|
int in_arg;
|
|
|
|
char *argptr;
|
|
|
|
char next;
|
2003-11-12 02:08:18 -05:00
|
|
|
CONFIGELEMENT *pce;
|
|
|
|
|
|
|
|
DPRINTF(ERR_DEBUG,"Entereing config_handler\n");
|
2003-11-12 01:23:01 -05:00
|
|
|
|
|
|
|
pwsc->close=1;
|
|
|
|
ws_addresponseheader(pwsc,"Connection","close");
|
|
|
|
|
|
|
|
snprintf(path,PATH_MAX,"%s/%s",config.web_root,pwsc->uri);
|
|
|
|
if(!realpath(path,resolved_path)) {
|
|
|
|
pwsc->error=errno;
|
|
|
|
DPRINTF(ERR_WARN,"Cannot resolve %s\n",path);
|
|
|
|
ws_returnerror(pwsc,404,"Not found");
|
|
|
|
return;
|
2003-10-19 16:03:54 -04:00
|
|
|
}
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
/* this should really return a 302:Found */
|
|
|
|
stat(resolved_path,&sb);
|
|
|
|
if(sb.st_mode & S_IFDIR)
|
|
|
|
strcat(resolved_path,"/index.html");
|
|
|
|
|
|
|
|
DPRINTF(ERR_DEBUG,"Thread %d: Preparing to serve %s\n",
|
|
|
|
pwsc->threadno, resolved_path);
|
|
|
|
|
|
|
|
if(strncmp(resolved_path,config.web_root,
|
|
|
|
strlen(config.web_root))) {
|
|
|
|
pwsc->error=EINVAL;
|
|
|
|
DPRINTF(ERR_WARN,"Thread %d: Requested file %s out of root\n",
|
|
|
|
pwsc->threadno,resolved_path);
|
|
|
|
ws_returnerror(pwsc,403,"Forbidden");
|
|
|
|
return;
|
2003-10-19 16:03:54 -04:00
|
|
|
}
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
file_fd=r_open2(resolved_path,O_RDONLY);
|
|
|
|
if(file_fd == -1) {
|
|
|
|
pwsc->error=errno;
|
|
|
|
DPRINTF(ERR_WARN,"Thread %d: Error opening %s: %s\n",
|
|
|
|
pwsc->threadno,resolved_path,strerror(errno));
|
|
|
|
ws_returnerror(pwsc,404,"Not found");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(strcasecmp(pwsc->uri,"/config-update.html")==0) {
|
|
|
|
/* we need to update stuff */
|
|
|
|
argptr=ws_getvar(pwsc,"adminpw");
|
|
|
|
if(argptr) {
|
|
|
|
if(config.adminpassword)
|
|
|
|
free(config.adminpassword);
|
|
|
|
config.adminpassword=strdup(argptr);
|
|
|
|
}
|
2003-11-03 15:34:18 -05:00
|
|
|
}
|
|
|
|
|
2003-11-12 01:23:01 -05:00
|
|
|
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
|
|
|
ws_emitheaders(pwsc);
|
|
|
|
|
|
|
|
/* now throw out the file, with replacements */
|
|
|
|
in_arg=0;
|
|
|
|
argptr=argbuffer;
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
if(r_read(file_fd,&next,1) <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(in_arg) {
|
|
|
|
if(next == '@') {
|
|
|
|
in_arg=0;
|
2003-11-12 02:08:18 -05:00
|
|
|
|
|
|
|
DPRINTF(ERR_DEBUG,"Got directive %s\n",argbuffer);
|
|
|
|
|
|
|
|
pce=config_elements;
|
|
|
|
while(pce->config_element != -1) {
|
|
|
|
if(strcasecmp(argbuffer,pce->name) == 0) {
|
|
|
|
pce->emit(pwsc, pce->var);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pce++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pce->config_element == -1) { /* bad subst */
|
|
|
|
ws_writefd(pwsc,"@%s@",argbuffer);
|
2003-11-12 01:23:01 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if((argptr - argbuffer) < (sizeof(argbuffer)-1))
|
|
|
|
*argptr++ = next;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(next == '@') {
|
|
|
|
argptr=argbuffer;
|
|
|
|
memset(argbuffer,0,sizeof(argbuffer));
|
|
|
|
in_arg=1;
|
|
|
|
} else {
|
|
|
|
if(r_write(pwsc->fd,&next,1) == -1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r_close(file_fd);
|
|
|
|
DPRINTF(ERR_DEBUG,"Thread %d: Served successfully\n",pwsc->threadno);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_auth(char *user, char *password) {
|
2003-11-12 02:08:18 -05:00
|
|
|
if((!password)||(!config.adminpassword))
|
|
|
|
return 0;
|
2003-11-12 01:23:01 -05:00
|
|
|
return !strcmp(password,config.adminpassword);
|
2003-10-19 16:03:54 -04:00
|
|
|
}
|
|
|
|
|
2003-10-13 11:03:14 -04:00
|
|
|
|
|
|
|
/*
|
2003-11-12 01:23:01 -05:00
|
|
|
* config_emit_string
|
2003-10-13 11:03:14 -04:00
|
|
|
*
|
2003-11-12 01:23:01 -05:00
|
|
|
* write a simple string value to the connection
|
2003-10-13 11:03:14 -04:00
|
|
|
*/
|
2003-11-12 02:08:18 -05:00
|
|
|
void config_emit_string(WS_CONNINFO *pwsc, void *value) {
|
|
|
|
ws_writefd(pwsc,"%s",*((char**)value));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* config_emit_literal
|
|
|
|
*
|
|
|
|
* Emit a regular char *
|
|
|
|
*/
|
|
|
|
void config_emit_literal(WS_CONNINFO *pwsc, void *value) {
|
|
|
|
ws_writefd(pwsc,"%s",(char*)value);
|
2003-11-12 01:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* config_emit_int
|
|
|
|
*
|
|
|
|
* write a simple int value to the connection
|
|
|
|
*/
|
2003-11-12 02:08:18 -05:00
|
|
|
void config_emit_int(WS_CONNINFO *pwsc, void *value) {
|
|
|
|
ws_writefd(pwsc,"%d",*((int*)value));
|
2003-10-19 16:03:54 -04:00
|
|
|
}
|
2003-10-13 11:03:14 -04:00
|
|
|
|