1/***************************************************************************
2 * CVSID: $Id$
3 *
4 * hal-is-caller-privileged.c : Determine if a caller is privileged
5 *
6 * Copyright (C) 2007 David Zeuthen, <david@fubar.dk>
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23 *
24 **************************************************************************/
25
26
27#ifdef HAVE_CONFIG_H
28#  include <config.h>
29#endif
30
31#include <stdio.h>
32#include <string.h>
33#include <unistd.h>
34#include <getopt.h>
35#include <glib.h>
36#include <stdlib.h>
37
38#include <libhal.h>
39#ifdef HAVE_POLKIT
40#include <libpolkit.h>
41#endif
42
43/**
44 *  usage:
45 *  @argc:                Number of arguments given to program
46 *  @argv:                Arguments given to program
47 *
48 *  Print out program usage.
49 */
50static void
51usage (int argc, char *argv[])
52{
53	fprintf (stderr,
54                 "\n"
55                 "usage : hal-is-caller-privileged --udi <udi> --action <action>\n"
56                 "                                 --caller <caller-name>\n"
57                 "                                 [--help] [--version]\n");
58	fprintf (stderr,
59                 "\n"
60                 "        --udi            Unique Device Id\n"
61                 "        --action         PolicyKit action to check for\n"
62                 "        --caller         The name of the caller\n"
63                 "        --version        Show version and exit\n"
64                 "        --help           Show this information and exit\n"
65                 "\n"
66                 "This program determines if a given process on the system bus is\n"
67                 "privileged for a given PolicyKit action for a given device. If an error\n"
68                 "occurs this program exits with a non-zero exit code. Otherwise\n"
69                 "the textual reply will be printed on stdout and this program will\n"
70                 "exit with exit code 0. Note that only the super user (root)\n"
71                 "or other privileged users can use this tool.\n"
72                 "\n");
73}
74
75#ifdef HAVE_POLKIT
76static void
77permission_denied_privilege (const char *privilege, const char *uid)
78{
79        fprintf (stderr, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy\n"
80);
81        fprintf (stderr, "%s refused uid %s\n", privilege, uid);
82        exit (1);
83}
84#endif
85
86/**
87 *  main:
88 *  @argc:                Number of arguments given to program
89 *  @argv:                Arguments given to program
90 *
91 *  Returns:              Return code
92 *
93 *  Main entry point
94 */
95int
96main (int argc, char *argv[])
97{
98	char *udi = NULL;
99	char *action = NULL;
100	char *caller = NULL;
101        dbus_bool_t is_version = FALSE;
102	DBusError error;
103#ifdef HAVE_POLKIT
104	LibPolKitContext *pol_ctx = NULL;
105#endif
106	DBusConnection *system_bus = NULL;
107	uid_t calling_uid;
108	char *privilege = NULL;
109	const char *invoked_by_uid;
110	gboolean allowed_by_privilege = FALSE;
111        gboolean is_temporary_privilege;
112
113	if (argc <= 1) {
114		usage (argc, argv);
115		return 1;
116	}
117
118	while (1) {
119		int c;
120		int option_index = 0;
121		const char *opt;
122		static struct option long_options[] = {
123			{"udi", 1, NULL, 0},
124			{"action", 1, NULL, 0},
125			{"caller", 1, NULL, 0},
126			{"version", 0, NULL, 0},
127			{"help", 0, NULL, 0},
128			{NULL, 0, NULL, 0}
129		};
130
131		c = getopt_long (argc, argv, "",
132				 long_options, &option_index);
133		if (c == -1)
134			break;
135
136		switch (c) {
137		case 0:
138			opt = long_options[option_index].name;
139
140			if (strcmp (opt, "help") == 0) {
141				usage (argc, argv);
142				return 0;
143			} else if (strcmp (opt, "version") == 0) {
144				is_version = TRUE;
145			} else if (strcmp (opt, "udi") == 0) {
146				udi = strdup (optarg);
147			} else if (strcmp (opt, "caller") == 0) {
148				caller = strdup (optarg);
149			} else if (strcmp (opt, "action") == 0) {
150				privilege = strdup (optarg);
151			}
152			break;
153
154		default:
155			usage (argc, argv);
156			return 1;
157			break;
158		}
159	}
160
161	if (is_version) {
162		printf ("hal-is-caller-privileged " PACKAGE_VERSION "\n");
163		return 0;
164	}
165
166	if (udi == NULL || caller == NULL || privilege == NULL) {
167		usage (argc, argv);
168		return 1;
169	}
170
171	dbus_error_init (&error);
172        system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
173        if (system_bus == NULL) {
174                printf ("Cannot connect to the system bus\n");
175                LIBHAL_FREE_DBUS_ERROR (&error);
176		fprintf (stderr, "This program should only be started by hald.\n");
177		exit (1);
178        }
179
180#ifdef HAVE_POLKIT
181	pol_ctx = libpolkit_new_context (system_bus);
182        if (pol_ctx == NULL) {
183                printf ("Cannot get libpolkit context\n");
184        }
185	invoked_by_uid = getenv("HAL_METHOD_INVOKED_BY_UID");
186
187        if (libpolkit_is_uid_allowed_for_privilege (pol_ctx,
188						    caller,
189                                                    invoked_by_uid,
190                                                    privilege,
191                                                    udi,
192                                                    &allowed_by_privilege,
193                                                    &is_temporary_privilege,
194                                                    NULL) != LIBPOLKIT_RESULT_OK
195) {
196                printf ("cannot lookup privilege\n");
197                fprintf (stderr, "Cannot lookup privilege from PolicyKit");
198		exit (1);
199        }
200
201        if (!allowed_by_privilege) {
202                printf ("caller don't possess privilege\n");
203                permission_denied_privilege (privilege, invoked_by_uid);
204        }
205#endif
206
207	printf("yes\n");
208        return 0;
209}
210