/*
** Copyright (c) 2007 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** 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.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** Implementation of the Setup page
*/
#include "config.h"
#include
#include "setup.h"
/*
** Increment the "cfgcnt" variable, so that ETags will know that
** the configuration has changed.
*/
void setup_incr_cfgcnt(void){
static int once = 1;
if( once ){
once = 0;
db_multi_exec("UPDATE config SET value=value+1 WHERE name='cfgcnt'");
if( db_changes()==0 ){
db_multi_exec("INSERT INTO config(name,value) VALUES('cfgcnt',1)");
}
}
}
/*
** Output a single entry for a menu generated using an HTML table.
** If zLink is not NULL or an empty string, then it is the page that
** the menu entry will hyperlink to. If zLink is NULL or "", then
** the menu entry has no hyperlink - it is disabled.
*/
void setup_menu_entry(
const char *zTitle,
const char *zLink,
const char *zDesc
){
@
}
/*
** WEBPAGE: setup
**
** Main menu for the administrative pages. Requires Admin privileges.
*/
void setup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed(0);
}
style_header("Server Administration");
/* Make sure the header contains . Issue a warning
** if it does not. */
if( !cgi_header_contains("Configuration Error: Please add
@ <base href="$secureurl/$current_page"> after
@ <head> in the
@ HTML header!
}
#if !defined(_WIN32)
/* Check for /dev/null and /dev/urandom. We want both devices to be present,
** but they are sometimes omitted (by mistake) from chroot jails. */
if( access("/dev/null", R_OK|W_OK) ){
@
WARNING: Device "/dev/null" is not available
@ for reading and writing.
}
if( access("/dev/urandom", R_OK) ){
@
WARNING: Device "/dev/urandom" is not available
@ for reading. This means that the pseudo-random number generator used
@ by SQLite will be poorly seeded.
}
#endif
@
setup_menu_entry("Users", "setup_ulist",
"Grant privileges to individual users.");
setup_menu_entry("Access", "setup_access",
"Control access settings.");
setup_menu_entry("Configuration", "setup_config",
"Configure the WWW components of the repository");
setup_menu_entry("Security-Audit", "secaudit0",
"Analyze the current configuration for security problems");
setup_menu_entry("Settings", "setup_settings",
"Web interface to the \"fossil settings\" command");
setup_menu_entry("Timeline", "setup_timeline",
"Timeline display preferences");
setup_menu_entry("Login-Group", "setup_login_group",
"Manage single sign-on between this repository and others"
" on the same server");
setup_menu_entry("Tickets", "tktsetup",
"Configure the trouble-ticketing system for this repository");
setup_menu_entry("Search","srchsetup",
"Configure the built-in search engine");
setup_menu_entry("URL Aliases", "waliassetup",
"Configure URL aliases");
setup_menu_entry("Notification", "setup_notification",
"Automatic notifications of changes via outbound email");
setup_menu_entry("Email-Server", "setup_smtp",
"Activate and configure the built-in email server");
setup_menu_entry("Transfers", "xfersetup",
"Configure the transfer system for this repository");
setup_menu_entry("Skins", "setup_skin",
"Select and/or modify the web interface \"skins\"");
setup_menu_entry("Moderation", "setup_modreq",
"Enable/Disable requiring moderator approval of Wiki and/or Ticket"
" changes and attachments.");
setup_menu_entry("Ad-Unit", "setup_adunit",
"Edit HTML text for an ad unit inserted after the menu bar");
setup_menu_entry("URLs & Checkouts", "urllist",
"Show URLs used to access this repo and known check-outs");
setup_menu_entry("Web-Cache", "cachestat",
"View the status of the expensive-page cache");
setup_menu_entry("Logo", "setup_logo",
"Change the logo and background images for the server");
setup_menu_entry("Shunned", "shun",
"Show artifacts that are shunned by this repository");
setup_menu_entry("Artifact Receipts Log", "rcvfromlist",
"A record of received artifacts and their sources");
setup_menu_entry("User Log", "access_log",
"A record of login attempts");
setup_menu_entry("Administrative Log", "admin_log",
"View the admin_log entries");
setup_menu_entry("Error Log", "errorlog",
"View the Fossil server error log");
setup_menu_entry("Unversioned Files", "uvlist?byage=1",
"Show all unversioned files held");
setup_menu_entry("Stats", "stat",
"Repository Status Reports");
setup_menu_entry("Sitemap", "sitemap",
"Links to miscellaneous pages");
setup_menu_entry("SQL", "admin_sql",
"Enter raw SQL commands");
setup_menu_entry("TH1", "admin_th1",
"Enter raw TH1 commands");
@
style_footer();
}
/*
** Generate a checkbox for an attribute.
*/
void onoff_attribute(
const char *zLabel, /* The text label on the checkbox */
const char *zVar, /* The corresponding row in the VAR table */
const char *zQParm, /* The query parameter */
int dfltVal, /* Default value if VAR table entry does not exist */
int disabled /* 1 if disabled */
){
const char *zQ = P(zQParm);
int iVal = db_get_boolean(zVar, dfltVal);
if( zQ==0 && !disabled && P("submit") ){
zQ = "off";
}
if( zQ ){
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
if( iQ!=iVal ){
login_verify_csrf_secret();
db_set(zVar, iQ ? "1" : "0", 0);
admin_log("Set option [%q] to [%q].",
zVar, iQ ? "on" : "off");
iVal = iQ;
}
}
@
}
/*
** Generate an entry box for an attribute.
*/
void entry_attribute(
const char *zLabel, /* The text label on the entry box */
int width, /* Width of the entry box */
const char *zVar, /* The corresponding row in the VAR table */
const char *zQParm, /* The query parameter */
const char *zDflt, /* Default value if VAR table entry does not exist */
int disabled /* 1 if disabled */
){
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
const int nZQ = (int)strlen(zQ);
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
admin_log("Set entry_attribute %Q to: %.*s%s",
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
zVal = zQ;
}
@ %s(zLabel)
}
/*
** Generate a text box for an attribute.
*/
const char *textarea_attribute(
const char *zLabel, /* The text label on the textarea */
int rows, /* Rows in the textarea */
int cols, /* Columns in the textarea */
const char *zVar, /* The corresponding row in the VAR table */
const char *zQP, /* The query parameter */
const char *zDflt, /* Default value if VAR table entry does not exist */
int disabled /* 1 if the textarea should not be editable */
){
const char *z = db_get(zVar, zDflt);
const char *zQ = P(zQP);
if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
const int nZQ = (int)strlen(zQ);
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
admin_log("Set textarea_attribute %Q to: %.*s%s",
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
z = zQ;
}
if( rows>0 && cols>0 ){
@
if( zLabel && *zLabel ){
@ %s(zLabel)
}
}
return z;
}
/*
** Generate a text box for an attribute.
*/
void multiple_choice_attribute(
const char *zLabel, /* The text label on the menu */
const char *zVar, /* The corresponding row in the VAR table */
const char *zQP, /* The query parameter */
const char *zDflt, /* Default value if VAR table entry does not exist */
int nChoice, /* Number of choices */
const char *const *azChoice /* Choices. 2 per choice: (VAR value, Display) */
){
const char *z = db_get(zVar, zDflt);
const char *zQ = P(zQP);
int i;
if( zQ && fossil_strcmp(zQ,z)!=0){
const int nZQ = (int)strlen(zQ);
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
z = zQ;
}
@ %h(zLabel)
}
/*
** WEBPAGE: setup_access
**
** The access-control settings page. Requires Admin privileges.
*/
void setup_access(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed(0);
return;
}
style_header("Access Control Settings");
db_begin_transaction();
@
db_end_transaction(0);
style_footer();
}
/*
** WEBPAGE: setup_login_group
**
** Change how the current repository participates in a login
** group.
*/
void setup_login_group(void){
const char *zGroup;
char *zErrMsg = 0;
Blob fullName;
char *zSelfRepo;
const char *zRepo = PD("repo", "");
const char *zLogin = PD("login", "");
const char *zPw = PD("pw", "");
const char *zNewName = PD("newname", "New Login Group");
login_check_credentials();
if( !g.perm.Setup ){
login_needed(0);
return;
}
file_canonical_name(g.zRepositoryName, &fullName, 0);
zSelfRepo = fossil_strdup(blob_str(&fullName));
blob_reset(&fullName);
if( P("join")!=0 ){
login_group_join(zRepo, zLogin, zPw, zNewName, &zErrMsg);
}else if( P("leave") ){
login_group_leave(&zErrMsg);
}
style_header("Login Group Configuration");
if( zErrMsg ){
@
%s(zErrMsg)
}
zGroup = login_group_name();
if( zGroup==0 ){
@
This repository (in the file named "%h(zSelfRepo)")
@ is not currently part of any login-group.
@ To join a login group, fill out the form below.
@
@
}else{
Stmt q;
int n = 0;
@
This repository (in the file "%h(zSelfRepo)")
@ is currently part of the "%h(zGroup)" login group.
@ Other repositories in that group are:
@
@
Project Name
@
Repository File
db_prepare(&q,
"SELECT value,"
" (SELECT value FROM config"
" WHERE name=('peer-name-' || substr(x.name,11)))"
" FROM config AS x"
" WHERE name GLOB 'peer-repo-*'"
" ORDER BY value"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zRepo = db_column_text(&q, 0);
const char *zTitle = db_column_text(&q, 1);
n++;
@