diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-10-08 17:36:05 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-10-08 17:36:05 +0300 |
commit | 9b56a5b05db6630a667ad0c9b16ec45a4e52044d (patch) | |
tree | eca8c25be90428656c24f76f68899c22d0091528 | |
parent | 04f58aaf7a6f27e3b79e8f5ccffeb006db56aeaf (diff) | |
download | eclat-9b56a5b05db6630a667ad0c9b16ec45a4e52044d.tar.gz eclat-9b56a5b05db6630a667ad0c9b16ec45a4e52044d.tar.bz2 |
Improve LDAP map.
* lib/expand.c: New file.
* lib/getans.c: New file.
* lib/Makefile.am: Add new files.
* lib/ldapmap.c (ldap_map) <passfile,prompt>: New members.
(ldapmap_kw) <passfile,prompt>: New keywords.
(ldap_map_open): Prompt for undefined credentials if the
"prompt" statement is set to true.
(ldap_map_get): Use eclat_expand_kw to expand the filter.
* lib/libeclat.h (eclat_trimnl,eclat_getans)
(eclat_expand_kw): New protos.
* lib/map.c (eclat_map_get): Use eclat_expand_kw.
* src/eclat.c (read_format): Likewise.
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/expand.c | 75 | ||||
-rw-r--r-- | lib/getans.c | 90 | ||||
-rw-r--r-- | lib/ldapmap.c | 106 | ||||
-rw-r--r-- | lib/libeclat.h | 4 | ||||
-rw-r--r-- | lib/map.c | 29 | ||||
-rw-r--r-- | src/eclat.c | 37 |
7 files changed, 277 insertions, 66 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index bdbab92..703eeda 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -32,11 +32,13 @@ maps = \ libeclat_a_SOURCES=\ base64.c\ diag.c\ + expand.c\ forlan.c\ forlan.h\ forlangrm.h\ forlangrm.y\ forlanlex.l\ + getans.c\ hmac_sha1.c\ libeclat.h\ map.c\ diff --git a/lib/expand.c b/lib/expand.c new file mode 100644 index 0000000..2db35e0 --- /dev/null +++ b/lib/expand.c @@ -0,0 +1,75 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat 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. + + Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include "wordsplit.h" +#include <sysexits.h> +#include <termios.h> +#include <unistd.h> +#include <pwd.h> + +char * +eclat_expand_kw(const char *input, const char **ukw) +{ + struct wordsplit ws; + char *ret; + static char **defkw; + static size_t defkwsize = 4; + const char **kw; + size_t kwsize; + int i; + + if (!defkw) { + uid_t uid = getuid(); + struct passwd *pw = getpwuid(uid); + if (!pw) + die(EX_UNAVAILABLE, + "cannot determine user name (uid=%lu)", + (unsigned long) uid); + defkw = grecs_calloc(defkwsize, sizeof(defkw[0])); + defkw[0] = "user"; + defkw[1] = grecs_strdup(pw->pw_name); + defkw[2] = "home"; + defkw[3] = grecs_strdup(pw->pw_dir); + } + + if (ukw) { + for (i = 0; ukw[i]; i++); + kwsize = defkwsize + i + 1; + } else + kwsize = defkwsize + 1; + kw = grecs_calloc(kwsize, sizeof(kw[0])); + i = 0; + if (ukw) + for (; ukw[i]; i++) + kw[i] = ukw[i]; + for (; i < defkwsize; i++) + kw[i] = defkw[i]; + kw[i] = NULL; + + ws.ws_env = kw; + ws.ws_error = err; + if (wordsplit(input, &ws, + WRDSF_NOSPLIT | WRDSF_NOCMD | + WRDSF_ENV | WRDSF_ENV_KV | WRDSF_WARNUNDEF | WRDSF_ERROR)) + die(EX_SOFTWARE, "error expanding pattern %s: %s", + input, wordsplit_strerror(&ws)); + free(kw); + ret = ws.ws_wordv[0]; + ws.ws_wordv[0] = NULL; + wordsplit_free(&ws); + return ret; +} diff --git a/lib/getans.c b/lib/getans.c new file mode 100644 index 0000000..77a7fbe --- /dev/null +++ b/lib/getans.c @@ -0,0 +1,90 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat 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. + + Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <termios.h> +#include <signal.h> +#include <sysexits.h> +#include <errno.h> +#include <string.h> + +void +eclat_trimnl(char *s) +{ + size_t len = strlen(s); + while (len > 0 && s[len-1] == '\n') + --len; + s[len] = 0; +} + +#ifndef TCSASOFT +# define TCSASOFT 0 +#endif +char * +eclat_getans(char *prompt, char *dfl, int pass) +{ + char *buf = NULL; + size_t size = 0; + struct termios t, tsave; + int rc; + int fd = fileno(stdin); + sigset_t oldset; + + fprintf(stdout, "%s", prompt); + if (dfl) + fprintf(stdout, " [%s]", dfl); + fprintf(stdout, ": "); + fflush(stdout); + + if (pass) { + sigset_t set; + static int signum[] = { + SIGHUP, SIGINT, SIGQUIT, SIGABRT, SIGPIPE, + SIGALRM, SIGTERM + }; + int i; + + if (tcgetattr(fd, &t)) + die(EX_SOFTWARE, "cannot query console attributes: %s", + strerror(errno)); + tsave = t; + t.c_lflag &= ~(ECHO | ISIG); + if (tcsetattr(fd, TCSAFLUSH | TCSASOFT, &t)) + die(EX_SOFTWARE, "cannot turn echo off; %s", + strerror(errno)); + sigemptyset(&set); + for (i = 0; i < sizeof(signum)/sizeof(signum[0]); i++) + sigaddset(&set, signum[i]); + sigprocmask(SIG_BLOCK, &set, &oldset); + } + rc = grecs_getline(&buf, &size, stdin); + if (pass) { + if (tcsetattr(fd, TCSAFLUSH | TCSASOFT, &tsave)) + die(EX_SOFTWARE, "failed to restore echo state: %s", + strerror(errno)); + sigprocmask(SIG_SETMASK, &oldset, NULL); + } + if (rc <= 0) { + free(buf); + return NULL; + } + eclat_trimnl(buf); + if (buf[0] == 0 && dfl) { + free(buf); + buf = grecs_strdup(dfl); + } + return buf; +} diff --git a/lib/ldapmap.c b/lib/ldapmap.c index 5829f67..8d687e4 100644 --- a/lib/ldapmap.c +++ b/lib/ldapmap.c @@ -19,6 +19,8 @@ #include <ldap.h> #include <errno.h> #include <sysexits.h> +#include <signal.h> +#include <pwd.h> enum { tls_no, tls_yes, tls_only }; @@ -28,7 +30,9 @@ struct ldap_map { char *base; char *binddn; char *bindpw; + char *passfile; int tls; + int prompt; char *filter; char *attr; int dbg; @@ -96,6 +100,10 @@ static struct grecs_keyword ldapmap_kw[] = { "Set bind password", grecs_type_string, GRECS_DFLT, NULL, offsetof(struct ldap_map, bindpw) }, + { "passfile", "filename", + "Read bind password from <filename>", + grecs_type_string, GRECS_DFLT, + NULL, offsetof(struct ldap_map, passfile) }, { "tls", "arg", "TLS mode", grecs_type_string, GRECS_DFLT, @@ -116,6 +124,10 @@ static struct grecs_keyword ldapmap_kw[] = { "LDAP version to use", grecs_type_int, GRECS_DFLT, NULL, offsetof(struct ldap_map, ldap_version) }, + { "prompt", NULL, + "Prompt for missing credentials", + grecs_type_bool, GRECS_DFLT, + NULL, offsetof(struct ldap_map, prompt) }, { NULL } }; @@ -171,6 +183,7 @@ ldap_map_free(int dbg, void *data) free(data); } + static void ldap_unbind(LDAP *ld); @@ -367,7 +380,7 @@ ldap_bind(int dbg, struct ldap_map *map) return 1; } - if (ldap_result(map->ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1) { + if (ldap_result(map->ld, msgid, LDAP_MSG_ALL, NULL, &result) == -1) { err("ldap_result failed"); return 1; } @@ -389,7 +402,7 @@ ldap_bind(int dbg, struct ldap_map *map) || refs) { /* FIXME: Use debug output for that */ debug(dbg, 2, ("ldap_bind: %s (%d)%s", - ldap_err2string(ec), ec, msgbuf)); + ldap_err2string(ec), ec, msgbuf)); if (matched && *matched) debug(dbg, 2, ("matched DN: %s", matched)); @@ -428,7 +441,63 @@ static int ldap_map_open(int dbg, void *data) { struct ldap_map *map = data; + char *user = NULL, *p; + uid_t uid = getuid(); + int i = 0; + struct passwd *pw; + const char *kw[3]; + + pw = getpwuid(uid); + if (!pw) + die(EX_UNAVAILABLE, + "cannot determine user name (uid=%lu)", + (unsigned long) uid); + + user = grecs_strdup(pw->pw_name); + + kw[0] = NULL; + + if (map->prompt && isatty(0)) { + p = eclat_getans("User name", user, 0); + free(user); + user = p; + if (map->binddn) { + kw[0] = "user"; + kw[1] = user; + kw[2] = NULL; + p = eclat_expand_kw(map->binddn, kw); + } else + p = grecs_strdup(user); + free(map->binddn); + map->binddn = p; + } + + if (map->passfile) { + char *filename = eclat_expand_kw(map->passfile, kw); + FILE *fp = fopen(filename, "r"); + if (!fp) + err("cannot open password file %s: %s", + filename, strerror(errno)); + else { + char *buf = NULL; + size_t size = 0; + int rc = grecs_getline(&buf, &size, fp); + + if (rc <= 0) + err("error reading password file %s: %s", + filename, + rc == 0 ? "empty file?" : strerror(errno)); + else + map->bindpw = buf; + } + fclose(fp); + free(filename); + } + if (!map->bindpw && map->prompt && isatty(0)) + map->bindpw = eclat_getans("User password", NULL, 1); + free(user); + map->ld = ldap_connect(dbg, map); if (!map->ld) return eclat_map_failure; @@ -445,15 +514,6 @@ ldap_map_close(int dbg, void *data) return 0; } -static void -trimnl(char *s) -{ - size_t len = strlen(s); - while (len > 0 && s[len-1] == '\n') - --len; - s[len] = 0; -} - static int keycmp(const void *a, const void *b) { @@ -489,7 +549,7 @@ get_ldap_attrs(LDAP *ld, LDAPMessage *msg, const char *attr) char *p = grecs_malloc(values[i]->bv_len + 1); memcpy(p, values[i]->bv_val, values[i]->bv_len); p[values[i]->bv_len] = 0; - trimnl(p); + eclat_trimnl(p); ret[i] = p; } @@ -516,27 +576,21 @@ ldap_map_get(int dbg, void *data, const char *key, char **return_value) ber_int_t msgid; char *attrs[2]; char **ret; - const char *kve[3]; + const char *kwe[3]; struct wordsplit ws; - - kve[0] = "key"; - kve[1] = key; - kve[2] = NULL; - - ws.ws_env = kve; + char *filter; - if (wordsplit(map->filter, &ws, - WRDSF_NOSPLIT | WRDSF_NOCMD | - WRDSF_ENV | WRDSF_ENV_KV)) - die(EX_SOFTWARE, "error expanding filter: %s", - wordsplit_strerror(&ws)); + kwe[0] = "key"; + kwe[1] = key; + kwe[2] = NULL; + filter = eclat_expand_kw(map->filter, kwe); attrs[0] = (char*) map->attr; attrs[1] = NULL; rc = ldap_search_ext(map->ld, map->base, LDAP_SCOPE_SUBTREE, - ws.ws_wordv[0], attrs, 0, + filter, attrs, 0, NULL, NULL, NULL, -1, &msgid); - wordsplit_free(&ws); + free(filter); if (rc != LDAP_SUCCESS) { err("ldap_search_ext: %s", ldap_err2string(rc)); diff --git a/lib/libeclat.h b/lib/libeclat.h index 2f4c32c..2b40f43 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -101,6 +101,10 @@ void eclat_partial_tree_data_handler(void *data, const XML_Char *s, int len); void eclat_partial_tree_start_handler(void *data, const XML_Char *name, const XML_Char **atts); void eclat_partial_tree_end_handler(void *data, const XML_Char *name); + +void eclat_trimnl(char *s); +char *eclat_expand_kw(const char *input, const char **ukw); +char *eclat_getans(char *prompt, char *dfl, int pass); #define ECLAT_MAP_OPEN 0x01 @@ -242,7 +242,7 @@ int eclat_map_get(struct eclat_map *map, const char *key, char **value) { int rc; - struct wordsplit ws; + char *p = NULL; debug(map_dbg, 1, ("looking up \"%s\" in map \"%s\"", key, map->name)); @@ -252,30 +252,23 @@ eclat_map_get(struct eclat_map *map, const char *key, char **value) } if (map->keytrans) { - const char *kve[5]; - kve[0] = "key"; - kve[1] = key; - kve[2] = "map"; - kve[3] = map->name; - kve[4] = NULL; - - ws.ws_env = kve; + const char *kwe[5]; + kwe[0] = "key"; + kwe[1] = key; + kwe[2] = "map"; + kwe[3] = map->name; + kwe[4] = NULL; - if (wordsplit(map->keytrans, &ws, - WRDSF_NOSPLIT | WRDSF_NOCMD | - WRDSF_ENV | WRDSF_ENV_KV)) - die(EX_SOFTWARE, "error transforming key: %s", - wordsplit_strerror(&ws)); + p = eclat_expand_kw(map->keytrans, kwe); debug(map_dbg, 1, ("transformed key \"%s\" => \"%s\"", - key, ws.ws_wordv[0])); - key = ws.ws_wordv[0]; + key, p)); + key = p; } rc = map->drv->map_get(map_dbg, map->data, key, value); - if (map->keytrans) - wordsplit_free(&ws); + free(p); debug(map_dbg, 1, ("result: \"%s\"", eclat_map_strerror(rc))); if (rc == eclat_map_ok) diff --git a/src/eclat.c b/src/eclat.c index ab3375a..64119fd 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -527,46 +527,39 @@ read_format(struct command *cmd) env = forlan_parse_buffer(cmd->fmt, strlen(cmd->fmt), &cmd->locus.beg); else if (format_file) { - struct wordsplit ws; - const char *kve[5]; + const char *kwe[5]; struct grecs_locus_point pt; FILE *fp; + char *filename; - kve[0] = "command"; - kve[1] = cmd->ident; - kve[2] = "action"; - kve[3] = cmd->tag; - kve[4] = NULL; - - ws.ws_env = kve; - if (wordsplit(format_file, &ws, - WRDSF_NOSPLIT | WRDSF_NOCMD | - WRDSF_ENV | WRDSF_ENV_KV)) - die(EX_SOFTWARE, - "error expanding format-file: %s", - wordsplit_strerror(&ws)); - - fp = fopen(ws.ws_wordv[0], "r"); + kwe[0] = "command"; + kwe[1] = cmd->ident; + kwe[2] = "action"; + kwe[3] = cmd->tag; + kwe[4] = NULL; + + filename = eclat_expand_kw(format_file, kwe); + fp = fopen(filename, "r"); if (!fp) { if (errno == ENOENT) { debug(ECLAT_DEBCAT_MAIN, 1, ("cannot open format source \"%s\": %s", - ws.ws_wordv[0], strerror(errno))); - wordsplit_free(&ws); + filename, strerror(errno))); + free(filename); return NULL; } die(EX_UNAVAILABLE, "cannot open format file %s: %s", - ws.ws_wordv[0], strerror(errno)); + filename, strerror(errno)); } - pt.file = ws.ws_wordv[0]; + pt.file = filename; pt.line = 1; pt.col = 0; env = forlan_parse_file(fp, &pt); fclose(fp); - wordsplit_free(&ws); + free(filename); } else return NULL; |