summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/db/sysdb.h5
-rw-r--r--server/db/sysdb_ops.c67
-rw-r--r--server/infopipe/infopipe.c43
-rw-r--r--server/infopipe/infopipe_groups.c169
-rw-r--r--server/infopipe/infopipe_private.h6
-rw-r--r--server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml2
6 files changed, 289 insertions, 3 deletions
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index f59b56c1d..e323ad0d6 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -285,6 +285,11 @@ int sysdb_add_group(struct sysdb_req *sysreq,
const char *name, gid_t gid,
sysdb_callback_t fn, void *pvt);
+int sysdb_set_group_gid(struct sysdb_req *sysreq,
+ struct sss_domain_info *domain,
+ const char *name, gid_t gid,
+ sysdb_callback_t fn, void *pvt);
+
/* legacy functions for proxy providers */
int sysdb_legacy_store_user(struct sysdb_req *sysreq,
diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c
index 6762575f2..9ea2a0aa5 100644
--- a/server/db/sysdb_ops.c
+++ b/server/db/sysdb_ops.c
@@ -1022,7 +1022,74 @@ static int group_add_call(struct group_add_ctx *group_ctx)
return EOK;
}
+/* This function is not safe, but is included for completeness
+ * It is much better to allow SSSD to internally manage the
+ * group GID values. sysdb_set_group_gid() will perform no
+ * validation that the new GID is unused. The only check it
+ * will perform is whether the requested GID is in the range
+ * of IDs allocated for the domain.
+ */
+int sysdb_set_group_gid(struct sysdb_req *sysreq,
+ struct sss_domain_info *domain,
+ const char *name, gid_t gid,
+ sysdb_callback_t fn, void *pvt)
+{
+ struct group_add_ctx *group_ctx;
+ struct sysdb_ctx *sysdb;
+ struct ldb_message *msg;
+ struct ldb_request *req;
+ int flags = LDB_FLAG_MOD_REPLACE;
+ int ret;
+
+ if (!sysdb_req_check_running(sysreq)) {
+ DEBUG(2, ("Invalid request! Not running at this time.\n"));
+ return EINVAL;
+ }
+
+ /* Validate that the target GID is within the domain range */
+ if((gid < domain->id_min) ||
+ (domain->id_max && (gid > domain->id_max))) {
+ DEBUG(2, ("Invalid request. Domain ID out of range"));
+ return EDOM;
+ }
+
+ group_ctx = talloc(sysreq, struct group_add_ctx);
+ if (!group_ctx) return ENOMEM;
+
+ group_ctx->cbctx = talloc_zero(group_ctx, struct sysdb_cb_ctx);
+ if (!group_ctx->cbctx) return ENOMEM;
+
+ group_ctx->sysreq = sysreq;
+ group_ctx->domain = domain;
+ group_ctx->cbctx->fn = fn;
+ group_ctx->cbctx->pvt = pvt;
+ group_ctx->name = name;
+ group_ctx->gid = gid;
+
+ sysdb = sysdb_req_get_ctx(group_ctx->sysreq);
+
+ msg = ldb_msg_new(group_ctx);
+ if (!msg) return ENOMEM;
+
+ msg->dn = sysdb_group_dn(sysdb, msg,
+ group_ctx->domain->name,
+ group_ctx->name);
+ if (!msg->dn) return ENOMEM;
+ ret = add_ulong(msg, flags, SYSDB_GIDNUM,
+ (unsigned long)(group_ctx->gid));
+
+ ret = ldb_build_mod_req(&req, sysdb->ldb, group_ctx, msg, NULL,
+ group_ctx->cbctx, sysdb_op_callback, NULL);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_request(sysdb->ldb, req);
+ }
+ if (ret != LDB_SUCCESS) {
+ return sysdb_error_to_errno(ret);
+ }
+
+ return EOK;
+}
/* "sysdb_legacy_" functions
* the set of functions named sysdb_legacy_* are used by modules
diff --git a/server/infopipe/infopipe.c b/server/infopipe/infopipe.c
index 09ffcbdf6..4ec971caa 100644
--- a/server/infopipe/infopipe.c
+++ b/server/infopipe/infopipe.c
@@ -141,6 +141,49 @@ static int infp_monitor_init(struct infp_ctx *infp_ctx)
return EOK;
}
+/* Helper function to return an immediate error message in the event
+ * of internal error in the InfoPipe to avoid forcing the clients to
+ * time out waiting for a reply.
+ */
+void infp_return_failure(struct infp_req_ctx *infp_req, const char *message)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_error(infp_req->req_message,
+ DBUS_ERROR_FAILED,
+ message);
+ /* If the reply was NULL, we ran out of memory, so we won't
+ * bother trying to queue the message to send. In this case,
+ * our safest move is to allow the client to time out waiting
+ * for a reply.
+ */
+ if(reply) {
+ sbus_conn_send_reply(infp_req->sconn, reply);
+ dbus_message_unref(reply);
+ }
+}
+
+/* Helper function to return an ack to the caller to indicate
+ * that the internal process completed succesfully. An ack in
+ * InfoPipe is simply an empty D-BUS method return (as opposed
+ * to a D-BUS error or signal)
+ */
+void infp_return_success(struct infp_req_ctx *infp_req)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(infp_req->req_message);
+ /* If the reply was NULL, we ran out of memory, so we won't
+ * bother trying to queue the message to send. In this case,
+ * our safest move is to allow the client to time out waiting
+ * for a reply.
+ */
+ if(reply) {
+ sbus_conn_send_reply(infp_req->sconn, reply);
+ dbus_message_unref(reply);
+ }
+}
+
struct sbus_method infp_methods[] = {
INFP_PERMISSION_METHODS
INFP_USER_METHODS
diff --git a/server/infopipe/infopipe_groups.c b/server/infopipe/infopipe_groups.c
index bb3741c9a..9aaecf2f2 100644
--- a/server/infopipe/infopipe_groups.c
+++ b/server/infopipe/infopipe_groups.c
@@ -657,15 +657,182 @@ int infp_groups_remove_members(DBusMessage *message,
INFP_ACTION_TYPE_REMOVEMEMBER);
}
+struct infp_setgid_ctx {
+ struct infp_req_ctx *infp_req;
+ char *group_name;
+ gid_t gid;
+ struct sysdb_req *sysdb_req;
+};
+
+static void infp_do_gid_callback(void *ptr,
+ int status,
+ struct ldb_result *res)
+{
+ char *error_msg = NULL;
+ struct infp_setgid_ctx *grmod_req =
+ talloc_get_type(ptr, struct infp_setgid_ctx);
+
+ /* Commit or cancel the transaction, based on the
+ * return status
+ */
+ sysdb_transaction_done(grmod_req->sysdb_req, status);
+
+ if(status != EOK) {
+ if (status == ENOENT) {
+ error_msg = talloc_strdup(grmod_req, "No such group");
+ }
+ infp_return_failure(grmod_req->infp_req, error_msg);
+ talloc_free(grmod_req);
+ return;
+ }
+
+ infp_return_success(grmod_req->infp_req);
+ talloc_free(grmod_req);
+}
+
+static void infp_do_gid(struct sysdb_req *req, void *pvt)
+{
+ int ret;
+ DBusMessage *reply;
+ char *error_msg;
+ gid_t max;
+ struct infp_setgid_ctx *grmod_req =
+ talloc_get_type(pvt, struct infp_setgid_ctx);
+ grmod_req->sysdb_req = req;
+
+ ret = sysdb_set_group_gid(grmod_req->sysdb_req,
+ grmod_req->infp_req->domain,
+ grmod_req->group_name,
+ grmod_req->gid,
+ infp_do_gid_callback,
+ grmod_req);
+ if (ret != EOK) {
+ if(ret == EDOM) {
+ /* GID was out of range */
+ max = grmod_req->infp_req->domain->id_max?
+ grmod_req->infp_req->domain->id_max:
+ (gid_t)-1;
+ error_msg = talloc_asprintf(grmod_req,
+ "GID %u outside the range [%u..%u]",
+ grmod_req->gid,
+ grmod_req->infp_req->domain->id_min,
+ max);
+ reply = dbus_message_new_error(grmod_req->infp_req->req_message,
+ DBUS_ERROR_LIMITS_EXCEEDED,
+ error_msg);
+ if (reply) sbus_conn_send_reply(grmod_req->infp_req->sconn, reply);
+ }
+ talloc_free(grmod_req);
+ return;
+ }
+}
+
int infp_groups_set_gid(DBusMessage *message, struct sbus_conn_ctx *sconn)
{
DBusMessage *reply;
+ DBusError error;
+ char *einval_msg;
+ struct infp_setgid_ctx *grmod_req;
+ int ret;
- reply = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, "Not yet implemented");
+ /* Arguments */
+ const char *arg_group;
+ const char *arg_domain;
+ const gid_t arg_gid;
+ grmod_req = talloc_zero(NULL, struct infp_setgid_ctx);
+ if (grmod_req == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ /* Create an infp_req_ctx */
+ grmod_req->infp_req = infp_req_init(grmod_req, message, sconn);
+ if(grmod_req->infp_req == NULL) {
+ ret = EIO;
+ goto error;
+ }
+
+ dbus_error_init(&error);
+ if (!dbus_message_get_args(message, &error,
+ DBUS_TYPE_STRING, &arg_group,
+ DBUS_TYPE_STRING, &arg_domain,
+ DBUS_TYPE_UINT32, &arg_gid,
+ DBUS_TYPE_INVALID)) {
+ DEBUG(0, ("Parsing arguments to %s failed: %s:%s\n",
+ INFP_GROUPS_SET_GID, error.name, error.message));
+ einval_msg = talloc_strdup(grmod_req, error.message);
+ dbus_error_free(&error);
+ goto einval;
+ }
+
+ /* FIXME: Allow modifying groups on domains other than LOCAL */
+ if (strcasecmp(arg_domain, "LOCAL") != 0) {
+ goto denied;
+ }
+
+ grmod_req->infp_req->domain =
+ btreemap_get_value(grmod_req->infp_req->infp->domain_map,
+ (const void *)arg_domain);
+
+ /* Check for a valid domain */
+ if(grmod_req->infp_req->domain == NULL) {
+ einval_msg = talloc_strdup(grmod_req, "Invalid domain.");
+ goto einval;
+ }
+
+ /* Check permissions */
+ if (!infp_get_permissions(grmod_req->infp_req->caller,
+ grmod_req->infp_req->domain,
+ INFP_OBJ_TYPE_GROUP,
+ arg_group,
+ INFP_ACTION_TYPE_MODIFY,
+ INFP_ATTR_TYPE_GROUPID)) goto denied;
+
+ grmod_req->gid = arg_gid;
+ grmod_req->group_name = talloc_strdup(grmod_req, arg_group);
+ if (grmod_req->group_name == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ ret = sysdb_transaction(grmod_req,
+ grmod_req->infp_req->infp->sysdb,
+ infp_do_gid,
+ grmod_req);
+ if (ret != EOK) goto error;
+
+ return EOK;
+
+denied:
+ reply = dbus_message_new_error(message, DBUS_ERROR_ACCESS_DENIED, NULL);
+ if(reply == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
/* send reply */
sbus_conn_send_reply(sconn, reply);
+ dbus_message_unref(reply);
+ talloc_free(grmod_req);
+ return EOK;
+
+einval:
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_INVALID_ARGS,
+ einval_msg);
+ if (reply == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+ sbus_conn_send_reply(sconn, reply);
dbus_message_unref(reply);
+ talloc_free(grmod_req);
return EOK;
+
+error:
+ talloc_free(grmod_req);
+ return ret;
+
+
}
diff --git a/server/infopipe/infopipe_private.h b/server/infopipe/infopipe_private.h
index 0f523c00f..066f11e90 100644
--- a/server/infopipe/infopipe_private.h
+++ b/server/infopipe/infopipe_private.h
@@ -72,7 +72,8 @@ enum infp_attribute_types {
INFP_ATTR_TYPE_SESSION,
INFP_ATTR_TYPE_LAST_LOGIN,
INFP_ATTR_TYPE_USERPIC,
- INFP_ATTR_TYPE_USERID
+ INFP_ATTR_TYPE_USERID,
+ INFP_ATTR_TYPE_GROUPID
};
int infp_get_attribute_type(const char *attribute);
@@ -91,4 +92,7 @@ int infp_get_ldb_val_from_dbus(TALLOC_CTX *mem_ctx, DBusMessageIter *iter, struc
struct infp_req_ctx *infp_req_init(TALLOC_CTX *mem_ctx, DBusMessage *message, struct sbus_conn_ctx *sconn);
+void infp_return_success(struct infp_req_ctx *infp_req);
+void infp_return_failure(struct infp_req_ctx *infp_req, const char *message);
+
#endif /* INFOPIPE_PRIVATE_H_ */
diff --git a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
index c1a8b3df2..5656d42ce 100644
--- a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
+++ b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
@@ -269,7 +269,7 @@
/>
<arg name="group" type="s" direction="in" />
<arg name="domain" type="s" direction="in" />
- <arg name="guid" type="t" direction="in" />
+ <arg name="gid" type="t" direction="in" />
</method>
</interface>
</node>