1
/* frontend.h: definitions of the dbus and scm-enhanced dbus
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>
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.
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.
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.
26
int daemonise = FALSE;
27
bool setns_pid_supported = false;
28
unsigned long mypidns;
29
bool setns_user_supported = false;
30
unsigned long myuserns;
32
bool sane_cgroup(const char *cgroup)
36
if (strstr(cgroup, ".."))
38
if (strchr(cgroup, '\\'))
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)
47
struct scm_sock_data *d;
48
int optval = -1, dbusfd;
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));
56
d = NIH_MUST( nih_alloc(NULL, sizeof(*d)) );
57
memset(d, 0, sizeof(*d));
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.");
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",
79
static const char *req_type_to_str(enum req_type 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";
97
* All Scm-enhanced transactions take at least one SCM cred,
98
* the requestor's. Some require a second SCM cred to identify
101
static bool need_two_creds(enum req_type t)
104
case REQ_TYPE_GET_PID:
105
case REQ_TYPE_MOVE_PID:
106
case REQ_TYPE_MOVE_PID_ABS:
114
static void scm_sock_error_handler (void *data, NihIo *io)
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));
123
static void scm_sock_close (struct scm_sock_data *data, NihIo *io)
133
* Write a char over the socket to tell the client we're ready for
134
* the next SCM credential.
136
static bool kick_fd_client(int fd)
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));
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.
153
static void sock_scm_reader(struct scm_sock_data *data,
154
NihIo *io, const char *buf, size_t len)
158
if (!get_nih_io_creds(io, &ucred)) {
159
nih_error("failed to read ucred");
163
if (data->step == 0) {
164
memcpy(&data->rcred, &ucred, sizeof(struct ucred));
165
if (need_two_creds(data->type)) {
167
if (!kick_fd_client(data->fd))
172
memcpy(&data->vcred, &ucred, sizeof(struct ucred));
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;
186
nih_fatal("%s: bad req_type %d", __func__, data->type);
192
int cgmanager_ping (void *data, NihDBusMessage *message, int junk)
194
if (message == NULL) {
195
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
203
void get_pid_scm_complete(struct scm_sock_data *data)
208
ret = get_pid_cgroup_main(data, data->controller, data->pcred,
209
data->rcred, data->vcred, &output);
211
ret = write(data->fd, output, strlen(output)+1);
213
// Let the client know it failed
214
ret = write(data->fd, &data->rcred, 0);
216
nih_error("GetPidCgroupScm: Error writing final result to client: %s",
221
* This is one of the dbus callbacks.
222
* Caller requests the cgroup of @pid in a given @controller
224
int cgmanager_get_pid_cgroup_scm (void *data, NihDBusMessage *message,
225
const char *controller, int sockfd)
227
struct scm_sock_data *d;
229
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_GET_PID);
232
d->controller = NIH_MUST( nih_strdup(d, controller) );
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);
245
if (!kick_fd_client(sockfd)) {
246
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
247
"Error writing to client: %s", strerror(errno));
255
* This is one of the dbus callbacks.
256
* Caller requests the cgroup of @pid in a given @controller
258
int cgmanager_get_pid_cgroup (void *data, NihDBusMessage *message,
259
const char *controller, int plain_pid, char **output)
262
struct ucred rcred, vcred;
265
if (message == NULL) {
266
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
285
nih_info (_("GetPidCgroup: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
286
fd, rcred.pid, rcred.uid, rcred.gid);
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
294
if (!is_same_pidns(rcred.pid)) {
295
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
296
"GetPidCgroup called from non-init namespace");
301
vcred.pid = plain_pid;
302
ret = get_pid_cgroup_main(message, controller, rcred, rcred, vcred, output);
304
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
311
void move_pid_scm_complete(struct scm_sock_data *data)
315
if (move_pid_main(data->controller, data->cgroup, data->pcred,
316
data->rcred, data->vcred) == 0)
318
if (write(data->fd, &b, 1) < 0)
319
nih_error("MovePidScm: Error writing final result to client");
322
int cgmanager_move_pid_scm (void *data, NihDBusMessage *message,
323
const char *controller, const char *cgroup,
326
struct scm_sock_data *d;
328
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_MOVE_PID);
331
d->controller = NIH_MUST( nih_strdup(d, controller) );
332
d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
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);
344
if (!kick_fd_client(sockfd)) {
345
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
346
"Error writing to client: %s", strerror(errno));
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).
357
int cgmanager_move_pid (void *data, NihDBusMessage *message,
358
const char *controller, const char *cgroup, int plain_pid)
361
struct ucred rcred, vcred;
364
if (message == NULL) {
365
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
384
nih_info (_("MovePid: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
385
fd, rcred.pid, rcred.uid, rcred.gid);
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");
396
vcred.pid = plain_pid;
397
ret = move_pid_main(controller, cgroup, rcred, rcred, vcred);
399
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
404
void move_pid_abs_scm_complete(struct scm_sock_data *data)
408
if (move_pid_abs_main(data->controller, data->cgroup, data->pcred,
409
data->rcred, data->vcred) == 0)
411
if (write(data->fd, &b, 1) < 0)
412
nih_error("MovePidScm: Error writing final result to client");
415
int cgmanager_move_pid_abs_scm (void *data, NihDBusMessage *message,
416
const char *controller, const char *cgroup,
419
struct scm_sock_data *d;
421
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_MOVE_PID_ABS);
424
d->controller = NIH_MUST( nih_strdup(d, controller) );
425
d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
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);
437
if (!kick_fd_client(sockfd)) {
438
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
439
"Error writing to client: %s", strerror(errno));
445
int cgmanager_move_pid_abs (void *data, NihDBusMessage *message,
446
const char *controller, const char *cgroup, int plain_pid)
449
struct ucred rcred, vcred;
452
if (message == NULL) {
453
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
472
nih_info (_("MovePid: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
473
fd, rcred.pid, rcred.uid, rcred.gid);
477
vcred.pid = plain_pid;
481
* On an older kernel, require a proxy
483
if (!setns_pid_supported) {
484
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
485
"A proxy is required");
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");
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
503
struct ucred mycred = {
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
517
ret = move_pid_abs_main(controller, cgroup, mycred, rcred, vcred);
519
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
524
void create_scm_complete(struct scm_sock_data *data)
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");
536
int cgmanager_create_scm (void *data, NihDBusMessage *message,
537
const char *controller, const char *cgroup, int sockfd)
539
struct scm_sock_data *d;
541
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_CREATE);
544
d->controller = NIH_MUST( nih_strdup(d, controller) );
545
d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
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);
557
if (!kick_fd_client(sockfd)) {
558
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
559
"Error writing to client: %s", strerror(errno));
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 .. .
571
int cgmanager_create (void *data, NihDBusMessage *message,
572
const char *controller, const char *cgroup, int32_t *existed)
579
if (message == NULL) {
580
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
599
nih_info (_("Create: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
600
fd, rcred.pid, rcred.uid, rcred.gid);
602
ret = create_main(controller, cgroup, rcred, rcred, existed);
604
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
606
nih_info(_("%s: returning %d; existed is %d"), __func__, ret, *existed);
610
void chown_scm_complete(struct scm_sock_data *data)
614
if (chown_main(data->controller, data->cgroup, data->pcred,
615
data->rcred, data->vcred) == 0)
617
if (write(data->fd, &b, 1) < 0)
618
nih_error("ChownScm: Error writing final result to client");
621
int cgmanager_chown_scm (void *data, NihDBusMessage *message,
622
const char *controller, const char *cgroup, int sockfd)
624
struct scm_sock_data *d;
626
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_CHOWN);
629
d->controller = NIH_MUST( nih_strdup(d, controller) );
630
d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
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);
642
if (!kick_fd_client(sockfd)) {
643
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
644
"Error writing to client: %s", strerror(errno));
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.
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.
660
int cgmanager_chown (void *data, NihDBusMessage *message,
661
const char *controller, const char *cgroup, int uid, int gid)
664
struct ucred rcred, vcred;
667
if (message == NULL) {
668
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
687
nih_info (_("Chown: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
688
fd, rcred.pid, rcred.uid, rcred.gid);
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
697
if (!is_same_userns(rcred.pid)) {
698
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
699
"chown called from different user namespace");
703
vcred.pid = getpid(); // cgmanager ignores this
707
ret = chown_main(controller, cgroup, rcred, rcred, vcred);
709
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
714
void chmod_scm_complete(struct scm_sock_data *data)
718
if (chmod_main(data->controller, data->cgroup, data->file,
719
data->pcred, data->rcred, data->mode) == 0)
721
if (write(data->fd, &b, 1) < 0)
722
nih_error("ChownScm: Error writing final result to client");
725
int cgmanager_chmod_scm (void *data, NihDBusMessage *message,
726
const char *controller, const char *cgroup,
727
const char *file, int mode, int sockfd)
729
struct scm_sock_data *d;
731
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_CHMOD);
734
d->controller = NIH_MUST( nih_strdup(d, controller) );
735
d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
737
d->file = NIH_MUST( nih_strdup(d, file) );
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);
749
if (!kick_fd_client(sockfd)) {
750
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
751
"Error writing to client: %s", strerror(errno));
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.
761
int cgmanager_chmod (void *data, NihDBusMessage *message,
762
const char *controller, const char *cgroup,
763
const char *file, int mode)
769
if (message == NULL) {
770
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
789
nih_info (_("Chown: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
790
fd, rcred.pid, rcred.uid, rcred.gid);
792
ret = chmod_main(controller, cgroup, file, rcred, rcred, mode);
794
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
799
void get_value_complete(struct scm_sock_data *data)
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);
808
ret = write(data->fd, &data->rcred, 0); // kick the client
810
nih_error("GetValueScm: Error writing final result to client");
813
int cgmanager_get_value_scm (void *data, NihDBusMessage *message,
814
const char *controller, const char *req_cgroup,
815
const char *key, int sockfd)
817
struct scm_sock_data *d;
819
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_GET_VALUE);
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) );
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);
836
if (!kick_fd_client(sockfd)) {
837
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
838
"Error writing to client: %s", strerror(errno));
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 '..'.
852
* XXX Should '/' be disallowed, only '..' allowed? Otherwise callers can't
853
* pretend to be the cgroup root which is annoying in itself
855
int cgmanager_get_value (void *data, NihDBusMessage *message,
856
const char *controller, const char *req_cgroup,
857
const char *key, char **value)
864
if (message == NULL) {
865
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
884
nih_info (_("GetValue: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
885
fd, rcred.pid, rcred.uid, rcred.gid);
887
ret = get_value_main(message, controller, req_cgroup, key, rcred, rcred, value);
889
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
894
void set_value_complete(struct scm_sock_data *data)
897
if (set_value_main(data->controller, data->cgroup, data->key,
898
data->value, data->pcred, data->rcred) == 0)
900
if (write(data->fd, &b, 1) < 0)
901
nih_error("SetValueScm: Error writing final result to client");
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)
908
struct scm_sock_data *d;
910
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_SET_VALUE);
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) );
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);
928
if (!kick_fd_client(sockfd)) {
929
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
930
"Error writing to client: %s", strerror(errno));
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.
943
int cgmanager_set_value (void *data, NihDBusMessage *message,
944
const char *controller, const char *req_cgroup,
945
const char *key, const char *value)
952
if (message == NULL) {
953
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
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.");
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",
972
nih_info (_("SetValue: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
973
fd, rcred.pid, rcred.uid, rcred.gid);
975
ret = set_value_main(controller, req_cgroup, key, value, rcred, rcred);
977
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
982
void remove_scm_complete(struct scm_sock_data *data)
986
int32_t existed = -1;
988
ret = remove_main(data->controller, data->cgroup, data->pcred,
989
data->rcred, data->recursive, &existed);
991
b = existed == 1 ? '2' : '1';
992
if (write(data->fd, &b, 1) < 0)
993
nih_error("removeScm: Error writing final result to client");
996
int cgmanager_remove_scm (void *data, NihDBusMessage *message,
997
const char *controller, const char *cgroup, int recursive, int sockfd)
999
struct scm_sock_data *d;
1001
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_REMOVE);
1004
d->controller = NIH_MUST( nih_strdup(d, controller) );
1005
d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
1006
d->recursive = recursive;
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);
1018
if (!kick_fd_client(sockfd)) {
1019
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1020
"Error writing to client: %s", strerror(errno));
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 .. .
1032
int cgmanager_remove (void *data, NihDBusMessage *message, const char *controller,
1033
const char *cgroup, int recursive, int32_t *existed)
1040
if (message == NULL) {
1041
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1042
"message was null");
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.");
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",
1060
nih_info (_("Remove: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
1061
fd, rcred.pid, rcred.uid, rcred.gid);
1063
ret = remove_main(controller, cgroup, rcred, rcred, recursive, existed);
1065
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1070
void get_tasks_scm_complete(struct scm_sock_data *data)
1074
int32_t *pids, nrpids;
1075
ret = get_tasks_main(data, data->controller, data->cgroup,
1076
data->pcred, data->rcred, &pids);
1078
nih_error("Error getting nrtasks for %s:%s for pid %d",
1079
data->controller, data->cgroup, data->rcred.pid);
1083
if (write(data->fd, &nrpids, sizeof(int32_t)) != sizeof(int32_t)) {
1084
nih_error("get_tasks_scm: Error writing final result to client");
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");
1097
int cgmanager_get_tasks_scm (void *data, NihDBusMessage *message,
1098
const char *controller, const char *cgroup, int sockfd)
1100
struct scm_sock_data *d;
1102
d = alloc_scm_sock_data(message, sockfd, REQ_TYPE_GET_TASKS);
1105
d->controller = NIH_MUST( nih_strdup(d, controller) );
1106
d->cgroup = NIH_MUST( nih_strdup(d, cgroup) );
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);
1118
if (!kick_fd_client(sockfd)) {
1119
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1120
"Error writing to client: %s", strerror(errno));
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.
1131
int cgmanager_get_tasks (void *data, NihDBusMessage *message, const char *controller,
1132
const char *cgroup, int32_t **pids, size_t *nrpids)
1139
if (message == NULL) {
1140
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1141
"message was null");
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.");
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",
1159
nih_info (_("GetTasks: Client fd is: %d (pid=%d, uid=%u, gid=%u)"),
1160
fd, rcred.pid, rcred.uid, rcred.gid);
1162
ret = get_tasks_main(message, controller, cgroup, rcred, rcred, &tmp);
1168
nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1174
cgmanager_get_api_version(void *data, NihDBusMessage *message, int *version)
1176
nih_assert(message);
1177
nih_assert(version);
1178
*version = API_VERSION;
1182
static dbus_bool_t allow_user(DBusConnection *connection, unsigned long uid, void *data)
1187
int client_connect (DBusServer *server, DBusConnection *conn)
1189
if (server == NULL || conn == NULL) {
1190
nih_error("client_connect called with bad arguments");
1194
dbus_connection_set_unix_user_function(conn, allow_user, NULL, NULL);
1195
dbus_connection_set_allow_anonymous(conn, TRUE);
1197
nih_info (_("Connection from private client"));
1199
NIH_MUST (nih_dbus_object_new (NULL, conn,
1200
"/org/linuxcontainers/cgmanager",
1201
cgmanager_interfaces, NULL));
1206
void client_disconnect (DBusConnection *conn)
1211
nih_info (_("Disconnected from private client"));