diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-07-24 12:12:33 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-07-24 12:12:33 +0300 |
commit | eb7f98862dbe400f801de9f47f379fbed428f0f3 (patch) | |
tree | 745737c82c70bf13e80f92c384e12c68ee6079e2 /dico | |
parent | 38e0c8ac1be999f5303b7f7cc690f9a2a76f0414 (diff) | |
download | dico-eb7f98862dbe400f801de9f47f379fbed428f0f3.tar.gz dico-eb7f98862dbe400f801de9f47f379fbed428f0f3.tar.bz2 |
Finish SASL support.
* dico/autologin.c (parse_autologin): Support for new
keywords: realm, service and host.
* dico/cmdline.opt: New options --sasl, --nosasl.
* dico/connect.c (dict_auth): Rewrite authention to avoid dependency from
"auth" capability.
(auth_cred_free): Free new auth_cred members.
(get_credentials): Rename to auth_cred_get, make global.
* dico/dico-priv.h (struct auth_cred): New fields service, realm and
hostname.
(GETCRED_OK, GETCRED_FAIL, GETCRED_NOAUTH): New defines.
(auth_cred_get, auth_cred_free): New prototypes.
(set_bool): Change return type to int.
(ds_sasl): New prototype.
(saslauth): Change signature.
* dico/func.c (set_bool): Change return type to int.
(ds_sasl): New function.
* dico/saslauth.c (callback): Use new auth_cred members.
(saslauth): Rename to saslauth0.
(saslauth, sasl_enable, sasl_enabled_p): New functions.
* dico/shell.c: Add `sasl' command.
* dicod/main.c (get_full_hostname): Moved to libxdico.
* include/xdico.h (xdico_local_hostname): New prototype.
* lib/Makefile.am (libxdico_a_SOURCES): Add xhostname.c.
Diffstat (limited to 'dico')
-rw-r--r-- | dico/autologin.c | 167 | ||||
-rw-r--r-- | dico/cmdline.opt | 12 | ||||
-rw-r--r-- | dico/connect.c | 73 | ||||
-rw-r--r-- | dico/dico-priv.h | 17 | ||||
-rw-r--r-- | dico/func.c | 45 | ||||
-rw-r--r-- | dico/saslauth.c | 70 | ||||
-rw-r--r-- | dico/shell.c | 12 |
7 files changed, 284 insertions, 112 deletions
diff --git a/dico/autologin.c b/dico/autologin.c index ca4dafd..232589f 100644 --- a/dico/autologin.c +++ b/dico/autologin.c @@ -88,6 +88,47 @@ argv_expand(int *pargc, char ***pargv, int xargc, char **xargv) *pargv = nargv; } +enum kw_tok { + kw_login, + kw_password, + kw_noauth, + kw_nosasl, + kw_sasl, + kw_mechanism, + kw_realm, + kw_service, + kw_host +}; + +struct keyword { + char *name; + int arg; + enum kw_tok tok; +}; + +static struct keyword kwtab[] = { + { "login", 1, kw_login }, + { "password", 1, kw_password }, + { "noauth", 0, kw_noauth }, + { "nosasl", 0, kw_nosasl }, + { "sasl", 0, kw_sasl }, + { "mechanism", 1, kw_mechanism }, + { "realm", 1, kw_realm }, + { "service", 1, kw_service }, + { "host", 1, kw_host }, + { NULL } +}; + +static struct keyword * +findkw(const char *name) +{ + struct keyword *p; + for (p = kwtab; p->name; p++) + if (strcmp(p->name, name) == 0) + return p; + return NULL; +} + /* Parse netrc-like autologin file and set up user and key accordingly. */ int parse_autologin(const char *filename, char *host, struct auth_cred *pcred, @@ -192,68 +233,90 @@ parse_autologin(const char *filename, char *host, struct auth_cred *pcred, if (p_argv) { line = def_line; + pcred->sasl = sasl_enabled_p(); while (*p_argv) { if (strcmp(*p_argv, "\n") == 0) { line++; p_argv++; - } if (strcmp(*p_argv, "login") == 0) { - if (!p_argv[1]) { + } else { + struct keyword *kw = findkw(*p_argv); + char *arg; + + if (!kw) { dico_log(L_ERR, 0, - _("%s:%d: %s without argument"), - filename, line, p_argv[0]); - break; + _("%s:%d: unknown keyword"), filename, line); + p_argv++; + continue; } - pcred->user = xstrdup(p_argv[1]); - p_argv += 2; - flags |= AUTOLOGIN_USERNAME; - } else if (strcmp(*p_argv, "password") == 0) { - if (!p_argv[1]) { - dico_log(L_ERR, 0, - _("%s:%d: %s without argument"), - filename, line, p_argv[0]); + + if (kw->arg) { + if (!p_argv[1]) { + dico_log(L_ERR, 0, + _("%s:%d: %s without argument"), + filename, line, p_argv[0]); + break; + } + arg = p_argv[1]; + p_argv += 2; + } else + p_argv++; + + switch (kw->tok) { + case kw_login: + pcred->user = xstrdup(arg); + flags |= AUTOLOGIN_USERNAME; break; - } - pcred->pass = xstrdup(p_argv[1]); - flags |= AUTOLOGIN_PASSWORD; - p_argv += 2; - } else if (strcmp(*p_argv, "noauth") == 0) { - flags |= AUTOLOGIN_NOAUTH; - p_argv++; - } else if (strcmp(*p_argv, "nosasl") == 0) { - pcred->sasl = 0; - p_argv++; - } else if (strcmp(*p_argv, "sasl") == 0) { - pcred->sasl = 1; - p_argv++; - } else if (strcmp(*p_argv, "mechanism") == 0) { - int i, c; - char **v; + + case kw_password: + pcred->pass = xstrdup(arg); + flags |= AUTOLOGIN_PASSWORD; + break; + + case kw_service: + pcred->service = xstrdup(arg); + break; + + case kw_realm: + pcred->realm = xstrdup(arg); + break; + + case kw_host: + pcred->hostname = xstrdup(arg); + break; + + case kw_noauth: + flags |= AUTOLOGIN_NOAUTH; + break; + + case kw_nosasl: + pcred->sasl = 0; + break; + + case kw_sasl: + pcred->sasl = 1; + break; + + case kw_mechanism: { + int i, c; + char **v; - if (!p_argv[1]) { - dico_log(L_ERR, 0, - _("%s:%d: %s without argument"), - filename, line, p_argv[0]); + if (!(flags & AUTOLOGIN_MECH)) { + pcred->mech = xdico_list_create(); + flags |= AUTOLOGIN_MECH; + } + if (dico_argcv_get(arg, ",", NULL, &c, &v)) { + dico_log(L_ERR, 0, + _("%s:%d: not enough memory"), + filename, line); + exit(1); + } + for (i = 0; i < c; i++) + xdico_list_append(pcred->mech, v[i]); + + free(v); break; + } } - if (!(flags & AUTOLOGIN_MECH)) { - pcred->mech = xdico_list_create(); - flags |= AUTOLOGIN_MECH; - } - if (dico_argcv_get(p_argv[1], ",", NULL, &c, &v)) { - dico_log(L_ERR, 0, - _("%s:%d: not enough memory"), - filename, line); - exit(1); - } - for (i = 0; i < c; i++) - xdico_list_append(pcred->mech, v[i]); - - free(v); - p_argv += 2; - } else { - dico_log(L_ERR, 0, - _("%s:%d: unknown keyword"), filename, line); - p_argv++; } } } diff --git a/dico/cmdline.opt b/dico/cmdline.opt index fa2b48f..dfbc135 100644 --- a/dico/cmdline.opt +++ b/dico/cmdline.opt @@ -123,6 +123,18 @@ BEGIN noauth_option = 1; END +OPTION(sasl,, + [<Enable SASL authentication (default).>]) +BEGIN + sasl_enable(1); +END + +OPTION(nosasl,, + [<Disable SASL authentication.>]) +BEGIN + sasl_enable(0); +END + OPTION(user,u,NAME, [<Set user name for authentication.>]) BEGIN diff --git a/dico/connect.c b/dico/connect.c index 1b9c12d..0370d40 100644 --- a/dico/connect.c +++ b/dico/connect.c @@ -93,16 +93,35 @@ apop_auth(struct dict_connection *conn, struct auth_cred *cred) } static int -dict_auth(struct dict_connection *conn, struct auth_cred *cred) +dict_auth(struct dict_connection *conn, dico_url_t url) { - int rc = saslauth(conn, cred);/*FIXME: ignored */ + int rc = saslauth(conn, url); + switch (rc) { case AUTH_OK: return 0; case AUTH_CONT: - return apop_auth(conn, cred); + if (dict_capa(conn, "auth")) { + struct auth_cred cred; + + switch (auth_cred_get(url->host, &cred)) { + case GETCRED_OK: + rc = apop_auth(conn, &cred); + auth_cred_free(&cred); + return rc; + + case GETCRED_FAIL: + dico_log(L_WARN, 0, + _("Not enough credentials for authentication")); + break; + case GETCRED_NOAUTH: + break; + } + } + return 0; + case AUTH_FAIL: return 1; } @@ -161,19 +180,26 @@ auth_cred_dup(struct auth_cred *dst, const struct auth_cred *src) dst->pass = src->pass ? xstrdup(src->pass) : NULL; } -static void +static int +_cred_free(void *item, void *data) +{ + free(item); + return 0; +} + +void auth_cred_free(struct auth_cred *cred) { free(cred->user); free(cred->pass); + dico_list_destroy(&cred->mech, _cred_free, NULL); + free(cred->service); + free(cred->realm); + free(cred->hostname); } -#define GETCRED_OK 0 -#define GETCRED_FAIL 1 -#define GETCRED_NOAUTH 2 - -static int -get_credentials(char *host, struct auth_cred *cred) +int +auth_cred_get(char *host, struct auth_cred *cred) { memset(cred, 0, sizeof(cred[0])); auth_cred_dup(cred, &default_cred); @@ -316,29 +342,10 @@ dict_connect(struct dict_connection **pconn, dico_url_t url) obstack_init(&conn->stk); - if (!noauth_option && dict_capa(conn, "auth")) { - struct auth_cred cred; - int rc; - - switch (get_credentials(url->host, &cred)) { - case GETCRED_OK: - rc = dict_auth(conn, &cred); - auth_cred_free(&cred); - if (rc) { - dico_log(L_ERR, 0, _("Authentication failed")); - dict_conn_close(conn); - return 1; - } - break; - - case GETCRED_FAIL: - dico_log(L_WARN, 0, - _("Not enough credentials for authentication")); - break; - - case GETCRED_NOAUTH: - break; - } + if (!noauth_option && dict_auth(conn, url)) { + dico_log(L_ERR, 0, _("Authentication failed")); + dict_conn_close(conn); + return 1; } *pconn = conn; diff --git a/dico/dico-priv.h b/dico/dico-priv.h index 2ed23dc..e9104b8 100644 --- a/dico/dico-priv.h +++ b/dico/dico-priv.h @@ -117,6 +117,9 @@ struct auth_cred { char *pass; int sasl; dico_list_t mech; + char *service; + char *realm; + char *hostname; }; struct funtab { @@ -164,6 +167,13 @@ int dict_match(struct dict_connection *conn, char *database, char *strategy, char *get_homedir(void); int ds_tilde_expand(const char *str, char **output); +#define GETCRED_OK 0 +#define GETCRED_FAIL 1 +#define GETCRED_NOAUTH 2 + +int auth_cred_get(char *host, struct auth_cred *cred); +void auth_cred_free(struct auth_cred *cred); + /* lookup.c */ int dict_lookup_url(dico_url_t url); int dict_word(char *word); @@ -195,7 +205,7 @@ char **dict_completion_matches(int argc, char **argv, int ws, /* func.c */ int ensure_connection(void); -void set_bool(int *pval, char *str); +int set_bool(int *pval, char *str); void ds_silent_close(void); void ds_open(int argc, char **argv); void ds_close(int argc, char **argv); @@ -212,6 +222,7 @@ void ds_warranty(int argc, char **argv); void ds_show_db(int argc, char **argv); void ds_show_strat(int argc, char **argv); void ds_show_info(int argc, char **argv); +void ds_sasl(int argc, char **argv); char **ds_compl_database(int argc, char **argv, int ws); char **ds_compl_strategy(int argc, char **argv, int ws); @@ -225,4 +236,6 @@ dico_stream_t create_pager_stream(size_t nlines); #define AUTH_FAIL 1 #define AUTH_CONT 2 -int saslauth(struct dict_connection *conn, struct auth_cred *cred); +int saslauth(struct dict_connection *conn, dico_url_t url); +void sasl_enable(int val); +int sasl_enabled_p(void); diff --git a/dico/func.c b/dico/func.c index 1dbc9d6..e9bcb56 100644 --- a/dico/func.c +++ b/dico/func.c @@ -18,6 +18,24 @@ static struct dict_connection *conn; +int +set_bool(int *pval, char *str) +{ + if (strcmp(str, "yes") == 0 + || strcmp(str, "on") == 0 + || strcmp(str, "true") == 0) + *pval = 1; + else if (strcmp(str, "no") == 0 + || strcmp(str, "off") == 0 + || strcmp(str, "false") == 0) + *pval = 0; + else { + script_error(_("Expected boolean value")); + return 1; + } + return 0; +} + void ds_silent_close() { @@ -149,6 +167,18 @@ ds_autologin(int argc, char **argv) } void +ds_sasl(int argc, char **argv) +{ + if (argc == 1) { + printf("%s\n", sasl_enabled_p() ? _("on") : _("off")); + } else { + int val; + if (set_bool(&val, argv[1]) == 0) + sasl_enable(val); + } +} + +void ds_database(int argc, char **argv) { if (argc == 1) { @@ -213,21 +243,6 @@ ds_compl_strategy(int argc, char **argv, int ws) void -set_bool(int *pval, char *str) -{ - if (strcmp(str, "yes") == 0 - || strcmp(str, "on") == 0 - || strcmp(str, "true") == 0) - *pval = 1; - else if (strcmp(str, "no") == 0 - || strcmp(str, "off") == 0 - || strcmp(str, "false") == 0) - *pval = 0; - else - script_error(_("Expected boolean value")); -} - -void ds_transcript(int argc, char **argv) { if (argc == 1) diff --git a/dico/saslauth.c b/dico/saslauth.c index 9ac4979..c2a9675 100644 --- a/dico/saslauth.c +++ b/dico/saslauth.c @@ -105,12 +105,15 @@ selectmech(struct dict_connection *conn, Gsasl *ctx, struct auth_cred *cred) return mech; } +#define CRED_HOSTNAME(c) ((c)->hostname ? (c)->hostname : \ + ((c)->hostname = xdico_local_hostname())) + static int callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop) { int rc = GSASL_NO_CALLBACK; struct auth_cred *cred = gsasl_callback_hook_get(ctx); -#define hostname "Trurl.gnu.org.ua" + switch (prop) { case GSASL_PASSWORD: gsasl_property_set(sctx, prop, cred->pass); @@ -124,17 +127,19 @@ callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop) break; case GSASL_SERVICE: - gsasl_property_set(sctx, prop, "dico");//FIXME: configurable + gsasl_property_set(sctx, prop, + cred->service ? cred->service : "dico"); rc = GSASL_OK; break; case GSASL_REALM: - gsasl_property_set(sctx, prop, hostname); + gsasl_property_set(sctx, prop, + cred->realm ? cred->realm : CRED_HOSTNAME(cred)); rc = GSASL_OK; break; case GSASL_HOSTNAME: - gsasl_property_set(sctx, prop, hostname); + gsasl_property_set(sctx, prop, CRED_HOSTNAME(cred)); rc = GSASL_OK; break; @@ -234,7 +239,7 @@ do_gsasl_auth(Gsasl *ctx, struct dict_connection *conn, char *mech) } int -saslauth(struct dict_connection *conn, struct auth_cred *cred) +saslauth0(struct dict_connection *conn, struct auth_cred *cred) { Gsasl *ctx; int rc; @@ -263,10 +268,63 @@ saslauth(struct dict_connection *conn, struct auth_cred *cred) /* FIXME */ return rc == 0 ? AUTH_OK : AUTH_FAIL; } + +int +saslauth(struct dict_connection *conn, dico_url_t url) +{ + int rc = AUTH_FAIL; + struct auth_cred cred; + + switch (auth_cred_get(url->host, &cred)) { + case GETCRED_OK: + if (cred.sasl) { + rc = saslauth0(conn, &cred); + auth_cred_free(&cred); + } else + rc = AUTH_CONT; + break; + + case GETCRED_FAIL: + dico_log(L_WARN, 0, + _("Not enough credentials for authentication")); + break; + + case GETCRED_NOAUTH: + rc = AUTH_OK; + } + return rc; +} + +static int sasl_enable_state = 1; + +void +sasl_enable(int val) +{ + sasl_enable_state = 1; +} + +int +sasl_enabled_p() +{ + return sasl_enable_state; +} + #else int -saslauth(struct dict_connection *conn, struct auth_cred *cred) +saslauth(struct dict_connection *conn, dico_url_t url) { return AUTH_CONT; } + +void +sasl_enable(int val) +{ + dico_log(L_WARN, 0, _("Dico compiled without SASL support")); +} + +int +sasl_enabled_p() +{ + return 0; +} #endif diff --git a/dico/shell.c b/dico/shell.c index d7afc27..828503c 100644 --- a/dico/shell.c +++ b/dico/shell.c @@ -49,10 +49,6 @@ struct funtab funtab[] = { NULL, N_("Close the connection."), ds_close, }, - { "autologin", 1, 2, - N_("[FILE]"), - N_("Set or display autologin file name."), - ds_autologin,}, { "database", 1, 2, N_("[NAME]"), N_("Set or display current database name."), @@ -93,6 +89,14 @@ struct funtab funtab[] = { N_("STRING"), N_("Change or display pager settings."), ds_pager, no_compl }, + { "autologin", 1, 2, + N_("[FILE]"), + N_("Set or display autologin file name."), + ds_autologin,}, + { "sasl", 1, 2, + N_("[BOOL]"), + N_("Enable SASL authentication."), + ds_sasl, no_compl }, #ifdef WITH_READLINE { "history", 1, 1, NULL, |