gnome-shell-3.6.3.1/src/shell-polkit-authentication-agent.c

Location Tool Test ID Function Issue
shell-polkit-authentication-agent.c:259:11 clang-analyzer Access to field 'g_class' results in a dereference of a null pointer (loaded from field 'data')
  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 
  3 /*
  4  * Copyright (C) 20011 Red Hat, Inc.
  5  *
  6  * Author: David Zeuthen <davidz@redhat.com>
  7  */
  8 
  9 #include "config.h"
 10 
 11 #include <pwd.h>
 12 
 13 #define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
 14 #include <polkitagent/polkitagent.h>
 15 #include "shell-polkit-authentication-agent.h"
 16 
 17 #include <glib/gi18n.h>
 18 
 19 /* uncomment for useful debug output */
 20 /* #define SHOW_DEBUG */
 21 
 22 #ifdef SHOW_DEBUG
 23 static void
 24 print_debug (const gchar *format, ...)
 25 {
 26   gchar *s;
 27   va_list ap;
 28   gchar timebuf[64];
 29   GTimeVal now;
 30   time_t now_t;
 31   struct tm broken_down;
 32 
 33   g_get_current_time (&now);
 34   now_t = now.tv_sec;
 35   localtime_r (&now_t, &broken_down);
 36   strftime (timebuf, sizeof timebuf, "%H:%M:%S", &broken_down);
 37 
 38   va_start (ap, format);
 39   s = g_strdup_vprintf (format, ap);
 40   va_end (ap);
 41 
 42   g_print ("ShellPolkitAuthenticationAgent: %s.%03d: %s\n", timebuf, (gint) (now.tv_usec / 1000), s);
 43   g_free (s);
 44 }
 45 #else
 46 static void
 47 print_debug (const gchar *str, ...)
 48 {
 49 }
 50 #endif
 51 
 52 
 53 struct _ShellPolkitAuthenticationAgentClass
 54 {
 55   PolkitAgentListenerClass parent_class;
 56 };
 57 
 58 struct _AuthRequest;
 59 typedef struct _AuthRequest AuthRequest;
 60 
 61 struct _ShellPolkitAuthenticationAgent {
 62   PolkitAgentListener parent_instance;
 63 
 64   GList *scheduled_requests;
 65   AuthRequest *current_request;
 66 
 67   gpointer handle;
 68 };
 69 
 70 /* Signals */
 71 enum
 72 {
 73   INITIATE_SIGNAL,
 74   CANCEL_SIGNAL,
 75   LAST_SIGNAL
 76 };
 77 
 78 static guint signals[LAST_SIGNAL] = { 0 };
 79 
 80 G_DEFINE_TYPE (ShellPolkitAuthenticationAgent, shell_polkit_authentication_agent, POLKIT_AGENT_TYPE_LISTENER);
 81 
 82 static void initiate_authentication (PolkitAgentListener  *listener,
 83                                      const gchar          *action_id,
 84                                      const gchar          *message,
 85                                      const gchar          *icon_name,
 86                                      PolkitDetails        *details,
 87                                      const gchar          *cookie,
 88                                      GList                *identities,
 89                                      GCancellable         *cancellable,
 90                                      GAsyncReadyCallback   callback,
 91                                      gpointer              user_data);
 92 
 93 static gboolean initiate_authentication_finish (PolkitAgentListener  *listener,
 94                                                 GAsyncResult         *res,
 95                                                 GError              **error);
 96 
 97 void
 98 shell_polkit_authentication_agent_init (ShellPolkitAuthenticationAgent *agent)
 99 {
100 }
101 
102 void
103 shell_polkit_authentication_agent_register (ShellPolkitAuthenticationAgent *agent,
104                                             GError                        **error_out)
105 {
106   GError *error = NULL;
107   PolkitSubject *subject;
108 
109   subject = polkit_unix_session_new_for_process_sync (getpid (),
110                                                       NULL, /* GCancellable* */
111                                                       &error);
112   if (subject == NULL)
113     {
114       if (error == NULL) /* polkit version 104 and older don't properly set error on failure */
115         error = g_error_new (POLKIT_ERROR, POLKIT_ERROR_FAILED,
116                              "PolKit failed to properly get our session");
117       goto out;
118     }
119 
120   agent->handle = polkit_agent_listener_register (POLKIT_AGENT_LISTENER (agent),
121                                                   POLKIT_AGENT_REGISTER_FLAGS_NONE,
122                                                   subject,
123                                                   NULL, /* use default object path */
124                                                   NULL, /* GCancellable */
125                                                   &error);
126 
127  out:
128   if (error != NULL)
129     g_propagate_error (error_out, error);
130 
131   if (subject != NULL)
132     g_object_unref (subject);
133 }
134 
135 static void
136 shell_polkit_authentication_agent_finalize (GObject *object)
137 {
138   ShellPolkitAuthenticationAgent *agent = SHELL_POLKIT_AUTHENTICATION_AGENT (object);
139   shell_polkit_authentication_agent_unregister (agent);
140   G_OBJECT_CLASS (shell_polkit_authentication_agent_parent_class)->finalize (object);
141 }
142 
143 static void
144 shell_polkit_authentication_agent_class_init (ShellPolkitAuthenticationAgentClass *klass)
145 {
146   GObjectClass *gobject_class;
147   PolkitAgentListenerClass *listener_class;
148 
149   gobject_class = G_OBJECT_CLASS (klass);
150   gobject_class->finalize = shell_polkit_authentication_agent_finalize;
151 
152   listener_class = POLKIT_AGENT_LISTENER_CLASS (klass);
153   listener_class->initiate_authentication = initiate_authentication;
154   listener_class->initiate_authentication_finish = initiate_authentication_finish;
155 
156   signals[INITIATE_SIGNAL] =
157     g_signal_new ("initiate",
158                   G_TYPE_FROM_CLASS (klass),
159                   G_SIGNAL_RUN_LAST,
160                   0,    /* class_offset */
161                   NULL, /* accumulator */
162                   NULL, /* accumulator data */
163                   NULL, /* marshaller */
164                   G_TYPE_NONE,
165                   5,
166                   G_TYPE_STRING,
167                   G_TYPE_STRING,
168                   G_TYPE_STRING,
169                   G_TYPE_STRING,
170                   G_TYPE_STRV);
171 
172   signals[CANCEL_SIGNAL] =
173     g_signal_new ("cancel",
174                   G_TYPE_FROM_CLASS (klass),
175                   G_SIGNAL_RUN_LAST,
176                   0,    /* class_offset */
177                   NULL, /* accumulator */
178                   NULL, /* accumulator data */
179                   NULL, /* marshaller */
180                   G_TYPE_NONE,
181                   0);
182 }
183 
184 ShellPolkitAuthenticationAgent *
185 shell_polkit_authentication_agent_new (void)
186 {
187   return SHELL_POLKIT_AUTHENTICATION_AGENT (g_object_new (SHELL_TYPE_POLKIT_AUTHENTICATION_AGENT, NULL));
188 }
189 
190 struct _AuthRequest {
191   /* not holding ref */
192   ShellPolkitAuthenticationAgent *agent;
193   GCancellable *cancellable;
194   gulong handler_id;
195 
196   /* copies */
197   gchar          *action_id;
198   gchar          *message;
199   gchar          *icon_name;
200   PolkitDetails  *details;
201   gchar          *cookie;
202   GList          *identities;
203 
204   GSimpleAsyncResult *simple;
205 };
206 
207 static void
208 auth_request_free (AuthRequest *request)
209 {
210   g_cancellable_disconnect (request->cancellable, request->handler_id);
211   g_free (request->action_id);
212   g_free (request->message);
213   g_free (request->icon_name);
214   g_object_unref (request->details);
215   g_free (request->cookie);
216   g_list_foreach (request->identities, (GFunc) g_object_unref, NULL);
217   g_list_free (request->identities);
218   g_object_unref (request->simple);
219   g_free (request);
220 }
221 
222 static void
223 auth_request_initiate (AuthRequest *request)
224 {
225   gchar **user_names;
226   GPtrArray *p;
227   GList *l;
228 
229   p = g_ptr_array_new ();
230   for (l = request->identities; l != NULL; l = l->next)
231     {
232       if (POLKIT_IS_UNIX_USER (l->data))
233         {
234           PolkitUnixUser *user = POLKIT_UNIX_USER (l->data);
235           gint uid;
236           gchar buf[4096];
237           struct passwd pwd;
238           struct passwd *ppwd;
239 
240           uid = polkit_unix_user_get_uid (user);
241           if (getpwuid_r (uid, &pwd, buf, sizeof (buf), &ppwd) == 0)
242             {
243               if (!g_utf8_validate (pwd.pw_name, -1, NULL))
244                 {
245                   g_warning ("Invalid UTF-8 in username for uid %d. Skipping", uid);
246                 }
247               else
248                 {
249                   g_ptr_array_add (p, g_strdup (pwd.pw_name));
250                 }
251             }
252           else
253             {
254               g_warning ("Error looking up user name for uid %d", uid);
255             }
256         }
257       else
258         {
259           g_warning ("Unsupporting identity of GType %s", g_type_name (G_TYPE_FROM_INSTANCE (l->data)));
Access to field 'g_class' results in a dereference of a null pointer (loaded from field 'data')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

260 } 261 } 262 g_ptr_array_add (p, NULL); 263 user_names = (gchar **) g_ptr_array_free (p, FALSE); 264 g_signal_emit (request->agent, 265 signals[INITIATE_SIGNAL], 266 0, /* detail */ 267 request->action_id, 268 request->message, 269 request->icon_name, 270 request->cookie, 271 user_names); 272 g_strfreev (user_names); 273 } 274 275 static void auth_request_complete (AuthRequest *request, 276 gboolean dismissed); 277 278 static gboolean 279 handle_cancelled_in_idle (gpointer user_data) 280 { 281 AuthRequest *request = user_data; 282 283 print_debug ("CANCELLED %s cookie %s", request->action_id, request->cookie); 284 if (request == request->agent->current_request) 285 { 286 g_signal_emit (request->agent, 287 signals[CANCEL_SIGNAL], 288 0); /* detail */ 289 } 290 else 291 { 292 auth_request_complete (request, FALSE); 293 } 294 295 return FALSE; 296 } 297 298 static void 299 on_request_cancelled (GCancellable *cancellable, 300 gpointer user_data) 301 { 302 AuthRequest *request = user_data; 303 /* post-pone to idle to handle GCancellable deadlock in 304 * 305 * https://bugzilla.gnome.org/show_bug.cgi?id=642968 306 */ 307 g_idle_add (handle_cancelled_in_idle, request); 308 } 309 310 static void 311 auth_request_dismiss (AuthRequest *request) 312 { 313 auth_request_complete (request, TRUE); 314 } 315 316 void 317 shell_polkit_authentication_agent_unregister (ShellPolkitAuthenticationAgent *agent) 318 { 319 if (agent->scheduled_requests != NULL) 320 { 321 g_list_foreach (agent->scheduled_requests, (GFunc)auth_request_dismiss, NULL); 322 agent->scheduled_requests = NULL; 323 } 324 if (agent->current_request != NULL) 325 auth_request_dismiss (agent->current_request); 326 327 polkit_agent_listener_unregister (agent->handle); 328 agent->handle = NULL; 329 } 330 331 static void maybe_process_next_request (ShellPolkitAuthenticationAgent *agent); 332 333 static void 334 auth_request_complete (AuthRequest *request, 335 gboolean dismissed) 336 { 337 ShellPolkitAuthenticationAgent *agent = request->agent; 338 339 if (dismissed) 340 g_simple_async_result_set_error (request->simple, 341 POLKIT_ERROR, 342 POLKIT_ERROR_CANCELLED, 343 _("Authentication dialog was dismissed by the user")); 344 345 if (agent->current_request == request) 346 { 347 print_debug ("COMPLETING CURRENT %s cookie %s", request->action_id, request->cookie); 348 349 g_simple_async_result_complete_in_idle (request->simple); 350 auth_request_free (request); 351 352 agent->current_request = NULL; 353 354 maybe_process_next_request (agent); 355 } 356 else 357 { 358 print_debug ("COMPLETING SCHEDULED %s cookie %s", request->action_id, request->cookie); 359 agent->scheduled_requests = g_list_remove (agent->scheduled_requests, request); 360 g_simple_async_result_complete_in_idle (request->simple); 361 auth_request_free (request); 362 } 363 } 364 365 static void 366 maybe_process_next_request (ShellPolkitAuthenticationAgent *agent) 367 { 368 print_debug ("MAYBE_PROCESS cur=%p len(scheduled)=%d", agent->current_request, g_list_length (agent->scheduled_requests)); 369 370 if (agent->current_request == NULL && agent->scheduled_requests != NULL) 371 { 372 AuthRequest *request; 373 374 request = agent->scheduled_requests->data; 375 376 agent->current_request = request; 377 agent->scheduled_requests = g_list_remove (agent->scheduled_requests, request); 378 379 print_debug ("INITIATING %s cookie %s", request->action_id, request->cookie); 380 auth_request_initiate (request); 381 } 382 } 383 384 static void 385 initiate_authentication (PolkitAgentListener *listener, 386 const gchar *action_id, 387 const gchar *message, 388 const gchar *icon_name, 389 PolkitDetails *details, 390 const gchar *cookie, 391 GList *identities, 392 GCancellable *cancellable, 393 GAsyncReadyCallback callback, 394 gpointer user_data) 395 { 396 ShellPolkitAuthenticationAgent *agent = SHELL_POLKIT_AUTHENTICATION_AGENT (listener); 397 AuthRequest *request; 398 399 request = g_new0 (AuthRequest, 1); 400 request->agent = agent; 401 request->action_id = g_strdup (action_id); 402 request->message = g_strdup (message); 403 request->icon_name = g_strdup (icon_name); 404 request->details = g_object_ref (details); 405 request->cookie = g_strdup (cookie); 406 request->identities = g_list_copy (identities); 407 g_list_foreach (request->identities, (GFunc) g_object_ref, NULL); 408 request->simple = g_simple_async_result_new (G_OBJECT (listener), 409 callback, 410 user_data, 411 initiate_authentication); 412 request->cancellable = cancellable; 413 request->handler_id = g_cancellable_connect (request->cancellable, 414 G_CALLBACK (on_request_cancelled), 415 request, 416 NULL); /* GDestroyNotify for request */ 417 418 print_debug ("SCHEDULING %s cookie %s", request->action_id, request->cookie); 419 agent->scheduled_requests = g_list_append (agent->scheduled_requests, request); 420 421 maybe_process_next_request (agent); 422 } 423 424 static gboolean 425 initiate_authentication_finish (PolkitAgentListener *listener, 426 GAsyncResult *res, 427 GError **error) 428 { 429 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); 430 if (g_simple_async_result_propagate_error (simple, error)) 431 return FALSE; 432 else 433 return TRUE; 434 } 435 436 void 437 shell_polkit_authentication_agent_complete (ShellPolkitAuthenticationAgent *agent, 438 gboolean dismissed) 439 { 440 g_return_if_fail (SHELL_IS_POLKIT_AUTHENTICATION_AGENT (agent)); 441 g_return_if_fail (agent->current_request != NULL); 442 443 auth_request_complete (agent->current_request, dismissed); 444 }