sysdb_sudo.c revision dd7192379e5fc5bb852863e60ad4b6a20c5da183
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/*
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen Authors:
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen Jakub Hrozek <jhrozek@redhat.com>
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
ff487c974815bdaa2d05a3b834f4c2c841f4cc34Timo Sirainen Copyright (C) 2011 Red Hat
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen This program is free software; you can redistribute it and/or modify
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen it under the terms of the GNU General Public License as published by
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen the Free Software Foundation; either version 3 of the License, or
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen (at your option) any later version.
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen This program is distributed in the hope that it will be useful,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen GNU General Public License for more details.
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen You should have received a copy of the GNU General Public License
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen*/
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#define _XOPEN_SOURCE
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#include <talloc.h>
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#include <time.h>
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#include "db/sysdb.h"
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#include "db/sysdb_private.h"
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#include "db/sysdb_sudo.h"
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#define NULL_CHECK(val, rval, label) do { \
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen if (!val) { \
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen rval = ENOMEM; \
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen goto label; \
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen } \
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen} while(0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen/* ==================== Utility functions ==================== */
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainenstatic errno_t sysdb_sudo_convert_time(const char *str, time_t *unix_time)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen{
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen struct tm tm;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen char *tret = NULL;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen /* SUDO requires times to be in generalized time format:
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen * YYYYMMDDHHMMSS[.|,fraction][(+|-HHMM)|Z]
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen *
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen * We need to use more format strings to parse this with strptime().
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen */
1f1e81aab38d833d1c9cdc244c91fd762e0080d4Timo Sirainen const char **format = NULL;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen const char *formats[] = {"%Y%m%d%H%M%SZ", /* 201212121300Z */
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen "%Y%m%d%H%M%S%z", /* 201212121300+-0200 */
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen "%Y%m%d%H%M%S.0Z",
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen "%Y%m%d%H%M%S.0%z",
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen "%Y%m%d%H%M%S,0Z",
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen "%Y%m%d%H%M%S,0%z",
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen NULL};
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen for (format = formats; *format != NULL; format++) {
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen tret = strptime(str, *format, &tm);
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen if (tret != NULL && *tret == '\0') {
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen *unix_time = mktime(&tm);
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen return EOK;
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen }
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen }
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen return EINVAL;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen}
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainenstatic errno_t sysdb_sudo_check_time(struct sysdb_attrs *rule,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen time_t now,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen bool *result)
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen{
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen TALLOC_CTX *tmp_ctx = NULL;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen const char **values = NULL;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen const char *name = NULL;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen time_t notBefore = 0;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen time_t notAfter = 0;
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen time_t converted;
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen errno_t ret;
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen int i;
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen if (!result) return EINVAL;
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen *result = false;
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen tmp_ctx = talloc_new(NULL);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen NULL_CHECK(tmp_ctx, ret, done);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen ret = sysdb_attrs_get_string(rule, SYSDB_SUDO_CACHE_AT_CN, &name);
49e513d090753ccbf95560b2f3a21f081a5b6c51Timo Sirainen if (ret == ENOENT) {
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen name = "<missing>";
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen } else if(ret != EOK) {
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen goto done;
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen }
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen /*
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen * From man sudoers.ldap:
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen *
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen * If multiple sudoNotBefore entries are present, the *earliest* is used.
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen * If multiple sudoNotAfter entries are present, the *last one* is used.
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen *
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen * From sudo sources, ldap.c:
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen * If either the sudoNotAfter or sudoNotBefore attributes are missing,
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen * no time restriction shall be imposed.
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen */
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen /* check for sudoNotBefore */
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen ret = sysdb_attrs_get_string_array(rule, SYSDB_SUDO_CACHE_AT_NOTBEFORE,
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen tmp_ctx, &values);
d368bfd671ae6d04a69eb7f418521d49b8bbf77aTimo Sirainen if (ret == ENOENT) {
d368bfd671ae6d04a69eb7f418521d49b8bbf77aTimo Sirainen DEBUG(SSSDBG_TRACE_LIBS,
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen ("notBefore attribute is missing, the rule [%s] is valid\n",
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen name));
d368bfd671ae6d04a69eb7f418521d49b8bbf77aTimo Sirainen *result = true;
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen ret = EOK;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen goto done;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen } else if (ret != EOK) {
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen goto done;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen for (i=0; values[i] ; i++) {
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen ret = sysdb_sudo_convert_time(values[i], &converted);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen if (ret != EOK) {
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen DEBUG(SSSDBG_MINOR_FAILURE, ("Invalid time format in rule [%s]!\n",
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen name));
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen goto done;
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen }
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen /* Grab the earliest */
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen if (!notBefore) {
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen notBefore = converted;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen } else if (notBefore > converted) {
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen notBefore = converted;
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen }
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen /* check for sudoNotAfter */
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen ret = sysdb_attrs_get_string_array(rule, SYSDB_SUDO_CACHE_AT_NOTAFTER,
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen tmp_ctx, &values);
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen if (ret == ENOENT) {
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen DEBUG(SSSDBG_TRACE_LIBS,
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen ("notAfter attribute is missing, the rule [%s] is valid\n",
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen name));
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen *result = true;
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen ret = EOK;
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen goto done;
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainen } else if (ret != EOK) {
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen goto done;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen for (i=0; values[i] ; i++) {
157bce86d0a01477bb8ebd0d380e6b2297f326f7Timo Sirainen ret = sysdb_sudo_convert_time(values[i], &converted);
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen if (ret != EOK) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen DEBUG(SSSDBG_MINOR_FAILURE, ("Invalid time format in rule [%s]!\n",
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen name));
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen goto done;
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen }
91e4199476cb2add8143c18583fa57e1decfea88Timo Sirainen
0727e38ac12efb8963a339daf56255e2be1f29fcTimo Sirainen /* Grab the latest */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (!notAfter) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen notAfter = converted;
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen } else if (notAfter < converted) {
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen notAfter = converted;
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainen }
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen }
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen if (now >= notBefore && now <= notAfter) {
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen *result = true;
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen }
747e77e3ab073a8e9e69c7a3e71b4593c5655d03Timo Sirainen
747e77e3ab073a8e9e69c7a3e71b4593c5655d03Timo Sirainen ret = EOK;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainendone:
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainen talloc_free(tmp_ctx);
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainen return ret;
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainen}
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainen
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainenerrno_t sysdb_sudo_filter_rules_by_time(TALLOC_CTX *mem_ctx,
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainen size_t in_num_rules,
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen struct sysdb_attrs **in_rules,
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen time_t now,
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen size_t *_num_rules,
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen struct sysdb_attrs ***_rules)
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen{
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen size_t num_rules = 0;
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen struct sysdb_attrs **rules = NULL;
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen TALLOC_CTX *tmp_ctx = NULL;
157bce86d0a01477bb8ebd0d380e6b2297f326f7Timo Sirainen bool allowed = false;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen errno_t ret;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen int i;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainen tmp_ctx = talloc_new(NULL);
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen NULL_CHECK(tmp_ctx, ret, done);
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (now == 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen now = time(NULL);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen for (i = 0; i < in_num_rules; i++) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen ret = sysdb_sudo_check_time(in_rules[i], now, &allowed);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (ret == EOK && allowed) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen num_rules++;
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainen rules = talloc_realloc(tmp_ctx, rules, struct sysdb_attrs *,
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainen num_rules);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen NULL_CHECK(rules, ret, done);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen rules[num_rules - 1] = in_rules[i];
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen }
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen }
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen *_num_rules = num_rules;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen *_rules = talloc_steal(mem_ctx, rules);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen ret = EOK;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainendone:
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen talloc_free(tmp_ctx);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return ret;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen}
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainenerrno_t
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainensysdb_get_sudo_filter(TALLOC_CTX *mem_ctx, const char *username,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen uid_t uid, char **groupnames, unsigned int flags,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen char **_filter)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen{
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen TALLOC_CTX *tmp_ctx = NULL;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen char *filter = NULL;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen char *specific_filter = NULL;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen time_t now;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen errno_t ret;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen int i;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen tmp_ctx = talloc_new(NULL);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen NULL_CHECK(tmp_ctx, ret, done);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen /* build specific filter */
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen specific_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen NULL_CHECK(specific_filter, ret, done);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
if (flags & SYSDB_SUDO_FILTER_INCLUDE_ALL) {
specific_filter = talloc_asprintf_append(specific_filter, "(%s=ALL)",
SYSDB_SUDO_CACHE_AT_USER);
NULL_CHECK(specific_filter, ret, done);
}
if (flags & SYSDB_SUDO_FILTER_INCLUDE_DFL) {
specific_filter = talloc_asprintf_append(specific_filter, "(%s=defaults)",
SYSDB_NAME);
NULL_CHECK(specific_filter, ret, done);
}
if ((flags & SYSDB_SUDO_FILTER_USERNAME) && (username != NULL)) {
specific_filter = talloc_asprintf_append(specific_filter, "(%s=%s)",
SYSDB_SUDO_CACHE_AT_USER,
username);
NULL_CHECK(specific_filter, ret, done);
}
if ((flags & SYSDB_SUDO_FILTER_UID) && (uid != 0)) {
specific_filter = talloc_asprintf_append(specific_filter, "(%s=#%llu)",
SYSDB_SUDO_CACHE_AT_USER,
(unsigned long long) uid);
NULL_CHECK(specific_filter, ret, done);
}
if ((flags & SYSDB_SUDO_FILTER_GROUPS) && (groupnames != NULL)) {
for (i=0; groupnames[i] != NULL; i++) {
specific_filter = talloc_asprintf_append(specific_filter, "(%s=%%%s)",
SYSDB_SUDO_CACHE_AT_USER,
groupnames[i]);
NULL_CHECK(specific_filter, ret, done);
}
}
if (flags & SYSDB_SUDO_FILTER_NGRS) {
specific_filter = talloc_asprintf_append(specific_filter, "(%s=+*)",
SYSDB_SUDO_CACHE_AT_USER);
NULL_CHECK(specific_filter, ret, done);
}
/* build global filter */
filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)",
SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC);
NULL_CHECK(filter, ret, done);
if (specific_filter[0] != '\0') {
filter = talloc_asprintf_append(filter, "(|%s)", specific_filter);
NULL_CHECK(filter, ret, done);
}
if (flags & SYSDB_SUDO_FILTER_ONLY_EXPIRED) {
now = time(NULL);
filter = talloc_asprintf_append(filter, "(&(%s<=%lld))",
SYSDB_CACHE_EXPIRE, (long long)now);
NULL_CHECK(filter, ret, done);
}
filter = talloc_strdup_append(filter, ")");
NULL_CHECK(filter, ret, done);
ret = EOK;
*_filter = talloc_steal(mem_ctx, filter);
done:
talloc_free(tmp_ctx);
return ret;
}
errno_t
sysdb_get_sudo_user_info(TALLOC_CTX *mem_ctx, const char *username,
struct sysdb_ctx *sysdb, uid_t *_uid,
char ***groupnames)
{
TALLOC_CTX *tmp_ctx;
errno_t ret;
struct ldb_message *msg;
struct ldb_message *group_msg = NULL;
char **sysdb_groupnames = NULL;
const char *primary_group = NULL;
struct ldb_message_element *groups;
uid_t uid = 0;
gid_t gid = 0;
size_t num_groups = 0;
int i;
const char *attrs[] = { SYSDB_MEMBEROF,
SYSDB_GIDNUM,
SYSDB_UIDNUM,
NULL };
const char *group_attrs[] = { SYSDB_NAME,
NULL };
tmp_ctx = talloc_new(NULL);
NULL_CHECK(tmp_ctx, ret, done);
ret = sysdb_search_user_by_name(tmp_ctx, sysdb, sysdb->domain,
username, attrs, &msg);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up user %s\n", username));
goto done;
}
if (_uid != NULL) {
uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
if (!uid) {
DEBUG(SSSDBG_CRIT_FAILURE, ("A user with no UID?\n"));
ret = EIO;
goto done;
}
}
/* resolve secondary groups */
if (groupnames != NULL) {
groups = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
if (!groups || groups->num_values == 0) {
/* No groups for this user in sysdb currently */
sysdb_groupnames = NULL;
num_groups = 0;
} else {
num_groups = groups->num_values;
sysdb_groupnames = talloc_array(tmp_ctx, char *, num_groups + 1);
NULL_CHECK(sysdb_groupnames, ret, done);
/* Get a list of the groups by groupname only */
for (i = 0; i < groups->num_values; i++) {
ret = sysdb_group_dn_name(sysdb,
sysdb_groupnames,
(const char *)groups->values[i].data,
&sysdb_groupnames[i]);
if (ret != EOK) {
ret = ENOMEM;
goto done;
}
}
sysdb_groupnames[groups->num_values] = NULL;
}
}
/* resolve primary group */
gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
if (gid != 0) {
ret = sysdb_search_group_by_gid(tmp_ctx, sysdb, sysdb->domain, gid,
group_attrs, &group_msg);
if (ret == EOK) {
primary_group = ldb_msg_find_attr_as_string(group_msg, SYSDB_NAME,
NULL);
if (primary_group == NULL) {
ret = ENOMEM;
goto done;
}
num_groups++;
sysdb_groupnames = talloc_realloc(tmp_ctx, sysdb_groupnames,
char *, num_groups + 1);
NULL_CHECK(sysdb_groupnames, ret, done);
sysdb_groupnames[num_groups - 1] = talloc_strdup(sysdb_groupnames,
primary_group);
NULL_CHECK(sysdb_groupnames[num_groups - 1], ret, done);
sysdb_groupnames[num_groups] = NULL;
} else if (ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up group [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
}
ret = EOK;
if (_uid != NULL) {
*_uid = uid;
}
if (groupnames != NULL) {
*groupnames = talloc_steal(mem_ctx, sysdb_groupnames);
}
done:
talloc_free(tmp_ctx);
return ret;
}
errno_t
sysdb_save_sudorule(struct sysdb_ctx *sysdb_ctx,
const char *rule_name,
struct sysdb_attrs *attrs)
{
errno_t ret;
DEBUG(SSSDBG_TRACE_FUNC, ("Adding sudo rule %s\n", rule_name));
ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS,
SYSDB_SUDO_CACHE_OC);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not set rule object class [%d]: %s\n",
ret, strerror(ret)));
return ret;
}
ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, rule_name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not set name attribute [%d]: %s\n",
ret, strerror(ret)));
return ret;
}
ret = sysdb_store_custom(sysdb_ctx, sysdb_ctx->domain, rule_name, SUDORULE_SUBDIR, attrs);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("sysdb_store_custom failed [%d]: %s\n",
ret, strerror(ret)));
return ret;
}
return EOK;
}
static errno_t sysdb_sudo_set_refresh_time(struct sysdb_ctx *sysdb,
const char *attr_name,
time_t value)
{
TALLOC_CTX *tmp_ctx;
struct ldb_dn *dn;
struct ldb_message *msg = NULL;
struct ldb_result *res = NULL;
errno_t ret;
int lret;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
ret = ENOMEM;
goto done;
}
dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE,
SUDORULE_SUBDIR, sysdb->domain->name);
if (!dn) {
ret = ENOMEM;
goto done;
}
lret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
NULL, NULL);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
msg = ldb_msg_new(tmp_ctx);
if (msg == NULL) {
ret = ENOMEM;
goto done;
}
msg->dn = dn;
if (res->count == 0) {
lret = ldb_msg_add_string(msg, "cn", SUDORULE_SUBDIR);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
} else if (res->count != 1) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Got more than one reply for base search!\n"));
ret = EIO;
goto done;
} else {
lret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
}
lret = ldb_msg_add_fmt(msg, attr_name, "%lld", (long long)value);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
if (res->count) {
lret = ldb_modify(sysdb->ldb, msg);
} else {
lret = ldb_add(sysdb->ldb, msg);
}
ret = sysdb_error_to_errno(lret);
done:
talloc_free(tmp_ctx);
return ret;
}
static errno_t sysdb_sudo_get_refresh_time(struct sysdb_ctx *sysdb,
const char *attr_name,
time_t *value)
{
TALLOC_CTX *tmp_ctx;
struct ldb_dn *dn;
struct ldb_result *res;
errno_t ret;
int lret;
const char *attrs[2] = {attr_name, NULL};
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
return ENOMEM;
}
dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE,
SUDORULE_SUBDIR, sysdb->domain->name);
if (!dn) {
ret = ENOMEM;
goto done;
}
lret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
attrs, NULL);
if (lret != LDB_SUCCESS) {
ret = sysdb_error_to_errno(lret);
goto done;
}
if (res->count == 0) {
/* This entry has not been populated in LDB
* This is a common case, as unlike LDAP,
* LDB does not need to have all of its parent
* objects actually exist.
*/
*value = 0;
ret = EOK;
goto done;
} else if (res->count != 1) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Got more than one reply for base search!\n"));
ret = EIO;
goto done;
}
*value = ldb_msg_find_attr_as_int(res->msgs[0], attr_name, 0);
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
errno_t sysdb_sudo_set_last_full_refresh(struct sysdb_ctx *sysdb, time_t value)
{
return sysdb_sudo_set_refresh_time(sysdb, SYSDB_SUDO_AT_LAST_FULL_REFRESH,
value);
}
errno_t sysdb_sudo_get_last_full_refresh(struct sysdb_ctx *sysdb, time_t *value)
{
return sysdb_sudo_get_refresh_time(sysdb, SYSDB_SUDO_AT_LAST_FULL_REFRESH,
value);
}
/* ==================== Purge functions ==================== */
static errno_t sysdb_sudo_purge_all(struct sysdb_ctx *sysdb,
struct sss_domain_info *domain)
{
struct ldb_dn *base_dn = NULL;
TALLOC_CTX *tmp_ctx = NULL;
errno_t ret;
tmp_ctx = talloc_new(NULL);
NULL_CHECK(tmp_ctx, ret, done);
base_dn = sysdb_custom_subtree_dn(sysdb, tmp_ctx, domain, SUDORULE_SUBDIR);
NULL_CHECK(base_dn, ret, done);
ret = sysdb_delete_recursive(sysdb, base_dn, true);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("sysdb_delete_recursive failed.\n"));
goto done;
}
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
errno_t sysdb_sudo_purge_byname(struct sysdb_ctx *sysdb,
const char *name)
{
DEBUG(SSSDBG_TRACE_INTERNAL, ("Deleting sudo rule %s\n", name));
return sysdb_delete_custom(sysdb, name, SUDORULE_SUBDIR);
}
errno_t sysdb_sudo_purge_byfilter(struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
const char *filter)
{
TALLOC_CTX *tmp_ctx;
size_t count;
struct ldb_message **msgs;
const char *name;
int i;
errno_t ret;
errno_t sret;
bool in_transaction = false;
const char *attrs[] = { SYSDB_OBJECTCLASS,
SYSDB_NAME,
SYSDB_SUDO_CACHE_AT_CN,
NULL };
/* just purge all if there's no filter */
if (!filter) {
return sysdb_sudo_purge_all(sysdb, domain);
}
tmp_ctx = talloc_new(NULL);
NULL_CHECK(tmp_ctx, ret, done);
/* match entries based on the filter and remove them one by one */
ret = sysdb_search_custom(tmp_ctx, sysdb, filter,
SUDORULE_SUBDIR, attrs,
&count, &msgs);
if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, ("No rules matched\n"));
ret = EOK;
goto done;
} else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up SUDO rules"));
goto done;
}
ret = sysdb_transaction_start(sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
goto done;
}
in_transaction = true;
for (i = 0; i < count; i++) {
name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
if (name == NULL) {
DEBUG(SSSDBG_OP_FAILURE, ("A rule without a name?\n"));
/* skip this one but still delete other entries */
continue;
}
ret = sysdb_sudo_purge_byname(sysdb, name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not delete rule %s\n", name));
goto done;
}
}
ret = sysdb_transaction_commit(sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
goto done;
}
in_transaction = false;
done:
if (in_transaction) {
sret = sysdb_transaction_cancel(sysdb);
if (sret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n"));
}
}
talloc_free(tmp_ctx);
return ret;
}