6
Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
25
#include "util/util.h"
26
#include "confdb/confdb.h"
27
#include "confdb/confdb_private.h"
28
#include "util/btreemap.h"
31
#define CONFDB_DOMAINS_PATH "config/domains"
32
#define CONFDB_DOMAIN_BASEDN "cn=domains,cn=config"
33
#define CONFDB_DOMAIN_ATTR "cn"
34
#define CONFDB_MPG "magicPrivateGroups"
35
#define CONFDB_FQ "useFullyQualifiedNames"
37
#define CONFDB_ZERO_CHECK_OR_JUMP(var, ret, err, label) do { \
44
static char *prepend_cn(char *str, int *slen, const char *comp, int clen)
48
ret = talloc_realloc(NULL, str, char, *slen + 4 + clen + 1);
52
/* move current string to the end */
53
memmove(&ret[clen +4], ret, *slen+1); /* includes termination */
54
memcpy(ret, "cn=", 3);
55
memcpy(&ret[3], comp, clen);
58
*slen = *slen + 4 + clen;
63
int parse_section(TALLOC_CTX *mem_ctx, const char *section,
64
char **sec_dn, const char **rdn_name)
72
/* section must be a non null string and must not start with '/' */
73
if (!section || !*section || *section == '/') return EINVAL;
75
tmp_ctx = talloc_new(mem_ctx);
76
if (!tmp_ctx) return ENOMEM;
80
while ((p = strchrnul(s, '/'))) {
82
dn = talloc_asprintf(tmp_ctx, "cn=%s", s);
86
dn = prepend_cn(dn, &l, s, p-s);
93
if (rdn_name) *rdn_name = s;
94
break; /* reached end */
97
if (*s == '\0') { /* a section cannot end in '.' */
103
*sec_dn = talloc_steal(mem_ctx, dn);
107
talloc_free(tmp_ctx);
111
/* split a string into an allocated array of strings.
112
* the separator is a string, and is case-sensitive.
113
* optionally single values can be trimmed of of spaces and tabs */
114
static int split_on_separator(TALLOC_CTX *mem_ctx, const char *str,
115
const char *sep, bool trim, char ***_list, int *size)
117
const char *t, *p, *n;
121
if (!str || !*str || !sep || !*sep || !_list) return EINVAL;
130
while (*t == ' ' || *t == '\t') t++;
132
while (t && (p = strstr(t, sep))) {
134
n = p + s; /* save next string starting point */
136
while (*t == ' ' || *t == '\t') {
142
while (len > 0 && (*p == ' ' || *p == '\t')) {
148
r = talloc_realloc(mem_ctx, list, char *, l + 2);
157
list[l] = talloc_strdup(list, "");
159
list[l] = talloc_strndup(list, t, len);
167
t = n; /* move to next string */
171
r = talloc_realloc(mem_ctx, list, char *, l + 2);
181
while (*t == ' ' || *t == '\t') {
187
while (len > 0 && (*p == ' ' || *p == '\t')) {
193
list[l] = talloc_strdup(list, "");
195
list[l] = talloc_strndup(list, t, len);
198
list[l] = talloc_strdup(list, t);
207
list[l] = NULL; /* terminate list */
209
if (size) *size = l + 1;
215
int confdb_add_param(struct confdb_ctx *cdb,
218
const char *attribute,
221
TALLOC_CTX *tmp_ctx = NULL;
222
struct ldb_message *msg;
223
struct ldb_result *res;
226
const char *rdn_name;
229
tmp_ctx = talloc_new(NULL);
235
ret = parse_section(tmp_ctx, section, &secdn, &rdn_name);
240
dn = ldb_dn_new(tmp_ctx, cdb->ldb, secdn);
241
CONFDB_ZERO_CHECK_OR_JUMP(dn, ret, EIO, done);
243
ret = ldb_search(cdb->ldb, tmp_ctx, &res,
244
dn, LDB_SCOPE_BASE, NULL, NULL);
245
if (ret != LDB_SUCCESS) {
250
msg = ldb_msg_new(tmp_ctx);
251
CONFDB_ZERO_CHECK_OR_JUMP(msg, ret, ENOMEM, done);
253
msg->dn = talloc_steal(msg, dn);
254
CONFDB_ZERO_CHECK_OR_JUMP(msg->dn, ret, ENOMEM, done);
256
if (res->count == 0) { /* add a new message */
260
ret = ldb_msg_add_string(msg, "cn", rdn_name);
261
if (ret != LDB_SUCCESS) {
262
if (errno) ret = errno;
267
/* now the requested attribute */
268
for (i = 0; values[i]; i++) {
269
ret = ldb_msg_add_string(msg, attribute, values[i]);
270
if (ret != LDB_SUCCESS) {
271
if (errno) ret = errno;
277
ret = ldb_add(cdb->ldb, msg);
278
if (ret != LDB_SUCCESS) {
287
/* mark this as a replacement */
288
if (replace) optype = LDB_FLAG_MOD_REPLACE;
289
else optype = LDB_FLAG_MOD_ADD;
290
ret = ldb_msg_add_empty(msg, attribute, optype, NULL);
291
if (ret != LDB_SUCCESS) {
292
if (errno) ret = errno;
297
/* now the requested attribute */
298
for (i = 0; values[i]; i++) {
299
ret = ldb_msg_add_string(msg, attribute, values[i]);
300
if (ret != LDB_SUCCESS) {
301
if (errno) ret = errno;
307
ret = ldb_modify(cdb->ldb, msg);
308
if (ret != LDB_SUCCESS) {
317
talloc_free(tmp_ctx);
319
DEBUG(1, ("Failed to add [%s] to [%s], error [%d] (%s)",
320
attribute, section, ret, strerror(ret)));
325
int confdb_get_param(struct confdb_ctx *cdb,
328
const char *attribute,
332
struct ldb_result *res;
335
const char *attrs[] = { attribute, NULL };
337
struct ldb_message_element *el;
340
tmp_ctx = talloc_new(mem_ctx);
344
ret = parse_section(tmp_ctx, section, &secdn, NULL);
349
dn = ldb_dn_new(tmp_ctx, cdb->ldb, secdn);
355
ret = ldb_search(cdb->ldb, tmp_ctx, &res,
356
dn, LDB_SCOPE_BASE, attrs, NULL);
357
if (ret != LDB_SUCCESS) {
361
if (res->count > 1) {
366
vals = talloc_zero(mem_ctx, char *);
369
if (res->count > 0) {
370
el = ldb_msg_find_element(res->msgs[0], attribute);
371
if (el && el->num_values > 0) {
372
vals = talloc_realloc(mem_ctx, vals, char *, el->num_values +1);
377
/* should always be strings so this should be safe */
378
for (i = 0; i < el->num_values; i++) {
379
struct ldb_val v = el->values[i];
380
vals[i] = talloc_strndup(vals, (char *)v.data, v.length);
393
talloc_free(tmp_ctx);
395
DEBUG(1, ("Failed to get [%s] from [%s], error [%d] (%s)",
396
attribute, section, ret, strerror(ret)));
401
int confdb_get_string(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
402
const char *section, const char *attribute,
403
const char *defstr, char **result)
405
char **values = NULL;
409
ret = confdb_get_param(cdb, ctx, section, attribute, &values);
415
if (values[1] != NULL) {
416
/* too many values */
420
restr = talloc_steal(ctx, values[0]);
422
/* Did not return a value, so use the default */
424
if (defstr == NULL) { /* No default given */
430
/* Copy the default string */
431
restr = talloc_strdup(ctx, defstr);
445
DEBUG(1, ("Failed to get [%s] from [%s], error [%d] (%s)",
446
attribute, section, ret, strerror(ret)));
450
int confdb_get_int(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
451
const char *section, const char *attribute,
452
int defval, int *result)
454
char **values = NULL;
458
ret = confdb_get_param(cdb, ctx, section, attribute, &values);
464
if (values[1] != NULL) {
465
/* too many values */
471
val = strtol(values[0], NULL, 0);
477
if (val < INT_MIN || val > INT_MAX) {
493
DEBUG(1, ("Failed to read [%s] from [%s], error [%d] (%s)",
494
attribute, section, ret, strerror(ret)));
498
long confdb_get_long(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
499
const char *section, const char *attribute,
500
long defval, long *result)
502
char **values = NULL;
506
ret = confdb_get_param(cdb, ctx, section, attribute, &values);
512
if (values[1] != NULL) {
513
/* too many values */
519
val = strtol(values[0], NULL, 0);
536
DEBUG(1, ("Failed to read [%s] from [%s], error [%d] (%s)",
537
attribute, section, ret, strerror(ret)));
541
int confdb_get_bool(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
542
const char *section, const char *attribute,
543
bool defval, bool *result)
545
char **values = NULL;
549
ret = confdb_get_param(cdb, ctx, section, attribute, &values);
555
if (values[1] != NULL) {
556
/* too many values */
561
if (strcasecmp(values[0], "FALSE") == 0) {
564
} else if (strcasecmp(values[0], "TRUE") == 0) {
569
DEBUG(2, ("Value is not a boolean!\n"));
585
DEBUG(1, ("Failed to read [%s] from [%s], error [%d] (%s)",
586
attribute, section, ret, strerror(ret)));
590
/* WARNING: Unlike other similar functions, this one does NOT take a default,
591
* and returns ENOENT if the attribute was not found ! */
592
int confdb_get_string_as_list(struct confdb_ctx *cdb, TALLOC_CTX *ctx,
593
const char *section, const char *attribute,
596
char **values = NULL;
599
ret = confdb_get_param(cdb, ctx, section, attribute, &values);
604
if (values && values[0]) {
605
if (values[1] != NULL) {
606
/* too many values */
611
/* Did not return a value */
616
ret = split_on_separator(ctx, values[0], ",", true, result, NULL);
620
if (ret != EOK && ret != ENOENT) {
621
DEBUG(2, ("Failed to get [%s] from [%s], error [%d] (%s)",
622
attribute, section, ret, strerror(ret)));
627
int confdb_init(TALLOC_CTX *mem_ctx,
628
struct tevent_context *ev,
629
struct confdb_ctx **cdb_ctx,
630
char *confdb_location)
632
struct confdb_ctx *cdb;
635
cdb = talloc_zero(mem_ctx, struct confdb_ctx);
639
/* Because confdb calls use sync ldb calls, we create a separate event
640
* context here. This will prevent the ldb sync calls to start nested
642
* NOTE: this means that we *cannot* do async calls and return in confdb
643
* unless we convert all calls and hook back to the main event context.
646
cdb->pev = tevent_context_init(cdb);
652
cdb->ldb = ldb_init(cdb, cdb->pev);
658
ret = ldb_set_debug(cdb->ldb, ldb_debug_messages, NULL);
659
if (ret != LDB_SUCCESS) {
660
DEBUG(0,("Could not set up debug fn.\n"));
665
ret = ldb_connect(cdb->ldb, confdb_location, 0, NULL);
666
if (ret != LDB_SUCCESS) {
676
int confdb_get_domain(struct confdb_ctx *cdb,
679
struct sss_domain_info **_domain)
681
struct sss_domain_info *domain;
682
struct ldb_result *res;
688
tmp_ctx = talloc_new(mem_ctx);
689
if (!tmp_ctx) return ENOMEM;
691
dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb,
692
"cn=%s,%s", name, CONFDB_DOMAIN_BASEDN);
698
ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn,
699
LDB_SCOPE_BASE, NULL, NULL);
700
if (ret != LDB_SUCCESS) {
705
if (res->count != 1) {
706
DEBUG(0, ("Unknown domain [%s]\n", name));
711
domain = talloc_zero(mem_ctx, struct sss_domain_info);
717
tmp = ldb_msg_find_attr_as_string(res->msgs[0], "cn", NULL);
719
DEBUG(0, ("Invalid configuration entry, fatal error!\n"));
723
domain->name = talloc_strdup(domain, tmp);
729
tmp = ldb_msg_find_attr_as_string(res->msgs[0], "provider", NULL);
731
domain->provider = talloc_strdup(domain, tmp);
732
if (!domain->provider) {
738
DEBUG(0, ("Domain [%s] does not specify a provider, disabling!\n",
743
domain->timeout = ldb_msg_find_attr_as_int(res->msgs[0],
746
/* Determine if this domain can be enumerated */
747
domain->enumerate = ldb_msg_find_attr_as_int(res->msgs[0],
749
if (domain->enumerate == 0) {
750
DEBUG(1, ("No enumeration for [%s]!\n", domain->name));
753
/* Determine if this is a legacy domain */
754
if (ldb_msg_find_attr_as_bool(res->msgs[0], "legacy", 0)) {
755
domain->legacy = true;
758
/* Determine if this is domain uses MPG */
759
if (strcasecmp(domain->provider, "local") == 0 ||
760
ldb_msg_find_attr_as_bool(res->msgs[0], CONFDB_MPG, 0)) {
764
/* Determine if user/group names will be Fully Qualified
765
* in NSS interfaces */
766
if (ldb_msg_find_attr_as_bool(res->msgs[0], CONFDB_FQ, 0)) {
767
domain->fqnames = true;
770
domain->id_min = ldb_msg_find_attr_as_uint(res->msgs[0],
771
"minId", SSSD_MIN_ID);
772
domain->id_max = ldb_msg_find_attr_as_uint(res->msgs[0],
775
/* Do we allow to cache credentials */
776
if (ldb_msg_find_attr_as_bool(res->msgs[0], "cache-credentials", 0)) {
777
domain->cache_credentials = true;
780
if (ldb_msg_find_attr_as_bool(res->msgs[0], "store-legacy-passwords", 0)) {
781
domain->legacy_passwords = true;
787
talloc_free(tmp_ctx);
791
int confdb_get_domains(struct confdb_ctx *cdb,
793
struct sss_domain_info **domains)
796
struct sss_domain_info *domain, *prevdom = NULL;
797
struct sss_domain_info *first = NULL;
801
tmp_ctx = talloc_new(mem_ctx);
802
if (!tmp_ctx) return ENOMEM;
804
ret = confdb_get_string_as_list(cdb, tmp_ctx,
805
CONFDB_DOMAINS_PATH, "domains", &domlist);
807
DEBUG(0, ("No domains configured, fatal error!\n"));
811
DEBUG(0, ("Fatal error retrieving domains list!\n"));
815
for (i = 0; domlist[i]; i++) {
816
ret = confdb_get_domain(cdb, mem_ctx, domlist[i], &domain);
818
DEBUG(0, ("Error (%d [%s]) retrieving domain [%s], skipping!\n",
819
ret, strerror(ret), domlist[i]));
828
prevdom->next = domain;
834
DEBUG(0, ("No domains configured, fatal error!\n"));
841
talloc_free(tmp_ctx);