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  */
50 static void
usage(int argc,char * argv[])51 usage (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
76 static void
permission_denied_privilege(const char * privilege,const char * uid)77 permission_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  */
95 int
main(int argc,char * argv[])96 main (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