| /* |
| Copyright 2015-2021 Rivoreo |
| |
| This Source Code Form is subject to the terms of the Mozilla Public |
| License, v. 2.0. If a copy of the MPL was not distributed with this |
| file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| */ |
| |
| #include "common.h" |
| #include <priv.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <bash/command.h> |
| |
| static int get_privileges_common(char ***names, char **grants, char ***descriptions, unsigned int *count, int granted_only, const struct word_list *filter) { |
| priv_set_t *priv_set = priv_allocset(); |
| if(!priv_set) { |
| perror("priv_allocset"); |
| return -1; |
| } |
| int r = -1; |
| if(getppriv(PRIV_EFFECTIVE, priv_set) < 0) { |
| perror("getppriv"); |
| goto cleanup; |
| } |
| |
| //const priv_impl_info_t *pii = getprivimplinfo(); |
| //fprintf(stderr, "pii->priv_max = %u\n", (unsigned int)pii->priv_max); |
| |
| if(names) *names = NULL; |
| if(grants) *grants = NULL; |
| if(descriptions) *descriptions = NULL; |
| *count = 0; |
| |
| unsigned int current_count = 0; |
| unsigned int i = 0; |
| const char *name; |
| while((name = priv_getbynum(i++))) { |
| if((names || grants || descriptions) && (*count + 1) > current_count) { |
| current_count += 2; |
| if(names) { |
| char **new_p = realloc(*names, current_count * sizeof(char *)); |
| if(!new_p) { |
| fputs("Out of memory\n", stderr); |
| return -1; |
| } |
| *names = new_p; |
| } |
| if(grants) { |
| char *new_p = realloc(*grants, current_count); |
| if(!new_p) { |
| fputs("Out of memory\n", stderr); |
| return -1; |
| } |
| *grants = new_p; |
| } |
| if(descriptions) { |
| char **new_p = realloc(*descriptions, current_count * sizeof(char *)); |
| if(!new_p) { |
| fputs("Out of memory\n", stderr); |
| return -1; |
| } |
| *descriptions = new_p; |
| } |
| } |
| if(filter && !is_in_list_ignore_case(filter, name)) continue; |
| if(grants || granted_only) { |
| int is_granted = priv_ismember(priv_set, name); |
| if(!is_granted && granted_only) continue; |
| if(grants) (*grants)[*count] = is_granted; |
| }; |
| if(names) { |
| (*names)[*count] = strdup(name); |
| if(!(*names)[*count]) { |
| fputs("Out of memory\n", stderr); |
| goto failed; |
| } |
| } |
| if(descriptions) { |
| char *desc = priv_gettext(name); |
| (*descriptions)[*count] = desc; |
| if(desc) { |
| char *p = desc; |
| while((p = strchr(p, '\n'))) { |
| if(p > desc && p[-1] == '.') { |
| p[-1] = 0; |
| break; |
| } |
| *p = ' '; |
| } |
| } |
| } |
| (*count)++; |
| } |
| //fprintf(stderr, "i = %u\n", i); |
| r = 0; |
| cleanup: |
| priv_freeset(priv_set); |
| return r; |
| failed: |
| r = -1; |
| if(names && *names) { |
| unsigned int i = 0; |
| while(i < *count) free((*names)[i++]); |
| free(*names); |
| } |
| if(descriptions && *descriptions) { |
| unsigned int i = 0; |
| while(i < *count) free((*descriptions)[i++]); |
| free(*descriptions); |
| } |
| goto cleanup; |
| } |
| |
| int get_privileges(char ***names, char ***descriptions, unsigned int *count) { |
| return get_privileges_common(names, NULL, descriptions, count, 1, NULL); |
| } |
| |
| int get_all_privileges(char ***names, char **grants, char ***descriptions, unsigned int *count, const struct word_list *filter) { |
| return get_privileges_common(names, grants, descriptions, count, 0, filter); |
| } |
| |
| int set_privileges(const struct word_list *priv_list, int how) { |
| priv_set_t *priv_set = priv_allocset(); |
| if(!priv_set) { |
| perror("priv_allocset"); |
| return -1; |
| } |
| |
| int r = -1; |
| switch(how) { |
| case ADJUST: |
| if(getppriv(PRIV_EFFECTIVE, priv_set) < 0) { |
| perror("getppriv"); |
| goto cleanup; |
| } |
| break; |
| case ALLOW_OTHER: |
| priv_fillset(priv_set); |
| break; |
| case DENY_OTHER: |
| priv_emptyset(priv_set); |
| break; |
| case BASIC_SET: |
| priv_basicset(priv_set); |
| break; |
| default: |
| abort(); |
| } |
| |
| while(priv_list) { |
| const char *s = priv_list->word->word; |
| if((*s == '!' ? priv_delset(priv_set, ++s) : priv_addset(priv_set, s)) < 0) { |
| perror(s); |
| goto cleanup; |
| } |
| priv_list = priv_list->next; |
| } |
| |
| if(setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) < 0) { |
| perror("setppriv: PRIV_EFFECTIVE"); |
| goto cleanup; |
| } |
| if(setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) < 0) { |
| perror("setppriv: PRIV_INHERITABLE"); |
| goto cleanup; |
| } |
| |
| r = 0; |
| cleanup: |
| priv_freeset(priv_set); |
| return r; |
| } |