int ParseModeString(const char *modestring, mode_t *plusmask, mode_t *minusmask) { int affected = 0, value = 0, gotaction, no_error = true; char action = '='; enum modestate state = wild; enum modesort found_sort = unknown; /* Already found "sort" of mode */ enum modesort sort = unknown; /* Sort of started but not yet finished mode */ *plusmask = *minusmask = 0; if (modestring == NULL) { return true; } gotaction = false; for (const char *sp = modestring; true; sp++) { switch (*sp) { case 'a': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 07777; sort = symbolic; break; case 'u': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 04700; sort = symbolic; break; case 'g': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 02070; sort = symbolic; break; case 'o': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 00007; sort = symbolic; break; case '+': case '-': case '=': if (gotaction) { Log(LOG_LEVEL_ERR, "Too many +-= in mode string"); return false; } no_error = CheckModeState(who, state, symbolic, sort, *sp); action = *sp; state = which; gotaction = true; sort = unknown; break; case 'r': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 0444 & affected; sort = symbolic; break; case 'w': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 0222 & affected; sort = symbolic; break; case 'x': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 0111 & affected; sort = symbolic; break; case 's': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 06000 & affected; sort = symbolic; break; case 't': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 01000; sort = symbolic; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': no_error = CheckModeState(which, state, numeric, sort, *sp); sort = numeric; gotaction = true; state = which; affected = 07777; /* TODO: Hard-coded; see below */ sscanf(sp, "%o", &value); if (value & S_IFMT) { Log(LOG_LEVEL_INFO, "Mode-Value is not entirely within the system's allowed permissions (octal %o) and will be filtered accordingly : %s", S_IFMT, modestring); } /* stat() returns the file types in the mode, but they * can't be set. So we clear the file-type as per POSIX * 2001 instead of erroring out, leaving just the * permissions. */ value &= ~S_IFMT; if (value > 07777) /* TODO: Hardcoded ! Is this correct for all sorts of Unix ? What about NT ? Any (POSIX)-constants ?? */ { Log(LOG_LEVEL_ERR, "Mode-Value too big : %s", modestring); return false; } while ((isdigit((int) *sp)) && (*sp != '\0')) { sp++; } sp--; break; case ',': if (!SetModeMask(action, value, affected, plusmask, minusmask)) { return false; } if ((found_sort != unknown) && (found_sort != sort)) { Log(LOG_LEVEL_INFO, "Symbolic and numeric form for modes mixed"); } found_sort = sort; sort = unknown; action = '='; affected = 0; value = 0; gotaction = false; state = who; break; case '\0': if ((state == who) || (value == 0)) { if ((strcmp(modestring, "0000") != 0) && (strcmp(modestring, "000") != 0)) { Log(LOG_LEVEL_ERR, "mode string is incomplete"); return false; } } if (!SetModeMask(action, value, affected, plusmask, minusmask)) { return false; } if ((found_sort != unknown) && (found_sort != sort)) { Log(LOG_LEVEL_INFO, "Symbolic and numeric form for modes mixed"); } Log(LOG_LEVEL_DEBUG, "Modestring [PLUS = %" PRIoMAX "] [MINUS = %" PRIoMAX "]", (uintmax_t)*plusmask, (uintmax_t)*minusmask); return true; default: Log(LOG_LEVEL_ERR, "Invalid mode string (%s)", modestring); return false; } } if (!no_error) { Log(LOG_LEVEL_ERR, "Error validating mode string %s", modestring); } return no_error; }
int ParseModeString(const char *modestring, mode_t *plusmask, mode_t *minusmask) { int affected = 0, value = 0, gotaction, no_error = true; char action = '='; enum modestate state = wild; enum modesort found_sort = unknown; /* Already found "sort" of mode */ enum modesort sort = unknown; /* Sort of started but not yet finished mode */ *plusmask = *minusmask = 0; if (modestring == NULL) { return true; } CfDebug("ParseModeString(%s)\n", modestring); gotaction = false; for (const char *sp = modestring; true; sp++) { switch (*sp) { case 'a': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 07777; sort = symbolic; break; case 'u': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 04700; sort = symbolic; break; case 'g': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 02070; sort = symbolic; break; case 'o': no_error = CheckModeState(who, state, symbolic, sort, *sp); affected |= 00007; sort = symbolic; break; case '+': case '-': case '=': if (gotaction) { CfOut(cf_error, "", "Too many +-= in mode string"); return false; } no_error = CheckModeState(who, state, symbolic, sort, *sp); action = *sp; state = which; gotaction = true; sort = unknown; break; case 'r': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 0444 & affected; sort = symbolic; break; case 'w': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 0222 & affected; sort = symbolic; break; case 'x': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 0111 & affected; sort = symbolic; break; case 's': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 06000 & affected; sort = symbolic; break; case 't': no_error = CheckModeState(which, state, symbolic, sort, *sp); value |= 01000; sort = symbolic; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': no_error = CheckModeState(which, state, numeric, sort, *sp); sort = numeric; gotaction = true; state = which; affected = 07777; /* TODO: Hard-coded; see below */ sscanf(sp, "%o", &value); if (value > 07777) /* TODO: Hardcoded ! Is this correct for all sorts of Unix ? What about NT ? Any (POSIX)-constants ?? */ { CfOut(cf_error, "", "Mode-Value too big : %s\n", modestring); return false; } while (isdigit((int) *sp) && (*sp != '\0')) { sp++; } sp--; break; case ',': if (!SetModeMask(action, value, affected, plusmask, minusmask)) { return false; } if (found_sort != unknown && found_sort != sort) { CfOut(cf_inform, "", "Symbolic and numeric form for modes mixed"); } found_sort = sort; sort = unknown; action = '='; affected = 0; value = 0; gotaction = false; state = who; break; case '\0': if (state == who || value == 0) { if (strcmp(modestring, "0000") != 0 && strcmp(modestring, "000") != 0) { CfOut(cf_error, "", "mode string is incomplete"); return false; } } if (!SetModeMask(action, value, affected, plusmask, minusmask)) { return false; } if (found_sort != unknown && found_sort != sort) { CfOut(cf_inform, "", "Symbolic and numeric form for modes mixed"); } CfDebug("[PLUS=%jo][MINUS=%jo]\n", (uintmax_t)*plusmask, (uintmax_t)*minusmask); return true; default: CfOut(cf_error, "", "Invalid mode string (%s)", modestring); return false; } } if (!no_error) { CfOut(cf_error, "", "Error validating mode string %s\n", modestring); } return no_error; }