// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // // Contributor: Julien Vehent jvehent@mozilla.com [:ulfr] package mig /* import "github.com/mozilla/mig" */ import ( "fmt" "time" ) // Investigator describes a single MIG investigator type Investigator struct { ID float64 `json:"id,omitempty"` Name string `json:"name"` PGPFingerprint string `json:"pgpfingerprint"` PublicKey []byte `json:"publickey,omitempty"` PrivateKey []byte `json:"privatekey,omitempty"` Status string `json:"status"` CreatedAt time.Time `json:"createdat"` LastModified time.Time `json:"lastmodified"` APIKey string `json:"apikey,omitempty"` Permissions InvestigatorPerms `json:"permissions"` } // CheckPermission validates if an investigator has given permission pv func (i *Investigator) CheckPermission(pv int64) bool { switch pv { case PermSearch: return i.Permissions.Search case PermAction: return i.Permissions.Action case PermActionCreate: return i.Permissions.ActionCreate case PermCommand: return i.Permissions.Command case PermAgent: return i.Permissions.Agent case PermDashboard: return i.Permissions.Dashboard case PermLoader: return i.Permissions.Loader case PermLoaderStatus: return i.Permissions.LoaderStatus case PermLoaderExpect: return i.Permissions.LoaderExpect case PermLoaderKey: return i.Permissions.LoaderKey case PermLoaderNew: return i.Permissions.LoaderNew case PermManifest: return i.Permissions.Manifest case PermManifestSign: return i.Permissions.ManifestSign case PermManifestNew: return i.Permissions.ManifestNew case PermManifestLoaders: return i.Permissions.ManifestLoaders case PermInvestigator: return i.Permissions.Investigator case PermInvestigatorCreate: return i.Permissions.InvestigatorCreate case PermInvestigatorUpdate: return i.Permissions.InvestigatorUpdate } return false } // InvestigatorPerms describes permissions assigned to an investigator type InvestigatorPerms struct { Search bool `json:"search"` Action bool `json:"action"` ActionCreate bool `json:"action_create"` Command bool `json:"command"` Agent bool `json:"agent"` Dashboard bool `json:"dashboard"` Loader bool `json:"loader"` LoaderStatus bool `json:"loader_status"` LoaderExpect bool `json:"loader_expect"` LoaderKey bool `json:"loader_key"` LoaderNew bool `json:"loader_new"` Manifest bool `json:"manifest"` ManifestSign bool `json:"manifest_sign"` ManifestStatus bool `json:"manifest_status"` ManifestNew bool `json:"manifest_new"` ManifestLoaders bool `json:"manifest_loaders"` Investigator bool `json:"investigator"` InvestigatorCreate bool `json:"investigator_create"` InvestigatorUpdate bool `json:"investigator_update"` } // FromMask converts a permission bit mask into a boolean permission set func (ip *InvestigatorPerms) FromMask(mask int64) { if (mask & PermSearch) != 0 { ip.Search = true } if (mask & PermAction) != 0 { ip.Action = true } if (mask & PermActionCreate) != 0 { ip.ActionCreate = true } if (mask & PermCommand) != 0 { ip.Command = true } if (mask & PermAgent) != 0 { ip.Agent = true } if (mask & PermDashboard) != 0 { ip.Dashboard = true } if (mask & PermLoader) != 0 { ip.Loader = true } if (mask & PermLoaderStatus) != 0 { ip.LoaderStatus = true } if (mask & PermLoaderExpect) != 0 { ip.LoaderExpect = true } if (mask & PermLoaderKey) != 0 { ip.LoaderKey = true } if (mask & PermLoaderNew) != 0 { ip.LoaderNew = true } if (mask & PermManifest) != 0 { ip.Manifest = true } if (mask & PermManifestSign) != 0 { ip.ManifestSign = true } if (mask & PermManifestNew) != 0 { ip.ManifestNew = true } if (mask & PermManifestStatus) != 0 { ip.ManifestStatus = true } if (mask & PermManifestLoaders) != 0 { ip.ManifestLoaders = true } if (mask & PermInvestigator) != 0 { ip.Investigator = true } if (mask & PermInvestigatorCreate) != 0 { ip.InvestigatorCreate = true } if (mask & PermInvestigatorUpdate) != 0 { ip.InvestigatorUpdate = true } } // ToMask converts a boolean permission set to a permission bit mask func (ip *InvestigatorPerms) ToMask() (ret int64) { if ip.Search { ret |= PermSearch } if ip.Action { ret |= PermAction } if ip.ActionCreate { ret |= PermActionCreate } if ip.Command { ret |= PermCommand } if ip.Agent { ret |= PermAgent } if ip.Dashboard { ret |= PermDashboard } if ip.Loader { ret |= PermLoader } if ip.LoaderStatus { ret |= PermLoaderStatus } if ip.LoaderExpect { ret |= PermLoaderExpect } if ip.LoaderKey { ret |= PermLoaderKey } if ip.LoaderNew { ret |= PermLoaderNew } if ip.Manifest { ret |= PermManifest } if ip.ManifestSign { ret |= PermManifestSign } if ip.ManifestNew { ret |= PermManifestNew } if ip.ManifestStatus { ret |= PermManifestStatus } if ip.ManifestLoaders { ret |= PermManifestLoaders } if ip.Investigator { ret |= PermInvestigator } if ip.InvestigatorCreate { ret |= PermInvestigatorCreate } if ip.InvestigatorUpdate { ret |= PermInvestigatorUpdate } return ret } // ToDescriptive converts an existing boolean permission set to a descriptive string, used // primarily in mig-console for summarizing permissions assigned to an investigator func (ip *InvestigatorPerms) ToDescriptive() string { cf := func(want int64, have int64) (bool, int64) { var ( wantcnt, havecnt int64 n uint = 64 sb uint ) for sb = 0; sb < n; sb++ { wantcnt += (want >> sb) & 0x01 } for sb = 0; sb < n; sb++ { havecnt += ((have & want) >> sb) & 0x01 } return (havecnt == wantcnt), havecnt } ret := "" // Compare the permissions applied to the investigator to the various // permission sets; if the user has the full set of permissions from the // set we note that tv := InvestigatorPerms{} tv.DefaultSet() fs, part := cf(tv.ToMask(), ip.ToMask()) if fs { ret = "Default" } else if part > 0 { ret = "Default(partial)" } av := "" tv = InvestigatorPerms{} tv.AdminSet() fs, part = cf(tv.ToMask(), ip.ToMask()) if fs { av = "PermAdmin" } else if part > 0 { av = "PermAdmin(partial)" } if ret != "" && av != "" { ret += "," } ret += av av = "" tv = InvestigatorPerms{} tv.LoaderSet() fs, part = cf(tv.ToMask(), ip.ToMask()) if fs { av = "PermLoader" } else if part > 0 { av = "PermLoader(partial)" } if ret != "" && av != "" { ret += "," } ret += av av = "" tv = InvestigatorPerms{} tv.ManifestSet() fs, part = cf(tv.ToMask(), ip.ToMask()) if fs { av = "PermManifest" } else if part > 0 { av = "PermManifest(partial)" } if ret != "" && av != "" { ret += "," } ret += av return ret } // PermSets describes permission sets that can be applied; note default is omitted as this // is currently always applied var PermSets = []string{"PermManifest", "PermLoader", "PermAdmin"} // FromSetList applies permission sets in slice sl to the investigator func (ip *InvestigatorPerms) FromSetList(sl []string) error { for _, x := range sl { switch x { case "PermManifest": ip.ManifestSet() case "PermLoader": ip.LoaderSet() case "PermAdmin": ip.AdminSet() default: return fmt.Errorf("invalid permission %q", x) } } return nil } // DefaultSet sets a default set of permissions on the investigator func (ip *InvestigatorPerms) DefaultSet() { ip.Search = true ip.Action = true ip.ActionCreate = true ip.Command = true ip.Agent = true ip.Dashboard = true } // ManifestSet sets manifest related permissions on the investigator func (ip *InvestigatorPerms) ManifestSet() { ip.Manifest = true ip.ManifestSign = true ip.ManifestNew = true ip.ManifestStatus = true ip.ManifestLoaders = true } // LoaderSet sets loader related permissions on the investigator func (ip *InvestigatorPerms) LoaderSet() { ip.Loader = true ip.LoaderStatus = true ip.LoaderExpect = true ip.LoaderKey = true ip.LoaderNew = true } // AdminSet sets administrative permissions on the investigator func (ip *InvestigatorPerms) AdminSet() { ip.Investigator = true ip.InvestigatorCreate = true ip.InvestigatorUpdate = true } // Permissions that can be assigned to investigators const ( PermSearch = 1 << iota PermAction PermActionCreate PermCommand PermAgent PermDashboard PermLoader PermLoaderStatus PermLoaderExpect PermLoaderKey PermLoaderNew PermManifest PermManifestSign PermManifestNew PermManifestStatus PermManifestLoaders PermInvestigator PermInvestigatorCreate PermInvestigatorUpdate ) // Possible status values for an investigator const ( StatusActiveInvestigator string = "active" StatusDisabledInvestigator string = "disabled" ) // InvestigatorAPIAuthHelper is a small struct used to pass information between // the database and the API, and is used primarily for authorizing requests using // API keys. type InvestigatorAPIAuthHelper struct { ID float64 // Investigator ID APIKey []byte // Key hash Salt []byte // Key salt }