Commit 18590880 18590880814ffb1941ba9a67b49a246323e36d37 by Sergey Poznyakoff

Implement normal UNIX-style configuration files:

* mailbox/cfg_lexer.c: New file.
* mailbox/cfg_parser.c: New file.
* mailbox/cfg_parser.h: New file.
* mailbox/Makefile.am: Add cfg_ sources and socket_stream.c.

* include/mailutils/cfg.h: New file.
* include/mailutils/Makefile.am (pkginclude_HEADERS): Add cfg.h.
* include/mailutils/argp.h: Include cfg.h.
(mu_create_argcv): Remove prototype.
* include/mailutils/mu_auth.h (struct mu_auth_module): New member
`cfg'.
(MU_AUTH_REGISTER_ALL_MODULES): Call mu_auth_init first.

* mailbox/mu_argp.c: Rewrite. Implement normal configuration
(resource) file support. Overloaded command line options begin to
phase out.
* mailbox/mu_auth.c, auth/gsasl.c, auth/pam.c, auth/radius.c,
auth/sql.c, auth/tls.c, auth/virtual.c, libsieve/argp.c,
mailbox/system.c: Implement configuration statements.

* imap4d/imap4d.c: Begin switching to the new configuration scheme.
1 parent 1f6c71fc
......@@ -41,8 +41,7 @@ char *mu_gsasl_cram_md5_pwd = SITE_CRAM_MD5_PWD;
#define ARG_CRAM_PASSWD 1
static struct argp_option _gsasl_argp_options[] = {
{NULL, 0, NULL, 0, N_("GSASL options"), 0},
{"cram-passwd", ARG_CRAM_PASSWD, N_("FILE"), 0,
{"cram-passwd", ARG_CRAM_PASSWD, N_("FILE"), OPTION_HIDDEN,
N_("Specify password file for CRAM-MD5 authentication"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
};
......@@ -77,7 +76,7 @@ static struct argp_child _gsasl_argp_child = {
void
mu_gsasl_init_argp ()
{
if (mu_register_capa ("gsasl", &_gsasl_argp_child))
if (mu_register_capa ("gsasl", &_gsasl_argp_child, NULL))
{
mu_error (_("INTERNAL ERROR: cannot register argp capability gsasl"));
abort ();
......
......@@ -150,7 +150,7 @@ mu_pam_argp_parser (int key, char *arg, struct argp_state *state)
}
static struct argp_option mu_pam_argp_option[] = {
{ "pam-service", ARG_PAM_SERVICE, N_("STRING"), 0,
{ "pam-service", ARG_PAM_SERVICE, N_("STRING"), OPTION_HIDDEN,
N_("Use STRING as PAM service name"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
};
......@@ -179,8 +179,10 @@ struct mu_auth_module mu_auth_pam_module = {
"pam",
#ifdef USE_LIBPAM
&mu_pam_argp,
NULL,
#else
NULL,
NULL,
#endif
mu_authenticate_pam,
NULL,
......
......@@ -51,13 +51,13 @@
#define ARG_RADIUS_DIR 259
static struct argp_option mu_radius_argp_option[] = {
{ "radius-auth-request", ARG_AUTH_REQUEST, N_("REQUEST"), 0,
{ "radius-auth-request", ARG_AUTH_REQUEST, N_("REQUEST"), OPTION_HIDDEN,
N_("Radius request to authenitcate the user"), 0 },
{ "radius-getpwnam-request", ARG_GETPWNAM_REQUEST, N_("REQUEST"), 0,
{ "radius-getpwnam-request", ARG_GETPWNAM_REQUEST, N_("REQUEST"), OPTION_HIDDEN,
N_("Radius request to retrieve a passwd entry based on username"), 0 },
{ "radius-getpwuid-request", ARG_GETPWUID_REQUEST, N_("REQUEST"), 0,
{ "radius-getpwuid-request", ARG_GETPWUID_REQUEST, N_("REQUEST"), OPTION_HIDDEN,
N_("Radius request to retrieve a passwd entry based on UID"), 0 },
{ "radius-directory", ARG_RADIUS_DIR, N_("DIR"), 0,
{ "radius-directory", ARG_RADIUS_DIR, N_("DIR"), OPTION_HIDDEN,
N_("Set path to the radius configuration directory"), 0 },
{ NULL }
};
......@@ -598,8 +598,10 @@ struct mu_auth_module mu_auth_radius_module = {
"radius",
#ifdef ENABLE_RADIUS
&mu_radius_argp,
NULL,
#else
NULL,
NULL,
#endif
mu_radius_authenticate,
NULL,
......
......@@ -175,6 +175,22 @@ mu_sql_expand_query (const char *query, const char *ustr)
return res;
}
static int
set_sql_password_type (const char *arg)
{
if (strcmp (arg, "plain") == 0)
mu_sql_password_type = password_plaintext;
else if (strcmp (arg, "hash") == 0)
mu_sql_password_type = password_hash;
else if (strcmp (arg, "scrambled") == 0)
mu_sql_password_type = password_scrambled;
else
return 1;
return 0;
}
/* Command-line configuration */
# define ARG_SQL_INTERFACE 256
# define ARG_SQL_GETPWNAM 257
# define ARG_SQL_GETPWUID 258
......@@ -188,27 +204,27 @@ mu_sql_expand_query (const char *query, const char *ustr)
# define ARG_SQL_FIELD_MAP 266
static struct argp_option mu_sql_argp_option[] = {
{"sql-interface", ARG_SQL_INTERFACE, N_("NAME"), 0,
N_("Type of SQL interface to use"), 0},
{"sql-getpwnam", ARG_SQL_GETPWNAM, N_("QUERY"), 0,
{"sql-interface", ARG_SQL_INTERFACE, N_("NAME"), OPTION_HIDDEN,
N_("Type of SQL interface to use"), },
{"sql-getpwnam", ARG_SQL_GETPWNAM, N_("QUERY"), OPTION_HIDDEN,
N_("SQL query to retrieve a passwd entry based on username"), 0},
{"sql-getpwuid", ARG_SQL_GETPWUID, N_("QUERY"), 0,
{"sql-getpwuid", ARG_SQL_GETPWUID, N_("QUERY"), OPTION_HIDDEN,
N_("SQL query to retrieve a passwd entry based on UID"), 0},
{"sql-getpass", ARG_SQL_GETPASS, N_("QUERY"), 0,
{"sql-getpass", ARG_SQL_GETPASS, N_("QUERY"), OPTION_HIDDEN,
N_("SQL query to retrieve a password from the database"), 0},
{"sql-host", ARG_SQL_HOST, N_("HOSTNAME"), 0,
{"sql-host", ARG_SQL_HOST, N_("HOSTNAME"), OPTION_HIDDEN,
N_("Name or IP of MySQL server to connect to"), 0},
{"sql-user", ARG_SQL_USER, N_("NAME"), 0,
{"sql-user", ARG_SQL_USER, N_("NAME"), OPTION_HIDDEN,
N_("SQL user name"), 0},
{"sql-passwd", ARG_SQL_PASSWD, N_("STRING"), 0,
{"sql-passwd", ARG_SQL_PASSWD, N_("STRING"), OPTION_HIDDEN,
N_("SQL connection password"), 0},
{"sql-db", ARG_SQL_DB, N_("STRING"), 0,
{"sql-db", ARG_SQL_DB, N_("STRING"), OPTION_HIDDEN,
N_("Name of the database to connect to"), 0},
{"sql-port", ARG_SQL_PORT, N_("NUMBER"), 0,
{"sql-port", ARG_SQL_PORT, N_("NUMBER"), OPTION_HIDDEN,
N_("Port to use"), 0},
{"sql-password-type", ARG_SQL_MU_PASSWORD_TYPE, N_("STRING"), 0,
{"sql-password-type", ARG_SQL_MU_PASSWORD_TYPE, N_("STRING"), OPTION_HIDDEN,
N_("Type of password returned by --sql-getpass query. STRING is one of: plain, hash, scrambled"), 0},
{"sql-field-map", ARG_SQL_FIELD_MAP, N_("MAP"), 0,
{"sql-field-map", ARG_SQL_FIELD_MAP, N_("MAP"), OPTION_HIDDEN,
N_("Declare a name translation map for SQL fields in results of sql-getpwnam and "
"sql-getpwuid queries"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
......@@ -260,13 +276,7 @@ mu_sql_argp_parser (int key, char *arg, struct argp_state *state)
break;
case ARG_SQL_MU_PASSWORD_TYPE:
if (strcmp (arg, "plain") == 0)
mu_sql_password_type = password_plaintext;
else if (strcmp (arg, "hash") == 0)
mu_sql_password_type = password_hash;
else if (strcmp (arg, "scrambled") == 0)
mu_sql_password_type = password_scrambled;
else
if (set_sql_password_type (arg))
argp_error (state, _("Unknown password type `%s'"), arg);
break;
......@@ -283,11 +293,59 @@ mu_sql_argp_parser (int key, char *arg, struct argp_state *state)
return 0;
}
struct argp mu_sql_argp = {
static struct argp mu_sql_argp = {
mu_sql_argp_option,
mu_sql_argp_parser,
};
/* Resource file configuration */
static int
cb_iface (mu_cfg_locus_t *locus, void *data, char *arg)
{
sql_interface = mu_sql_interface_index (arg);
if (sql_interface == 0)
mu_error (_("%s:%d: Unknown SQL interface `%s'"),
locus->file, locus->line, arg);
return 0;
}
static int
cb_password_type (mu_cfg_locus_t *locus, void *data, char *arg)
{
if (set_sql_password_type (arg))
mu_error (_("%s:%d: Unknown password type `%s'"),
locus->file, locus->line, arg);
return 0;
}
static int
cb_field_map (mu_cfg_locus_t *locus, void *data, char *arg)
{
int err;
int rc = mutil_parse_field_map (arg, &sql_field_map, &err);
if (rc)
mu_error (_("%s:%d: Error near element %d: %s"),
locus->file, locus->line, err, mu_strerror (rc));
return 0;
}
static struct mu_cfg_param mu_sql_param[] = {
{ "interface", mu_cfg_callback, NULL, cb_iface },
{ "getwpnam", mu_cfg_string, &mu_sql_getpwnam_query },
{ "getpwuid", mu_cfg_string, &mu_sql_getpwuid_query },
{ "getpass", mu_cfg_string, &mu_sql_getpass_query },
{ "host", mu_cfg_string, &mu_sql_host },
{ "user", mu_cfg_string, &mu_sql_user },
{ "passwd", mu_cfg_string, &mu_sql_passwd },
{ "db", mu_cfg_string, &mu_sql_db },
{ "port", mu_cfg_int, &mu_sql_port },
{ "password-type", mu_cfg_callback, NULL, cb_password_type },
{ "field-map", mu_cfg_callback, NULL, cb_field_map },
{ NULL }
};
static int
decode_tuple_v1_0 (mu_sql_connection_t conn, int n,
struct mu_auth_data **return_data)
......@@ -787,8 +845,10 @@ struct mu_auth_module mu_auth_sql_module = {
"sql",
#ifdef USE_SQL
&mu_sql_argp,
mu_sql_param,
#else
NULL,
NULL,
#endif
mu_sql_authenticate,
NULL,
......
......@@ -55,12 +55,11 @@ static char *ssl_cafile = NULL;
#define ARG_SSL_CAFILE 4
static struct argp_option _tls_argp_options[] = {
{NULL, 0, NULL, 0, N_("Encryption options"), 0},
{"ssl-cert", ARG_SSL_CERT, N_("FILE"), 0,
{"ssl-cert", ARG_SSL_CERT, N_("FILE"), OPTION_HIDDEN,
N_("Specify SSL certificate file"), 0},
{"ssl-key", ARG_SSL_KEY, N_("FILE"), 0,
N_("Specify SSL certificate key"), 0},
{"ssl-cafile", ARG_SSL_CAFILE, N_("FILE"), 0,
{"ssl-key", ARG_SSL_KEY, N_("FILE"), OPTION_HIDDEN,
N_("Specify SSL certificate key"), },
{"ssl-cafile", ARG_SSL_CAFILE, N_("FILE"), OPTION_HIDDEN,
N_("Specify trusted CAs file"), 0},
{NULL, 0, NULL, 0, NULL, 0}
};
......@@ -117,7 +116,7 @@ static struct argp_child _tls_argp_child = {
void
mu_tls_init_argp ()
{
if (mu_register_capa ("tls", &_tls_argp_child))
if (mu_register_capa ("tls", &_tls_argp_child, NULL))
{
mu_error (_("INTERNAL ERROR: cannot register argp capability tls"));
abort ();
......@@ -145,7 +144,7 @@ static struct argp_child _tls_argp_client_child = {
void
mu_tls_init_client_argp ()
{
if (mu_register_capa ("tls", &_tls_argp_client_child))
if (mu_register_capa ("tls", &_tls_argp_client_child, NULL))
{
mu_error (_("INTERNAL ERROR: cannot register argp capability tls"));
abort ();
......
......@@ -191,7 +191,7 @@ mu_virt_argp_parser (int key, char *arg, struct argp_state *state)
}
static struct argp_option mu_virt_argp_option[] = {
{ "virtual-passwd-dir", ARG_PWDDIR, N_("DIR"), 0,
{ "virtual-passwd-dir", ARG_PWDDIR, N_("DIR"), OPTION_HIDDEN,
N_("Search for virtual passwd file in DIR"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
};
......@@ -216,8 +216,10 @@ struct mu_auth_module mu_auth_virtual_module = {
"virtdomain",
#ifdef ENABLE_VIRTUAL_DOMAINS
&mu_virt_argp,
NULL,
#else
NULL,
NULL,
#endif
mu_auth_nosupport,
NULL,
......
......@@ -41,7 +41,8 @@ int login_disabled; /* Disable LOGIN command */
int tls_required; /* Require STARTTLS */
int create_home_dir; /* Create home directory if it does not
exist */
int home_dir_mode;
int home_dir_mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
/* Number of child processes. */
size_t children;
......@@ -54,21 +55,23 @@ static char doc[] = N_("GNU imap4d -- the IMAP4D daemon");
#define ARG_CREATE_HOME_DIR 3
static struct argp_option options[] = {
{"other-namespace", 'O', N_("PATHLIST"), 0,
{"other-namespace", 'O', N_("PATHLIST"), OPTION_HIDDEN,
N_("Set the `other' namespace"), 0},
{"shared-namespace", 'S', N_("PATHLIST"), 0,
{"shared-namespace", 'S', N_("PATHLIST"), OPTION_HIDDEN,
N_("Set the `shared' namespace"), 0},
{"login-disabled", ARG_LOGIN_DISABLED, NULL, 0,
{"login-disabled", ARG_LOGIN_DISABLED, NULL, OPTION_HIDDEN,
N_("Disable LOGIN command")},
{"create-home-dir", ARG_CREATE_HOME_DIR, N_("MODE"), OPTION_ARG_OPTIONAL,
{"create-home-dir", ARG_CREATE_HOME_DIR, N_("MODE"),
OPTION_ARG_OPTIONAL|OPTION_HIDDEN,
N_("Create home directory, if it does not exist")},
#ifdef WITH_TLS
{"tls-required", ARG_TLS_REQUIRED, NULL, 0,
{"tls-required", ARG_TLS_REQUIRED, NULL, OPTION_HIDDEN,
N_("Always require STARTTLS before entering authentication phase")},
#endif
{NULL, 0, NULL, 0, NULL, 0}
};
static error_t imap4d_parse_opt (int key, char *arg,
struct argp_state *state);
......@@ -120,7 +123,6 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state)
case ARG_LOGIN_DISABLED:
login_disabled = 1;
imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
break;
case ARG_CREATE_HOME_DIR:
......@@ -132,14 +134,11 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state)
if (p || (home_dir_mode & 0777))
argp_error (state, _("Invalid mode specification: %s"), arg);
}
else
home_dir_mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
break;
#ifdef WITH_TLS
case ARG_TLS_REQUIRED:
tls_required = 1;
imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED);
break;
#endif
......@@ -149,6 +148,41 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state)
return 0;
}
static int
cb_other (mu_cfg_locus_t *locus, void *data, char *arg)
{
set_namespace (NS_OTHER, arg);
return 0;
}
static int
cb_shared (mu_cfg_locus_t *locus, void *data, char *arg)
{
set_namespace (NS_SHARED, arg);
return 0;
}
static int
cb_mode (mu_cfg_locus_t *locus, void *data, char *arg)
{
char *p;
home_dir_mode = strtoul (arg, &p, 8);
if (p || (home_dir_mode & 0777))
mu_error (_("%s:%d: Invalid mode specification: %s"),
locus->file, locus->line, arg);
return 0;
}
static struct mu_cfg_param imap4d_cfg_param[] = {
{ "other-namespace", mu_cfg_callback, NULL, cb_other },
{ "shared-namespace", mu_cfg_callback, NULL, cb_shared },
{ "login-disabled", mu_cfg_int, &login_disabled },
{ "create-home-dir", mu_cfg_bool, &create_home_dir },
{ "home-dir-mode", mu_cfg_callback, NULL, cb_mode },
{ "tls-required", mu_cfg_int, &tls_required },
{ NULL }
};
int
main (int argc, char **argv)
{
......@@ -170,8 +204,16 @@ main (int argc, char **argv)
#ifdef WITH_GSASL
mu_gsasl_init_argp ();
#endif
mu_config_register_plain_section (NULL, NULL, imap4d_cfg_param);
mu_argp_parse (&argp, &argc, &argv, 0, imap4d_capa, NULL, &daemon_param);
if (login_disabled)
imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
#ifdef WITH_TLS
if (tls_required)
imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED);
#endif
auth_gssapi_init ();
auth_gsasl_init ();
......
......@@ -36,6 +36,7 @@ pkginclude_HEADERS = \
attribute.h \
auth.h \
body.h \
cfg.h \
compat.h \
daemon.h \
debug.h \
......
......@@ -21,6 +21,7 @@
#define _MAILUTILS_ARGP_H
#include <mailutils/types.h>
#include <mailutils/cfg.h>
#include <argp.h>
#include <errno.h> /* May declare program_invocation_name */
......@@ -49,15 +50,13 @@ extern "C" {
extern void mu_argp_init (const char *vers, const char *bugaddr);
extern void mu_create_argcv (const char *capa[],
int argc, char **argv,
int *p_argc, char ***p_argv);
extern error_t mu_argp_parse (const struct argp * argp,
int *p_argc, char ***p_argv,
unsigned flags,
const char *capa[],
int *arg_index, void *input);
extern int mu_register_capa (const char *name, struct argp_child *child);
extern int mu_register_capa (const char *name, struct argp_child *child,
struct mu_cfg_param *param);
extern void mu_print_options (void);
extern const char *mu_check_option (char *name);
......
/* cfg.h -- general-purpose configuration file parser
Copyright (C) 2007 Free Software Foundation, Inc.
GNU Mailutils 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 3, 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MAILUTILS_CFG_H
#define _MAILUTILS_CFG_H
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef enum mu_cfg_node_type mu_cfg_node_type_t;
typedef struct mu_cfg_node mu_cfg_node_t;
typedef struct mu_cfg_locus mu_cfg_locus_t;
typedef int (*mu_cfg_lexer_t) (void *ptr);
typedef void (*mu_cfg_perror_t) (void *ptr, const mu_cfg_locus_t *loc,
const char *fmt, ...);
typedef void *(*mu_cfg_alloc_t) (size_t size);
typedef void (*mu_cfg_free_t) (void *ptr);
enum mu_cfg_node_type
{
mu_cfg_node_undefined,
mu_cfg_node_tag,
mu_cfg_node_param
};
struct mu_cfg_locus
{
char *file;
size_t line;
};
struct mu_cfg_node
{
mu_cfg_node_t *next;
mu_cfg_locus_t locus;
enum mu_cfg_node_type type;
char *tag_name;
char *tag_label;
mu_cfg_node_t *node;
};
int mu_cfg_parse (mu_cfg_node_t **ptree,
void *data,
mu_cfg_lexer_t lexer,
mu_cfg_perror_t perror,
mu_cfg_alloc_t alloc,
mu_cfg_free_t free);
extern mu_cfg_locus_t mu_cfg_locus;
extern int mu_cfg_tie_in;
extern mu_cfg_perror_t mu_cfg_perror;
#define MU_CFG_ITER_OK 0
#define MU_CFG_ITER_SKIP 1
#define MU_CFG_ITER_STOP 2
typedef int (*mu_cfg_iter_func_t) (const mu_cfg_node_t *node, void *data);
void mu_cfg_destroy_tree (mu_cfg_node_t **tree);
int mu_cfg_preorder (mu_cfg_node_t *node,
mu_cfg_iter_func_t fun, mu_cfg_iter_func_t endfun,
void *data);
int mu_cfg_postorder (mu_cfg_node_t *node,
mu_cfg_iter_func_t fun, mu_cfg_iter_func_t endfun,
void *data);
int mu_cfg_find_node (mu_cfg_node_t *tree, const char *path,
mu_cfg_node_t **pval);
int mu_cfg_find_node_label (mu_cfg_node_t *tree, const char *path,
const char **pval);
/* Table-driven parsing */
enum mu_cfg_param_data_type
{
mu_cfg_string,
mu_cfg_short,
mu_cfg_ushort,
mu_cfg_int,
mu_cfg_uint,
mu_cfg_long,
mu_cfg_ulong,
mu_cfg_size,
mu_cfg_off,
mu_cfg_bool,
mu_cfg_ipv4,
mu_cfg_cidr,
mu_cfg_host,
mu_cfg_callback
};
typedef int (*mu_cfg_callback_t) (mu_cfg_locus_t *, void *, char *);
struct mu_cfg_param
{
const char *ident;
enum mu_cfg_param_data_type type;
void *data;
mu_cfg_callback_t callback;
};
enum mu_cfg_section_stage
{
mu_cfg_section_start,
mu_cfg_section_end
};
typedef int (*mu_cfg_section_fp) (enum mu_cfg_section_stage stage,
const mu_cfg_node_t *node,
void *section_data, void *call_data);
struct mu_cfg_section
{
const char *ident;
mu_cfg_section_fp parser;
void *data;
struct mu_cfg_section *subsec;
struct mu_cfg_param *param;
};
typedef struct mu_cfg_cidr mu_cfg_cidr_t;
struct mu_cfg_cidr
{
struct in_addr addr;
unsigned long mask;
};
int mu_cfg_scan_tree (mu_cfg_node_t *node,
struct mu_cfg_section *sections,
void *data, mu_cfg_perror_t perror,
mu_cfg_alloc_t palloc, mu_cfg_free_t pfree);
int mu_cfg_find_section (struct mu_cfg_section *root_sec,
const char *path, struct mu_cfg_section **retval);
int mu_config_register_section (const char *parent_path,
const char *ident,
mu_cfg_section_fp parser,
void *data,
struct mu_cfg_param *param);
int mu_config_register_plain_section (const char *parent_path,
const char *ident,
struct mu_cfg_param *params);
#endif
......@@ -116,7 +116,7 @@ sieve_argp_parser (int key, char *arg, struct argp_state *state)
void
mu_sieve_argp_init ()
{
if (mu_register_capa ("sieve", &sieve_argp_child))
if (mu_register_capa ("sieve", &sieve_argp_child, NULL))
{
mu_error ("INTERNAL ERROR: cannot register argp capability sieve");
abort ();
......
......@@ -32,7 +32,7 @@ AM_CPPFLAGS = \
-DSITE_VIRTUAL_PWDDIR=\"@SITE_VIRTUAL_PWDDIR@\"\
-DLOCALEDIR=\"$(localedir)\"
EXTRA_DIST = @MU_EXTRA_DIST@ errors muerrno.cin parsedate.y fgetpwent.c
EXTRA_DIST = @MU_EXTRA_DIST@ errors muerrno.cin parsedate.y fgetpwent.c cfg_parser.y cfg_parser.h
libmailutils_la_SOURCES = \
address.c \
......@@ -46,6 +46,8 @@ body.c \
daemon.c \
date.c \
debug.c \
cfg_lexer.c \
cfg_parser.c \
envelope.c \
file_stream.c \
filter.c \
......@@ -83,6 +85,7 @@ parsedate.c \
property.c \
registrar.c \
rfc2047.c \
socket_stream.c \
stream.c \
system.c \
tcp.c \
......@@ -98,6 +101,12 @@ parsedate.c: $(srcdir)/parsedate.y
y.tab.c parsedate.c y.output parsedate.y.output \
-- -yy pd_yy
cfg_parser.c: $(srcdir)/cfg_parser.y
$(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \
y.tab.c cfg_parser.c y.tab.h cfg_parser.h \
y.output cfg_parser.y.output \
-- -yy mu_cfg_yy
muerrno.c: errors muerrno.cin
$(AWK) -f $(top_srcdir)/scripts/generr.awk $^ > $@
......
/* cfg_lexer.c -- default lexer for Mailutils configuration files
Copyright (C) 2007 Free Software Foundation, Inc.
GNU Mailutils 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 3, 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <mailutils/argcv.h>
#include <mailutils/nls.h>
#include <mailutils/cfg.h>
#include <mailutils/errno.h>
#include <mailutils/error.h>
#include <mailutils/mutil.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "cfg_parser.h"
struct lexer_data
{
char *buffer;
char *curp;
struct obstack stk;
};
static void
skipws (struct lexer_data *p)
{
while (*p->curp && isspace (*p->curp))
{
if (*p->curp == '\n')
mu_cfg_locus.line++;
p->curp++;
}
}
static void
skipline (struct lexer_data *p)
{
while (*p->curp && *p->curp != '\n')
p->curp++;
}
static int
isword (int c)
{
if (mu_cfg_tie_in)
return c && c != ';';
return isalnum (c) || c == '_' || c == '-';
}
static char *
copy_alpha (struct lexer_data *p)
{
do
{
if (*p->curp == '\n')
mu_cfg_locus.line++;
obstack_1grow (&p->stk, *p->curp);
p->curp++;
} while (*p->curp && isword(*p->curp));
obstack_1grow (&p->stk, 0);
return obstack_finish (&p->stk);
}
static char *
copy_string(struct lexer_data *p)
{
int quote = *p->curp++;
while (*p->curp)
{
if (*p->curp == '\\')
{
char c;
if (*++p->curp == 0)
{
obstack_1grow (&p->stk, '\\');
break;
}
c = mu_argcv_unquote_char (*p->curp);
if (c == *p->curp)
{
obstack_1grow (&p->stk, '\\');
obstack_1grow (&p->stk, *p->curp);
}
else
obstack_1grow (&p->stk, c);
p->curp++;
}
else if (*p->curp == quote)
{
p->curp++;
break;
}
else
{
obstack_1grow (&p->stk, *p->curp);
p->curp++;
}
}
obstack_1grow (&p->stk, 0);
return obstack_finish (&p->stk);
}
int
default_lexer (void *dp)
{
struct lexer_data *p = dp;
char *save_start;
char *tag, *label;
again:
skipws (p);
if (*p->curp == '#')
{
skipline (p);
goto again;
}
if (*p->curp == '/' && p->curp[1] == '*')
{
int keep_line = mu_cfg_locus.line;
p->curp += 2;
do
{
while (*p->curp != '*')
{
if (*p->curp == 0)
{
mu_cfg_perror (p,
&mu_cfg_locus,
_("unexpected EOF in comment started at line %d"),
keep_line);
return 0;
}
else if (*p->curp == '\n')
mu_cfg_locus.line++;
++p->curp;
}
} while (*++p->curp != '/');
++p->curp;
goto again;
}
if (*p->curp == 0)
return 0;
if (*p->curp == '\"')
{
mu_cfg_yylval.string = copy_string (p);
return MU_CFG_STRING_TOKEN;
}
if (mu_cfg_tie_in)
{
mu_cfg_yylval.string = copy_alpha (p);
return MU_CFG_STRING_TOKEN;
}
if (*p->curp == '}')
{
p->curp++;
memset (&mu_cfg_yylval.node, 0, sizeof mu_cfg_yylval.node);
mu_cfg_yylval.node.locus = mu_cfg_locus;
return MU_CFG_END_TOKEN;
}
if (*p->curp == ';')
{
p->curp++;
return MU_CFG_EOL_TOKEN;
}
tag = copy_alpha (p);
skipws (p);
if (*p->curp == '"')
{
mu_cfg_yylval.string = tag;
return MU_CFG_STRING_TOKEN;
}
save_start = p->curp;
if (*p->curp != '{')
{
label = copy_alpha(p);
skipws(p);
}
else
label = NULL;
if (*p->curp == '{')
{
p->curp++;
mu_cfg_yylval.node.tag_name = tag;
mu_cfg_yylval.node.locus = mu_cfg_locus;
mu_cfg_yylval.node.tag_label = label;
return MU_CFG_START_TOKEN;
}
else
{
p->curp = save_start;
mu_cfg_yylval.string = tag;
}
return MU_CFG_STRING_TOKEN;
}
static struct mu_cfg_section *root_section;
int
mu_config_register_section (const char *parent_path,
const char *ident,
mu_cfg_section_fp parser,
void *data,
struct mu_cfg_param *param)
{
struct mu_cfg_section *parent;
size_t size = 0;
if (!root_section)
{
root_section = calloc (1, sizeof (root_section[0]));
if (!root_section)
return MU_ERR_NOENT;
}
if (parent_path)
{
if (mu_cfg_find_section (root_section, parent_path, &parent))
return MU_ERR_NOENT;
}
else
parent = root_section;
if (ident)
{
struct mu_cfg_section *s;
if (parent->subsec)
for (s = parent->subsec; s->ident; s++)
size++;
s = realloc (parent->subsec, (size + 2) * sizeof parent->subsec[0]);
if (!s)
return ENOMEM;
parent->subsec = s;
s = parent->subsec + size;
s[1].ident = NULL;
s->ident = strdup (ident);
s->parser = parser;
s->data = data;
s->subsec = NULL;
s->param = param;
}
else
{
size_t orig_size = 0;
struct mu_cfg_param *p;
if (parent->param)
for (p = parent->param; p->ident; p++)
orig_size++;
size = 0;
for (p = param; p->ident; p++)
size++;
parent->param = realloc (parent->param,
(size + orig_size + 1)
* sizeof (parent->param[0]));
memcpy (parent->param + orig_size, param,
size * sizeof (parent->param[0]));
if (!parent->parser)
parent->parser = parser;
if (!parent->data)
parent->data = data;
}
return 0;
}
int
mu_config_register_plain_section (const char *parent_path, const char *ident,
struct mu_cfg_param *params)
{
return mu_config_register_section (parent_path, ident, NULL, NULL, params);
}
static int
_mu_parse_config (char *file, char *progname)
{
struct lexer_data data;
struct stat st;
int fd;
extern int mu_cfg_yydebug;
int rc;
mu_cfg_node_t *parse_tree;
mu_cfg_locus.file = file;
mu_cfg_locus.line = 1;
if (stat (mu_cfg_locus.file, &st))
{
mu_error (_("can't stat `%s'"), mu_cfg_locus.file);
return -1;
}
fd = open (mu_cfg_locus.file, O_RDONLY);
if (fd == -1)
{
if (errno != ENOENT)
mu_error (_("can't open config file `%s'"),
mu_cfg_locus.file);
return -1;
}
data.buffer = malloc (st.st_size+1);
read (fd, data.buffer, st.st_size);
data.buffer[st.st_size] = 0;
close (fd);
data.curp = data.buffer;
mu_cfg_yydebug = strncmp (data.curp, "#debug", 6) == 0;
obstack_init (&data.stk);
/* Parse configuration */
rc = mu_cfg_parse (&parse_tree,
&data,
default_lexer,
NULL,
NULL,
NULL);
if (rc == 0)
{
rc = mu_cfg_scan_tree (parse_tree, root_section,
progname, NULL, NULL, NULL);
}
mu_cfg_destroy_tree (&parse_tree);
obstack_free (&data.stk, NULL);
free (data.buffer);
return rc;
}
int
mu_parse_config (char *file, char *progname)
{
int rc;
char *full_name = mu_tilde_expansion (file, "/", NULL);
if (full_name)
{
if (access (full_name, R_OK) == 0)
{
rc = _mu_parse_config (full_name, progname);
free (full_name);
}
else
rc = ENOENT;
}
else
rc = ENOMEM;
return rc;
}
/* A Bison parser, made by GNU Bison 2.3. */
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
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, 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., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum mu_cfg_yytokentype {
MU_CFG_EOL_TOKEN = 258,
MU_CFG_START_TOKEN = 259,
MU_CFG_END_TOKEN = 260,
MU_CFG_STRING_TOKEN = 261
};
#endif
/* Tokens. */
#define MU_CFG_EOL_TOKEN 258
#define MU_CFG_START_TOKEN 259
#define MU_CFG_END_TOKEN 260
#define MU_CFG_STRING_TOKEN 261
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
#line 115 "cfg_parser.y"
{
mu_cfg_node_t node;
mu_cfg_node_t *pnode;
struct
{
mu_cfg_node_t *head, *tail;
} nodelist;
char *string;
}
/* Line 1489 of yacc.c. */
#line 71 "cfg_parser.h"
YYSTYPE;
# define mu_cfg_yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE mu_cfg_yylval;
......@@ -241,8 +241,10 @@ mu_authenticate (struct mu_auth_data *auth_data, char *pass)
return mu_auth_runlist (mu_authenticate_list, NULL, auth_data, pass);
}
/* Modules & configuration */
/* ************************************************************************* */
/* Traditional configuration */
/* ************************************************************************* */
#define ARG_AUTHORIZATION 1
#define ARG_AUTHENTICATION 2
......@@ -252,22 +254,22 @@ static error_t mu_auth_argp_parser (int key, char *arg,
/* Options used by programs that use extended authentication mechanisms. */
static struct argp_option mu_auth_argp_option[] = {
{ "authentication", ARG_AUTHENTICATION, N_("MODLIST"), 0,
{ "authentication", ARG_AUTHENTICATION, N_("MODLIST"), OPTION_HIDDEN,
N_("Set the list of modules to be used for authentication"), 0 },
{ "authorization", ARG_AUTHORIZATION, N_("MODLIST"), 0,
{ "authorization", ARG_AUTHORIZATION, N_("MODLIST"), OPTION_HIDDEN,
N_("Set list of modules to be used for authorization"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
};
struct argp mu_auth_argp = {
static struct argp mu_auth_argp = {
mu_auth_argp_option,
mu_auth_argp_parser,
};
struct argp_child mu_auth_argp_child = {
static struct argp_child mu_auth_argp_child = {
&mu_auth_argp,
0,
"Authentication options",
NULL,
0
};
......@@ -296,6 +298,43 @@ mu_auth_argp_parser (int key, char *arg, struct argp_state *state)
}
/* ************************************************************************* */
/* Resource-style configuration */
/* ************************************************************************* */
static int
cb_authentication (mu_cfg_locus_t *locus, void *data, char *arg)
{
mu_authentication_add_module_list (arg);/*FIXME: error reporting*/
return 0;
}
static int
cb_authorization (mu_cfg_locus_t *locus, void *data, char *arg)
{
mu_authorization_add_module_list (arg);
return 0;
}
static struct mu_cfg_param mu_auth_param[] = {
{ "authentication", mu_cfg_callback, NULL, cb_authentication },
{ "authorization", mu_cfg_callback, NULL, cb_authorization },
{ NULL }
};
void
mu_auth_init ()
{
if (mu_register_capa ("auth", &mu_auth_argp_child, mu_auth_param))
{
mu_error (_("INTERNAL ERROR: cannot register argp capability auth (please report)"));
abort ();
}
}
/* ************************************************************************* */
struct _module_handler {
struct auth_stack_entry authenticate;
struct auth_stack_entry auth_by_name;
......@@ -343,6 +382,9 @@ mu_auth_register_module (struct mu_auth_module *mod)
cp->argp = NULL;
}
if (mod->cfg)
mu_config_register_plain_section (NULL, mod->name, mod->cfg);
if (!module_handler_list && mu_list_create (&module_handler_list))
abort ();
......
......@@ -138,6 +138,7 @@ mu_authenticate_system (struct mu_auth_data **return_data MU_ARG_UNUSED,
struct mu_auth_module mu_auth_system_module = {
"system",
NULL,
NULL,
mu_authenticate_system,
NULL,
mu_auth_system_by_name,
......@@ -150,6 +151,7 @@ struct mu_auth_module mu_auth_system_module = {
struct mu_auth_module mu_auth_generic_module = {
"generic",
NULL,
NULL,
mu_authenticate_generic,
NULL,
mu_auth_nosupport,
......