summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2012-10-08 14:36:05 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2012-10-08 14:36:05 (GMT)
commit9b56a5b05db6630a667ad0c9b16ec45a4e52044d (patch) (side-by-side diff)
treeeca8c25be90428656c24f76f68899c22d0091528
parent04f58aaf7a6f27e3b79e8f5ccffeb006db56aeaf (diff)
downloadeclat-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.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/expand.c75
-rw-r--r--lib/getans.c90
-rw-r--r--lib/ldapmap.c106
-rw-r--r--lib/libeclat.h4
-rw-r--r--lib/map.c29
-rw-r--r--src/eclat.c37
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
--- a/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
--- a/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
diff --git a/lib/map.c b/lib/map.c
index 5a8d2fd..c8acfee 100644
--- a/lib/map.c
+++ b/lib/map.c
@@ -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;

Return to:

Send suggestions and report system problems to the System administrator.