~ubuntu-branches/ubuntu/trusty/cgmanager/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/0002-implement-list_children.patch/frontend.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2014-02-27 16:51:30 UTC
  • Revision ID: package-import@ubuntu.com-20140227165130-lnj1mj2kigy2kjvy
Tags: 0.20-0ubuntu3
Implement ListChildren method to list child cgroups (LP: #1285900)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* frontend.h: definitions of the dbus and scm-enhanced dbus
 
2
 *             frontend routines.
 
3
 *
 
4
 * Copyright © 2013 Stphane Graber
 
5
 * Author: Stphane Graber <stgraber@ubuntu.com>
 
6
 * Copyright © 2014 Canonical Group Limited
 
7
 * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License version 2, as
 
11
 * published by the Free Software Foundation.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License along
 
19
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
20
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
21
 */
 
22
 
 
23
#define __frontend_c
 
24
#include <frontend.h>
 
25
 
 
26
int daemonise = FALSE;
 
27
bool setns_pid_supported = false;
 
28
unsigned long mypidns;
 
29
bool setns_user_supported = false;
 
30
unsigned long myuserns;
 
31
 
 
32
bool sane_cgroup(const char *cgroup)
 
33
{
 
34
        if (!cgroup)
 
35
                return false;
 
36
        if (strstr(cgroup, ".."))
 
37
                return false;
 
38
        if (strchr(cgroup, '\\'))
 
39
                return false;
 
40
        return true;
 
41
}
 
42
 
 
43
/* This function is done at the start of every Scm-enhanced transaction */
 
44
static struct scm_sock_data *alloc_scm_sock_data(NihDBusMessage *message,
 
45
                int fd, enum req_type t)
 
46
{
 
47
        struct scm_sock_data *d;
 
48
        int optval = -1, dbusfd;
 
49
        socklen_t len;
 
50
 
 
51
        if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
 
52
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
53
                                "Failed to set passcred: %s", strerror(errno));
 
54
                return NULL;
 
55
        }
 
56
        d = NIH_MUST( nih_alloc(NULL, sizeof(*d)) );
 
57
        memset(d, 0, sizeof(*d));
 
58
        d->fd = fd;
 
59
        d->type = t;
 
60
 
 
61
        if (!dbus_connection_get_socket(message->connection, &dbusfd)) {
 
62
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
63
                                             "Could not get client socket.");
 
64
                return NULL;
 
65
        }
 
66
 
 
67
        /* Read the proxy's credentials from dbus fd */
 
68
        len = sizeof(struct ucred);
 
69
        if (getsockopt(dbusfd, SOL_SOCKET, SO_PEERCRED, &d->pcred, &len) < 0) {
 
70
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
71
                                             "Could not get peer cred: %s",
 
72
                                             strerror(errno));
 
73
                return NULL;
 
74
        }
 
75
 
 
76
        return d;
 
77
}
 
78
 
 
79
static const char *req_type_to_str(enum req_type r)
 
80
{
 
81
        switch(r) {
 
82
                case REQ_TYPE_GET_PID: return "get_pid";
 
83
                case REQ_TYPE_MOVE_PID: return "move_pid";
 
84
                case REQ_TYPE_MOVE_PID_ABS: return "move_pid";
 
85
                case REQ_TYPE_CREATE: return "create";
 
86
                case REQ_TYPE_CHOWN: return "chown";
 
87
                case REQ_TYPE_GET_VALUE: return "get_value";
 
88
                case REQ_TYPE_SET_VALUE: return "set_value";
 
89
                case REQ_TYPE_REMOVE: return "remove";
 
90
                case REQ_TYPE_GET_TASKS: return "get_tasks";
 
91
                case REQ_TYPE_CHMOD: return "chmod";
 
92
                default: return "invalid";
 
93
        }
 
94
}
 
95
 
 
96
/*
 
97
 * All Scm-enhanced transactions take at least one SCM cred,
 
98
 * the requestor's.  Some require a second SCM cred to identify
 
99
 * a pid or uid/gid:
 
100
 */
 
101
static bool need_two_creds(enum req_type t)
 
102
{
 
103
        switch (t) {
 
104
        case REQ_TYPE_GET_PID:
 
105
        case REQ_TYPE_MOVE_PID:
 
106
        case REQ_TYPE_MOVE_PID_ABS:
 
107
        case REQ_TYPE_CHOWN:
 
108
                return true;
 
109
        default:
 
110
                return false;
 
111
        }
 
112
}
 
113
 
 
114
static void scm_sock_error_handler (void *data, NihIo *io)
 
115
{
 
116
        struct scm_sock_data *d = data;
 
117
        NihError *error = nih_error_get ();
 
118
        nih_error("got an error, type %s", req_type_to_str(d->type));
 
119
        nih_error("error %s", strerror(error->number));
 
120
        nih_free(error);
 
121
}
 
122
 
 
123
static void scm_sock_close (struct scm_sock_data *data, NihIo *io)
 
124
{
 
125
        nih_assert (data);
 
126
        nih_assert (io);
 
127
        close (data->fd);
 
128
        nih_free (data);
 
129
        nih_free (io);
 
130
}
 
131
 
 
132
/*
 
133
 * Write a char over the socket to tell the client we're ready for
 
134
 * the next SCM credential.
 
135
 */
 
136
static bool kick_fd_client(int fd)
 
137
{
 
138
        char buf = '1';
 
139
        if (write(fd, &buf, 1) != 1) {
 
140
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
141
                        "Failed to start write on scm fd: %s", strerror(errno));
 
142
                return false;
 
143
        }
 
144
        return true;
 
145
}
 
146
 
 
147
/*
 
148
 * Called when an scm credential has been received.  If this was
 
149
 * the first of two expected creds, then kick the client again
 
150
 * and wait (async) for the next credential.  Otherwise, call
 
151
 * the appropriate completion function to finish the transaction.
 
152
 */
 
153
static void sock_scm_reader(struct scm_sock_data *data,
 
154
                        NihIo *io, const char *buf, size_t len)
 
155
{
 
156
        struct ucred ucred;
 
157
 
 
158
        if (!get_nih_io_creds(io, &ucred)) {
 
159
                nih_error("failed to read ucred");
 
160
                nih_io_shutdown(io);
 
161
                return;
 
162
        }
 
163
        if (data->step == 0) {
 
164
                memcpy(&data->rcred, &ucred, sizeof(struct ucred));
 
165
                if (need_two_creds(data->type)) {
 
166
                        data->step = 1;
 
167
                        if (!kick_fd_client(data->fd))
 
168
                                nih_io_shutdown(io);
 
169
                        return;
 
170
                }
 
171
        } else
 
172
                memcpy(&data->vcred, &ucred, sizeof(struct ucred));
 
173
 
 
174
        switch (data->type) {
 
175
        case REQ_TYPE_GET_PID: get_pid_scm_complete(data); break;
 
176
        case REQ_TYPE_MOVE_PID: move_pid_scm_complete(data); break;
 
177
        case REQ_TYPE_MOVE_PID_ABS: move_pid_abs_scm_complete(data); break;
 
178
        case REQ_TYPE_CREATE: create_scm_complete(data); break;
 
179
        case REQ_TYPE_CHOWN: chown_scm_complete(data); break;
 
180
        case REQ_TYPE_CHMOD: chmod_scm_complete(data); break;
 
181
        case REQ_TYPE_GET_VALUE: get_value_complete(data); break;
 
182
        case REQ_TYPE_SET_VALUE: set_value_complete(data); break;
 
183
        case REQ_TYPE_REMOVE: remove_scm_complete(data); break;
 
184
        case REQ_TYPE_GET_TASKS: get_tasks_scm_complete(data); break;
 
185
        default:
 
186
                nih_fatal("%s: bad req_type %d", __func__, data->type);
 
187
                exit(1);
 
188
        }
 
189
        nih_io_shutdown(io);
 
190
}
 
191
 
 
192
int cgmanager_ping (void *data, NihDBusMessage *message, int junk)
 
193
{
 
194
        if (message == NULL) {
 
195
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
196
                        "message was null");
 
197
                return -1;
 
198
        }
 
199
 
 
200
        return 0;
 
201
}
 
202
 
 
203
void get_pid_scm_complete(struct scm_sock_data *data)
 
204
{
 
205
        char *output = NULL;
 
206
        int ret;
 
207
 
 
208
        ret = get_pid_cgroup_main(data, data->controller, data->pcred,
 
209
                        data->rcred, data->vcred, &output);
 
210
        if (ret == 0)
 
211
                ret = write(data->fd, output, strlen(output)+1);
 
212
        else
 
213
                // Let the client know it failed
 
214
                ret = write(data->fd, &data->rcred, 0);
 
215
        if (ret < 0)
 
216
                nih_error("GetPidCgroupScm: Error writing final result to client: %s",
 
217
                        strerror(errno));
 
218
}
 
219
 
 
220
/*
 
221
 * This is one of the dbus callbacks.
 
222
 * Caller requests the cgroup of @pid in a given @controller
 
223
 */
 
224
int cgmanager_get_pid_cgroup_scm (void *data, NihDBusMessage *message,
 
225
                        const char *controller, int sockfd)
 
226
{
 
227
        struct scm_sock_data *d;
 
228
 
 
229
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_GET_PID);
 
230
        if (!d)
 
231
                return -1;
 
232
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
233
 
 
234
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
235
                                (NihIoReader) sock_scm_reader,
 
236
                                (NihIoCloseHandler) scm_sock_close,
 
237
                                scm_sock_error_handler, d)) {
 
238
                NihError *error = nih_error_steal ();
 
239
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
240
                        "Failed queue scm message: %s", error->message);
 
241
                nih_free(error);
 
242
                return -1;
 
243
        }
 
244
 
 
245
        if (!kick_fd_client(sockfd)) {
 
246
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
247
                        "Error writing to client: %s", strerror(errno));
 
248
                return -1;
 
249
        }
 
250
        return 0;
 
251
}
 
252
 
 
253
/* GetPidCgroup */
 
254
/*
 
255
 * This is one of the dbus callbacks.
 
256
 * Caller requests the cgroup of @pid in a given @controller
 
257
 */
 
258
int cgmanager_get_pid_cgroup (void *data, NihDBusMessage *message,
 
259
                        const char *controller, int plain_pid, char **output)
 
260
{
 
261
        int fd = 0, ret;
 
262
        struct ucred rcred, vcred;
 
263
        socklen_t len;
 
264
 
 
265
        if (message == NULL) {
 
266
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
267
                        "message was null");
 
268
                return -1;
 
269
        }
 
270
 
 
271
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
272
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
273
                                             "Could not get client socket.");
 
274
                return -1;
 
275
        }
 
276
 
 
277
        len = sizeof(struct ucred);
 
278
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
279
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
280
                                             "Could not get peer cred: %s",
 
281
                                             strerror(errno));
 
282
                return -1;
 
283
        }
 
284
 
 
285
        nih_info (_("GetPidCgroup: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
286
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
287
 
 
288
        /*
 
289
         * getpidcgroup results cannot make sense as the pid is not
 
290
         * translated.  Note that on an old enough kernel we cannot detect
 
291
         * this situation.  In that case we allow it - it will confuse the
 
292
         * caller, but cause no harm
 
293
         */
 
294
        if (!is_same_pidns(rcred.pid)) {
 
295
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
296
                                "GetPidCgroup called from non-init namespace");
 
297
                return -1;
 
298
        }
 
299
        vcred.uid = 0;
 
300
        vcred.gid = 0;
 
301
        vcred.pid = plain_pid;
 
302
        ret = get_pid_cgroup_main(message, controller, rcred, rcred, vcred, output);
 
303
        if (ret) {
 
304
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
305
                                "invalid request");
 
306
                return -1;
 
307
        }
 
308
        return 0;
 
309
}
 
310
 
 
311
void move_pid_scm_complete(struct scm_sock_data *data)
 
312
{
 
313
        char b = '0';
 
314
 
 
315
        if (move_pid_main(data->controller, data->cgroup, data->pcred,
 
316
                                data->rcred, data->vcred) == 0)
 
317
                b = '1';
 
318
        if (write(data->fd, &b, 1) < 0)
 
319
                nih_error("MovePidScm: Error writing final result to client");
 
320
}
 
321
 
 
322
int cgmanager_move_pid_scm (void *data, NihDBusMessage *message,
 
323
                        const char *controller, const char *cgroup,
 
324
                        int sockfd)
 
325
{
 
326
        struct scm_sock_data *d;
 
327
 
 
328
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_MOVE_PID);
 
329
        if (!d)
 
330
                return -1;
 
331
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
332
        d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
 
333
 
 
334
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
335
                                (NihIoReader) sock_scm_reader,
 
336
                                (NihIoCloseHandler) scm_sock_close,
 
337
                                scm_sock_error_handler, d)) {
 
338
                NihError *error = nih_error_steal ();
 
339
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
340
                        "Failed queue scm message: %s", error->message);
 
341
                nih_free(error);
 
342
                return -1;
 
343
        }
 
344
        if (!kick_fd_client(sockfd)) {
 
345
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
346
                        "Error writing to client: %s", strerror(errno));
 
347
                return -1;
 
348
        }
 
349
        return 0;
 
350
}
 
351
 
 
352
/*
 
353
 * This is one of the dbus callbacks.
 
354
 * Caller requests moving a @pid to a particular cgroup identified
 
355
 * by the name (@cgroup) and controller type (@controller).
 
356
 */
 
357
int cgmanager_move_pid (void *data, NihDBusMessage *message,
 
358
                        const char *controller, const char *cgroup, int plain_pid)
 
359
{
 
360
        int fd = 0, ret;
 
361
        struct ucred rcred, vcred;
 
362
        socklen_t len;
 
363
 
 
364
        if (message == NULL) {
 
365
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
366
                        "message was null");
 
367
                return -1;
 
368
        }
 
369
 
 
370
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
371
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
372
                                             "Could not get client socket.");
 
373
                return -1;
 
374
        }
 
375
 
 
376
        len = sizeof(struct ucred);
 
377
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
378
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
379
                                             "Could not get peer cred: %s",
 
380
                                             strerror(errno));
 
381
                return -1;
 
382
        }
 
383
 
 
384
        nih_info (_("MovePid: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
385
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
386
 
 
387
        /* If task is in a different namespace, require a proxy */
 
388
        if (!is_same_pidns(rcred.pid)) {
 
389
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
390
                             "Escape request from different namespace requires a proxy");
 
391
                return -1;
 
392
        }
 
393
 
 
394
        vcred.uid = 0;
 
395
        vcred.gid = 0;
 
396
        vcred.pid = plain_pid;
 
397
        ret = move_pid_main(controller, cgroup, rcred, rcred, vcred);
 
398
        if (ret)
 
399
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
400
                                             "invalid request");
 
401
        return ret;
 
402
}
 
403
 
 
404
void move_pid_abs_scm_complete(struct scm_sock_data *data)
 
405
{
 
406
        char b = '0';
 
407
 
 
408
        if (move_pid_abs_main(data->controller, data->cgroup, data->pcred,
 
409
                                data->rcred, data->vcred) == 0)
 
410
                b = '1';
 
411
        if (write(data->fd, &b, 1) < 0)
 
412
                nih_error("MovePidScm: Error writing final result to client");
 
413
}
 
414
 
 
415
int cgmanager_move_pid_abs_scm (void *data, NihDBusMessage *message,
 
416
                        const char *controller, const char *cgroup,
 
417
                        int sockfd)
 
418
{
 
419
        struct scm_sock_data *d;
 
420
 
 
421
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_MOVE_PID_ABS);
 
422
        if (!d)
 
423
                return -1;
 
424
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
425
        d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
 
426
 
 
427
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
428
                                (NihIoReader) sock_scm_reader,
 
429
                                (NihIoCloseHandler) scm_sock_close,
 
430
                                scm_sock_error_handler, d)) {
 
431
                NihError *error = nih_error_steal ();
 
432
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
433
                        "Failed queue scm message: %s", error->message);
 
434
                nih_free(error);
 
435
                return -1;
 
436
        }
 
437
        if (!kick_fd_client(sockfd)) {
 
438
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
439
                        "Error writing to client: %s", strerror(errno));
 
440
                return -1;
 
441
        }
 
442
        return 0;
 
443
}
 
444
 
 
445
int cgmanager_move_pid_abs (void *data, NihDBusMessage *message,
 
446
                        const char *controller, const char *cgroup, int plain_pid)
 
447
{
 
448
        int fd = 0, ret;
 
449
        struct ucred rcred, vcred;
 
450
        socklen_t len;
 
451
 
 
452
        if (message == NULL) {
 
453
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
454
                        "message was null");
 
455
                return -1;
 
456
        }
 
457
 
 
458
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
459
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
460
                                             "Could not get client socket.");
 
461
                return -1;
 
462
        }
 
463
 
 
464
        len = sizeof(struct ucred);
 
465
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
466
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
467
                                             "Could not get peer cred: %s",
 
468
                                             strerror(errno));
 
469
                return -1;
 
470
        }
 
471
 
 
472
        nih_info (_("MovePid: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
473
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
474
 
 
475
        vcred.uid = 0;
 
476
        vcred.gid = 0;
 
477
        vcred.pid = plain_pid;
 
478
 
 
479
#ifdef CGMANAGER
 
480
        /*
 
481
         * On an older kernel, require a proxy
 
482
         */
 
483
        if (!setns_pid_supported) {
 
484
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
485
                                             "A proxy is required");
 
486
                return -1;
 
487
        }
 
488
#endif
 
489
 
 
490
        /* If task is in a different namespace, require a proxy */
 
491
        if (!is_same_pidns(rcred.pid)) {
 
492
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
493
                             "Escape request from different namespace requires a proxy");
 
494
                return -1;
 
495
        }
 
496
 
 
497
#ifdef CGMANAGER
 
498
        /*
 
499
         * A plain dbus request to escape cgroup root was made by a root
 
500
         * owned task in cgmanager's namespace.  We will send ourselves as the
 
501
         * proxy.
 
502
         */
 
503
        struct ucred mycred = {
 
504
                .pid = getpid(),
 
505
                .uid = getuid(),
 
506
                .gid = getgid()
 
507
        };
 
508
#else
 
509
        /*
 
510
         * This is the !CGMANAGER case.  We are in the proxy.  We don't
 
511
         * support chained proxying anyway, so it is simple - the requestor
 
512
         * is the proxy at this point;  then we will proxy the call on to
 
513
         * the cgmanager
 
514
         */
 
515
#define mycred rcred
 
516
#endif
 
517
        ret = move_pid_abs_main(controller, cgroup, mycred, rcred, vcred);
 
518
        if (ret)
 
519
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
520
                                             "invalid request");
 
521
        return ret;
 
522
}
 
523
 
 
524
void create_scm_complete(struct scm_sock_data *data)
 
525
{
 
526
        char b = '0';
 
527
        int32_t existed;
 
528
 
 
529
        if (create_main(data->controller, data->cgroup, data->pcred,
 
530
                                data->rcred, &existed) == 0)
 
531
                b = existed == 1 ? '2' : '1';
 
532
        if (write(data->fd, &b, 1) < 0)
 
533
                nih_error("createScm: Error writing final result to client");
 
534
}
 
535
 
 
536
int cgmanager_create_scm (void *data, NihDBusMessage *message,
 
537
                 const char *controller, const char *cgroup, int sockfd)
 
538
{
 
539
        struct scm_sock_data *d;
 
540
 
 
541
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_CREATE);
 
542
        if (!d)
 
543
                return -1;
 
544
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
545
        d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
 
546
 
 
547
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
548
                                (NihIoReader) sock_scm_reader,
 
549
                                (NihIoCloseHandler) scm_sock_close,
 
550
                                scm_sock_error_handler, d)) {
 
551
                NihError *error = nih_error_steal ();
 
552
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
553
                        "Failed queue scm message: %s", error->message);
 
554
                nih_free(error);
 
555
                return -1;
 
556
        }
 
557
        if (!kick_fd_client(sockfd)) {
 
558
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
559
                        "Error writing to client: %s", strerror(errno));
 
560
                return -1;
 
561
        }
 
562
        return 0;
 
563
}
 
564
 
 
565
/* 
 
566
 * This is one of the dbus callbacks.
 
567
 * Caller requests creating a new @cgroup name of type @controller.
 
568
 * @name is taken to be relative to the caller's cgroup and may not
 
569
 * start with / or .. .
 
570
 */
 
571
int cgmanager_create (void *data, NihDBusMessage *message,
 
572
                         const char *controller, const char *cgroup, int32_t *existed)
 
573
{
 
574
        int fd = 0, ret;
 
575
        struct ucred rcred;
 
576
        socklen_t len;
 
577
 
 
578
        *existed = -1;
 
579
        if (message == NULL) {
 
580
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
581
                                "message was null");
 
582
                return -1;
 
583
        }
 
584
 
 
585
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
586
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
587
                                "Could not get client socket.");
 
588
                return -1;
 
589
        }
 
590
 
 
591
        len = sizeof(struct ucred);
 
592
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
593
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
594
                                             "Could not get peer cred: %s",
 
595
                                             strerror(errno));
 
596
                return -1;
 
597
        }
 
598
 
 
599
        nih_info (_("Create: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
600
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
601
 
 
602
        ret = create_main(controller, cgroup, rcred, rcred, existed);
 
603
        if (ret)
 
604
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
605
                                "invalid request");
 
606
        nih_info(_("%s: returning %d; existed is %d"), __func__, ret, *existed);
 
607
        return ret;
 
608
}
 
609
 
 
610
void chown_scm_complete(struct scm_sock_data *data)
 
611
{
 
612
        char b = '0';
 
613
 
 
614
        if (chown_main(data->controller, data->cgroup, data->pcred,
 
615
                                data->rcred, data->vcred) == 0)
 
616
                b = '1';
 
617
        if (write(data->fd, &b, 1) < 0)
 
618
                nih_error("ChownScm: Error writing final result to client");
 
619
}
 
620
 
 
621
int cgmanager_chown_scm (void *data, NihDBusMessage *message,
 
622
                        const char *controller, const char *cgroup, int sockfd)
 
623
{
 
624
        struct scm_sock_data *d;
 
625
 
 
626
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_CHOWN);
 
627
        if (!d)
 
628
                return -1;
 
629
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
630
        d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
 
631
 
 
632
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
633
                                (NihIoReader)  sock_scm_reader,
 
634
                                (NihIoCloseHandler) scm_sock_close,
 
635
                                scm_sock_error_handler, d)) {
 
636
                NihError *error = nih_error_steal ();
 
637
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
638
                        "Failed queue scm message: %s", error->message);
 
639
                nih_free(error);
 
640
                return -1;
 
641
        }
 
642
        if (!kick_fd_client(sockfd)) {
 
643
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
644
                        "Error writing to client: %s", strerror(errno));
 
645
                return -1;
 
646
        }
 
647
        return 0;
 
648
}
 
649
 
 
650
/*
 
651
 * This is one of the dbus callbacks.
 
652
 * Caller requests chowning a cgroup @name in controller @cgroup to a
 
653
 * particular @uid.  The uid must be passed in as an scm_cred so the
 
654
 * kernel translates it for us.  @r must be root in its own user ns.
 
655
 *
 
656
 * If we are asked to chown /b to UID, then we will chown:
 
657
 * /b itself, /b/tasks, and /b/procs.  Any other files in /b will not be
 
658
 * chown.  UID can then create subdirs of /b, but not raise his limits.
 
659
 */
 
660
int cgmanager_chown (void *data, NihDBusMessage *message,
 
661
                        const char *controller, const char *cgroup, int uid, int gid)
 
662
{
 
663
        int fd = 0, ret;
 
664
        struct ucred rcred, vcred;
 
665
        socklen_t len;
 
666
 
 
667
        if (message == NULL) {
 
668
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
669
                        "message was null");
 
670
                return -1;
 
671
        }
 
672
 
 
673
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
674
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
675
                                             "Could not get client socket.");
 
676
                return -1;
 
677
        }
 
678
 
 
679
        len = sizeof(struct ucred);
 
680
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
681
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
682
                                             "Could not get peer cred: %s",
 
683
                                             strerror(errno));
 
684
                return -1;
 
685
        }
 
686
 
 
687
        nih_info (_("Chown: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
688
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
689
 
 
690
        /*
 
691
         * If chown is called from a different user namespace, then the
 
692
         * results cannot make sense.  Note that on an old enough kernel
 
693
         * we cannot detect this.  However, in that case the caller will
 
694
         * not have privilege so will simply get a confusing -EPERM.  In
 
695
         * other words, we are doing this as a courtesy when possible
 
696
         */
 
697
        if (!is_same_userns(rcred.pid)) {
 
698
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
699
                                "chown called from different user namespace");
 
700
                return -1;
 
701
        }
 
702
 
 
703
        vcred.pid = getpid(); // cgmanager ignores this
 
704
        vcred.uid = uid;
 
705
        vcred.gid = gid;
 
706
 
 
707
        ret = chown_main(controller, cgroup, rcred, rcred, vcred);
 
708
        if (ret)
 
709
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
710
                                             "invalid request");
 
711
        return ret;
 
712
}
 
713
 
 
714
void chmod_scm_complete(struct scm_sock_data *data)
 
715
{
 
716
        char b = '0';
 
717
 
 
718
        if (chmod_main(data->controller, data->cgroup, data->file,
 
719
                                data->pcred, data->rcred, data->mode) == 0)
 
720
                b = '1';
 
721
        if (write(data->fd, &b, 1) < 0)
 
722
                nih_error("ChownScm: Error writing final result to client");
 
723
}
 
724
 
 
725
int cgmanager_chmod_scm (void *data, NihDBusMessage *message,
 
726
                        const char *controller, const char *cgroup,
 
727
                        const char *file, int mode, int sockfd)
 
728
{
 
729
        struct scm_sock_data *d;
 
730
 
 
731
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_CHMOD);
 
732
        if (!d)
 
733
                return -1;
 
734
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
735
        d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
 
736
        d->mode = mode;
 
737
        d->file = NIH_MUST( nih_strdup(d, file) );
 
738
 
 
739
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
740
                                (NihIoReader)  sock_scm_reader,
 
741
                                (NihIoCloseHandler) scm_sock_close,
 
742
                                scm_sock_error_handler, d)) {
 
743
                NihError *error = nih_error_steal ();
 
744
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
745
                        "Failed queue scm message: %s", error->message);
 
746
                nih_free(error);
 
747
                return -1;
 
748
        }
 
749
        if (!kick_fd_client(sockfd)) {
 
750
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
751
                        "Error writing to client: %s", strerror(errno));
 
752
                return -1;
 
753
        }
 
754
        return 0;
 
755
}
 
756
 
 
757
/*
 
758
 * This is one of the dbus callbacks.  Caller requests chmoding a file @path in
 
759
 * cgroup @name in controller @cgroup to a new @mode.  
 
760
 */
 
761
int cgmanager_chmod (void *data, NihDBusMessage *message,
 
762
                        const char *controller, const char *cgroup,
 
763
                        const char *file, int mode)
 
764
{
 
765
        int fd = 0, ret;
 
766
        struct ucred rcred;
 
767
        socklen_t len;
 
768
 
 
769
        if (message == NULL) {
 
770
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
771
                        "message was null");
 
772
                return -1;
 
773
        }
 
774
 
 
775
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
776
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
777
                                             "Could not get client socket.");
 
778
                return -1;
 
779
        }
 
780
 
 
781
        len = sizeof(struct ucred);
 
782
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
783
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
784
                                             "Could not get peer cred: %s",
 
785
                                             strerror(errno));
 
786
                return -1;
 
787
        }
 
788
 
 
789
        nih_info (_("Chown: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
790
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
791
 
 
792
        ret = chmod_main(controller, cgroup, file, rcred, rcred, mode);
 
793
        if (ret)
 
794
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
795
                                             "invalid request");
 
796
        return ret;
 
797
}
 
798
 
 
799
void get_value_complete(struct scm_sock_data *data)
 
800
{
 
801
        char *output = NULL;
 
802
        int ret;
 
803
 
 
804
        if (!get_value_main(data, data->controller, data->cgroup, data->key,
 
805
                        data->pcred, data->rcred, &output))
 
806
                ret = write(data->fd, output, strlen(output)+1);
 
807
        else
 
808
                ret = write(data->fd, &data->rcred, 0);  // kick the client
 
809
        if (ret < 0)
 
810
                nih_error("GetValueScm: Error writing final result to client");
 
811
}
 
812
 
 
813
int cgmanager_get_value_scm (void *data, NihDBusMessage *message,
 
814
                                 const char *controller, const char *req_cgroup,
 
815
                                 const char *key, int sockfd)
 
816
{
 
817
        struct scm_sock_data *d;
 
818
 
 
819
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_GET_VALUE);
 
820
        if (!d)
 
821
                return -1;
 
822
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
823
        d->cgroup = NIH_MUST( nih_strdup(d, req_cgroup) );
 
824
        d->key = NIH_MUST( nih_strdup(d, key) );
 
825
 
 
826
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
827
                                (NihIoReader) sock_scm_reader,
 
828
                                (NihIoCloseHandler) scm_sock_close,
 
829
                                scm_sock_error_handler, d)) {
 
830
                NihError *error = nih_error_steal ();
 
831
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
832
                        "Failed queue scm message: %s", error->message);
 
833
                nih_free(error);
 
834
                return -1;
 
835
        }
 
836
        if (!kick_fd_client(sockfd)) {
 
837
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
838
                        "Error writing to client: %s", strerror(errno));
 
839
                return -1;
 
840
        }
 
841
        return 0;
 
842
 
 
843
}
 
844
 
 
845
/* 
 
846
 * This is one of the dbus callbacks.
 
847
 * Caller requests the value of a particular cgroup file.
 
848
 * @controller is the controller, @req_cgroup the cgroup name, and @key the
 
849
 * file being queried (i.e. memory.usage_in_bytes).  @req_cgroup is relative
 
850
 * to the caller's cgroup, unless it begins with '/' or '..'.
 
851
 *
 
852
 * XXX Should '/' be disallowed, only '..' allowed?  Otherwise callers can't
 
853
 * pretend to be the cgroup root which is annoying in itself
 
854
 */
 
855
int cgmanager_get_value (void *data, NihDBusMessage *message,
 
856
                                 const char *controller, const char *req_cgroup,
 
857
                                 const char *key, char **value)
 
858
 
 
859
{
 
860
        int fd = 0, ret;
 
861
        struct ucred rcred;
 
862
        socklen_t len;
 
863
 
 
864
        if (message == NULL) {
 
865
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
866
                        "Message was NULL");
 
867
                return -1;
 
868
        }
 
869
 
 
870
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
871
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
872
                                             "Could not get client socket.");
 
873
                return -1;
 
874
        }
 
875
 
 
876
        len = sizeof(struct ucred);
 
877
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
878
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
879
                                             "Could not get peer cred: %s",
 
880
                                             strerror(errno));
 
881
                return -1;
 
882
        }
 
883
 
 
884
        nih_info (_("GetValue: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
885
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
886
 
 
887
        ret = get_value_main(message, controller, req_cgroup, key, rcred, rcred, value);
 
888
        if (ret)
 
889
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
890
                                "invalid request");
 
891
        return ret;
 
892
}
 
893
 
 
894
void set_value_complete(struct scm_sock_data *data)
 
895
{
 
896
        char b = '0';
 
897
        if (set_value_main(data->controller, data->cgroup, data->key,
 
898
                                data->value, data->pcred, data->rcred) == 0)
 
899
                b = '1';
 
900
        if (write(data->fd, &b, 1) < 0)
 
901
                nih_error("SetValueScm: Error writing final result to client");
 
902
}
 
903
 
 
904
int cgmanager_set_value_scm (void *data, NihDBusMessage *message,
 
905
                                 const char *controller, const char *req_cgroup,
 
906
                                 const char *key, const char *value, int sockfd)
 
907
{
 
908
        struct scm_sock_data *d;
 
909
 
 
910
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_SET_VALUE);
 
911
        if (!d)
 
912
                return -1;
 
913
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
914
        d->cgroup = NIH_MUST( nih_strdup(d, req_cgroup) );
 
915
        d->key = NIH_MUST( nih_strdup(d, key) );
 
916
        d->value = NIH_MUST( nih_strdup(d, value) );
 
917
 
 
918
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
919
                                (NihIoReader) sock_scm_reader,
 
920
                                (NihIoCloseHandler) scm_sock_close,
 
921
                                scm_sock_error_handler, d)) {
 
922
                NihError *error = nih_error_steal ();
 
923
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
924
                        "Failed queue scm message: %s", error->message);
 
925
                nih_free(error);
 
926
                return -1;
 
927
        }
 
928
        if (!kick_fd_client(sockfd)) {
 
929
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
930
                        "Error writing to client: %s", strerror(errno));
 
931
                return -1;
 
932
        }
 
933
        return 0;
 
934
}
 
935
 
 
936
/* 
 
937
 * This is one of the dbus callbacks.
 
938
 * Caller requests that a particular cgroup @key be set to @value
 
939
 * @controller is the controller, @req_cgroup the cgroup name, and @key the
 
940
 * file being queried (i.e. memory.usage_in_bytes).  @req_cgroup is relative
 
941
 * to the caller's cgroup.
 
942
 */
 
943
int cgmanager_set_value (void *data, NihDBusMessage *message,
 
944
                                 const char *controller, const char *req_cgroup,
 
945
                                 const char *key, const char *value)
 
946
 
 
947
{
 
948
        int fd = 0, ret;
 
949
        struct ucred rcred;
 
950
        socklen_t len;
 
951
 
 
952
        if (message == NULL) {
 
953
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
954
                        "Message was NULL");
 
955
                return -1;
 
956
        }
 
957
 
 
958
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
959
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
960
                                             "Could not get client socket.");
 
961
                return -1;
 
962
        }
 
963
 
 
964
        len = sizeof(struct ucred);
 
965
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
966
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
967
                                             "Could not get peer cred: %s",
 
968
                                             strerror(errno));
 
969
                return -1;
 
970
        }
 
971
 
 
972
        nih_info (_("SetValue: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
973
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
974
 
 
975
        ret = set_value_main(controller, req_cgroup, key, value, rcred, rcred);
 
976
        if (ret)
 
977
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
978
                                             "invalid request");
 
979
        return ret;
 
980
}
 
981
 
 
982
void remove_scm_complete(struct scm_sock_data *data)
 
983
{
 
984
        char b = '0';
 
985
        int ret;
 
986
        int32_t existed = -1;
 
987
 
 
988
        ret = remove_main(data->controller, data->cgroup, data->pcred,
 
989
                        data->rcred, data->recursive, &existed);
 
990
        if (ret == 0)
 
991
                b = existed == 1 ? '2' : '1';
 
992
        if (write(data->fd, &b, 1) < 0)
 
993
                nih_error("removeScm: Error writing final result to client");
 
994
}
 
995
 
 
996
int cgmanager_remove_scm (void *data, NihDBusMessage *message,
 
997
                 const char *controller, const char *cgroup, int recursive, int sockfd)
 
998
{
 
999
        struct scm_sock_data *d;
 
1000
 
 
1001
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_REMOVE);
 
1002
        if (!d)
 
1003
                return -1;
 
1004
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
1005
        d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
 
1006
        d->recursive = recursive;
 
1007
 
 
1008
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
1009
                                (NihIoReader) sock_scm_reader,
 
1010
                                (NihIoCloseHandler) scm_sock_close,
 
1011
                                scm_sock_error_handler, d)) {
 
1012
                NihError *error = nih_error_steal ();
 
1013
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1014
                        "Failed queue scm message: %s", error->message);
 
1015
                nih_free(error);
 
1016
                return -1;
 
1017
        }
 
1018
        if (!kick_fd_client(sockfd)) {
 
1019
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1020
                        "Error writing to client: %s", strerror(errno));
 
1021
                return -1;
 
1022
        }
 
1023
        return 0;
 
1024
}
 
1025
 
 
1026
/* 
 
1027
 * This is one of the dbus callbacks.
 
1028
 * Caller requests creating a new @cgroup name of type @controller.
 
1029
 * @name is taken to be relative to the caller's cgroup and may not
 
1030
 * start with / or .. .
 
1031
 */
 
1032
int cgmanager_remove (void *data, NihDBusMessage *message, const char *controller,
 
1033
                        const char *cgroup, int recursive, int32_t *existed)
 
1034
{
 
1035
        int fd = 0, ret;
 
1036
        struct ucred rcred;
 
1037
        socklen_t len;
 
1038
 
 
1039
        *existed = -1;
 
1040
        if (message == NULL) {
 
1041
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1042
                        "message was null");
 
1043
                return -1;
 
1044
        }
 
1045
 
 
1046
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
1047
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1048
                                             "Could not get client socket.");
 
1049
                return -1;
 
1050
        }
 
1051
 
 
1052
        len = sizeof(struct ucred);
 
1053
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
1054
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1055
                                             "Could not get peer cred: %s",
 
1056
                                             strerror(errno));
 
1057
                return -1;
 
1058
        }
 
1059
 
 
1060
        nih_info (_("Remove: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
1061
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
1062
 
 
1063
        ret = remove_main(controller, cgroup, rcred, rcred, recursive, existed);
 
1064
        if (ret)
 
1065
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1066
                                             "invalid request");
 
1067
        return ret;
 
1068
}
 
1069
 
 
1070
void get_tasks_scm_complete(struct scm_sock_data *data)
 
1071
{
 
1072
        struct ucred pcred;
 
1073
        int i, ret;
 
1074
        int32_t *pids, nrpids;
 
1075
        ret = get_tasks_main(data, data->controller, data->cgroup,
 
1076
                        data->pcred, data->rcred, &pids);
 
1077
        if (ret < 0) {
 
1078
                nih_error("Error getting nrtasks for %s:%s for pid %d",
 
1079
                        data->controller, data->cgroup, data->rcred.pid);
 
1080
                return;
 
1081
        }
 
1082
        nrpids = ret;
 
1083
        if (write(data->fd, &nrpids, sizeof(int32_t)) != sizeof(int32_t)) {
 
1084
                nih_error("get_tasks_scm: Error writing final result to client");
 
1085
                return;
 
1086
        }
 
1087
        pcred.uid = 0; pcred.gid = 0;
 
1088
        for (i=0; i<ret; i++) {
 
1089
                pcred.pid = pids[i];
 
1090
                if (send_creds(data->fd, &pcred)) {
 
1091
                        nih_error("get_tasks_scm: error writing pids back to client");
 
1092
                        return;
 
1093
                }
 
1094
        }
 
1095
}
 
1096
 
 
1097
int cgmanager_get_tasks_scm (void *data, NihDBusMessage *message,
 
1098
                 const char *controller, const char *cgroup, int sockfd)
 
1099
{
 
1100
        struct scm_sock_data *d;
 
1101
 
 
1102
        d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_GET_TASKS);
 
1103
        if (!d)
 
1104
                return -1;
 
1105
        d->controller = NIH_MUST( nih_strdup(d, controller) );
 
1106
        d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
 
1107
 
 
1108
        if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
 
1109
                                (NihIoReader) sock_scm_reader,
 
1110
                                (NihIoCloseHandler) scm_sock_close,
 
1111
                                scm_sock_error_handler, d)) {
 
1112
                NihError *error = nih_error_steal ();
 
1113
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1114
                        "Failed queue scm message: %s", error->message);
 
1115
                nih_free(error);
 
1116
                return -1;
 
1117
        }
 
1118
        if (!kick_fd_client(sockfd)) {
 
1119
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1120
                        "Error writing to client: %s", strerror(errno));
 
1121
                return -1;
 
1122
        }
 
1123
        return 0;
 
1124
}
 
1125
 
 
1126
/* 
 
1127
 * This is one of the dbus callbacks.
 
1128
 * Caller requests the number of tasks in @cgroup in @controller
 
1129
 * returns nrpids, or -1 on error.
 
1130
 */
 
1131
int cgmanager_get_tasks (void *data, NihDBusMessage *message, const char *controller,
 
1132
                        const char *cgroup, int32_t **pids, size_t *nrpids)
 
1133
{
 
1134
        int fd = 0, ret;
 
1135
        struct ucred rcred;
 
1136
        socklen_t len;
 
1137
        int32_t *tmp;
 
1138
 
 
1139
        if (message == NULL) {
 
1140
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1141
                        "message was null");
 
1142
                return -1;
 
1143
        }
 
1144
 
 
1145
        if (!dbus_connection_get_socket(message->connection, &fd)) {
 
1146
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1147
                                             "Could not get client socket.");
 
1148
                return -1;
 
1149
        }
 
1150
 
 
1151
        len = sizeof(struct ucred);
 
1152
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &rcred, &len) < 0) {
 
1153
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1154
                                             "Could not get peer cred: %s",
 
1155
                                             strerror(errno));
 
1156
                return -1;
 
1157
        }
 
1158
 
 
1159
        nih_info (_("GetTasks: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
 
1160
                        fd, rcred.pid, rcred.uid, rcred.gid);
 
1161
 
 
1162
        ret = get_tasks_main(message, controller, cgroup, rcred, rcred, &tmp);
 
1163
        if (ret >= 0) {
 
1164
                *nrpids = ret;
 
1165
                *pids = tmp;
 
1166
                ret = 0;
 
1167
        } else
 
1168
                nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
 
1169
                                             "invalid request");
 
1170
        return ret;
 
1171
}
 
1172
 
 
1173
int
 
1174
cgmanager_get_api_version(void *data, NihDBusMessage *message, int *version)
 
1175
{
 
1176
        nih_assert(message);
 
1177
        nih_assert(version);
 
1178
        *version = API_VERSION;
 
1179
        return 0;
 
1180
}
 
1181
 
 
1182
static dbus_bool_t allow_user(DBusConnection *connection, unsigned long uid, void *data)
 
1183
{
 
1184
        return TRUE;
 
1185
}
 
1186
 
 
1187
int client_connect (DBusServer *server, DBusConnection *conn)
 
1188
{
 
1189
        if (server == NULL || conn == NULL) {
 
1190
                nih_error("client_connect called with bad arguments");
 
1191
                return FALSE;
 
1192
        }
 
1193
 
 
1194
        dbus_connection_set_unix_user_function(conn, allow_user, NULL, NULL);
 
1195
        dbus_connection_set_allow_anonymous(conn, TRUE);
 
1196
 
 
1197
        nih_info (_("Connection from private client"));
 
1198
 
 
1199
        NIH_MUST (nih_dbus_object_new (NULL, conn,
 
1200
                                "/org/linuxcontainers/cgmanager",
 
1201
                                cgmanager_interfaces, NULL));
 
1202
 
 
1203
        return TRUE;
 
1204
}
 
1205
 
 
1206
void client_disconnect (DBusConnection *conn)
 
1207
{
 
1208
        if (conn == NULL)
 
1209
                return;
 
1210
 
 
1211
        nih_info (_("Disconnected from private client"));
 
1212
}