/* PureAdmin
* Copyright (C) 2003 Isak Savo
*
* 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.
*/
/*
* Configuration backend.
*
* Copyright (C) 2003-2006 Isak Savo
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include "globals.h"
#include "helper.h"
#include "cfg.h"
/* Global configuration structure */
cfg_t cfg;
/* cfg_write_settings: Writes the configuration to disk (~/.pureadminrc).
*
* Returns: TRUE if everything was saved.
* FALSE if something went wrong. (i.e. file couldn't be opened)
*/
gboolean cfg_write_settings (void)
{
FILE *f;
gchar filename[FILEPATH_MAX];
g_snprintf (filename, FILEPATH_MAX, "%s/" RCFILE, g_get_home_dir ());
if (!(f = fopen (filename, "w")))
{
perror ("Unable to open config-file for writing");
return FALSE;
}
fputs ("# -*- sh -*-\n"
"# ~/.pureadminrc - Configuration file for pureadmin\n"
"# All variables are in the form VARNAME=VALUE where VALUE should be an UN-quoted string\n"
"# Comment lines BEGINS with a '#'. Otherwise the # is considered a part of the value/variablename\n\n", f);
fputs ("# Default UID and GID to assign to new virtual users. These should point to an un-priveliged system account.\n", f);
if (cfg.default_uid > 0)
fprintf (f, "defaultuid=%d\n", cfg.default_uid);
if (cfg.default_gid > 0)
fprintf (f, "defaultgid=%d\n\n", cfg.default_gid);
if (cfg.default_home)
{
fputs ("# Default home is the directory which will be assigned to new users by default.\n", f);
fprintf (f, "defaulthome=%s\n\n", cfg.default_home);
}
if (cfg.cmd_purepw)
{
fputs ("# Name and optional full path to the pure-pw command. Path is only needed if it is not installed in a standard location (i.e. Not in $PATH)\n", f);
fprintf (f, "cmd_purepw=%s\n\n", cfg.cmd_purepw);
}
fputs ("# Name and location of the password files where pureftpd reads user-information. The pdb-file is a binary database file,\n", f);
if (cfg.pwfile)
fprintf (f, "pwfile=%s\n", cfg.pwfile);
if (cfg.pdbfile)
fprintf (f, "pdbfile=%s\n\n", cfg.pdbfile);
if (cfg.logfile)
{
fputs ("# Location of the logfile where pureftpd writes logging info\n", f);
fprintf (f, "logfile=%s\n\n", cfg.logfile);
}
fputs ("# Logging method, 0 means syslog and 1 means custom logfile\n", f);
fprintf (f, "logmethod=%d\n", cfg.logmethod);
fputs ("# If this is enabled, then DNS name lookups will be performed resulting in IP-addresses being\n"
"# converted to human readable names\n"
"# Setting this to 0 will make PureAdmin seem faster and more responsive.\n", f);
fprintf (f, "resolve_hostnames=%d\n\n", cfg.resolve_hostnames);
fputs ("# Indicates wether the first-time user-dialog messagebox have been seen by the user\n", f);
fprintf (f, "seen_usrdlg_welcome=%d\n\n", cfg.seen_usrdlg_welcome);
fputs ("# Indicates wether the FAM Error dialog should be shown or not\n", f);
fprintf (f, "show_fam_errmsg=%d\n\n", cfg.show_fam_errmsg);
fputs ("# Should we display an icon in the system tray upon events?\n", f);
fprintf (f, "use_tray_icon=%d\n\n", cfg.use_tray_icon);
fputs ("# Character set to use for usernames\n", f);
fprintf (f, "username_encoding=%s\n", cfg.uname_encoding);
fprintf (f, "use_system_encoding=%d\n\n", cfg.use_system_encoding);
fputs ("# True if window size and position should be restored\n", f);
fprintf (f, "save_window_geometry=%d\n\n", cfg.save_window_geometry);
fputs ("# The window size and position in x:y pairs\n", f);
fprintf (f, "window_size=%d:%d\n", cfg.win_size[0], cfg.win_size[1]);
fprintf (f, "window_pos=%d:%d\n", cfg.win_pos[0], cfg.win_pos[1]);
fprintf (f, "divider_pos=%d\n", cfg.div_pos);
fprintf (f, "show_advinfo=%d\n", cfg.show_advinfo);
fclose (f);
return TRUE;
}
/* cfg_read_settings: Reads the settings from user configuration file (~/.pureadminrc)
*
* Returns: TRUE if all went well
* FALSE if something went wrong. (i.e. file couldn't be opened)
*/
gboolean cfg_read_settings (void)
{
FILE *f;
gchar filename[FILEPATH_MAX];
gchar buf[LINE_MAX], **arr;
g_snprintf (filename, FILEPATH_MAX, "%s/" RCFILE, g_get_home_dir ());
if (!(f = fopen (filename, "r")))
{
pur_log_wrn ("Unable to open config-file for reading: %s", strerror (errno));
pur_log_nfo ("Using default configuration\n");
return FALSE;
}
while (fgets (buf, LINE_MAX, f))
{
g_strstrip (buf);
if (*buf == '#' || *buf == '\0')
continue;
arr = g_strsplit (buf, "=", 2);
if (!arr || !arr[0] || !arr[1])
continue;
g_strstrip (arr[0]);
g_strstrip (arr[1]);
gchar *key = arr[0];
gchar *val = arr[1];
if (*val == '\0') /* Ignore values that is empty (i.e. "") */
continue;
if (strncmp (key, "defaultuid", 10) == 0)
cfg.default_uid = atoi (val);
else if (strncmp (key, "defaultgid", 10) == 0)
cfg.default_gid = atoi (val);
else if (strncmp (key, "defaulthome", 11) == 0)
{
if (g_path_is_absolute(val))
{
g_free (cfg.default_home);
cfg.default_home = g_strdup (val);
}
}
else if (strncmp (key, "cmd_purepw", 10) == 0)
{
if ((g_path_is_absolute(val) && g_file_test(val, G_FILE_TEST_EXISTS)) ||
g_find_program_in_path(val))
{
g_free (cfg.cmd_purepw);
cfg.cmd_purepw = g_strdup (val);
}
}
else if (strncmp (key, "pwfile", 6) == 0)
{
if (g_path_is_absolute(val))
{
g_free (cfg.pwfile);
cfg.pwfile = g_strdup (val);
}
}
else if (strncmp (key, "pdbfile", 7) == 0)
{
if (g_path_is_absolute(val))
{
g_free (cfg.pdbfile);
cfg.pdbfile = g_strdup (val);
}
}
else if (strncmp (key, "logfile", 7) == 0)
{
if (g_path_is_absolute(val))
{
g_free (cfg.logfile);
cfg.logfile = g_strdup (val);
}
}
else if (strncmp (key, "logmethod", 9) == 0)
{
cfg.logmethod = atoi (val);
if (cfg.logmethod < 0 || cfg.logmethod >= NUM_LOGMETHODS)
cfg.logmethod = 0;
}
else if (strncmp (key, "window_size", 11) == 0)
sscanf (val,"%d:%d",&(cfg.win_size[0]), &(cfg.win_size[1]));
else if (strncmp (key, "window_pos", 10) == 0)
sscanf (val,"%d:%d",&(cfg.win_pos[0]), &(cfg.win_pos[1]));
else if (strncmp (key, "divider_pos", 11) == 0)
cfg.div_pos = atoi (val);
else if (strncmp (key, "save_window_geometry", 20) == 0)
cfg.save_window_geometry = atoi (val);
else if (strncmp (key, "show_advinfo", 12) == 0)
cfg.show_advinfo = atoi (val);
else if (strncmp (key, "resolve_hostnames", 17) == 0)
cfg.resolve_hostnames = atoi (val);
else if (strncmp (key, "seen_usrdlg_welcome", 19) == 0)
cfg.seen_usrdlg_welcome = atoi (val);
else if (strncmp (key, "show_fam_errmsg", 15) == 0)
cfg.show_fam_errmsg = atoi (val);
else if (strncmp (key, "use_tray_icon", 13) == 0)
cfg.use_tray_icon = atoi (val);
else if (strncmp (key, "username_encoding", 17) == 0)
{
g_free (cfg.uname_encoding);
cfg.uname_encoding = g_strdup (val);
}
else if (strncmp (key, "use_system_encoding", 19) == 0)
cfg.use_system_encoding = atoi (val);
g_strfreev (arr);
}
fclose (f);
return TRUE;
}
void cfg_terminate (void)
{
g_free (cfg.default_home);
g_free (cfg.cmd_purepw);
g_free (cfg.cmd_ftpwho);
g_free (cfg.cmd_startstop);
g_free (cfg.cmd_useradd);
g_free (cfg.cmd_groupadd);
g_free (cfg.pwfile);
g_free (cfg.pdbfile);
g_free (cfg.logfile);
g_free (cfg.uname_encoding);
}
gchar *cfg_find_default_home (void)
{
if (g_file_test ("/home/ftpuser", G_FILE_TEST_IS_DIR))
return g_strdup ("/home/ftpuser");
else if (g_file_test ("/home/ftpusers", G_FILE_TEST_IS_DIR))
return g_strdup ("/home/ftpusers");
else if (g_file_test ("/home/ftp", G_FILE_TEST_IS_DIR))
return g_strdup ("/home/ftp");
return g_strdup ("/home/ftpusers");
}
gchar *cfg_find_pwfile (void)
{
if (g_file_test (g_getenv ("PURE_PASSWDFILE"), G_FILE_TEST_IS_REGULAR))
return g_strdup (g_getenv ("PURE_PASSWDFILE"));
else if (g_file_test ("/etc/pureftpd.passwd", G_FILE_TEST_IS_REGULAR))
return g_strdup ("/etc/pureftpd.passwd");
else if (g_file_test ("/etc/pure-ftpd/pureftpd.passwd", G_FILE_TEST_IS_REGULAR))
return g_strdup ("/etc/pure-ftpd/pureftpd.passwd");
return NULL;
}
gchar *cfg_find_pdbfile (void)
{
if (g_file_test (g_getenv ("PURE_DBFILE"), G_FILE_TEST_IS_REGULAR))
return g_strdup (g_getenv ("PURE_DBFILE"));
else if (g_file_test ("/etc/pureftpd.pdb", G_FILE_TEST_IS_REGULAR))
return g_strdup ("/etc/pureftpd.pdb");
else if (g_file_test ("/etc/pure-ftpd/pureftpd.pdb", G_FILE_TEST_IS_REGULAR))
return g_strdup ("/etc/pure-ftpd/pureftpd.pdb");
/* No existing, default to the same as pwfile but with pdb-extension */
if (cfg.pwfile) {
gchar *s, *tmp ;
s = g_strdup (cfg.pwfile);
tmp = strrchr(s, '.');
if (tmp)
*tmp = '\0';
tmp = g_strconcat (s, ".pdb", NULL);
g_free (s);
return tmp;
}
/* We've done all we can, return NULL */
return NULL;
}
guint cfg_find_ftpuser_uid (void)
{
gchar *s, **arr;
guint rv = 0;
arr = NULL;
s = misc_get_line_beginning_with ("/etc/passwd", "ftpuser");
if (!s)
return 0;
arr = g_strsplit (s, ":", 0);
if (arr_count (arr) > 2)
rv = atoi (arr[2]);
g_strfreev (arr);
g_free (s);
return rv;
}
guint cfg_find_ftpgroup_gid (void)
{
gchar *s, **arr;
guint rv = 0;
arr = NULL;
s = misc_get_line_beginning_with ("/etc/group", "ftpgroup");
if (!s)
return 0;
arr = g_strsplit (s, ":", 0);
if (arr_count (arr) > 2)
rv = atoi (arr[2]);
g_strfreev (arr);
g_free (s);
return rv;
}
gchar *cfg_get_pftp_config_dir (void)
{
gchar *dir = NULL;
if (cfg.pwfile)
dir = g_path_get_dirname (cfg.pwfile);
else if (cfg.pdbfile)
dir = g_path_get_dirname (cfg.pdbfile);
else if (g_file_test("/etc/pure-ftpd", G_FILE_TEST_IS_DIR))
dir = g_strdup ("/etc/pure-ftpd");
else
dir = g_strdup ("/etc");
return dir;
}
/* Gets the default password file for pureftpd, regardless of whether it exists or not */
gchar *cfg_get_pftp_default_pwfile (void)
{
if (g_getenv ("PURE_PASSWDFILE") && g_path_is_absolute(g_getenv("PURE_PASSWDFILE")))
return g_strdup (g_getenv ("PURE_PASSWDFILE"));
gchar *dir = cfg_get_pftp_config_dir();
gchar *f = g_build_filename(dir, "pureftpd.passwd", NULL);
g_free(dir);
return f;
}
/* Gets the default dbfile for pureftpd, regardless of whether it exists or not */
gchar *cfg_get_pftp_default_pdbfile (void)
{
if (g_getenv ("PURE_DBFILE") && g_path_is_absolute(g_getenv("PURE_DBFILE")))
return g_strdup (g_getenv ("PURE_DBFILE"));
gchar *dir = cfg_get_pftp_config_dir();
gchar *f = g_build_filename(dir, "pureftpd.pdb", NULL);
g_free(dir);
return f;
}
/* cfg_fill_missing: Tries to find sane defaults for values that there are no
* configured setting for. This is mostly done by probing the
* file system for the relevant files.
*/
void cfg_fill_missing (void)
{
if (!cfg.cmd_purepw)
cfg.cmd_purepw = g_find_program_in_path ("pure-pw");
if (!cfg.cmd_ftpwho)
cfg.cmd_ftpwho = g_find_program_in_path ("pure-ftpwho");
if (!cfg.cmd_startstop) {
gchar prg_arr[][20] = { "rc.pure-ftpd", "rc.pureftpd", "pure-ftpd", "pure-ftpd-mysql"};
for (gint i = 0; i < G_N_ELEMENTS(prg_arr); i++)
{
gchar *s = prg_arr[i];
cfg.cmd_startstop = misc_find_prog_in_dirs
(s, "/etc/rc.d /etc/rc.d/init.d /etc/init.d /usr/local/etc/rc.d");
if (cfg.cmd_startstop)
break;
}
}
if (!cfg.pwfile)
{
gchar *base = cfg_get_pftp_config_dir();
cfg.pwfile = g_build_filename (base, "pureftpd.passwd", NULL);
g_free (base);
}
if (!cfg.pdbfile)
{
gchar *base = cfg_get_pftp_config_dir();
cfg.pdbfile = g_build_filename (base, "pureftpd.pdb", NULL);
g_free (base);
}
if (!cfg.default_home)
cfg.default_home = cfg_find_default_home ();
if (!cfg.pwfile)
cfg.pwfile = cfg_find_pwfile ();
if (!cfg.pdbfile)
cfg.pdbfile = cfg_find_pdbfile ();
/* Find User ID of ftpuser */
if (!cfg.default_uid)
cfg.default_uid = cfg_find_ftpuser_uid ();
/* Find Group ID of ftpgroup */
if (!cfg.default_gid)
cfg.default_gid = cfg_find_ftpgroup_gid ();
if (!cfg.cmd_useradd)
cfg.cmd_useradd = g_find_program_in_path ("useradd");
if (!cfg.cmd_groupadd)
cfg.cmd_groupadd = g_find_program_in_path ("groupadd");
}
/* cfg_set_defaults: Sets default values to the configuration struct.
* This should only be called ONCE and before any
* attempt to access or modify the cfg struct!
*
* Note: this function has no logic to make wise
* decisions. See the cfg_fill_missing for that!
*/
void cfg_set_defaults (void)
{
memset (&cfg, 0, sizeof (cfg_t));
cfg.logfile = g_strdup ("/var/log/messages");
cfg.use_system_encoding = TRUE;
cfg.uname_encoding = g_strdup ("UTF-8");
cfg.logmethod = LOG_SYSLOG;
cfg.show_fam_errmsg = TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1