mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
0ab5d5cece
One case needs an extra variable declared. Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Amitay Isaacs <amitay@gmail.com>
248 lines
5.1 KiB
C
248 lines
5.1 KiB
C
/*
|
|
Low level event script handling
|
|
|
|
Copyright (C) Amitay Isaacs 2017
|
|
Copyright (C) Martin Schwenke 2018
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "replace.h"
|
|
#include "system/filesys.h"
|
|
#include "system/dir.h"
|
|
#include "system/glob.h"
|
|
|
|
#include <talloc.h>
|
|
|
|
#include "common/event_script.h"
|
|
|
|
static int script_filter(const struct dirent *de)
|
|
{
|
|
int ret;
|
|
|
|
/* Match a script pattern */
|
|
ret = fnmatch("[0-9][0-9].*.script", de->d_name, 0);
|
|
if (ret == 0) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int event_script_get_list(TALLOC_CTX *mem_ctx,
|
|
const char *script_dir,
|
|
struct event_script_list **out)
|
|
{
|
|
struct dirent **namelist = NULL;
|
|
struct event_script_list *script_list = NULL;
|
|
size_t ds_len;
|
|
int count, ret;
|
|
int i;
|
|
|
|
count = scandir(script_dir, &namelist, script_filter, alphasort);
|
|
if (count == -1) {
|
|
ret = errno;
|
|
goto done;
|
|
}
|
|
|
|
script_list = talloc_zero(mem_ctx, struct event_script_list);
|
|
if (script_list == NULL) {
|
|
goto nomem;
|
|
}
|
|
|
|
if (count == 0) {
|
|
ret = 0;
|
|
*out = script_list;
|
|
goto done;
|
|
}
|
|
|
|
script_list->num_scripts = count;
|
|
script_list->script = talloc_zero_array(script_list,
|
|
struct event_script *,
|
|
count);
|
|
if (script_list->script == NULL) {
|
|
goto nomem;
|
|
}
|
|
|
|
ds_len = strlen(".script");
|
|
for (i = 0; i < count; i++) {
|
|
struct event_script *s;
|
|
struct stat statbuf;
|
|
|
|
s = talloc_zero(script_list->script, struct event_script);
|
|
if (s == NULL) {
|
|
goto nomem;
|
|
}
|
|
|
|
script_list->script[i] = s;
|
|
|
|
s->name = talloc_strndup(script_list->script,
|
|
namelist[i]->d_name,
|
|
strlen(namelist[i]->d_name) - ds_len);
|
|
if (s->name == NULL) {
|
|
goto nomem;
|
|
}
|
|
|
|
s->path = talloc_asprintf(script_list->script,
|
|
"%s/%s",
|
|
script_dir,
|
|
namelist[i]->d_name);
|
|
if (s->path == NULL) {
|
|
goto nomem;
|
|
}
|
|
|
|
ret = stat(s->path, &statbuf);
|
|
if (ret == 0) {
|
|
/*
|
|
* If ret != 0 this is either a dangling
|
|
* symlink or it has just disappeared. Either
|
|
* way, it isn't executable. See the note
|
|
* below about things that have disappeared.
|
|
*/
|
|
if (statbuf.st_mode & S_IXUSR) {
|
|
s->enabled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
*out = script_list;
|
|
ret = 0;
|
|
goto done;
|
|
|
|
nomem:
|
|
ret = ENOMEM;
|
|
talloc_free(script_list);
|
|
|
|
done:
|
|
if (namelist != NULL && count != -1) {
|
|
for (i=0; i<count; i++) {
|
|
free(namelist[i]);
|
|
}
|
|
free(namelist);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int event_script_chmod(const char *script_dir,
|
|
const char *script_name,
|
|
bool enable)
|
|
{
|
|
const char *dot_script = ".script";
|
|
size_t ds_len = strlen(dot_script);
|
|
size_t sn_len = strlen(script_name);
|
|
DIR *dirp;
|
|
struct dirent *de;
|
|
char buf[PATH_MAX];
|
|
const char *script_file;
|
|
int ret, new_mode;
|
|
char filename[PATH_MAX];
|
|
struct stat st;
|
|
bool found;
|
|
ino_t found_inode;
|
|
int fd = -1;
|
|
|
|
/* Allow script_name to already have ".script" suffix */
|
|
if (sn_len > ds_len &&
|
|
strcmp(&script_name[sn_len - ds_len], dot_script) == 0) {
|
|
script_file = script_name;
|
|
} else {
|
|
ret = snprintf(buf, sizeof(buf), "%s.script", script_name);
|
|
if (ret < 0 || (size_t)ret >= sizeof(buf)) {
|
|
return ENAMETOOLONG;
|
|
}
|
|
script_file = buf;
|
|
}
|
|
|
|
dirp = opendir(script_dir);
|
|
if (dirp == NULL) {
|
|
return errno;
|
|
}
|
|
|
|
found = false;
|
|
while ((de = readdir(dirp)) != NULL) {
|
|
if (strcmp(de->d_name, script_file) == 0) {
|
|
/* check for valid script names */
|
|
ret = script_filter(de);
|
|
if (ret == 0) {
|
|
closedir(dirp);
|
|
return EINVAL;
|
|
}
|
|
|
|
found = true;
|
|
found_inode = de->d_ino;
|
|
break;
|
|
}
|
|
}
|
|
closedir(dirp);
|
|
|
|
if (! found) {
|
|
return ENOENT;
|
|
}
|
|
|
|
ret = snprintf(filename,
|
|
sizeof(filename),
|
|
"%s/%s",
|
|
script_dir,
|
|
script_file);
|
|
if (ret < 0 || (size_t)ret >= sizeof(filename)) {
|
|
return ENAMETOOLONG;
|
|
}
|
|
|
|
fd = open(filename, O_RDWR);
|
|
if (fd == -1) {
|
|
ret = errno;
|
|
goto done;
|
|
}
|
|
|
|
ret = fstat(fd, &st);
|
|
if (ret != 0) {
|
|
ret = errno;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* If the directory entry inode number doesn't match the one
|
|
* returned by fstat() then this is probably a symlink, so the
|
|
* caller should not be calling this function. Note that this
|
|
* is a cheap sanity check to catch most programming errors.
|
|
* This doesn't cost any extra system calls but can still miss
|
|
* the unlikely case where the symlink is to a file on a
|
|
* different filesystem with the same inode number as the
|
|
* symlink.
|
|
*/
|
|
if (found && found_inode != st.st_ino) {
|
|
ret = EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (enable) {
|
|
new_mode = st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH);
|
|
} else {
|
|
new_mode = st.st_mode & ~(S_IXUSR | S_IXGRP | S_IXOTH);
|
|
}
|
|
|
|
ret = fchmod(fd, new_mode);
|
|
if (ret != 0) {
|
|
ret = errno;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if (fd != -1) {
|
|
close(fd);
|
|
}
|
|
return ret;
|
|
}
|