blob: fc54f868c45187a5c1d854c6ee93012efdf0bfc6 [file] [log] [blame] [raw]
/*
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;
}