Hi Jan,
I have few comments...
On Thu, 2009-05-14 at 11:49 +0200, Jan Friesse wrote:
>
>
>
>
>
> differences
> between files
> attachment
> (corosync-support-for-uidgid-try2.patch)
>
> diff --git a/trunk/exec/main.c b/trunk/exec/main.c
> index db22e96..2b41111 100644
> --- a/trunk/exec/main.c
> +++ b/trunk/exec/main.c
> @@ -138,6 +138,18 @@ static void sigusr2_handler (int num)
> }
> }
>
> +static void corosync_remove_uidgid_list (void) {
> + struct list_head *iter;
> +
> + for (iter = ug_config.uidgid_list.next; iter !=
> &ug_config.uidgid_list; ) {
> + struct uidgid_item *ugi = list_entry (iter, struct
> uidgid_item, list);
> + iter = iter->next;
> +
> + list_del (&ugi->list);
> + free (ugi);
> + }
> +}
> +
> /*
> * TODO this function needs some love
> */
> @@ -150,6 +162,10 @@ void corosync_request_shutdown (void)
> poll_stop (0);
> totempg_finalize ();
> coroipcs_ipc_exit ();
> +
> + /*Remove uidgid_list*/
> + corosync_remove_uidgid_list ();
Is there really a need to free this list on exit? we are about to abort
anyway and the kernel will take care of that.
> +
> corosync_exit_error (AIS_DONE_EXIT);
> }
>
> @@ -482,12 +498,18 @@ static coroipcs_handler_fn_lvalue
> corosync_handler_fn_get (unsigned int service,
>
> static int corosync_security_valid (int euid, int egid)
> {
> + struct list_head *iter;
> if (euid == 0 || egid == 0) {
> return (1);
> }
> - if (euid == ug_config.uid || egid == ug_config.gid) {
> - return (1);
> +
> + for (iter = ug_config.uidgid_list.next; iter !=
> &ug_config.uidgid_list; iter = iter->next) {
> + struct uidgid_item *ugi = list_entry (iter, struct
> uidgid_item, list);
> +
> + if (euid == ugi->uid || egid == ugi->gid)
> + return (1);
> }
> +
> return (0);
> }
It's entirely possible that I misunderstood but aren't we looking here
to allow a certain process name to access IPC via certain uid/gid?
Let say that we drop a file in /etc/corosync/uidgid.d/cman with uid/gid
foo:foo, it means to me that a process called cman (or identified as
such) is allowed to access corosync IPC with uid/gid foo:foo.
With this check I can see the possibility that a user X can get access
to IPC because somebody else did drop a file in there... not really sure
that's what you want.
>
> diff --git a/trunk/exec/mainconfig.c b/trunk/exec/mainconfig.c
> index 79e01cd..eb0563c 100644
> --- a/trunk/exec/mainconfig.c
> +++ b/trunk/exec/mainconfig.c
> @@ -671,6 +671,54 @@ static void add_logsys_config_notification(
>
> }
>
> +static int corosync_main_config_read_uidgid (
> + struct objdb_iface_ver0 *objdb,
> + const char **error_string,
> + struct ug_config *ug_config)
> +{
> + hdb_handle_t object_find_handle;
> + hdb_handle_t object_service_handle;
> + char *value;
> + int uid, gid;
> + struct uidgid_item *ugi;
> +
> + list_init (&ug_config->uidgid_list);
> +
> + objdb->object_find_create (
> + OBJECT_PARENT_HANDLE,
> + "uidgid",
> + strlen ("uidgid"),
> + &object_find_handle);
> +
> + while (objdb->object_find_next (
> + object_find_handle,
> + &object_service_handle) == 0) {
> + uid = -1;
> + gid = -1;
> +
> + if (!objdb_get_string (objdb,object_service_handle,
> "uid", &value)) {
> + uid = uid_determine(value);
> + }
> +
> + if (!objdb_get_string (objdb,object_service_handle,
> "gid", &value)) {
> + gid = gid_determine(value);
> + }
> +
> + if (uid > -1 || gid > -1) {
> + ugi = malloc (sizeof (*ugi));
> + if (ugi == NULL) {
> + _corosync_out_of_memory_error();
> + }
> + ugi->uid = uid;
> + ugi->gid = gid;
> + list_add (&ugi->list,
> &ug_config->uidgid_list);
> + }
> + }
> + objdb->object_find_destroy (object_find_handle);
> +
> + return 0;
> +}
> +
For the sake of tracking, it would be a good idea to have a record of
what service/file did open for a certain uid/gid set.
So perhaps add an objdb entry with the name of the file and record the
values both as strings and numeric (easier to read in debugging).
It adds a bit of complexity to code but imho it's worth the pain.
For example:
/etc/corosync/uidgid.d/foo
contains:
uidgid {
uid: root
gid: whatever
}
it will automatically translate to (into the objdb):
uidgid {
uid: 0
gid: $random_number
service: foo
file: /etc/corosync/uidgid.d/foo
uid_requested: root (uid_r or whatever keyname)
gid_requested: whatever ^^ same as above
}
a configfile could also contain more than one set:
cat /etc/corosync/uidgid.d/many
uidgid {
service: foo
uid: root
gid: root
}
uidgid {
service: cman
uid: ais
gid: ais
}
that would translate to this in the objdb:
uidgid {
uid: 0
gid: 0
service: foo
file: /etc/corosync/uidgid.d/many
uid_requested: root (uid_r or whatever keyname)
gid_requested: root ^^ same as above
}
uidgid {
uid: $random_number
gid: $random_number
service: cman
file: /etc/corosync/uidgid.d/many
uid_requested: ais (uid_r or whatever keyname)
gid_requested: ais ^^ same as above
}
> diff --git a/trunk/exec/mainconfig.h b/trunk/exec/mainconfig.h
> index c9ab7ea..26135ad 100644
> --- a/trunk/exec/mainconfig.h
> +++ b/trunk/exec/mainconfig.h
> @@ -37,6 +37,7 @@
>
> #include <corosync/engine/objdb.h>
> #include <corosync/engine/logsys.h>
> +#include <corosync/list.h>
>
> /*
> * All service handlers in the AIS
> @@ -49,14 +50,29 @@ struct dynamic_service {
> };
> #define MAX_DYNAMIC_SERVICES 128
>
> +/*
> + * Structure describing cached uidgid item
> + */
> +struct uidgid_item {
> + struct list_head list;
> + int uid;
> + int gid;
> +};
> +
> struct ug_config {
> /*
> * user/group to run as
> */
> int uid;
> int gid;
> +
> + /*
> + * Allowed users/group to connect. This is of type uidgid
> item.
> + */
> + struct list_head uidgid_list;
> };
Do we need to have 2 structs? at this point one should be plenty?
struct uidgid {
struct list_head list;
int uid;
int gid;
}
and init the first one to match corosync default conf.
The loader should make sure to filter the config entries to load only
uidgid entries (maybe it's already there and I haven't noticed).
Fabio
_______________________________________________
Openais mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/openais