1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3 * This file is part of libmount from util-linux project.
4 *
5 * Copyright (C) 2022 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 *
13 * This is X-mount.owner=, X-mount.group= and X-mount.mode= implementation.
14 *
15 * Please, see the comment in libmount/src/hooks.c to understand how hooks work.
16 */
17 #include <sched.h>
18
19 #include "mountP.h"
20 #include "fileutils.h"
21
22 struct hook_data {
23 uid_t owner;
24 gid_t group;
25 mode_t mode;
26 };
27
28 /* de-initiallize this module */
29 static int hookset_deinit(struct libmnt_context *cxt, const struct libmnt_hookset *hs)
30 {
31 void *data;
32
33 DBG(HOOK, ul_debugobj(hs, "deinit '%s'", hs->name));
34
35 /* remove all our hooks and free hook data */
36 while (mnt_context_remove_hook(cxt, hs, 0, &data) == 0) {
37 free(data);
38 data = NULL;
39 }
40
41 return 0;
42 }
43
44 static int hook_post(
45 struct libmnt_context *cxt,
46 const struct libmnt_hookset *hs __attribute__((__unused__)),
47 void *data)
48 {
49 struct hook_data *hd = (struct hook_data *) data;
50 const char *target;
51 int rc = 0;
52
53 assert(cxt);
54
55 if (!hd || !cxt->fs)
56 return 0;
57
58 target = mnt_fs_get_target(cxt->fs);
59 if (!target)
60 return 0;
61
62 if (hd->owner != (uid_t) -1 || hd->group != (uid_t) -1) {
63 DBG(CXT, ul_debugobj(cxt, " lchown(%s, %u, %u)", target, hd->owner, hd->group));
64 if (lchown(target, hd->owner, hd->group) == -1)
65 return -MNT_ERR_CHOWN;
66 }
67
68 if (hd->mode != (mode_t) -1) {
69 DBG(CXT, ul_debugobj(cxt, " chmod(%s, %04o)", target, hd->mode));
70 if (chmod(target, hd->mode) == -1)
71 return -MNT_ERR_CHMOD;
72 }
73
74 return rc;
75 }
76
77 static inline struct hook_data *new_hook_data(void)
78 {
79 struct hook_data *hd = calloc(1, sizeof(*hd));
80
81 if (!hd)
82 return NULL;
83
84 hd->owner = (uid_t) -1;
85 hd->group = (gid_t) -1;
86 hd->mode = (mode_t) -1;
87 return hd;
88 }
89
90 static int hook_prepare_options(
91 struct libmnt_context *cxt,
92 const struct libmnt_hookset *hs,
93 void *data __attribute__((__unused__)))
94 {
95 struct hook_data *hd = NULL;
96 struct libmnt_optlist *ol;
97 struct libmnt_opt *opt;
98 int rc = 0;
99
100 assert(cxt);
101 assert(cxt->map_userspace);
102
103 ol = mnt_context_get_optlist(cxt);
104 if (!ol)
105 return -ENOMEM;
106
107 opt = mnt_optlist_get_named(ol, "X-mount.owner", cxt->map_userspace);
108 if (opt) {
109 const char *value = mnt_opt_get_value(opt);
110 if (!value)
111 goto fail;
112 if (!hd) {
113 hd = new_hook_data();
114 if (!hd)
115 goto fail;
116 }
117 if (mnt_parse_uid(value, strlen(value), &hd->owner))
118 goto fail;
119 }
120
121 opt = mnt_optlist_get_named(ol, "X-mount.group", cxt->map_userspace);
122 if (opt) {
123 const char *value = mnt_opt_get_value(opt);
124 if (!value)
125 goto fail;
126 if (!hd) {
127 hd = new_hook_data();
128 if (!hd)
129 goto fail;
130 }
131 if (mnt_parse_gid(value, strlen(value), &hd->group))
132 goto fail;
133 }
134
135 opt = mnt_optlist_get_named(ol, "X-mount.mode", cxt->map_userspace);
136 if (opt) {
137 const char *value = mnt_opt_get_value(opt);
138 if (!value)
139 goto fail;
140 if (!hd) {
141 hd = new_hook_data();
142 if (!hd)
143 goto fail;
144 }
145 if (mnt_parse_mode(value, strlen(value), &hd->mode))
146 goto fail;
147 }
148
149 if (hd) {
150 DBG(CXT, ul_debugobj(cxt, " wanted ownership %d:%d, mode %04o",
151 hd->owner, hd->group, hd->mode));
152 rc = mnt_context_append_hook(cxt, hs,
153 MNT_STAGE_POST,
154 hd, hook_post);
155 if (rc < 0)
156 goto fail;
157 }
158 return 0;
159 fail:
160 if (rc == 0)
161 rc = -MNT_ERR_MOUNTOPT;
162 free(hd);
163 return rc;
164 }
165
166
167 const struct libmnt_hookset hookset_owner =
168 {
169 .name = "__owner",
170
171 .firststage = MNT_STAGE_PREP_OPTIONS,
172 .firstcall = hook_prepare_options,
173
174 .deinit = hookset_deinit
175 };