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