nsswitch/winbind_nss_aix: reimplement fetching the SID of a user
[Samba.git] / ctdb / common / event_script.c
blob8978d1452c0cb5fc11d5a3691dd69228eb47e619
1 /*
2 Low level event script handling
4 Copyright (C) Amitay Isaacs 2017
5 Copyright (C) Martin Schwenke 2018
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "replace.h"
22 #include "system/filesys.h"
23 #include "system/dir.h"
24 #include "system/glob.h"
26 #include <talloc.h>
28 #include "common/event_script.h"
30 static int script_filter(const struct dirent *de)
32 int ret;
34 /* Match a script pattern */
35 ret = fnmatch("[0-9][0-9].*.script", de->d_name, 0);
36 if (ret == 0) {
37 return 1;
40 return 0;
43 int event_script_get_list(TALLOC_CTX *mem_ctx,
44 const char *script_dir,
45 struct event_script_list **out)
47 struct dirent **namelist = NULL;
48 struct event_script_list *script_list = NULL;
49 size_t ds_len;
50 int count, ret;
51 int i;
53 count = scandir(script_dir, &namelist, script_filter, alphasort);
54 if (count == -1) {
55 ret = errno;
56 goto done;
59 script_list = talloc_zero(mem_ctx, struct event_script_list);
60 if (script_list == NULL) {
61 goto nomem;
64 if (count == 0) {
65 ret = 0;
66 *out = script_list;
67 goto done;
70 script_list->num_scripts = count;
71 script_list->script = talloc_zero_array(script_list,
72 struct event_script *,
73 count);
74 if (script_list->script == NULL) {
75 goto nomem;
78 ds_len = strlen(".script");
79 for (i = 0; i < count; i++) {
80 struct event_script *s;
81 struct stat statbuf;
83 s = talloc_zero(script_list->script, struct event_script);
84 if (s == NULL) {
85 goto nomem;
88 script_list->script[i] = s;
90 s->name = talloc_strndup(script_list->script,
91 namelist[i]->d_name,
92 strlen(namelist[i]->d_name) - ds_len);
93 if (s->name == NULL) {
94 goto nomem;
97 s->path = talloc_asprintf(script_list->script,
98 "%s/%s",
99 script_dir,
100 namelist[i]->d_name);
101 if (s->path == NULL) {
102 goto nomem;
105 ret = stat(s->path, &statbuf);
106 if (ret == 0) {
108 * If ret != 0 this is either a dangling
109 * symlink or it has just disappeared. Either
110 * way, it isn't executable. See the note
111 * below about things that have disappeared.
113 if (statbuf.st_mode & S_IXUSR) {
114 s->enabled = true;
119 *out = script_list;
120 return 0;
122 nomem:
123 ret = ENOMEM;
124 talloc_free(script_list);
126 done:
127 if (namelist != NULL && count != -1) {
128 for (i=0; i<count; i++) {
129 free(namelist[i]);
131 free(namelist);
134 return ret;
137 int event_script_chmod(const char *script_dir,
138 const char *script_name,
139 bool enable)
141 const char *dot_script = ".script";
142 size_t ds_len = strlen(dot_script);
143 size_t sn_len = strlen(script_name);
144 DIR *dirp;
145 struct dirent *de;
146 char buf[PATH_MAX];
147 const char *script_file;
148 int ret, new_mode;
149 char filename[PATH_MAX];
150 struct stat st;
151 bool found;
152 ino_t found_inode;
153 int fd = -1;
155 /* Allow script_name to already have ".script" suffix */
156 if (sn_len > ds_len &&
157 strcmp(&script_name[sn_len - ds_len], dot_script) == 0) {
158 script_file = script_name;
159 } else {
160 ret = snprintf(buf, sizeof(buf), "%s.script", script_name);
161 if (ret >= sizeof(buf)) {
162 return ENAMETOOLONG;
164 script_file = buf;
167 dirp = opendir(script_dir);
168 if (dirp == NULL) {
169 return errno;
172 found = false;
173 while ((de = readdir(dirp)) != NULL) {
174 if (strcmp(de->d_name, script_file) == 0) {
175 /* check for valid script names */
176 ret = script_filter(de);
177 if (ret == 0) {
178 closedir(dirp);
179 return EINVAL;
182 found = true;
183 found_inode = de->d_ino;
184 break;
187 closedir(dirp);
189 if (! found) {
190 return ENOENT;
193 ret = snprintf(filename,
194 sizeof(filename),
195 "%s/%s",
196 script_dir,
197 script_file);
198 if (ret >= sizeof(filename)) {
199 return ENAMETOOLONG;
202 fd = open(filename, O_RDWR);
203 if (fd == -1) {
204 ret = errno;
205 goto done;
208 ret = fstat(fd, &st);
209 if (ret != 0) {
210 ret = errno;
211 goto done;
215 * If the directory entry inode number doesn't match the one
216 * returned by fstat() then this is probably a symlink, so the
217 * caller should not be calling this function. Note that this
218 * is a cheap sanity check to catch most programming errors.
219 * This doesn't cost any extra system calls but can still miss
220 * the unlikely case where the symlink is to a file on a
221 * different filesystem with the same inode number as the
222 * symlink.
224 if (found && found_inode != st.st_ino) {
225 ret = EINVAL;
226 goto done;
229 if (enable) {
230 new_mode = st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH);
231 } else {
232 new_mode = st.st_mode & ~(S_IXUSR | S_IXGRP | S_IXOTH);
235 ret = fchmod(fd, new_mode);
236 if (ret != 0) {
237 ret = errno;
238 goto done;
241 done:
242 if (fd != -1) {
243 close(fd);
245 return ret;