MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / edit_path_classify

Function edit_path_classify

src/cli/config_edit_path.c:203–342  ·  view source on GitHub ↗

One classification serves both the resolver and the diagnostic, so the * reason a user reads is exactly the rule that refused the link. On REFUSED * every descriptor opened along the way is closed again. */

Source from the content-addressed store, hash-verified

201 * reason a user reads is exactly the rule that refused the link. On REFUSED
202 * every descriptor opened along the way is closed again. */
203static int edit_path_classify(const char *path, cbm_config_edit_target_t *target, char *reason,
204 size_t reason_size) {
205 edit_path_target_reset(target);
206 if (reason && reason_size > 0U) {
207 reason[0] = '\0';
208 }
209 if (!path || !path[0]) {
210 return CBM_CONFIG_EDIT_PATH_REFUSED;
211 }
212 struct stat link_state;
213 if (lstat(path, &link_state) != 0 || !S_ISLNK(link_state.st_mode)) {
214 return edit_path_copy(path, target->path, sizeof(target->path)) == 0
215 ? CBM_CONFIG_EDIT_PATH_DIRECT
216 : CBM_CONFIG_EDIT_PATH_REFUSED;
217 }
218 if (!edit_path_link_dir_under_root(path)) {
219 edit_path_note(reason, reason_size,
220 edit_path_root_count == 0U
221 ? "symlinks are not followed by this command"
222 : "symlink outside the opted-in configuration roots");
223 return CBM_CONFIG_EDIT_PATH_REFUSED;
224 }
225 uid_t self = edit_path_invoking_uid();
226 if (self == 0 && link_state.st_uid != 0) {
227 if (reason && reason_size > 0U) {
228 (void)snprintf(reason, reason_size,
229 "symlink owned by uid %lu is not followed by a root process",
230 (unsigned long)link_state.st_uid);
231 }
232 return CBM_CONFIG_EDIT_PATH_REFUSED;
233 }
234 if (link_state.st_uid != self) {
235 edit_path_note_owner(reason, reason_size, "symlink", (unsigned long)link_state.st_uid,
236 (unsigned long)self);
237 return CBM_CONFIG_EDIT_PATH_REFUSED;
238 }
239 char resolved[CBM_CONFIG_EDIT_PATH_MAX];
240 struct stat target_state;
241 if (!cbm_canonical_path(path, resolved, sizeof(resolved)) ||
242 stat(resolved, &target_state) != 0) {
243 edit_path_note(reason, reason_size, "dangling symlink");
244 return CBM_CONFIG_EDIT_PATH_REFUSED;
245 }
246 if (!S_ISREG(target_state.st_mode)) {
247 edit_path_note(reason, reason_size,
248 S_ISDIR(target_state.st_mode) ? "symlink to a directory"
249 : "symlink to a special file");
250 return CBM_CONFIG_EDIT_PATH_REFUSED;
251 }
252 if (target_state.st_uid != self) {
253 edit_path_note_owner(reason, reason_size, "symlink target",
254 (unsigned long)target_state.st_uid, (unsigned long)self);
255 return CBM_CONFIG_EDIT_PATH_REFUSED;
256 }
257#if CBM_CONFIG_EDIT_TARGET_UNDER_ROOT
258 if (!edit_path_under_root(resolved)) {
259 edit_path_note(reason, reason_size, "symlink target outside the configuration roots");
260 return CBM_CONFIG_EDIT_PATH_REFUSED;

Callers 2

Calls 11

edit_path_target_resetFunction · 0.85
edit_path_copyFunction · 0.85
edit_path_noteFunction · 0.85
edit_path_invoking_uidFunction · 0.85
edit_path_note_ownerFunction · 0.85
cbm_canonical_pathFunction · 0.85
edit_path_under_rootFunction · 0.85
edit_path_splitFunction · 0.85
statClass · 0.70

Tested by

no test coverage detected