20
20
*/
21
21
22
22
#include <inttypes.h>
23
+ #include <stdarg.h>
23
24
#include <stdio.h>
24
25
#include <stdlib.h>
25
26
#include <sys/syscall.h>
@@ -135,24 +136,44 @@ static
135
136
#endif
136
137
int protocol_version ;
137
138
138
- static char * remote_domain_name ; // guess what
139
+ static const char * remote_domain_name ; // guess what
140
+ static const char * remote_domain_uuid ;
139
141
static int remote_domain_id ;
140
142
143
+ static void unlink_or_exit (const char * path )
144
+ {
145
+ int v = unlink (path );
146
+ if (v != 0 && !(v == -1 && errno == ENOENT ))
147
+ err (1 , "unlink(%s)" , path );
148
+ }
149
+
150
+ static char __attribute__((format (printf , 1 , 2 ))) * xasprintf (const char * fmt , ...)
151
+ {
152
+ va_list x ;
153
+ char * res ;
154
+ va_start (x , fmt );
155
+ int r = vasprintf (& res , fmt , x );
156
+ va_end (x );
157
+ if (r < 0 )
158
+ abort ();
159
+ return res ;
160
+ }
161
+
141
162
static void unlink_qrexec_socket (void )
142
163
{
143
- char * socket_address ;
144
- char * link_to_socket_name ;
145
-
146
- if ( asprintf ( & socket_address , "%s/qrexec.%d" , socket_dir , remote_domain_id ) < 0 )
147
- err ( 1 , "asprintf" );
148
- if ( unlink ( socket_address ) != 0 && errno != ENOENT )
149
- err ( 1 , "unlink(%s)" , socket_address );
150
- free (socket_address );
151
- if ( asprintf ( & link_to_socket_name , "%s/qrexec.%s" , socket_dir , remote_domain_name ) < 0 )
152
- err ( 1 , "asprintf" );
153
- if ( unlink ( link_to_socket_name ) != 0 && errno != ENOENT )
154
- err ( 1 , "unlink(%s)" , link_to_socket_name );
155
- free (link_to_socket_name );
164
+ char * socket_name ;
165
+ const char * p [ 2 ] = { remote_domain_name , remote_domain_uuid } ;
166
+ int i ;
167
+
168
+ for ( i = 0 ; i < 2 ; ++ i ) {
169
+ char * link_to_socket_name = xasprintf ( "qrexec.%s%s" , i > 0 ? "uuid:" : "" , p [ i ]);
170
+ unlink_or_exit ( link_to_socket_name );
171
+ free (link_to_socket_name );
172
+ }
173
+ if ( asprintf ( & socket_name , "qrexec.%d" , remote_domain_id ) < 0 )
174
+ abort ();
175
+ unlink_or_exit ( socket_name );
176
+ free (socket_name );
156
177
}
157
178
158
179
static void handle_vchan_error (const char * op )
@@ -161,27 +182,25 @@ static void handle_vchan_error(const char *op)
161
182
exit (1 );
162
183
}
163
184
164
-
165
- static int create_qrexec_socket (int domid , const char * domname )
185
+ static int create_qrexec_socket (int domid , const char * domname , const char * domuuid )
166
186
{
167
- char socket_address [40 ];
168
- char * link_to_socket_name ;
169
-
170
- snprintf (socket_address , sizeof (socket_address ),
171
- "%s/qrexec.%d" , socket_dir , domid );
172
- if (asprintf (& link_to_socket_name ,
173
- "%s/qrexec.%s" , socket_dir , domname ) < 0 )
174
- err (1 , "asprintf" );
175
- unlink (link_to_socket_name );
176
-
177
187
/* When running as root, make the socket accessible; perms on /var/run/qubes still apply */
178
188
umask (0 );
179
- if (symlink (socket_address , link_to_socket_name )) {
180
- PERROR ("symlink(%s,%s)" , socket_address , link_to_socket_name );
189
+
190
+ const char * p [2 ] = { domuuid , domname };
191
+ char * socket_address = xasprintf ("qrexec.%d" , domid );
192
+ for (int i = 0 ; i < 2 ; ++ i ) {
193
+ if (p [i ] == NULL )
194
+ continue ;
195
+ char * link_to_socket_name = xasprintf ("qrexec.%s%s" , i ? "" : "uuid:" , p [i ]);
196
+ unlink_or_exit (link_to_socket_name );
197
+ if (symlink (socket_address , link_to_socket_name )) {
198
+ PERROR ("symlink(%s,%s)" , socket_address , link_to_socket_name );
199
+ }
200
+ free (link_to_socket_name );
181
201
}
182
202
int fd = get_server_socket (socket_address );
183
203
umask (0077 );
184
- free (link_to_socket_name );
185
204
return fd ;
186
205
}
187
206
@@ -407,7 +426,7 @@ static void init(int xid, bool opt_direct)
407
426
408
427
atexit (unlink_qrexec_socket );
409
428
qrexec_daemon_unix_socket_fd =
410
- create_qrexec_socket (xid , remote_domain_name );
429
+ create_qrexec_socket (xid , remote_domain_name , remote_domain_uuid );
411
430
412
431
struct sigaction sigchld_action = {
413
432
.sa_handler = signal_handler ,
@@ -856,11 +875,12 @@ static int parse_policy_response(
856
875
size_t result_bytes ,
857
876
bool daemon ,
858
877
char * * user ,
878
+ char * * target_uuid ,
859
879
char * * target ,
860
880
char * * requested_target ,
861
881
int * autostart
862
882
) {
863
- * user = * target = * requested_target = NULL ;
883
+ * user = * target_uuid = * target = * requested_target = NULL ;
864
884
int result = * autostart = -1 ;
865
885
const char * const msg = daemon ? "qrexec-policy-daemon" : "qrexec-policy-exec" ;
866
886
// At least one byte must be returned
@@ -905,6 +925,12 @@ static int parse_policy_response(
905
925
* target = strdup (current_response + (sizeof ("target=" ) - 1 ));
906
926
if (* target == NULL )
907
927
abort ();
928
+ } else if (!strncmp (current_response , "target_uuid=" , sizeof ("target_uuid=" ) - 1 )) {
929
+ if (* target_uuid != NULL )
930
+ goto bad_response ;
931
+ * target_uuid = strdup (current_response + 12 );
932
+ if (* target_uuid == NULL )
933
+ abort ();
908
934
} else if (!strncmp (current_response , "autostart=" , sizeof ("autostart=" ) - 1 )) {
909
935
current_response += sizeof ("autostart=" ) - 1 ;
910
936
if (* autostart != -1 )
@@ -1001,6 +1027,7 @@ static enum policy_response connect_daemon_socket(
1001
1027
const char * target_domain ,
1002
1028
const char * service_name ,
1003
1029
char * * user ,
1030
+ char * * target_uuid ,
1004
1031
char * * target ,
1005
1032
char * * requested_target ,
1006
1033
int * autostart
@@ -1028,7 +1055,7 @@ static enum policy_response connect_daemon_socket(
1028
1055
size_t result_bytes ;
1029
1056
// this closes the socket
1030
1057
char * result = qubes_read_all_to_malloc (daemon_socket , 64 , 4096 , & result_bytes );
1031
- int policy_result = parse_policy_response (result , result_bytes , true, user , target , requested_target , autostart );
1058
+ int policy_result = parse_policy_response (result , result_bytes , true, user , target_uuid , target , requested_target , autostart );
1032
1059
if (policy_result != RESPONSE_MALFORMED ) {
1033
1060
// This leaks 'result', but as the code execs later anyway this isn't a problem.
1034
1061
// 'result' cannot be freed as 'user', 'target', and 'requested_target' point into
@@ -1099,7 +1126,7 @@ static enum policy_response connect_daemon_socket(
1099
1126
// This leaks 'result', but as the code execs later anyway this isn't a problem.
1100
1127
// 'result' cannot be freed as 'user', 'target', and 'requested_target' point into
1101
1128
// the same buffer.
1102
- return parse_policy_response (result , result_bytes , true, user , target , requested_target , autostart );
1129
+ return parse_policy_response (result , result_bytes , true, user , target_uuid , target , requested_target , autostart );
1103
1130
}
1104
1131
}
1105
1132
@@ -1132,11 +1159,11 @@ _Noreturn static void handle_execute_service_child(
1132
1159
for (i = 3 ; i < MAX_FDS ; i ++ )
1133
1160
close (i );
1134
1161
1135
- char * user , * target , * requested_target ;
1136
- int autostart ;
1162
+ char * user = NULL , * target = NULL , * requested_target = NULL , * target_uuid = NULL ;
1163
+ int autostart = -1 ;
1137
1164
int policy_response =
1138
1165
connect_daemon_socket (remote_domain_name , target_domain , service_name ,
1139
- & user , & target , & requested_target , & autostart );
1166
+ & user , & target_uuid , & target , & requested_target , & autostart );
1140
1167
1141
1168
if (policy_response != RESPONSE_ALLOW )
1142
1169
daemon__exit (QREXEC_EXIT_REQUEST_REFUSED );
@@ -1152,8 +1179,7 @@ _Noreturn static void handle_execute_service_child(
1152
1179
const char * const trailer = strchr (service_name , '+' ) ? "" : "+" ;
1153
1180
1154
1181
/* Check if the target is dom0, which requires special handling. */
1155
- bool target_is_dom0 = strcmp (target , "@adminvm" ) == 0 ||
1156
- strcmp (target , "dom0" ) == 0 ;
1182
+ bool target_is_dom0 = target_refers_to_dom0 (target );
1157
1183
if (target_is_dom0 ) {
1158
1184
char * type ;
1159
1185
bool target_is_keyword = target_domain [0 ] == '@' ;
@@ -1178,17 +1204,21 @@ _Noreturn static void handle_execute_service_child(
1178
1204
5 /* 5 second timeout */ ,
1179
1205
false /* return 0 not remote status code */ ));
1180
1206
} else {
1207
+ bool const use_uuid = target_uuid != NULL ;
1208
+ const char * const selected_target = use_uuid ? target_uuid : target ;
1181
1209
int service_length = asprintf (& cmd , "%s:QUBESRPC %s%s %s" ,
1182
1210
user ,
1183
1211
service_name ,
1184
1212
trailer ,
1185
1213
remote_domain_name );
1186
1214
if (service_length < 0 )
1187
1215
daemon__exit (QREXEC_EXIT_PROBLEM );
1188
- daemon__exit (qrexec_execute_vm (target , autostart , remote_domain_id ,
1216
+ daemon__exit (qrexec_execute_vm (selected_target , autostart ,
1217
+ remote_domain_id ,
1189
1218
cmd ,
1190
1219
(size_t )service_length + 1 ,
1191
- request_id -> ident , false, false)
1220
+ request_id -> ident , false, false,
1221
+ use_uuid )
1192
1222
? 0 : QREXEC_EXIT_PROBLEM );
1193
1223
}
1194
1224
}
@@ -1511,7 +1541,7 @@ static int handle_agent_restart(int xid) {
1511
1541
err (1 , "sigaction" );
1512
1542
1513
1543
qrexec_daemon_unix_socket_fd =
1514
- create_qrexec_socket (xid , remote_domain_name );
1544
+ create_qrexec_socket (xid , remote_domain_name , remote_domain_uuid );
1515
1545
return 0 ;
1516
1546
}
1517
1547
@@ -1521,6 +1551,7 @@ static struct option longopts[] = {
1521
1551
{ "socket-dir" , required_argument , 0 , 'd' + 128 },
1522
1552
{ "policy-program" , required_argument , 0 , 'p' },
1523
1553
{ "direct" , no_argument , 0 , 'D' },
1554
+ { "uuid" , required_argument , 0 , 'u' },
1524
1555
{ NULL , 0 , 0 , 0 },
1525
1556
};
1526
1557
@@ -1556,7 +1587,7 @@ int main(int argc, char **argv)
1556
1587
1557
1588
setup_logging ("qrexec-daemon" );
1558
1589
1559
- while ((opt = getopt_long (argc , argv , "hqp:D " , longopts , NULL )) != -1 ) {
1590
+ while ((opt = getopt_long (argc , argv , "hqp:Du: " , longopts , NULL )) != -1 ) {
1560
1591
switch (opt ) {
1561
1592
case 'q' :
1562
1593
opt_quiet = 1 ;
@@ -1572,6 +1603,9 @@ int main(int argc, char **argv)
1572
1603
case 'D' :
1573
1604
opt_direct = 1 ;
1574
1605
break ;
1606
+ case 'u' :
1607
+ remote_domain_uuid = optarg ;
1608
+ break ;
1575
1609
case 'h' :
1576
1610
default : /* '?' */
1577
1611
usage (argv [0 ]);
0 commit comments