| File: | build-scan/../src/shared/acl-util.c |
| Warning: | line 400, column 13 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
| 2 | ||||
| 3 | #include <errno(*__errno_location ()).h> | |||
| 4 | #include <stdbool.h> | |||
| 5 | ||||
| 6 | #include "acl-util.h" | |||
| 7 | #include "alloc-util.h" | |||
| 8 | #include "string-util.h" | |||
| 9 | #include "strv.h" | |||
| 10 | #include "user-util.h" | |||
| 11 | #include "util.h" | |||
| 12 | ||||
| 13 | int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { | |||
| 14 | acl_entry_t i; | |||
| 15 | int r; | |||
| 16 | ||||
| 17 | assert(acl)do { if ((__builtin_expect(!!(!(acl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acl"), "../src/shared/acl-util.c", 17, __PRETTY_FUNCTION__ ); } while (0); | |||
| 18 | assert(entry)do { if ((__builtin_expect(!!(!(entry)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("entry"), "../src/shared/acl-util.c", 18 , __PRETTY_FUNCTION__); } while (0); | |||
| 19 | ||||
| 20 | for (r = acl_get_entry(acl, ACL_FIRST_ENTRY0, &i); | |||
| 21 | r > 0; | |||
| 22 | r = acl_get_entry(acl, ACL_NEXT_ENTRY1, &i)) { | |||
| 23 | ||||
| 24 | acl_tag_t tag; | |||
| 25 | uid_t *u; | |||
| 26 | bool_Bool b; | |||
| 27 | ||||
| 28 | if (acl_get_tag_type(i, &tag) < 0) | |||
| 29 | return -errno(*__errno_location ()); | |||
| 30 | ||||
| 31 | if (tag != ACL_USER(0x02)) | |||
| 32 | continue; | |||
| 33 | ||||
| 34 | u = acl_get_qualifier(i); | |||
| 35 | if (!u) | |||
| 36 | return -errno(*__errno_location ()); | |||
| 37 | ||||
| 38 | b = *u == uid; | |||
| 39 | acl_free(u); | |||
| 40 | ||||
| 41 | if (b) { | |||
| 42 | *entry = i; | |||
| 43 | return 1; | |||
| 44 | } | |||
| 45 | } | |||
| 46 | if (r < 0) | |||
| 47 | return -errno(*__errno_location ()); | |||
| 48 | ||||
| 49 | return 0; | |||
| 50 | } | |||
| 51 | ||||
| 52 | int calc_acl_mask_if_needed(acl_t *acl_p) { | |||
| 53 | acl_entry_t i; | |||
| 54 | int r; | |||
| 55 | bool_Bool need = false0; | |||
| 56 | ||||
| 57 | assert(acl_p)do { if ((__builtin_expect(!!(!(acl_p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acl_p"), "../src/shared/acl-util.c", 57 , __PRETTY_FUNCTION__); } while (0); | |||
| 58 | ||||
| 59 | for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY0, &i); | |||
| 60 | r > 0; | |||
| 61 | r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY1, &i)) { | |||
| 62 | acl_tag_t tag; | |||
| 63 | ||||
| 64 | if (acl_get_tag_type(i, &tag) < 0) | |||
| 65 | return -errno(*__errno_location ()); | |||
| 66 | ||||
| 67 | if (tag == ACL_MASK(0x10)) | |||
| 68 | return 0; | |||
| 69 | ||||
| 70 | if (IN_SET(tag, ACL_USER, ACL_GROUP)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){(0x02), (0x08)})/sizeof(int)]; switch(tag ) { case (0x02): case (0x08): _found = 1; break; default: break ; } _found; })) | |||
| 71 | need = true1; | |||
| 72 | } | |||
| 73 | if (r < 0) | |||
| 74 | return -errno(*__errno_location ()); | |||
| 75 | ||||
| 76 | if (need && acl_calc_mask(acl_p) < 0) | |||
| 77 | return -errno(*__errno_location ()); | |||
| 78 | ||||
| 79 | return need; | |||
| 80 | } | |||
| 81 | ||||
| 82 | int add_base_acls_if_needed(acl_t *acl_p, const char *path) { | |||
| 83 | acl_entry_t i; | |||
| 84 | int r; | |||
| 85 | bool_Bool have_user_obj = false0, have_group_obj = false0, have_other = false0; | |||
| 86 | struct stat st; | |||
| 87 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t basic = NULL((void*)0); | |||
| 88 | ||||
| 89 | assert(acl_p)do { if ((__builtin_expect(!!(!(acl_p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acl_p"), "../src/shared/acl-util.c", 89 , __PRETTY_FUNCTION__); } while (0); | |||
| 90 | ||||
| 91 | for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY0, &i); | |||
| 92 | r > 0; | |||
| 93 | r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY1, &i)) { | |||
| 94 | acl_tag_t tag; | |||
| 95 | ||||
| 96 | if (acl_get_tag_type(i, &tag) < 0) | |||
| 97 | return -errno(*__errno_location ()); | |||
| 98 | ||||
| 99 | if (tag == ACL_USER_OBJ(0x01)) | |||
| 100 | have_user_obj = true1; | |||
| 101 | else if (tag == ACL_GROUP_OBJ(0x04)) | |||
| 102 | have_group_obj = true1; | |||
| 103 | else if (tag == ACL_OTHER(0x20)) | |||
| 104 | have_other = true1; | |||
| 105 | if (have_user_obj && have_group_obj && have_other) | |||
| 106 | return 0; | |||
| 107 | } | |||
| 108 | if (r < 0) | |||
| 109 | return -errno(*__errno_location ()); | |||
| 110 | ||||
| 111 | r = stat(path, &st); | |||
| 112 | if (r < 0) | |||
| 113 | return -errno(*__errno_location ()); | |||
| 114 | ||||
| 115 | basic = acl_from_mode(st.st_mode); | |||
| 116 | if (!basic) | |||
| 117 | return -errno(*__errno_location ()); | |||
| 118 | ||||
| 119 | for (r = acl_get_entry(basic, ACL_FIRST_ENTRY0, &i); | |||
| 120 | r > 0; | |||
| 121 | r = acl_get_entry(basic, ACL_NEXT_ENTRY1, &i)) { | |||
| 122 | acl_tag_t tag; | |||
| 123 | acl_entry_t dst; | |||
| 124 | ||||
| 125 | if (acl_get_tag_type(i, &tag) < 0) | |||
| 126 | return -errno(*__errno_location ()); | |||
| 127 | ||||
| 128 | if ((tag == ACL_USER_OBJ(0x01) && have_user_obj) || | |||
| 129 | (tag == ACL_GROUP_OBJ(0x04) && have_group_obj) || | |||
| 130 | (tag == ACL_OTHER(0x20) && have_other)) | |||
| 131 | continue; | |||
| 132 | ||||
| 133 | r = acl_create_entry(acl_p, &dst); | |||
| 134 | if (r < 0) | |||
| 135 | return -errno(*__errno_location ()); | |||
| 136 | ||||
| 137 | r = acl_copy_entry(dst, i); | |||
| 138 | if (r < 0) | |||
| 139 | return -errno(*__errno_location ()); | |||
| 140 | } | |||
| 141 | if (r < 0) | |||
| 142 | return -errno(*__errno_location ()); | |||
| 143 | return 0; | |||
| 144 | } | |||
| 145 | ||||
| 146 | int acl_search_groups(const char *path, char ***ret_groups) { | |||
| 147 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **g = NULL((void*)0); | |||
| 148 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t acl = NULL((void*)0); | |||
| 149 | bool_Bool ret = false0; | |||
| 150 | acl_entry_t entry; | |||
| 151 | int r; | |||
| 152 | ||||
| 153 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/shared/acl-util.c", 153 , __PRETTY_FUNCTION__); } while (0); | |||
| 154 | ||||
| 155 | acl = acl_get_file(path, ACL_TYPE_DEFAULT(0x4000)); | |||
| 156 | if (!acl) | |||
| 157 | return -errno(*__errno_location ()); | |||
| 158 | ||||
| 159 | r = acl_get_entry(acl, ACL_FIRST_ENTRY0, &entry); | |||
| 160 | for (;;) { | |||
| 161 | _cleanup_(acl_free_gid_tpp)__attribute__((cleanup(acl_free_gid_tpp))) gid_t *gid = NULL((void*)0); | |||
| 162 | acl_tag_t tag; | |||
| 163 | ||||
| 164 | if (r < 0) | |||
| 165 | return -errno(*__errno_location ()); | |||
| 166 | if (r == 0) | |||
| 167 | break; | |||
| 168 | ||||
| 169 | if (acl_get_tag_type(entry, &tag) < 0) | |||
| 170 | return -errno(*__errno_location ()); | |||
| 171 | ||||
| 172 | if (tag != ACL_GROUP(0x08)) | |||
| 173 | goto next; | |||
| 174 | ||||
| 175 | gid = acl_get_qualifier(entry); | |||
| 176 | if (!gid) | |||
| 177 | return -errno(*__errno_location ()); | |||
| 178 | ||||
| 179 | if (in_gid(*gid) > 0) { | |||
| 180 | if (!ret_groups) | |||
| 181 | return true1; | |||
| 182 | ||||
| 183 | ret = true1; | |||
| 184 | } | |||
| 185 | ||||
| 186 | if (ret_groups) { | |||
| 187 | char *name; | |||
| 188 | ||||
| 189 | name = gid_to_name(*gid); | |||
| 190 | if (!name) | |||
| 191 | return -ENOMEM12; | |||
| 192 | ||||
| 193 | r = strv_consume(&g, name); | |||
| 194 | if (r < 0) | |||
| 195 | return r; | |||
| 196 | } | |||
| 197 | ||||
| 198 | next: | |||
| 199 | r = acl_get_entry(acl, ACL_NEXT_ENTRY1, &entry); | |||
| 200 | } | |||
| 201 | ||||
| 202 | if (ret_groups) | |||
| 203 | *ret_groups = TAKE_PTR(g)({ typeof(g) _ptr_ = (g); (g) = ((void*)0); _ptr_; }); | |||
| 204 | ||||
| 205 | return ret; | |||
| 206 | } | |||
| 207 | ||||
| 208 | int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool_Bool want_mask) { | |||
| 209 | _cleanup_free___attribute__((cleanup(freep))) char **a = NULL((void*)0), **d = NULL((void*)0); /* strings are not freed */ | |||
| 210 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **split; | |||
| 211 | char **entry; | |||
| 212 | int r = -EINVAL22; | |||
| 213 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t a_acl = NULL((void*)0), d_acl = NULL((void*)0); | |||
| 214 | ||||
| 215 | split = strv_split(text, ","); | |||
| 216 | if (!split) | |||
| 217 | return -ENOMEM12; | |||
| 218 | ||||
| 219 | STRV_FOREACH(entry, split)for ((entry) = (split); (entry) && *(entry); (entry)++ ) { | |||
| 220 | char *p; | |||
| 221 | ||||
| 222 | p = startswith(*entry, "default:"); | |||
| 223 | if (!p) | |||
| 224 | p = startswith(*entry, "d:"); | |||
| 225 | ||||
| 226 | if (p) | |||
| 227 | r = strv_push(&d, p); | |||
| 228 | else | |||
| 229 | r = strv_push(&a, *entry); | |||
| 230 | if (r < 0) | |||
| 231 | return r; | |||
| 232 | } | |||
| 233 | ||||
| 234 | if (!strv_isempty(a)) { | |||
| 235 | _cleanup_free___attribute__((cleanup(freep))) char *join; | |||
| 236 | ||||
| 237 | join = strv_join(a, ","); | |||
| 238 | if (!join) | |||
| 239 | return -ENOMEM12; | |||
| 240 | ||||
| 241 | a_acl = acl_from_text(join); | |||
| 242 | if (!a_acl) | |||
| 243 | return -errno(*__errno_location ()); | |||
| 244 | ||||
| 245 | if (want_mask) { | |||
| 246 | r = calc_acl_mask_if_needed(&a_acl); | |||
| 247 | if (r < 0) | |||
| 248 | return r; | |||
| 249 | } | |||
| 250 | } | |||
| 251 | ||||
| 252 | if (!strv_isempty(d)) { | |||
| 253 | _cleanup_free___attribute__((cleanup(freep))) char *join; | |||
| 254 | ||||
| 255 | join = strv_join(d, ","); | |||
| 256 | if (!join) | |||
| 257 | return -ENOMEM12; | |||
| 258 | ||||
| 259 | d_acl = acl_from_text(join); | |||
| 260 | if (!d_acl) | |||
| 261 | return -errno(*__errno_location ()); | |||
| 262 | ||||
| 263 | if (want_mask) { | |||
| 264 | r = calc_acl_mask_if_needed(&d_acl); | |||
| 265 | if (r < 0) | |||
| 266 | return r; | |||
| 267 | } | |||
| 268 | } | |||
| 269 | ||||
| 270 | *acl_access = TAKE_PTR(a_acl)({ typeof(a_acl) _ptr_ = (a_acl); (a_acl) = ((void*)0); _ptr_ ; }); | |||
| 271 | *acl_default = TAKE_PTR(d_acl)({ typeof(d_acl) _ptr_ = (d_acl); (d_acl) = ((void*)0); _ptr_ ; }); | |||
| 272 | ||||
| 273 | return 0; | |||
| 274 | } | |||
| 275 | ||||
| 276 | static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { | |||
| 277 | acl_tag_t tag_a, tag_b; | |||
| 278 | ||||
| 279 | if (acl_get_tag_type(a, &tag_a) < 0) | |||
| 280 | return -errno(*__errno_location ()); | |||
| 281 | ||||
| 282 | if (acl_get_tag_type(b, &tag_b) < 0) | |||
| 283 | return -errno(*__errno_location ()); | |||
| 284 | ||||
| 285 | if (tag_a != tag_b) | |||
| 286 | return false0; | |||
| 287 | ||||
| 288 | switch (tag_a) { | |||
| 289 | case ACL_USER_OBJ(0x01): | |||
| 290 | case ACL_GROUP_OBJ(0x04): | |||
| 291 | case ACL_MASK(0x10): | |||
| 292 | case ACL_OTHER(0x20): | |||
| 293 | /* can have only one of those */ | |||
| 294 | return true1; | |||
| 295 | case ACL_USER(0x02): { | |||
| 296 | _cleanup_(acl_free_uid_tpp)__attribute__((cleanup(acl_free_uid_tpp))) uid_t *uid_a = NULL((void*)0), *uid_b = NULL((void*)0); | |||
| 297 | ||||
| 298 | uid_a = acl_get_qualifier(a); | |||
| 299 | if (!uid_a) | |||
| 300 | return -errno(*__errno_location ()); | |||
| 301 | ||||
| 302 | uid_b = acl_get_qualifier(b); | |||
| 303 | if (!uid_b) | |||
| 304 | return -errno(*__errno_location ()); | |||
| 305 | ||||
| 306 | return *uid_a == *uid_b; | |||
| 307 | } | |||
| 308 | case ACL_GROUP(0x08): { | |||
| 309 | _cleanup_(acl_free_gid_tpp)__attribute__((cleanup(acl_free_gid_tpp))) gid_t *gid_a = NULL((void*)0), *gid_b = NULL((void*)0); | |||
| 310 | ||||
| 311 | gid_a = acl_get_qualifier(a); | |||
| 312 | if (!gid_a) | |||
| 313 | return -errno(*__errno_location ()); | |||
| 314 | ||||
| 315 | gid_b = acl_get_qualifier(b); | |||
| 316 | if (!gid_b) | |||
| 317 | return -errno(*__errno_location ()); | |||
| 318 | ||||
| 319 | return *gid_a == *gid_b; | |||
| 320 | } | |||
| 321 | default: | |||
| 322 | assert_not_reached("Unknown acl tag type")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unknown acl tag type"), "../src/shared/acl-util.c", 322, __PRETTY_FUNCTION__ ); } while (0); | |||
| 323 | } | |||
| 324 | } | |||
| 325 | ||||
| 326 | static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) { | |||
| 327 | acl_entry_t i; | |||
| 328 | int r; | |||
| 329 | ||||
| 330 | for (r = acl_get_entry(acl, ACL_FIRST_ENTRY0, &i); | |||
| 331 | r > 0; | |||
| 332 | r = acl_get_entry(acl, ACL_NEXT_ENTRY1, &i)) { | |||
| 333 | ||||
| 334 | r = acl_entry_equal(i, entry); | |||
| 335 | if (r < 0) | |||
| 336 | return r; | |||
| 337 | if (r > 0) { | |||
| 338 | *out = i; | |||
| 339 | return 1; | |||
| 340 | } | |||
| 341 | } | |||
| 342 | if (r < 0) | |||
| 343 | return -errno(*__errno_location ()); | |||
| 344 | return 0; | |||
| 345 | } | |||
| 346 | ||||
| 347 | int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { | |||
| 348 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t old; | |||
| 349 | acl_entry_t i; | |||
| 350 | int r; | |||
| 351 | ||||
| 352 | old = acl_get_file(path, type); | |||
| 353 | if (!old) | |||
| 354 | return -errno(*__errno_location ()); | |||
| 355 | ||||
| 356 | for (r = acl_get_entry(new, ACL_FIRST_ENTRY0, &i); | |||
| 357 | r > 0; | |||
| 358 | r = acl_get_entry(new, ACL_NEXT_ENTRY1, &i)) { | |||
| 359 | ||||
| 360 | acl_entry_t j; | |||
| 361 | ||||
| 362 | r = find_acl_entry(old, i, &j); | |||
| 363 | if (r < 0) | |||
| 364 | return r; | |||
| 365 | if (r == 0) | |||
| 366 | if (acl_create_entry(&old, &j) < 0) | |||
| 367 | return -errno(*__errno_location ()); | |||
| 368 | ||||
| 369 | if (acl_copy_entry(j, i) < 0) | |||
| 370 | return -errno(*__errno_location ()); | |||
| 371 | } | |||
| 372 | if (r < 0) | |||
| 373 | return -errno(*__errno_location ()); | |||
| 374 | ||||
| 375 | *acl = TAKE_PTR(old)({ typeof(old) _ptr_ = (old); (old) = ((void*)0); _ptr_; }); | |||
| 376 | ||||
| 377 | return 0; | |||
| 378 | } | |||
| 379 | ||||
| 380 | int add_acls_for_user(int fd, uid_t uid) { | |||
| 381 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t acl = NULL((void*)0); | |||
| 382 | acl_entry_t entry; | |||
| ||||
| 383 | acl_permset_t permset; | |||
| 384 | int r; | |||
| 385 | ||||
| 386 | acl = acl_get_fd(fd); | |||
| 387 | if (!acl) | |||
| 388 | return -errno(*__errno_location ()); | |||
| 389 | ||||
| 390 | r = acl_find_uid(acl, uid, &entry); | |||
| 391 | if (r <= 0) { | |||
| 392 | if (acl_create_entry(&acl, &entry) < 0 || | |||
| 393 | acl_set_tag_type(entry, ACL_USER(0x02)) < 0 || | |||
| 394 | acl_set_qualifier(entry, &uid) < 0) | |||
| 395 | return -errno(*__errno_location ()); | |||
| 396 | } | |||
| 397 | ||||
| 398 | /* We do not recalculate the mask unconditionally here, | |||
| 399 | * so that the fchmod() mask above stays intact. */ | |||
| 400 | if (acl_get_permset(entry, &permset) < 0 || | |||
| ||||
| 401 | acl_add_perm(permset, ACL_READ(0x04)) < 0) | |||
| 402 | return -errno(*__errno_location ()); | |||
| 403 | ||||
| 404 | r = calc_acl_mask_if_needed(&acl); | |||
| 405 | if (r < 0) | |||
| 406 | return r; | |||
| 407 | ||||
| 408 | return acl_set_fd(fd, acl); | |||
| 409 | } |