summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2009-01-11 17:21:11 -0500
committerSimo Sorce <idra@samba.org>2009-01-11 17:21:11 -0500
commit9aaaff891a0125dc1102668a99338530fb07abfa (patch)
tree42b728f445da593aafdba32ee2fb456324b27c44 /server
parent28fc5582c207d493a33406222da517a241a157ec (diff)
downloadsssd-9aaaff891a0125dc1102668a99338530fb07abfa.tar.gz
sssd-9aaaff891a0125dc1102668a99338530fb07abfa.tar.xz
sssd-9aaaff891a0125dc1102668a99338530fb07abfa.zip
Add support for getpwuid in proxy backend
Diffstat (limited to 'server')
-rw-r--r--server/nss/nsssrv_cmd.c91
-rw-r--r--server/providers/dp_backend.h1
-rw-r--r--server/providers/dp_backend_store.c123
-rw-r--r--server/providers/proxy.c61
4 files changed, 230 insertions, 46 deletions
diff --git a/server/nss/nsssrv_cmd.c b/server/nss/nsssrv_cmd.c
index 9347c329f..4d856e065 100644
--- a/server/nss/nsssrv_cmd.c
+++ b/server/nss/nsssrv_cmd.c
@@ -29,7 +29,7 @@
struct nss_cmd_ctx {
struct cli_ctx *cctx;
const char *name;
- uint64_t id;
+ uid_t id;
bool check_expiration;
};
@@ -189,12 +189,15 @@ done:
static void nss_cmd_getpwnam_callback(uint16_t err_maj, uint32_t err_min,
const char *err_msg, void *ptr);
+static void nss_cmd_getpwuid_callback(uint16_t err_maj, uint32_t err_min,
+ const char *err_msg, void *ptr);
static void nss_cmd_getpw_callback(void *ptr, int status,
struct ldb_result *res)
{
struct nss_cmd_ctx *nctx = talloc_get_type(ptr, struct nss_cmd_ctx);
struct cli_ctx *cctx = nctx->cctx;
+ nss_dp_callback_t callback_fn;
int timeout;
uint64_t lastUpdate;
uint8_t *body;
@@ -209,16 +212,24 @@ static void nss_cmd_getpw_callback(void *ptr, int status,
return;
}
+ if (nctx->name) {
+ callback_fn = &nss_cmd_getpwnam_callback;
+ } else {
+ callback_fn = &nss_cmd_getpwuid_callback;
+ }
+
if (res->count == 0 && nctx->check_expiration) {
/* dont loop forever :-) */
nctx->check_expiration = false;
+ timeout = SSS_NSS_SOCKET_TIMEOUT/2;
- ret = nss_dp_send_acct_req(cctx->nctx, nctx,
- nss_cmd_getpwnam_callback, nctx,
- SSS_NSS_SOCKET_TIMEOUT/2, "*",
- NSS_DP_USER, nctx->name, 0);
+ ret = nss_dp_send_acct_req(cctx->nctx, nctx, callback_fn, nctx,
+ timeout, "*", NSS_DP_USER,
+ nctx->name, nctx->id);
if (ret != EOK) {
+ DEBUG(3, ("Failed to dispatch request: %d(%s)",
+ ret, strerror(ret)));
ret = nss_cmd_send_error(nctx, ret);
}
if (ret != EOK) {
@@ -255,12 +266,14 @@ static void nss_cmd_getpw_callback(void *ptr, int status,
/* dont loop forever :-) */
nctx->check_expiration = false;
+ timeout = SSS_NSS_SOCKET_TIMEOUT/2;
- ret = nss_dp_send_acct_req(cctx->nctx, nctx,
- nss_cmd_getpwnam_callback, nctx,
- SSS_NSS_SOCKET_TIMEOUT/2, "*",
- NSS_DP_USER, nctx->name, 0);
+ ret = nss_dp_send_acct_req(cctx->nctx, nctx, callback_fn, nctx,
+ timeout, "*", NSS_DP_USER,
+ nctx->name, nctx->id);
if (ret != EOK) {
+ DEBUG(3, ("Failed to dispatch request: %d(%s)",
+ ret, strerror(ret)));
ret = nss_cmd_send_error(nctx, ret);
}
if (ret != EOK) {
@@ -319,7 +332,7 @@ static int nss_cmd_getpwnam(struct cli_ctx *cctx)
size_t blen;
int ret;
- nctx = talloc(cctx, struct nss_cmd_ctx);
+ nctx = talloc_zero(cctx, struct nss_cmd_ctx);
if (!nctx) {
return ENOMEM;
}
@@ -354,13 +367,45 @@ static int nss_cmd_getpwnam(struct cli_ctx *cctx)
return EOK;
}
+static void nss_cmd_getpwuid_callback(uint16_t err_maj, uint32_t err_min,
+ const char *err_msg, void *ptr)
+{
+ struct nss_cmd_ctx *nctx = talloc_get_type(ptr, struct nss_cmd_ctx);
+ struct cli_ctx *cctx = nctx->cctx;
+ int ret;
+
+ if (err_maj) {
+ DEBUG(2, ("Unable to get information from Data Provider\n"
+ "Error: %u, %u, %s\n"
+ "Will try to return what we have in cache\n",
+ (unsigned int)err_maj, (unsigned int)err_min, err_msg));
+ }
+
+ ret = nss_ldb_getpwuid(nctx, cctx->ev, cctx->nctx->lctx,
+ nctx->id, nss_cmd_getpw_callback, nctx);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to make request to our cache!\n"));
+
+ ret = nss_cmd_send_error(nctx, ret);
+ if (ret != EOK) {
+ NSS_CMD_FATAL_ERROR(cctx);
+ }
+ }
+}
+
static int nss_cmd_getpwuid(struct cli_ctx *cctx)
{
struct nss_cmd_ctx *nctx;
uint8_t *body;
size_t blen;
int ret;
- uint64_t uid;
+
+ nctx = talloc_zero(cctx, struct nss_cmd_ctx);
+ if (!nctx) {
+ return ENOMEM;
+ }
+ nctx->cctx = cctx;
+ nctx->check_expiration = true;
/* get uid to query */
nss_packet_get_body(cctx->creq->in, &body, &blen);
@@ -369,20 +414,24 @@ static int nss_cmd_getpwuid(struct cli_ctx *cctx)
return EINVAL;
}
- uid = *((uint64_t *)body);
+ nctx->id = (uid_t)*((uint64_t *)body);
- DEBUG(4, ("Requesting info for [%lu]\n", uid));
+ DEBUG(4, ("Requesting info for [%lu]\n", nctx->id));
- nctx = talloc(cctx, struct nss_cmd_ctx);
- if (!nctx) {
- return ENOMEM;
- }
- nctx->cctx = cctx;
+ /* FIXME: Just ask all backends for now, until we check for ranges */
- ret = nss_ldb_getpwuid(nctx, cctx->ev, cctx->nctx->lctx, uid,
- nss_cmd_getpw_callback, nctx);
+ ret = nss_ldb_getpwuid(nctx, cctx->ev, cctx->nctx->lctx,
+ nctx->id, nss_cmd_getpw_callback, nctx);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to make request to our cache!\n"));
- return ret;
+ ret = nss_cmd_send_error(nctx, ret);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+
+ return EOK;
}
/* to keep it simple at this stage we are retrieving the
diff --git a/server/providers/dp_backend.h b/server/providers/dp_backend.h
index c7cb61c40..1ad31d5ec 100644
--- a/server/providers/dp_backend.h
+++ b/server/providers/dp_backend.h
@@ -52,6 +52,7 @@ int dp_be_store_account_posix(struct be_ctx *ctx,
uint64_t uid, uint64_t gid,
char *gecos, char *homedir, char *shell);
int dp_be_remove_account_posix(struct be_ctx *ctx, char *name);
+int dp_be_remove_account_posix_by_uid(struct be_ctx *ctx, uid_t uid);
int dp_be_cachedb_init(struct be_ctx *ctx);
diff --git a/server/providers/dp_backend_store.c b/server/providers/dp_backend_store.c
index 9bccb2184..f9c55e0be 100644
--- a/server/providers/dp_backend_store.c
+++ b/server/providers/dp_backend_store.c
@@ -27,6 +27,11 @@
#include "providers/dp_backend.h"
#include <time.h>
+/* NOTE: these functions ues ldb sync calls, but the cache db is a
+ * local TDB, so there should never be an issue.
+ * In case this changes (ex. plugins that contact the network etc..
+ * make sure to split functions in multiple async calls */
+
int dp_be_store_account_posix(struct be_ctx *ctx,
char *name, char *pwd,
uint64_t uid, uint64_t gid,
@@ -47,7 +52,7 @@ int dp_be_store_account_posix(struct be_ctx *ctx,
}
account_dn = ldb_dn_new_fmt(tmp_ctx, ctx->ldb,
- "uid=%s,cn=users,cn=%s,cn=remote",
+ "uid=%s,cn=users,cn=%s,cn=accounts",
name, ctx->domain);
if (!account_dn) {
talloc_free(tmp_ctx);
@@ -61,26 +66,8 @@ int dp_be_store_account_posix(struct be_ctx *ctx,
goto done;
}
- res = talloc_zero(tmp_ctx, struct ldb_result);
- if (!res) {
- ret = ENOMEM;
- goto done;
- }
-
- lret = ldb_build_search_req(&req, ctx->ldb, tmp_ctx,
- account_dn, LDB_SCOPE_BASE,
- "(objectClass=User)", attrs, NULL,
- res, ldb_search_default_callback, NULL);
- if (lret != LDB_SUCCESS) {
- DEBUG(1, ("Failed to build search request (%d) !?\n", lret));
- ret = EIO;
- goto done;
- }
-
- lret = ldb_request(ctx->ldb, req);
- if (lret == LDB_SUCCESS) {
- lret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
+ lret = ldb_search(ctx->ldb, tmp_ctx, &res, account_dn,
+ LDB_SCOPE_BASE, attrs, "(objectClass=User)");
if (lret != LDB_SUCCESS) {
DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n",
ldb_strerror(lret), lret, ldb_errstring(ctx->ldb)));
@@ -88,7 +75,6 @@ int dp_be_store_account_posix(struct be_ctx *ctx,
goto done;
}
- talloc_free(req);
req = NULL;
msg = ldb_msg_new(tmp_ctx);
@@ -159,7 +145,7 @@ int dp_be_store_account_posix(struct be_ctx *ctx,
lret = ldb_msg_add_empty(msg, "uidNumber", flags, NULL);
if (lret == LDB_SUCCESS) {
lret = ldb_msg_add_fmt(msg, "uidNumber",
- "%lu", (long unsigned)uid);
+ "%lu", (unsigned long)uid);
}
if (lret != LDB_SUCCESS) {
ret = errno;
@@ -176,7 +162,7 @@ int dp_be_store_account_posix(struct be_ctx *ctx,
lret = ldb_msg_add_empty(msg, "gidNumber", flags, NULL);
if (lret == LDB_SUCCESS) {
lret = ldb_msg_add_fmt(msg, "gidNumber",
- "%lu", (long unsigned)gid);
+ "%lu", (unsigned long)gid);
}
if (lret != LDB_SUCCESS) {
ret = errno;
@@ -316,6 +302,95 @@ int dp_be_remove_account_posix(struct be_ctx *ctx, char *name)
return ret;
}
+int dp_be_remove_account_posix_by_uid(struct be_ctx *ctx, uid_t uid)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = { "name", "uid", NULL };
+ struct ldb_dn *base_dn;
+ struct ldb_dn *account_dn;
+ struct ldb_result *res;
+ int lret, ret;
+
+ tmp_ctx = talloc_new(ctx);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ base_dn = ldb_dn_new_fmt(tmp_ctx, ctx->ldb,
+ "cn=users,cn=%s,cn=accounts", ctx->domain);
+ if (!base_dn) {
+ talloc_free(tmp_ctx);
+ return ENOMEM;
+ }
+
+ lret = ldb_transaction_start(ctx->ldb);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret));
+ ret = EIO;
+ goto done;
+ }
+
+ lret = ldb_search(ctx->ldb, tmp_ctx, &res, base_dn,
+ LDB_SCOPE_BASE, attrs,
+ "(&(uid=%lu)(objectClass=User))",
+ (unsigned long)uid);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n",
+ ldb_strerror(lret), lret, ldb_errstring(ctx->ldb)));
+ ret = EIO;
+ goto done;
+ }
+
+ if (res->count == 0) {
+ ret = EOK;
+ goto done;
+ }
+ if (res->count > 1) {
+ DEBUG(0, ("Cache DB corrupted, base search returned %d results\n",
+ res->count));
+ ret = EOK;
+ goto done;
+ }
+
+ account_dn = ldb_dn_copy(tmp_ctx, res->msgs[0]->dn);
+ if (!account_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_free(res);
+ res = NULL;
+
+ ret = ldb_delete(ctx->ldb, account_dn);
+
+ if (ret != LDB_SUCCESS) {
+ DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n",
+ ldb_strerror(ret), ret, ldb_errstring(ctx->ldb)));
+ ret = EIO;
+ goto done;
+ }
+
+ lret = ldb_transaction_commit(ctx->ldb);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(1, ("Failed ldb transaction commit !! (%d)\n", lret));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ lret = ldb_transaction_cancel(ctx->ldb);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret));
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
/* TODO: Unify with nss_ldb and provide a single cachedb interface */
int dp_be_cachedb_init(struct be_ctx *ctx)
diff --git a/server/providers/proxy.c b/server/providers/proxy.c
index b5674490e..f93a5ede1 100644
--- a/server/providers/proxy.c
+++ b/server/providers/proxy.c
@@ -72,7 +72,8 @@ static int get_pw_name(struct be_ctx *be_ctx, struct proxy_ctx *proxy_ctx, char
ret = dp_be_remove_account_posix(be_ctx, name);
break;
case NSS_STATUS_SUCCESS:
- ret = dp_be_store_account_posix(be_ctx, name, result.pw_passwd,
+ ret = dp_be_store_account_posix(be_ctx,
+ result.pw_name, result.pw_passwd,
result.pw_uid, result.pw_gid,
result.pw_gecos, result.pw_dir,
result.pw_shell);
@@ -93,6 +94,46 @@ static int get_pw_name(struct be_ctx *be_ctx, struct proxy_ctx *proxy_ctx, char
return ret;
}
+static int get_pw_uid(struct be_ctx *be_ctx, struct proxy_ctx *proxy_ctx, uid_t uid)
+{
+ struct proxy_nss_ops *ops = &proxy_ctx->ops;
+ enum nss_status status;
+ struct passwd result;
+ char *buffer;
+ int ret;
+
+ buffer = talloc_size(NULL, 4096);
+ if (!buffer) return ENOMEM;
+
+ status = ops->getpwuid_r(uid, &result, buffer, 4096, &ret);
+
+ switch (status) {
+ case NSS_STATUS_NOTFOUND:
+ ret = dp_be_remove_account_posix_by_uid(be_ctx, uid);
+ break;
+ case NSS_STATUS_SUCCESS:
+ ret = dp_be_store_account_posix(be_ctx,
+ result.pw_name, result.pw_passwd,
+ result.pw_uid, result.pw_gid,
+ result.pw_gecos, result.pw_dir,
+ result.pw_shell);
+ break;
+ default:
+ DEBUG(2, ("proxy -> getpwuid_r failed for '%lu' (%d)[%s]\n",
+ (unsigned long)uid, ret, strerror(ret)));
+ talloc_free(buffer);
+ return ret;
+ }
+
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to update LDB Cache for '%lu' (%d) !?\n",
+ (unsigned long)uid, ret));
+ }
+
+ talloc_free(buffer);
+ return ret;
+}
+
static int proxy_check_online(struct be_ctx *be_ctx, int *reply)
{
*reply = MOD_ONLINE;
@@ -104,6 +145,7 @@ static int proxy_get_account_info(struct be_ctx *be_ctx,
int filter_type, char *filter_value)
{
struct proxy_ctx *ctx;
+ uid_t uid;
ctx = talloc_get_type(be_ctx->pvt_data, struct proxy_ctx);
@@ -124,6 +166,23 @@ static int proxy_get_account_info(struct be_ctx *be_ctx,
}
break;
case BE_FILTER_IDNUM:
+ switch (attr_type) {
+ case BE_ATTR_CORE:
+ if (strchr(filter_value, '*')) {
+ return EINVAL;
+ } else {
+ char *endptr;
+ errno = 0;
+ uid = (uid_t)strtol(filter_value, &endptr, 0);
+ if (errno || *endptr || (filter_value == endptr)) {
+ return EINVAL;
+ }
+ return get_pw_uid(be_ctx, ctx, uid);
+ }
+ break;
+ default:
+ return EINVAL;
+ }
break;
default:
return EINVAL;