1 /*
2  * Copyright (C) 2008 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: David Zeuthen <davidz@redhat.com>
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25 
26 #include <string.h>
27 #include <grp.h>
28 #include <errno.h>
29 #include "polkitunixgroup.h"
30 #include "polkitidentity.h"
31 #include "polkiterror.h"
32 #include "polkitprivate.h"
33 
34 /**
35  * SECTION:polkitunixgroup
36  * @title: PolkitUnixGroup
37  * @short_description: Unix groups
38  *
39  * An object representing a group identity on a UNIX system.
40  */
41 
42 /**
43  * PolkitUnixGroup:
44  *
45  * The #PolkitUnixGroup struct should not be accessed directly.
46  */
47 struct _PolkitUnixGroup
48 {
49   GObject parent_instance;
50 
51   gint gid;
52 };
53 
54 struct _PolkitUnixGroupClass
55 {
56   GObjectClass parent_class;
57 };
58 
59 enum
60 {
61   PROP_0,
62   PROP_GID,
63 };
64 
65 static void identity_iface_init (PolkitIdentityIface *identity_iface);
66 
67 G_DEFINE_TYPE_WITH_CODE (PolkitUnixGroup, polkit_unix_group, G_TYPE_OBJECT,
68                          G_IMPLEMENT_INTERFACE (POLKIT_TYPE_IDENTITY, identity_iface_init)
69                          );
70 
71 static void
polkit_unix_group_init(PolkitUnixGroup * unix_group)72 polkit_unix_group_init (PolkitUnixGroup *unix_group)
73 {
74   unix_group->gid = -1; /* (git_t) -1 is not a valid GID under Linux */
75 }
76 
77 static void
polkit_unix_group_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)78 polkit_unix_group_get_property (GObject    *object,
79                                 guint       prop_id,
80                                 GValue     *value,
81                                 GParamSpec *pspec)
82 {
83   PolkitUnixGroup *unix_group = POLKIT_UNIX_GROUP (object);
84 
85   switch (prop_id)
86     {
87     case PROP_GID:
88       g_value_set_int (value, unix_group->gid);
89       break;
90 
91     default:
92       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
93       break;
94     }
95 }
96 
97 static void
polkit_unix_group_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)98 polkit_unix_group_set_property (GObject      *object,
99                                guint         prop_id,
100                                const GValue *value,
101                                GParamSpec   *pspec)
102 {
103   PolkitUnixGroup *unix_group = POLKIT_UNIX_GROUP (object);
104   gint val;
105 
106   switch (prop_id)
107     {
108     case PROP_GID:
109       val = g_value_get_int (value);
110       g_return_if_fail (val != -1);
111       unix_group->gid = val;
112       break;
113 
114     default:
115       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
116       break;
117     }
118 }
119 
120 static void
polkit_unix_group_class_init(PolkitUnixGroupClass * klass)121 polkit_unix_group_class_init (PolkitUnixGroupClass *klass)
122 {
123   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
124 
125   gobject_class->get_property = polkit_unix_group_get_property;
126   gobject_class->set_property = polkit_unix_group_set_property;
127 
128   /**
129    * PolkitUnixGroup:gid:
130    *
131    * The UNIX group id.
132    */
133   g_object_class_install_property (gobject_class,
134                                    PROP_GID,
135                                    g_param_spec_int ("gid",
136                                                      "Group ID",
137                                                      "The UNIX group ID",
138                                                      G_MININT,
139                                                      G_MAXINT,
140                                                      -1,
141                                                      G_PARAM_CONSTRUCT |
142                                                      G_PARAM_READWRITE |
143                                                      G_PARAM_STATIC_NAME |
144                                                      G_PARAM_STATIC_BLURB |
145                                                      G_PARAM_STATIC_NICK));
146 
147 }
148 
149 /**
150  * polkit_unix_group_get_gid:
151  * @group: A #PolkitUnixGroup.
152  *
153  * Gets the UNIX group id for @group.
154  *
155  * Returns: A UNIX group id.
156  */
157 gint
polkit_unix_group_get_gid(PolkitUnixGroup * group)158 polkit_unix_group_get_gid (PolkitUnixGroup *group)
159 {
160   g_return_val_if_fail (POLKIT_IS_UNIX_GROUP (group), -1);
161   return group->gid;
162 }
163 
164 /**
165  * polkit_unix_group_set_gid:
166  * @group: A #PolkitUnixGroup.
167  * @gid: A UNIX group id.
168  *
169  * Sets @gid for @group.
170  */
171 void
polkit_unix_group_set_gid(PolkitUnixGroup * group,gint gid)172 polkit_unix_group_set_gid (PolkitUnixGroup *group,
173                            gint gid)
174 {
175   g_return_if_fail (POLKIT_IS_UNIX_GROUP (group));
176   g_return_if_fail (gid != -1);
177   group->gid = gid;
178 }
179 
180 /**
181  * polkit_unix_group_new:
182  * @gid: A UNIX group id.
183  *
184  * Creates a new #PolkitUnixGroup object for @gid.
185  *
186  * Returns: (transfer full): A #PolkitUnixGroup object. Free with g_object_unref().
187  */
188 PolkitIdentity *
polkit_unix_group_new(gint gid)189 polkit_unix_group_new (gint gid)
190 {
191   g_return_val_if_fail (gid != -1, NULL);
192 
193   return POLKIT_IDENTITY (g_object_new (POLKIT_TYPE_UNIX_GROUP,
194                                        "gid", gid,
195                                        NULL));
196 }
197 
198 /**
199  * polkit_unix_group_new_for_name:
200  * @name: A UNIX group name.
201  * @error: Return location for error.
202  *
203  * Creates a new #PolkitUnixGroup object for a group with the group name
204  * @name.
205  *
206  * Returns: (transfer full): (allow-none): A #PolkitUnixGroup object or %NULL if @error
207  * is set.
208  */
209 PolkitIdentity *
polkit_unix_group_new_for_name(const gchar * name,GError ** error)210 polkit_unix_group_new_for_name (const gchar    *name,
211                                 GError        **error)
212 {
213   struct group *group;
214   PolkitIdentity *identity;
215 
216   g_return_val_if_fail (name != NULL, NULL);
217   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
218 
219   identity = NULL;
220 
221   group = getgrnam (name);
222   if (group == NULL)
223     {
224       g_set_error (error,
225                    POLKIT_ERROR,
226                    POLKIT_ERROR_FAILED,
227                    "No UNIX group with name %s: %s",
228                    name,
229                    g_strerror (errno));
230       goto out;
231     }
232 
233   identity = polkit_unix_group_new (group->gr_gid);
234 
235  out:
236   return identity;
237 }
238 
239 static guint
polkit_unix_group_hash(PolkitIdentity * identity)240 polkit_unix_group_hash (PolkitIdentity *identity)
241 {
242   PolkitUnixGroup *group;
243 
244   group = POLKIT_UNIX_GROUP (identity);
245 
246   return g_direct_hash (GINT_TO_POINTER (((gint) (group->gid)) * 2 + 1));
247 }
248 
249 static gboolean
polkit_unix_group_equal(PolkitIdentity * a,PolkitIdentity * b)250 polkit_unix_group_equal (PolkitIdentity *a,
251                         PolkitIdentity *b)
252 {
253   PolkitUnixGroup *group_a;
254   PolkitUnixGroup *group_b;
255 
256   group_a = POLKIT_UNIX_GROUP (a);
257   group_b = POLKIT_UNIX_GROUP (b);
258 
259   return group_a->gid == group_b->gid;
260 }
261 
262 static gchar *
polkit_unix_group_to_string(PolkitIdentity * identity)263 polkit_unix_group_to_string (PolkitIdentity *identity)
264 {
265   PolkitUnixGroup *group = POLKIT_UNIX_GROUP (identity);
266   struct group *gr;
267 
268   gr = getgrgid (group->gid);
269 
270   if (gr == NULL)
271     return g_strdup_printf ("unix-group:%d", group->gid);
272   else
273     return g_strdup_printf ("unix-group:%s", gr->gr_name);
274 }
275 
276 static void
identity_iface_init(PolkitIdentityIface * identity_iface)277 identity_iface_init (PolkitIdentityIface *identity_iface)
278 {
279   identity_iface->hash      = polkit_unix_group_hash;
280   identity_iface->equal     = polkit_unix_group_equal;
281   identity_iface->to_string = polkit_unix_group_to_string;
282 }
283