// Copyright (C) 2016-2017 Luke Shumaker // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sd_login import ( "strconv" "strings" ) func valid_slice_name(s string) bool { return strings.HasSuffix(s, ".slice") && valid_unit_name(s) == unit_name_plain } func valid_user_tree(unit string) bool { sessStr, sessOk := trimPrefixSuffix(unit, "session-", ".scope") ownerStr, ownerOk := trimPrefixSuffix(unit, "user@", ".service") _, ownerErr := strconv.Atoi(ownerStr) return (sessOk && (SessionName(sessStr).isValid())) || (ownerOk && ownerErr == nil) } func valid_filename(s string) bool { switch s { case "", ".", "..": return false } if strings.ContainsRune(s, '/') { return false } return true } const ( unit_name_invalid = 0 unit_name_plain = 1 << 0 // foo.service unit_name_instance = 1 << 1 // foo@bar.service unit_name_template = 1 << 2 // foo@.service ) // valid_unit_name returns returns which type of unit the given unit // name is valid for. // // To simply check whether a unit name is valid, without caring about // the type, you can simply check that it doesn't return the "invalid" // type: // // is_valid := valid_unit_name(unitname) != unit_name_invalid // // To check whether it matches a specific type (in this example, // "template"), you can test equality against that type: // // is_valid_template := valid_unit_name(unitname) == unit_name_template // // If there are several acceptable types, you can treat multiple types // as bitmasks, and use the usual bitfield checks: // // is_valid_plain_or_instance := valid_unit_name(unitname)&(unit_name_plain|unit_name_instance) != 0 func valid_unit_name(unit string) int { const_unit_name_max := 256 const_unit_types := []string{ "service", "socket", "busname", "target", "device", "mount", "automount", "swap", "timer", "path", "slice", "scope", } if unit == "" { return unit_name_invalid } // If the unit name is too long if len(unit) >= const_unit_name_max { return unit_name_invalid } // If there is no dot in the unit name dot := strings.LastIndexByte(unit, '.') if dot < 0 || dot == 0 { return unit_name_invalid } // If the .suffix isn't a real unit type utype := unit[dot+1:] found := false for _, _utype := range const_unit_types { if utype == _utype { found = true break } } if !found { return unit_name_invalid } at := strings.IndexByte(unit, '@') // If the unit has more than one '@' if at >= 0 && strings.IndexByte(unit[at+1:], '@') >= 0 { return unit_name_invalid } // If the '@' is at the start of the unit if at == 0 { return unit_name_invalid } if at < 0 { return unit_name_plain } else { if dot > at+1 { return unit_name_instance } if dot == at+1 { return unit_name_template } } return unit_name_invalid }