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;
}