bool AuditRule::parse_add_F_arg()

in AuditRules.cpp [466:756]


bool AuditRule::parse_add_F_arg(const std::string& val, std::string& error) {
    auto idx = val.find_first_of("=!<>&");
    if (idx == 0) {
        error.append("Invalid value for option '-F': Missing field name: '");
        error.append(val);
        error.append("'");
        return false;
    }
    if (idx == std::string::npos) {
        error.append("Invalid value for option '-F': Missing operator: '");
        error.append(val);
        error.append("'");
        return false;
    }

    auto field_name = val.substr(0, idx);
    auto eidx = val.find_first_not_of("=!<>&", idx);
    if (eidx == std::string::npos) {
        error.append("Invalid value for option '-F': Missing value: '");
        error.append(val);
        error.append("'");
        return false;
    }

    auto op_str = val.substr(idx, eidx-idx);

    auto itr = s_F_ops.find(op_str);
    if (itr == s_F_ops.end()) {
        error.append("Invalid value for option '-F': Invalid operator: '");
        error.append(val);
        error.append("'");
        return false;
    }
    uint32_t op = itr->second;

    auto value = val.substr(eidx);
    if (value.empty()) {
        error.append("Invalid value for option '-F': Missing value: '");
        error.append(val);
        error.append("'");
        return false;
    }

    auto field = FieldNameToId(field_name);
    if (field < 0) {
        error.append("Invalid value for option '-F': Invalid field name: '");
        error.append(val);
        error.append("'");
        return false;
    }

    switch (field) {
        case AUDIT_UID:
        case AUDIT_EUID:
        case AUDIT_SUID:
        case AUDIT_FSUID:
        case AUDIT_LOGINUID:
        case AUDIT_OBJ_UID:
            try {
                if (std::isdigit(value[0])) {
                    uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
                    add_field(field, op, v);
                } else if (value.size() > 1 && value[0] == '-' && std::isdigit(value[1])) {
                    uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
                    add_field(field, op, v);
                } else {
                    if (value == "unset") {
                        add_field(field, op, 4294967295);
                    } else {
                        auto uid = UserDB::UserNameToUid(value);
                        if (uid < 0) {
                            error.append("Invalid value for option '-F': Unknown username: '");
                            error.append(val);
                            error.append("'");
                            return false;
                        }
                        add_field(field, op, uid);
                    }
                }
            } catch (std::exception &) {
                error.append("Invalid value for option '-F': Invalid numeric value: '");
                error.append(val);
                error.append("'");
                return false;
            }
            break;
        case AUDIT_GID:
        case AUDIT_EGID:
        case AUDIT_SGID:
        case AUDIT_FSGID:
        case AUDIT_OBJ_GID:
            try {
                if (std::isdigit(value[0])) {
                    uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
                    add_field(field, op, v);
                } else if (value.size() > 1 && value[0] == '-' && std::isdigit(value[1])) {
                    uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
                    add_field(field, op, v);
                } else {
                    if (value == "unset") {
                        add_field(field, op, 4294967295);
                    } else {
                        auto gid = UserDB::GroupNameToGid(value);
                        if (gid < 0) {
                            error.append("Invalid value for option '-F': Unknown group name: '");
                            error.append(val);
                            error.append("'");
                            return false;
                        }
                        add_field(field, op, gid);
                    }
                }
            } catch (std::exception &) {
                error.append("Invalid value for option '-F': Invalid numeric value: '");
                error.append(val);
                error.append("'");
                return false;
            }
            break;
        case AUDIT_EXIT:
            if ((ruleptr()->flags & FILTER_MASK) != AUDIT_FILTER_EXIT) {
                error.append("Invalid value for option '-F': Cannot filter on exit field unless flags (-a option) == 'exit'");
                return false;
            }
            try {
                if (std::isdigit(value[0])) {
                    uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
                    add_field(field, op, v);
                } else if (value.size() > 1 && value[0] == '-' && std::isdigit(value[1])) {
                    uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
                    add_field(field, op, v);
                } else {
                    auto v = NameToErrno(value);
                    if (v == 0) {
                        error.append("Invalid value for option '-F': Invalid errno name: '");
                        error.append(val);
                        error.append("'");
                        return false;
                    }
                    add_field(field, op, v);
                }
            } catch (std::exception &) {
                error.append("Invalid value for option '-F': Invalid numeric value: '");
                error.append(val);
                error.append("'");
                return false;
            }
            break;
        case AUDIT_MSGTYPE:
            if ((ruleptr()->flags & FILTER_MASK) != AUDIT_FILTER_TYPE) {
                error.append("Invalid value for option '-F': Cannot filter on msg type unless flags (-a option) == 'exclude'");
                return false;
            }
            if (std::isdigit(value[0])) {
                try {
                    uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
                    add_field(field, op, v);
                } catch (std::exception &) {
                    error.append("Invalid value for option '-F': Invalid numeric value: '");
                    error.append(val);
                    error.append("'");
                    return false;
                }
            } else {
                auto rt = RecordNameToType(value);
                if (rt == RecordType::UNKNOWN) {
                    error.append("Invalid value for option '-F': Invalid record type name: '");
                    error.append(val);
                    error.append("'");
                    return false;
                }
                add_field(field, op, static_cast<uint32_t>(rt));
            }
            break;
        case AUDIT_ARCH: {
            auto arch = ArchNameToArch(value);
            if (arch == 0) {
                error.append("Invalid value for option '-F': Invalid arch value: '");
                error.append(val);
                error.append("'");
            }
            if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL) {
                error.append("Invalid op(");
                error.append(op_str);
                error.append(") for option '-F': arch field only allows '=' and '!='");
            }
            add_field(field, op, arch);
            break;
        }
        case AUDIT_PERM: {
            uint32_t perms = 0;
            for (auto c: value) {
                switch (c) {
                    case 'a':
                        perms |= AUDIT_PERM_ATTR;
                        break;
                    case 'r':
                        perms |= AUDIT_PERM_READ;
                        break;
                    case 'w':
                        perms |= AUDIT_PERM_WRITE;
                        break;
                    case 'x':
                        perms |= AUDIT_PERM_EXEC;
                        break;
                    default:
                        error.append("Invalid value for option '-F': Invalid permission character: '");
                        error.append(val);
                        error.append("'");
                        return false;
                }
            }
            add_field(AUDIT_PERM, op, perms);
            break;
        }
        case AUDIT_OBJ_USER:
            /* fallthrough */
        case AUDIT_OBJ_ROLE:
            /* fallthrough */
        case AUDIT_OBJ_TYPE:
            /* fallthrough */
        case AUDIT_OBJ_LEV_LOW:
            /* fallthrough */
        case AUDIT_OBJ_LEV_HIGH:
            if (ruleptr()->flags != AUDIT_FILTER_EXIT) {
                error = "Field '" + field_name + "' can only be used with 'exit' filter";
                return false;
            }
            add_str_field(field, op, value);
            break;
        case AUDIT_WATCH:
            /* fallthrough */
        case AUDIT_DIR: {
            if (ruleptr()->flags != AUDIT_FILTER_EXIT) {
                error = "Field '" + field_name + "' can only be used with 'exit' filter";
                return false;
            }
            auto path = clean_path(value);
            if (!check_path(path, error)) {
                error = "Invalid path option: " + error;
                return false;
            }
            add_str_field(field, op, path);
            break;
        }
        case AUDIT_SUBJ_USER:
            /* fallthrough */
        case AUDIT_SUBJ_ROLE:
            /* fallthrough */
        case AUDIT_SUBJ_TYPE:
            /* fallthrough */
        case AUDIT_SUBJ_SEN:
            /* fallthrough */
        case AUDIT_SUBJ_CLR:
            /* fallthrough */
        case AUDIT_EXE:
            add_str_field(field, op, value);
            break;
        case AUDIT_FILTERKEY:
            AddKey(value);
            break;
        case AUDIT_FILETYPE: {
            if (ruleptr()->flags != AUDIT_FILTER_EXIT) {
                error = "Field '" + field_name + "' can only be used with 'exit' filter";
                return false;
            }
            auto ft = s_F_ftypes.find(value);
            if (ft != s_F_ftypes.end()) {
                add_field(field, op, ft->second);
            } else {
                error.append("Invalid value for option '-F': Invalid filetype name: '");
                error.append(val);
                error.append("'");
                return false;
            }
            break;
        }
        default:
            try {
                uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
                add_field(field, op, v);
            } catch (std::exception&) {
                error.append("Invalid value for option '-F': Invalid numeric value: '");
                error.append(val);
                error.append("'");
                return false;
            }
    }

    return true;
}