6a1bfb0afcf6cf9ee266f7f4840be08e3821d21a
[platform/upstream/polkit.git] / src / polkitbackend / polkitd.c
1 /*
2  * Copyright (C) 2008-2010 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 #include "config.h"
23
24 #include <signal.h>
25
26 #include <glib-unix.h>
27
28 #include <pwd.h>
29 #include <grp.h>
30
31 #include <polkit/polkit.h>
32 #include <polkitbackend/polkitbackend.h>
33
34 /* ---------------------------------------------------------------------------------------------------- */
35
36 static PolkitBackendAuthority *authority = NULL;
37 static gpointer                registration_id = NULL;
38 static GMainLoop              *loop = NULL;
39 static gboolean                opt_replace = FALSE;
40 static gboolean                opt_no_debug = FALSE;
41 static GOptionEntry            opt_entries[] = {
42   {"replace", 'r', 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL},
43   {"no-debug", 'n', 0, G_OPTION_ARG_NONE, &opt_no_debug, "Don't print debug information", NULL},
44   {NULL }
45 };
46
47 static void
48 on_bus_acquired (GDBusConnection *connection,
49                  const gchar     *name,
50                  gpointer         user_data)
51 {
52   GError *error;
53
54   g_print ("Connected to the system bus\n");
55
56   g_assert (authority == NULL);
57   g_assert (registration_id == NULL);
58
59   authority = polkit_backend_authority_get ();
60   g_print ("Using authority class %s\n", g_type_name (G_TYPE_FROM_INSTANCE (authority)));
61
62   error = NULL;
63   registration_id = polkit_backend_authority_register (authority,
64                                                        connection,
65                                                        "/org/freedesktop/PolicyKit1/Authority",
66                                                        &error);
67   if (registration_id == NULL)
68     {
69       g_printerr ("Error registering authority: %s\n", error->message);
70       g_error_free (error);
71       g_main_loop_quit (loop); /* exit */
72     }
73 }
74
75 static void
76 on_name_lost (GDBusConnection *connection,
77               const gchar     *name,
78               gpointer         user_data)
79 {
80   g_print ("Lost the name org.freedesktop.PolicyKit1 - exiting\n");
81   g_main_loop_quit (loop);
82 }
83
84 static void
85 on_name_acquired (GDBusConnection *connection,
86                   const gchar     *name,
87                   gpointer         user_data)
88 {
89   g_print ("Acquired the name org.freedesktop.PolicyKit1\n");
90 }
91
92 static gboolean
93 on_sigint (gpointer user_data)
94 {
95   g_print ("Handling SIGINT\n");
96   g_main_loop_quit (loop);
97   return FALSE;
98 }
99
100 static gboolean
101 become_user (const gchar  *user,
102              GError      **error)
103 {
104   gboolean ret = FALSE;
105   struct passwd *pw;
106
107   g_return_val_if_fail (user != NULL, FALSE);
108   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
109
110   pw = getpwnam (user);
111   if (pw == NULL)
112     {
113       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
114                    "Error calling getpwnam(): %m");
115       goto out;
116     }
117
118   if (setgroups (0, NULL) != 0)
119     {
120       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
121                    "Error clearing groups: %m");
122       goto out;
123     }
124   if (initgroups (pw->pw_name, pw->pw_gid) != 0)
125     {
126       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
127                    "Error initializing groups: %m");
128       goto out;
129     }
130
131   setregid (pw->pw_gid, pw->pw_gid);
132   setreuid (pw->pw_uid, pw->pw_uid);
133   if ((geteuid () != pw->pw_uid) || (getuid () != pw->pw_uid) ||
134       (getegid () != pw->pw_gid) || (getgid () != pw->pw_gid))
135     {
136       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
137                    "Error becoming real+effective uid %d and gid %d: %m",
138                    (int) pw->pw_uid, (int) pw->pw_gid);
139       goto out;
140     }
141
142   if (chdir (pw->pw_dir) != 0)
143     {
144       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
145                    "Error changing to home directory %s: %m",
146                    pw->pw_dir);
147       goto out;
148     }
149
150
151   ret = TRUE;
152
153  out:
154   return ret;
155 }
156
157 int
158 main (int    argc,
159       char **argv)
160 {
161   GError *error;
162   GOptionContext *opt_context;
163   gint ret;
164   guint name_owner_id;
165   guint sigint_id;
166
167   ret = 1;
168   loop = NULL;
169   opt_context = NULL;
170   name_owner_id = 0;
171   sigint_id = 0;
172   registration_id = NULL;
173
174   g_type_init ();
175
176   opt_context = g_option_context_new ("polkit system daemon");
177   g_option_context_add_main_entries (opt_context, opt_entries, NULL);
178   error = NULL;
179   if (!g_option_context_parse (opt_context, &argc, &argv, &error))
180     {
181       g_printerr ("Error parsing options: %s", error->message);
182       g_error_free (error);
183       goto out;
184     }
185
186   /* If --no-debug is requested don't clutter stdout/stderr etc.
187    */
188   if (opt_no_debug)
189     {
190       gint dev_null_fd;
191       dev_null_fd = open ("/dev/null", O_RDWR);
192       if (dev_null_fd >= 0)
193         {
194           dup2 (dev_null_fd, STDIN_FILENO);
195           dup2 (dev_null_fd, STDOUT_FILENO);
196           dup2 (dev_null_fd, STDERR_FILENO);
197           close (dev_null_fd);
198         }
199       else
200         {
201           g_warning ("Error opening /dev/null: %m");
202         }
203     }
204
205   error = NULL;
206   if (!become_user (POLKITD_USER, &error))
207     {
208       g_printerr ("Error switcing to user %s: %s\n",
209                   POLKITD_USER, error->message);
210       g_clear_error (&error);
211       goto out;
212     }
213
214   g_print ("Successfully changed to user %s\n", POLKITD_USER);
215
216   if (g_getenv ("PATH") == NULL)
217     g_setenv ("PATH", "/usr/bin:/bin:/usr/sbin:/sbin", TRUE);
218
219   loop = g_main_loop_new (NULL, FALSE);
220
221   sigint_id = g_unix_signal_add (SIGINT,
222                                  on_sigint,
223                                  NULL);
224
225   name_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
226                                   "org.freedesktop.PolicyKit1",
227                                   G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
228                                     (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
229                                   on_bus_acquired,
230                                   on_name_acquired,
231                                   on_name_lost,
232                                   NULL,
233                                   NULL);
234
235   g_print ("Entering main event loop\n");
236   g_main_loop_run (loop);
237
238   ret = 0;
239
240   g_print ("Shutting down\n");
241  out:
242   if (sigint_id > 0)
243     g_source_remove (sigint_id);
244   if (name_owner_id != 0)
245     g_bus_unown_name (name_owner_id);
246   if (registration_id != NULL)
247     polkit_backend_authority_unregister (registration_id);
248   if (authority != NULL)
249     g_object_unref (authority);
250   if (loop != NULL)
251     g_main_loop_unref (loop);
252   if (opt_context != NULL)
253     g_option_context_free (opt_context);
254
255   g_print ("Exiting with code %d\n", ret);
256   return ret;
257 }