NAME
oc_validate, validate_name, validate_dataset, is_in_exact_list, is_snapexists - validate OmniCube identifiers and test list and snapshot membership
SYNOPSIS
amp;. /opt/omnicube/lib/common/utils.sh
validate_name name [kind]
validate_dataset dataset
is_in_exact_list needle [item ...]
is_snapexists snapshot
DESCRIPTION
Almost every value these tools handle — a zone name, a node name, an ssh user, a ZFS dataset — arrives from outside the script: from an operator's command line, from an SMF property such as config/nodes, from a ZFS user property such as ${PROPPREFIX}:snappolicy, or from a backup policy file. Those values are then interpolated into privileged command lines: zonecfg(8), zoneadm(8), zfs(8), zpool(8), stmfadm(8), and — worse — into single-string remote commands passed to ssh(1), where they are re-parsed by a second shell. A value containing a space, a semicolon, a backquote, a $, a pipe, a redirection or a newline would run as a separate privileged command.
The two validators are the choke point for that risk. They are allow-lists, not sanitizers: nothing is stripped or quoted, the value is either accepted unchanged or rejected. Consumers call them before the value reaches a command line, and treat rejection as fatal for that item — see create_iscsi_lun.sh(8) (zone name into stmfadm/zfs), create_zone_pool.sh(8) (every node name from config/nodes), and manage_zone.sh(8) (remote dataset names before zfs set over ssh).
validate_name
Validates an identifier: a zone, a node, a host or a user name. kind is a noun used only in the diagnostic and defaults to name.
Accepted:
^[a-zA-Z0-9][a-zA-Z0-9._-]*$
that is, one leading alphanumeric followed by any number of alphanumerics, dots, underscores and hyphens. The leading-alphanumeric requirement rejects a value that begins with a hyphen and would otherwise be read as an option by the command it is passed to, and rejects a leading dot.
Rejected: the empty string, and any value containing anything else — space, tab, newline, ;, $, backquote, |, <, >, &, backslash, single or double quote, slash, colon, at sign, glob characters. On rejection it reports through error() (so the failure reaches syslog and the oc-alert mail, see oc_log(3)) with either
validate_name: empty <kind>
or
validate_name: invalid <kind> '<name>' (allowed: ...)
validate_dataset
Validates a ZFS dataset name. Identical to validate_name() except that the forward slash is also accepted, since a dataset name is a path:
^[a-zA-Z0-9][a-zA-Z0-9._/-]*$
The leading character still must be alphanumeric, so an absolute path or a -o style argument cannot pass. There is no kind argument; diagnostics name the function:
validate_dataset: empty dataset validate_dataset: invalid dataset '<ds>' (allowed: ...)
Note that @ is not accepted, so a snapshot name cannot be validated with this function; callers validate the dataset part and compose the @snapname suffix themselves.
is_in_exact_list
Tests whether needle equals any of the remaining arguments, character for character. Used to gate code paths on astring-list SMF properties, for instance config/monitor_exclude_pools in sys_monitor(8) and config/monitor_exclude_zones in zones_srv_monitor.sh(8), and to de-duplicate tuples in autocleansnap(8).
The comparison uses the literal [[ == ]] form deliberately, not [[ =~ ]]: an entry that happens to contain a regular-expression metacharacter, such as a pool or zone name with a dot in it, must match by character and must not act as a wildcard against unrelated names. An empty list — the usual case, when the SMF knob is unset — always yields false, so callers degrade safely to “nothing is excluded”.
is_snapexists
Tests whether snapshot exists, by running zfs list on it with both standard output and standard error discarded. It is a thin, unprivileged existence probe; autosnap(8) uses it to skip a snapshot it would otherwise try to create twice within one tick. It does not validate its argument, and it does not distinguish “does not exist” from “cannot be read”.
RETURN VALUES
None of these functions calls exit; all four are predicates and are meant to be tested. The idiomatic forms are validate_name "${x}" zone || return 1 and is_in_exact_list "${x}" "${list[@]}" && continue.
ENVIRONMENT
EXAMPLES
Example 1: validating operator input, fatally
zone=$2
validate_name "${zone}" "zone" || exit 1
${PFEXEC} zonecfg -z "${zone}" info
Example 2: validating configuration read from SMF
for node in ${nodes[@]}; do
validate_name "${node}" "node (from SMF config/nodes)" || exit 2
done
Example 3: exclusion list and snapshot skip
exclude_zones=($(svcprop -p config/monitor_exclude_zones ${OC_SMF}))
for zone in ${host_zones[@]}; do
is_in_exact_list "${zone}" "${exclude_zones[@]}" && continue
is_snapexists "${zone}@daily-$(date +%y-%W-%d)" && continue
done
SECURITY
These validators are the suite's injection boundary for values that reach privileged local commands and, over ssh(1), a remote shell. Two limitations must be understood.
First, they validate characters, not authorization: an accepted zone or dataset name is well-formed, not necessarily one the caller should be allowed to touch. Authorization comes from RBAC, through /etc/security/exec_attr.d/omnicube and /etc/security/prof_attr.d/omnicube.
Second, a validated value is still a string being pasted into a command line. Callers keep quoting it, and the accepted class is deliberately narrow enough that word splitting and glob expansion cannot change its meaning even where an older call site left it unquoted.
SEE ALSO
omnicube_utils(3), oc_log(3), oc_lock(3), oc_runlevel(3), oc_ssh(3), oc_policy(3), create_iscsi_lun.sh(8), create_zone_pool.sh(8), manage_zone.sh(8), autosnap(8), omnicube(7).
NOTES
The accepted classes are narrower than what ZFS and zones actually permit: zfs(8) allows : and % in dataset names, and a colon is common in third-party naming schemes. Such a name cannot be used with this suite. That is intentional — the class was chosen to be safe in a remote shell command line, not to be complete.
ssh_reachable() applies its own, separate pattern to an "[user@]host" target rather than calling validate_name(); see oc_ssh(3).
Rejection is reported with error(), which sends alert mail. A script that validates a long list of values from a misconfigured SMF property produces one alert per distinct bad value, subject to the mail throttle described in oc_log(3).