~ubuntu-core-dev/ubuntu/raring/upstart/raring

« back to all changes in this revision

Viewing changes to init/control.c

  • Committer: Stéphane Graber
  • Date: 2013-03-07 18:43:01 UTC
  • mfrom: (1182.56.54 upstart)
  • Revision ID: stgraber@ubuntu.com-20130307184301-dlmb1c5bwonqagkw
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 *
3
3
 * control.c - D-Bus connections, objects and methods
4
4
 *
5
 
 * Copyright © 2009-2011 Canonical Ltd.
 
5
 * Copyright  2009-2011 Canonical Ltd.
6
6
 * Author: Scott James Remnant <scott@netsplit.com>.
7
7
 *
8
8
 * This program is free software; you can redistribute it and/or modify
50
50
#include "environ.h"
51
51
#include "session.h"
52
52
#include "job_class.h"
 
53
#include "job.h"
53
54
#include "blocked.h"
54
55
#include "conf.h"
55
56
#include "control.h"
56
57
#include "errors.h"
57
58
#include "state.h"
 
59
#include "event.h"
 
60
#include "events.h"
 
61
#include "paths.h"
 
62
#include "xdg.h"
58
63
 
59
64
#include "com.ubuntu.Upstart.h"
60
65
 
61
66
/* Prototypes for static functions */
62
 
static int   control_server_connect (DBusServer *server, DBusConnection *conn);
63
 
static void  control_disconnected   (DBusConnection *conn);
64
 
static void  control_register_all   (DBusConnection *conn);
 
67
static int   control_server_connect      (DBusServer *server, DBusConnection *conn);
 
68
static void  control_disconnected        (DBusConnection *conn);
 
69
static void  control_register_all        (DBusConnection *conn);
65
70
 
66
 
static void  control_bus_flush      (void);
 
71
static void  control_bus_flush           (void);
 
72
static int   control_get_origin_uid      (NihDBusMessage *message, uid_t *uid)
 
73
        __attribute__ ((warn_unused_result));
 
74
static int   control_check_permission    (NihDBusMessage *message)
 
75
        __attribute__ ((warn_unused_result));
 
76
static void  control_session_file_create (void);
 
77
static void  control_session_file_remove (void);
67
78
 
68
79
/**
69
80
 * use_session_bus:
79
90
 *
80
91
 * Address on which the control server may be reached.
81
92
 **/
82
 
const char *control_server_address = DBUS_ADDRESS_UPSTART;
 
93
char *control_server_address = NULL;
83
94
 
84
95
/**
85
96
 * control_server:
104
115
 **/
105
116
NihList *control_conns = NULL;
106
117
 
 
118
/* External definitions */
 
119
extern int      user_mode;
 
120
extern int      disable_respawn;
 
121
extern char    *session_file;
107
122
 
108
123
/**
109
124
 * control_init:
115
130
{
116
131
        if (! control_conns)
117
132
                control_conns = NIH_MUST (nih_list_new (NULL));
118
 
}
119
 
 
 
133
 
 
134
        if (! control_server_address) {
 
135
                if (user_mode) {
 
136
                        NIH_MUST (nih_strcat_sprintf (&control_server_address, NULL,
 
137
                                            "%s-session/%d/%d", DBUS_ADDRESS_UPSTART, getuid (), getpid ()));
 
138
 
 
139
                        control_session_file_create ();
 
140
                } else {
 
141
                        control_server_address = NIH_MUST (nih_strdup (NULL, DBUS_ADDRESS_UPSTART));
 
142
                }
 
143
        }
 
144
}
 
145
 
 
146
/**
 
147
 * control_cleanup:
 
148
 *
 
149
 * Perform cleanup operations.
 
150
 **/
 
151
void
 
152
control_cleanup (void)
 
153
{
 
154
        control_session_file_remove ();
 
155
}
120
156
 
121
157
/**
122
158
 * control_server_open:
367
403
 * Called to request that Upstart reloads its configuration from disk,
368
404
 * useful when inotify is not available or the user is generally paranoid.
369
405
 *
 
406
 * Notes: chroot sessions are permitted to make this call.
 
407
 *
370
408
 * Returns: zero on success, negative value on raised error.
371
409
 **/
372
410
int
375
413
{
376
414
        nih_assert (message != NULL);
377
415
 
 
416
        if (! control_check_permission (message)) {
 
417
                nih_dbus_error_raise_printf (
 
418
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
419
                        _("You do not have permission to reload configuration"));
 
420
                return -1;
 
421
        }
 
422
 
378
423
        nih_info (_("Reloading configuration"));
379
424
 
380
425
        /* This can only be called after deserialisation */
563
608
                              int              wait,
564
609
                              int              file)
565
610
{
566
 
        Event   *event;
567
 
        Blocked *blocked;
 
611
        Event    *event;
 
612
        Blocked  *blocked;
568
613
 
569
614
        nih_assert (message != NULL);
570
615
        nih_assert (name != NULL);
571
616
        nih_assert (env != NULL);
572
617
 
 
618
        if (! control_check_permission (message)) {
 
619
                nih_dbus_error_raise_printf (
 
620
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
621
                        _("You do not have permission to emit an event"));
 
622
                return -1;
 
623
        }
 
624
 
573
625
        /* Verify that the name is valid */
574
626
        if (! strlen (name)) {
575
627
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
730
782
        nih_assert (message != NULL);
731
783
        nih_assert (log_priority != NULL);
732
784
 
 
785
        if (! control_check_permission (message)) {
 
786
                nih_dbus_error_raise_printf (
 
787
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
788
                        _("You do not have permission to set log priority"));
 
789
                return -1;
 
790
        }
 
791
 
733
792
        if (! strcmp (log_priority, "debug")) {
734
793
                nih_log_set_priority (NIH_LOG_DEBUG);
735
794
 
782
841
 * Called to flush the job logs for all jobs that ended before the log
783
842
 * disk became writeable.
784
843
 *
 
844
 * Notes: Session Inits are permitted to make this call. In the common
 
845
 * case of starting a Session Init as a child of a Display Manager this
 
846
 * is somewhat meaningless, but it does mean that if a Session Init were
 
847
 * started from a system job, behaviour would be as expected.
 
848
 *
785
849
 * Returns: zero on success, negative value on raised error.
786
850
 **/
787
851
int
793
857
 
794
858
        nih_assert (message != NULL);
795
859
 
796
 
        /* Get the relevant session */
797
 
        session = session_from_dbus (NULL, message);
798
 
 
799
 
        if (session && session->user) {
 
860
        if (! control_check_permission (message)) {
800
861
                nih_dbus_error_raise_printf (
801
862
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
802
863
                        _("You do not have permission to notify disk is writeable"));
803
864
                return -1;
804
865
        }
805
866
 
 
867
        /* Get the relevant session */
 
868
        session = session_from_dbus (NULL, message);
 
869
 
806
870
        /* "nop" when run from a chroot */
807
871
        if (session && session->chroot)
808
872
                return 0;
967
1031
                   char           **state)
968
1032
{
969
1033
        Session  *session;
970
 
        uid_t     uid;
971
1034
        size_t    len;
972
1035
 
973
1036
        nih_assert (message);
974
1037
        nih_assert (state);
975
1038
 
976
 
        uid = getuid ();
 
1039
        if (! control_check_permission (message)) {
 
1040
                nih_dbus_error_raise_printf (
 
1041
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1042
                        _("You do not have permission to request state"));
 
1043
                return -1;
 
1044
        }
977
1045
 
978
1046
        /* Get the relevant session */
979
1047
        session = session_from_dbus (NULL, message);
988
1056
                return 0;
989
1057
        }
990
1058
 
991
 
        /* Disallow users from obtaining state details, unless they
992
 
         * happen to own this process (which they may do in the test
993
 
         * scenario and when running Upstart as a non-privileged user).
994
 
         */
995
 
        if (session && session->user != uid) {
996
 
                nih_dbus_error_raise_printf (
997
 
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
998
 
                        _("You do not have permission to request state"));
999
 
                return -1;
1000
 
        }
1001
 
 
1002
1059
        if (state_to_string (state, &len) < 0)
1003
1060
                goto error;
1004
1061
 
1030
1087
                 NihDBusMessage *message)
1031
1088
{
1032
1089
        Session  *session;
1033
 
        uid_t     uid;
1034
1090
 
1035
1091
        nih_assert (message != NULL);
1036
1092
 
1037
 
        uid = getuid ();
 
1093
        if (! control_check_permission (message)) {
 
1094
                nih_dbus_error_raise_printf (
 
1095
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1096
                        _("You do not have permission to request restart"));
 
1097
                return -1;
 
1098
        }
1038
1099
 
1039
1100
        /* Get the relevant session */
1040
1101
        session = session_from_dbus (NULL, message);
1050
1111
                return 0;
1051
1112
        }
1052
1113
 
1053
 
        /* Disallow users from restarting Upstart, unless they happen to
1054
 
         * own this process (which they may do in the test scenario and
1055
 
         * when running Upstart as a non-privileged user).
1056
 
         */
1057
 
        if (session && session->user != uid) {
1058
 
                nih_dbus_error_raise_printf (
1059
 
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
1060
 
                        _("You do not have permission to request restart"));
1061
 
                return -1;
1062
 
        }
1063
 
 
1064
1114
        nih_info (_("Restarting"));
1065
1115
 
1066
1116
        stateful_reexec ();
1067
1117
 
1068
1118
        return 0;
1069
1119
}
 
1120
 
 
1121
/**
 
1122
 * control_notify_event_emitted
 
1123
 *
 
1124
 * Re-emits an event over DBUS using the EventEmitted signal
 
1125
 **/
 
1126
void
 
1127
control_notify_event_emitted (Event *event)
 
1128
{
 
1129
        nih_assert (event != NULL);
 
1130
 
 
1131
        control_init ();
 
1132
 
 
1133
        NIH_LIST_FOREACH (control_conns, iter) {
 
1134
                NihListEntry   *entry = (NihListEntry *)iter;
 
1135
                DBusConnection *conn = (DBusConnection *)entry->data;
 
1136
 
 
1137
                NIH_ZERO (control_emit_event_emitted (conn, DBUS_PATH_UPSTART,
 
1138
                                                            event->name, event->env));
 
1139
        }
 
1140
}
 
1141
 
 
1142
/**
 
1143
 * control_notify_restarted
 
1144
 *
 
1145
 * DBUS signal sent when upstart has re-executed itself.
 
1146
 **/
 
1147
void
 
1148
control_notify_restarted (void)
 
1149
{
 
1150
        control_init ();
 
1151
 
 
1152
        NIH_LIST_FOREACH (control_conns, iter) {
 
1153
                NihListEntry   *entry = (NihListEntry *)iter;
 
1154
                DBusConnection *conn = (DBusConnection *)entry->data;
 
1155
 
 
1156
                NIH_ZERO (control_emit_restarted (conn, DBUS_PATH_UPSTART));
 
1157
        }
 
1158
}
 
1159
 
 
1160
/**
 
1161
 * control_set_env:
 
1162
 *
 
1163
 * @data: not used,
 
1164
 * @message: D-Bus connection and message received,
 
1165
 * @job_details: name and instance of job to apply operation to,
 
1166
 * @var: name[/value] pair of environment variable to set,
 
1167
 * @replace: TRUE if @name should be overwritten if already set, else
 
1168
 *  FALSE.
 
1169
 *
 
1170
 * Implements the SetEnv method of the com.ubuntu.Upstart
 
1171
 * interface.
 
1172
 *
 
1173
 * Called to request Upstart store a particular name/value pair.
 
1174
 *
 
1175
 * If @job_details is empty, change will be applied to all job
 
1176
 * environments, else only apply changes to specific job environment
 
1177
 * encoded within @job_details.
 
1178
 *
 
1179
 * Returns: zero on success, negative value on raised error.
 
1180
 **/
 
1181
int
 
1182
control_set_env (void            *data,
 
1183
                 NihDBusMessage  *message,
 
1184
                 char * const    *job_details,
 
1185
                 const char      *var,
 
1186
                 int              replace)
 
1187
{
 
1188
        Session         *session;
 
1189
        Job             *job = NULL;
 
1190
        char            *job_name = NULL;
 
1191
        char            *instance = NULL;
 
1192
        nih_local char  *envvar = NULL;
 
1193
 
 
1194
        nih_assert (message);
 
1195
        nih_assert (job_details);
 
1196
        nih_assert (var);
 
1197
 
 
1198
        if (job_details[0]) {
 
1199
                job_name = job_details[0];
 
1200
 
 
1201
                /* this can be a null value */
 
1202
                instance = job_details[1];
 
1203
        } else if (getpid () == 1) {
 
1204
                nih_dbus_error_raise_printf (
 
1205
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1206
                        _("Not permissible to modify PID 1 job environment"));
 
1207
                return -1;
 
1208
        }
 
1209
 
 
1210
        if (! control_check_permission (message)) {
 
1211
                nih_dbus_error_raise_printf (
 
1212
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1213
                        _("You do not have permission to modify job environment"));
 
1214
                return -1;
 
1215
        }
 
1216
 
 
1217
        /* Verify that job name is valid */
 
1218
        if (job_name && ! strlen (job_name)) {
 
1219
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1220
                                             _("Job may not be empty string"));
 
1221
                return -1;
 
1222
        }
 
1223
 
 
1224
        /* Get the relevant session */
 
1225
        session = session_from_dbus (NULL, message);
 
1226
 
 
1227
        /* Chroot sessions must not be able to influence
 
1228
         * the outside system.
 
1229
         */
 
1230
        if (session && session->chroot) {
 
1231
                nih_warn (_("Ignoring set env request from chroot session"));
 
1232
                return 0;
 
1233
        }
 
1234
 
 
1235
        /* Lookup the job */
 
1236
        control_get_job (session, job, job_name, instance);
 
1237
 
 
1238
        /* If variable does not contain a delimiter, add one to ensure
 
1239
         * it gets entered into the job environment table. Without the
 
1240
         * delimiter, the variable will be silently ignored unless it's
 
1241
         * already set in inits environment. But in that case there is
 
1242
         * no point in setting such a variable to its already existing
 
1243
         * value.
 
1244
         */
 
1245
        if (! strchr (var, '='))
 
1246
                envvar = NIH_MUST (nih_sprintf (NULL, "%s=", var));
 
1247
        else
 
1248
                envvar = NIH_MUST (nih_strdup (NULL, var));
 
1249
 
 
1250
        if (job) {
 
1251
                /* Modify job-specific environment */
 
1252
 
 
1253
                nih_assert (job->env);
 
1254
 
 
1255
                NIH_MUST (environ_add (&job->env, job, NULL, replace, envvar));
 
1256
                return 0;
 
1257
        }
 
1258
 
 
1259
        if (job_class_environment_set (envvar, replace) < 0)
 
1260
                nih_return_no_memory_error (-1);
 
1261
 
 
1262
        return 0;
 
1263
}
 
1264
 
 
1265
/**
 
1266
 * control_unset_env:
 
1267
 *
 
1268
 * @data: not used,
 
1269
 * @message: D-Bus connection and message received,
 
1270
 * @job_details: name and instance of job to apply operation to,
 
1271
 * @name: variable to clear from the job environment array.
 
1272
 *
 
1273
 * Implements the UnsetEnv method of the com.ubuntu.Upstart
 
1274
 * interface.
 
1275
 *
 
1276
 * Called to request Upstart remove a particular variable from the job
 
1277
 * environment array.
 
1278
 *
 
1279
 * Returns: zero on success, negative value on raised error.
 
1280
 **/
 
1281
int
 
1282
control_unset_env (void            *data,
 
1283
                   NihDBusMessage  *message,
 
1284
                   char * const    *job_details,
 
1285
                   const char      *name)
 
1286
{
 
1287
        Session         *session;
 
1288
        Job             *job = NULL;
 
1289
        char            *job_name = NULL;
 
1290
        char            *instance = NULL;
 
1291
 
 
1292
        nih_assert (message);
 
1293
        nih_assert (job_details);
 
1294
        nih_assert (name);
 
1295
 
 
1296
        if (! control_check_permission (message)) {
 
1297
                nih_dbus_error_raise_printf (
 
1298
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1299
                        _("You do not have permission to modify job environment"));
 
1300
                return -1;
 
1301
        }
 
1302
 
 
1303
        if (job_details[0]) {
 
1304
                job_name = job_details[0];
 
1305
 
 
1306
                /* this can be a null value */
 
1307
                instance = job_details[1];
 
1308
        } else if (getpid () == 1) {
 
1309
                nih_dbus_error_raise_printf (
 
1310
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1311
                        _("Not permissible to modify PID 1 job environment"));
 
1312
                return -1;
 
1313
        }
 
1314
 
 
1315
        /* Verify that job name is valid */
 
1316
        if (job_name && ! strlen (job_name)) {
 
1317
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1318
                                             _("Job may not be empty string"));
 
1319
                return -1;
 
1320
        }
 
1321
 
 
1322
        /* Get the relevant session */
 
1323
        session = session_from_dbus (NULL, message);
 
1324
 
 
1325
        /* Chroot sessions must not be able to influence
 
1326
         * the outside system.
 
1327
         */
 
1328
        if (session && session->chroot) {
 
1329
                nih_warn (_("Ignoring unset env request from chroot session"));
 
1330
                return 0;
 
1331
        }
 
1332
 
 
1333
        /* Lookup the job */
 
1334
        control_get_job (session, job, job_name, instance);
 
1335
 
 
1336
        if (job) {
 
1337
                /* Modify job-specific environment */
 
1338
 
 
1339
                nih_assert (job->env);
 
1340
 
 
1341
                if (! environ_remove (&job->env, job, NULL, name))
 
1342
                        return -1;
 
1343
 
 
1344
                return 0;
 
1345
        }
 
1346
 
 
1347
        if (job_class_environment_unset (name) < 0)
 
1348
                goto error;
 
1349
 
 
1350
        return 0;
 
1351
 
 
1352
error:
 
1353
        nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1354
                        "%s: %s",
 
1355
                        _("No such variable"), name);
 
1356
        return -1;
 
1357
}
 
1358
 
 
1359
/**
 
1360
 * control_get_env:
 
1361
 *
 
1362
 * @data: not used,
 
1363
 * @message: D-Bus connection and message received,
 
1364
 * @job_details: name and instance of job to apply operation to,
 
1365
 * @name: name of environment variable to retrieve,
 
1366
 * @value: value of @name.
 
1367
 *
 
1368
 * Implements the GetEnv method of the com.ubuntu.Upstart
 
1369
 * interface.
 
1370
 *
 
1371
 * Called to obtain the value of a specified job environment variable.
 
1372
 *
 
1373
 * Returns: zero on success, negative value on raised error.
 
1374
 **/
 
1375
int
 
1376
control_get_env (void             *data,
 
1377
                 NihDBusMessage   *message,
 
1378
                 char * const     *job_details,
 
1379
                 const char       *name,
 
1380
                 char            **value)
 
1381
{
 
1382
        Session     *session;
 
1383
        const char  *tmp;
 
1384
        Job         *job = NULL;
 
1385
        char        *job_name = NULL;
 
1386
        char        *instance = NULL;
 
1387
 
 
1388
        nih_assert (message != NULL);
 
1389
        nih_assert (job_details);
 
1390
 
 
1391
        if (! control_check_permission (message)) {
 
1392
                nih_dbus_error_raise_printf (
 
1393
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1394
                        _("You do not have permission to query job environment"));
 
1395
                return -1;
 
1396
        }
 
1397
 
 
1398
        if (job_details[0]) {
 
1399
                job_name = job_details[0];
 
1400
 
 
1401
                /* this can be a null value */
 
1402
                instance = job_details[1];
 
1403
        }
 
1404
 
 
1405
        /* Verify that job name is valid */
 
1406
        if (job_name && ! strlen (job_name)) {
 
1407
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1408
                                             _("Job may not be empty string"));
 
1409
                return -1;
 
1410
        }
 
1411
 
 
1412
        /* Get the relevant session */
 
1413
        session = session_from_dbus (NULL, message);
 
1414
 
 
1415
        /* Chroot sessions must not be able to influence
 
1416
         * the outside system.
 
1417
         */
 
1418
        if (session && session->chroot) {
 
1419
                nih_warn (_("Ignoring get env request from chroot session"));
 
1420
                return 0;
 
1421
        }
 
1422
 
 
1423
        /* Lookup the job */
 
1424
        control_get_job (session, job, job_name, instance);
 
1425
 
 
1426
        if (job) {
 
1427
                tmp = environ_get (job->env, name);
 
1428
                if (! tmp)
 
1429
                        goto error;
 
1430
 
 
1431
                *value = nih_strdup (message, tmp);
 
1432
                if (! *value)
 
1433
                        nih_return_no_memory_error (-1);
 
1434
 
 
1435
                return 0;
 
1436
        }
 
1437
 
 
1438
        tmp = job_class_environment_get (name);
 
1439
 
 
1440
        if (! tmp)
 
1441
                goto error;
 
1442
 
 
1443
        *value = nih_strdup (message, tmp);
 
1444
        if (! *value)
 
1445
                nih_return_no_memory_error (-1);
 
1446
 
 
1447
        return 0;
 
1448
 
 
1449
error:
 
1450
        nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1451
                        "%s: %s",
 
1452
                        _("No such variable"), name);
 
1453
        return -1;
 
1454
}
 
1455
 
 
1456
/**
 
1457
 * control_list_env:
 
1458
 *
 
1459
 * @data: not used,
 
1460
 * @message: D-Bus connection and message received,
 
1461
 * @job_details: name and instance of job to apply operation to,
 
1462
 * @env: pointer to array of all job environment variables.
 
1463
 *
 
1464
 * Implements the ListEnv method of the com.ubuntu.Upstart
 
1465
 * interface.
 
1466
 *
 
1467
 * Called to obtain an unsorted array of all environment variables
 
1468
 * that will be set in a jobs environment.
 
1469
 *
 
1470
 * Returns: zero on success, negative value on raised error.
 
1471
 **/
 
1472
int
 
1473
control_list_env (void             *data,
 
1474
                 NihDBusMessage    *message,
 
1475
                 char * const      *job_details,
 
1476
                 char            ***env)
 
1477
{
 
1478
        Session   *session;
 
1479
        Job       *job = NULL;
 
1480
        char      *job_name = NULL;
 
1481
        char      *instance = NULL;
 
1482
 
 
1483
        nih_assert (message);
 
1484
        nih_assert (job_details);
 
1485
        nih_assert (env);
 
1486
 
 
1487
        if (! control_check_permission (message)) {
 
1488
                nih_dbus_error_raise_printf (
 
1489
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1490
                        _("You do not have permission to query job environment"));
 
1491
                return -1;
 
1492
        }
 
1493
 
 
1494
        if (job_details[0]) {
 
1495
                job_name = job_details[0];
 
1496
 
 
1497
                /* this can be a null value */
 
1498
                instance = job_details[1];
 
1499
        }
 
1500
 
 
1501
        /* Verify that job name is valid */
 
1502
        if (job_name && ! strlen (job_name)) {
 
1503
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1504
                                             _("Job may not be empty string"));
 
1505
                return -1;
 
1506
        }
 
1507
 
 
1508
        /* Get the relevant session */
 
1509
        session = session_from_dbus (NULL, message);
 
1510
 
 
1511
        /* Lookup the job */
 
1512
        control_get_job (session, job, job_name, instance);
 
1513
 
 
1514
        if (job) {
 
1515
                *env = nih_str_array_copy (job, NULL, job->env);
 
1516
                if (! *env)
 
1517
                        nih_return_no_memory_error (-1);
 
1518
 
 
1519
                return 0;
 
1520
        }
 
1521
 
 
1522
        *env = job_class_environment_get_all (message);
 
1523
        if (! *env)
 
1524
                nih_return_no_memory_error (-1);
 
1525
 
 
1526
        return 0;
 
1527
}
 
1528
 
 
1529
/**
 
1530
 * control_reset_env:
 
1531
 *
 
1532
 * @data: not used,
 
1533
 * @message: D-Bus connection and message received,
 
1534
 * @job_details: name and instance of job to apply operation to.
 
1535
 *
 
1536
 * Implements the ResetEnv method of the com.ubuntu.Upstart
 
1537
 * interface.
 
1538
 *
 
1539
 * Called to reset the environment all subsequent jobs will run in to
 
1540
 * the default minimal environment.
 
1541
 *
 
1542
 * Returns: zero on success, negative value on raised error.
 
1543
 **/
 
1544
int
 
1545
control_reset_env (void           *data,
 
1546
                 NihDBusMessage   *message,
 
1547
                 char * const    *job_details)
 
1548
{
 
1549
        Session    *session;
 
1550
        Job        *job = NULL;
 
1551
        char       *job_name = NULL;
 
1552
        char       *instance = NULL;
 
1553
 
 
1554
        nih_assert (message);
 
1555
        nih_assert (job_details);
 
1556
 
 
1557
        if (job_details[0]) {
 
1558
                job_name = job_details[0];
 
1559
 
 
1560
                /* this can be a null value */
 
1561
                instance = job_details[1];
 
1562
        } else if (getpid () == 1) {
 
1563
                nih_dbus_error_raise_printf (
 
1564
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1565
                        _("Not permissible to modify PID 1 job environment"));
 
1566
                return -1;
 
1567
        }
 
1568
 
 
1569
        if (! control_check_permission (message)) {
 
1570
                nih_dbus_error_raise_printf (
 
1571
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1572
                        _("You do not have permission to modify job environment"));
 
1573
                return -1;
 
1574
        }
 
1575
 
 
1576
        /* Verify that job name is valid */
 
1577
        if (job_name && ! strlen (job_name)) {
 
1578
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1579
                                             _("Job may not be empty string"));
 
1580
                return -1;
 
1581
        }
 
1582
 
 
1583
        /* Get the relevant session */
 
1584
        session = session_from_dbus (NULL, message);
 
1585
 
 
1586
        /* Chroot sessions must not be able to influence
 
1587
         * the outside system.
 
1588
         */
 
1589
        if (session && session->chroot) {
 
1590
                nih_warn (_("Ignoring reset env request from chroot session"));
 
1591
                return 0;
 
1592
        }
 
1593
 
 
1594
        /* Lookup the job */
 
1595
        control_get_job (session, job, job_name, instance);
 
1596
 
 
1597
 
 
1598
        if (job) {
 
1599
                size_t len;
 
1600
                if (job->env) {
 
1601
                        nih_free (job->env);
 
1602
                        job->env = NULL;
 
1603
                }
 
1604
 
 
1605
                job->env = job_class_environment (job, job->class, &len);
 
1606
                if (! job->env)
 
1607
                        nih_return_system_error (-1);
 
1608
 
 
1609
                return 0;
 
1610
        }
 
1611
 
 
1612
        job_class_environment_reset ();
 
1613
 
 
1614
        return 0;
 
1615
}
 
1616
 
 
1617
/**
 
1618
 * control_get_origin_uid:
 
1619
 * @message: D-Bus connection and message received,
 
1620
 * @uid: returned uid value.
 
1621
 *
 
1622
 * Returns TRUE: if @uid now contains uid corresponding to @message,
 
1623
 * else FALSE.
 
1624
 **/
 
1625
static int
 
1626
control_get_origin_uid (NihDBusMessage *message, uid_t *uid)
 
1627
{
 
1628
        DBusError       dbus_error;
 
1629
        unsigned long   unix_user = 0;
 
1630
        const char     *sender;
 
1631
 
 
1632
        nih_assert (message);
 
1633
        nih_assert (uid);
 
1634
 
 
1635
        dbus_error_init (&dbus_error);
 
1636
 
 
1637
        if (! message->message || ! message->connection)
 
1638
                return FALSE;
 
1639
 
 
1640
        sender = dbus_message_get_sender (message->message);
 
1641
        if (sender) {
 
1642
                unix_user = dbus_bus_get_unix_user (message->connection, sender,
 
1643
                                                    &dbus_error);
 
1644
                if (unix_user == (unsigned long)-1) {
 
1645
                        dbus_error_free (&dbus_error);
 
1646
                        return FALSE;
 
1647
                }
 
1648
        } else {
 
1649
                if (! dbus_connection_get_unix_user (message->connection,
 
1650
                                                     &unix_user)) {
 
1651
                        return FALSE;
 
1652
                }
 
1653
        }
 
1654
 
 
1655
        *uid = (uid_t)unix_user;
 
1656
 
 
1657
        return TRUE;
 
1658
}
 
1659
 
 
1660
/**
 
1661
 * control_check_permission:
 
1662
 *
 
1663
 * @message: D-Bus connection and message received.
 
1664
 *
 
1665
 * Determine if caller should be allowed to make a control request.
 
1666
 *
 
1667
 * Note that these permission checks rely on D-Bus to limit
 
1668
 * session bus access to the same user.
 
1669
 *
 
1670
 * Returns: TRUE if permission is granted, else FALSE.
 
1671
 **/
 
1672
static int
 
1673
control_check_permission (NihDBusMessage *message)
 
1674
{
 
1675
        int    ret;
 
1676
        uid_t  uid;
 
1677
        pid_t  pid;
 
1678
        uid_t  origin_uid = 0;
 
1679
 
 
1680
        nih_assert (message);
 
1681
 
 
1682
        uid = getuid ();
 
1683
        pid = getpid ();
 
1684
 
 
1685
        ret = control_get_origin_uid (message, &origin_uid);
 
1686
 
 
1687
        /* Its possible that D-Bus might be unable to determine the user
 
1688
         * making the request. In this case, deny the request unless
 
1689
         * we're running as a Session Init or via the test harness.
 
1690
         */
 
1691
        if ((ret && origin_uid == uid) || user_mode || (uid && pid != 1))
 
1692
                return TRUE;
 
1693
 
 
1694
        return FALSE;
 
1695
}
 
1696
 
 
1697
/**
 
1698
 * control_session_file_create:
 
1699
 *
 
1700
 * Create session file if possible.
 
1701
 *
 
1702
 * Errors are not fatal - the file is just not created.
 
1703
 **/
 
1704
static void
 
1705
control_session_file_create (void)
 
1706
{
 
1707
        nih_local char *session_dir = NULL;
 
1708
        FILE           *f;
 
1709
        int             ret;
 
1710
 
 
1711
        nih_assert (control_server_address);
 
1712
 
 
1713
        session_dir = get_session_dir ();
 
1714
 
 
1715
        if (! session_dir)
 
1716
                return;
 
1717
 
 
1718
        NIH_MUST (nih_strcat_sprintf (&session_file, NULL, "%s/%d%s",
 
1719
                                session_dir, (int)getpid (), SESSION_EXT));
 
1720
 
 
1721
        f = fopen (session_file, "w");
 
1722
        if (! f) {
 
1723
                nih_error ("%s: %s", _("unable to create session file"), session_file);
 
1724
                return;
 
1725
        }
 
1726
 
 
1727
        ret = fprintf (f, SESSION_ENV "=%s\n", control_server_address);
 
1728
 
 
1729
        if (ret < 0)
 
1730
                nih_error ("%s: %s", _("unable to write session file"), session_file);
 
1731
 
 
1732
        fclose (f);
 
1733
}
 
1734
 
 
1735
/**
 
1736
 * control_session_file_remove:
 
1737
 *
 
1738
 * Delete session file.
 
1739
 *
 
1740
 * Errors are not fatal.
 
1741
 **/
 
1742
static void
 
1743
control_session_file_remove (void)
 
1744
{
 
1745
        if (session_file)
 
1746
                (void)unlink (session_file);
 
1747
}
 
1748
 
 
1749
/**
 
1750
 * control_session_end:
 
1751
 *
 
1752
 * @data: not used,
 
1753
 * @message: D-Bus connection and message received.
 
1754
 *
 
1755
 * Implements the EndSession method of the com.ubuntu.Upstart
 
1756
 * interface.
 
1757
 *
 
1758
 * Called to request that Upstart stop all jobs and exit. Only
 
1759
 * appropriate when running as a Session Init and user wishes to
 
1760
 * 'logout'.
 
1761
 *
 
1762
 * Returns: zero on success, negative value on raised error.
 
1763
 **/
 
1764
int
 
1765
control_end_session (void             *data,
 
1766
                     NihDBusMessage   *message)
 
1767
{
 
1768
        Session  *session;
 
1769
 
 
1770
        nih_assert (message);
 
1771
 
 
1772
        /* Not supported at the system level */
 
1773
        if (getpid () == 1)
 
1774
                return 0;
 
1775
 
 
1776
        if (! control_check_permission (message)) {
 
1777
                nih_dbus_error_raise_printf (
 
1778
                        DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
 
1779
                        _("You do not have permission to end session"));
 
1780
                return -1;
 
1781
        }
 
1782
 
 
1783
        /* Get the relevant session */
 
1784
        session = session_from_dbus (NULL, message);
 
1785
 
 
1786
        if (session && session->chroot) {
 
1787
                nih_warn (_("Ignoring session end request from chroot session"));
 
1788
                return 0;
 
1789
        }
 
1790
 
 
1791
        quiesce (QUIESCE_REQUESTER_SESSION);
 
1792
 
 
1793
        return 0;
 
1794
}