github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/datalog_guard.go (about)

     1  // Copyright (c) 2014, Kevin Walsh.  All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // This interface was derived from the code in src/tao/tao_guard.h.
    16  
    17  package tao
    18  
    19  import (
    20  	"crypto/sha256"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/golang/glog"
    28  	"github.com/golang/protobuf/proto"
    29  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    30  	"github.com/jlmucb/cloudproxy/go/util"
    31  	"github.com/kevinawalsh/datalog"
    32  	"github.com/kevinawalsh/datalog/dlengine"
    33  )
    34  
    35  // Signing context for signatures on a set of Tao datalog rules.
    36  const (
    37  	DatalogRulesSigningContext = "Datalog Rules Signing Context V1"
    38  )
    39  
    40  // DatalogGuard implements a datalog-based policy engine. Rules in this engine
    41  // have the form:
    42  //   (forall X, Y, Z... : F implies G)
    43  // where
    44  //   F is a predicate or a conjunction of predicates
    45  //   G is a predicate
    46  // All predicate arguments must be either concrete terms (Int, Str, Prin, etc.)
    47  // or term-valued variables (TermVar) bound by the quantification. Any variable
    48  // appearing in G must also appear in F. If there are no variables, the
    49  // quantification can be omitted. The implication and its antecedent F can be
    50  // omitted (in which case there can be no variables so the quantification must
    51  // be omitted as well).
    52  //
    53  // TODO(kwalsh) We could easily support a slightly broader class of formulas,
    54  // e.g. by allowing G to be a conjunct of predicates, or by allowing a
    55  // disjunction of conjunctions for F. Anything beyond that seems complicated.
    56  //
    57  // Datalog translation
    58  //
    59  // We assume K speaksfor the guard, where K is the key used to sign the policy
    60  // file. If there is no signing key, a temporary principal (with a bogus key) is
    61  // used for K instead. All deduction takes place within the worldview of Guard.
    62  // Other than this relationship between K and the guard, we don't model the says
    63  // and speaksfor logic within datalog.
    64  //
    65  // Term objects are usually translated to datalog by just printing them. In this
    66  // case, a Prin object must not contain any TermVar objects. TermVar objects
    67  // must be uppercase.
    68  //
    69  // "Term says Pred(...)" is translated to "says(Term, \"Pred\", ...)".
    70  //
    71  // "Pred(...)" alone is translated to "says(K, \"Pred\", ...)".
    72  //
    73  // "forall ... F1 and F2 and ... imp G" is translated to "G :- F1, F2, ...".
    74  // Not safe for concurrent use by goroutines.
    75  type DatalogGuard struct {
    76  	Config DatalogGuardDetails
    77  	Key    *Verifier
    78  	// TODO(kwalsh) maybe use a version number or timestamp inside the file?
    79  	modTime time.Time // Modification time of signed rules file at time of reading.
    80  	db      DatalogRules
    81  	dl      *dlengine.Engine
    82  	sp      *subprinPrim
    83  }
    84  
    85  // subprinPrim is a custom datalog primitive that implements subprincipal
    86  // detection. The predicate Subprin(S, P, E) in auth is special-cased in
    87  // DatalogGuard to write in datalog to subprin/3 with arguments S, P, E.
    88  type subprinPrim struct {
    89  	datalog.DistinctPred
    90  	max int
    91  }
    92  
    93  // String returns a string representation of the subprin custom datalog
    94  // predicate.
    95  func (sp *subprinPrim) String() string {
    96  	return "subprin"
    97  }
    98  
    99  func (sp *subprinPrim) Assert(c *datalog.Clause) error {
   100  	return newError("datalog: can't assert for custom predicates")
   101  }
   102  
   103  func (sp *subprinPrim) Retract(c *datalog.Clause) error {
   104  	return newError("datalog: can't retract for custom predicates")
   105  }
   106  
   107  // parseRootExtPrins parses a pair of terms as a key/tpm principal and an
   108  // extension principal tail. Both Terms must implement fmt.Stringer.
   109  func parseRootExtPrins(o datalog.Term, e datalog.Term) (oprin auth.Prin, eprin auth.PrinTail, err error) {
   110  	// Report subprin(O.E, O, E) as discovered.
   111  	ostringer, ok1 := o.(fmt.Stringer)
   112  	estringer, ok2 := e.(fmt.Stringer)
   113  	if !ok1 || !ok2 {
   114  		err = fmt.Errorf("arguments 2 and 3 must implement fmt.Stringer in subprin/3")
   115  		return
   116  	}
   117  
   118  	// The first must be a regular rooted principal, and the second must be
   119  	// an ext principal tail.
   120  	var ostr string
   121  	if _, err = fmt.Sscanf(ostringer.String(), "%q", &ostr); err != nil {
   122  		return
   123  	}
   124  
   125  	var estr string
   126  	if _, err = fmt.Sscanf(estringer.String(), "%q", &estr); err != nil {
   127  		return
   128  	}
   129  
   130  	if _, err = fmt.Sscanf(ostr, "%v", &oprin); err != nil {
   131  		return
   132  	}
   133  	if _, err = fmt.Sscanf(estr, "%v", &eprin); err != nil {
   134  		return
   135  	}
   136  	return
   137  }
   138  
   139  // parseCompositePrin parses a Term (which must implement fmt.Stringer) as a
   140  // principal with at least one extension.
   141  func parseCompositePrin(p datalog.Term) (prin auth.Prin, err error) {
   142  	// Parse p as Parent.Ext and report subprin(Parent.Ext, Parent, Ext).
   143  	pstringer, ok := p.(fmt.Stringer)
   144  	if !ok {
   145  		err = fmt.Errorf("A composite principal must be a Stringer")
   146  		return
   147  	}
   148  
   149  	// Due to the way the translation works between DatalogGuard and the Datalog
   150  	// engine, this is a quoted string. So, trim the quotes at the beginning and
   151  	// the end of the string before parsing it.
   152  	var pstr string
   153  	if _, err = fmt.Sscanf(pstringer.String(), "%q", &pstr); err != nil {
   154  		return
   155  	}
   156  	if _, err = fmt.Sscanf(pstr, "%v", &prin); err != nil {
   157  		return
   158  	}
   159  	if len(prin.Ext) < 1 {
   160  		err = fmt.Errorf("A composite principal must have extensions")
   161  		return
   162  	}
   163  
   164  	return
   165  }
   166  
   167  // Search implements the subprinPrim custom datalog primitive by parsing
   168  // constant arguments of subprin/3 as principals and reporting any clauses it
   169  // discovers.
   170  func (sp *subprinPrim) Search(target *datalog.Literal, discovered func(c *datalog.Clause)) {
   171  	p := target.Arg[0]
   172  	o := target.Arg[1]
   173  	e := target.Arg[2]
   174  	if p.Constant() && o.Variable() && e.Variable() {
   175  		prin, err := parseCompositePrin(p)
   176  		if err != nil {
   177  			return
   178  		}
   179  		extIndex := len(prin.Ext) - 1
   180  		trimmedPrin := auth.Prin{
   181  			Type:    prin.Type,
   182  			KeyHash: prin.KeyHash,
   183  			Ext:     prin.Ext[:extIndex],
   184  		}
   185  		extPrin := auth.PrinTail{
   186  			Ext: []auth.PrinExt{prin.Ext[extIndex]},
   187  		}
   188  
   189  		parentIdent := dlengine.NewIdent(fmt.Sprintf("%q", trimmedPrin.String()))
   190  		extIdent := dlengine.NewIdent(fmt.Sprintf("%q", extPrin.String()))
   191  		discovered(datalog.NewClause(datalog.NewLiteral(sp, p, parentIdent, extIdent)))
   192  	} else if p.Variable() && o.Constant() && e.Constant() {
   193  		oprin, eprin, err := parseRootExtPrins(o, e)
   194  		if err != nil {
   195  			return
   196  		}
   197  		oprin.Ext = append(oprin.Ext, eprin.Ext...)
   198  		oeIdent := dlengine.NewIdent(fmt.Sprintf("%q", oprin.String()))
   199  		if len(oprin.Ext)+1 <= sp.max {
   200  			discovered(datalog.NewClause(datalog.NewLiteral(sp, oeIdent, o, e)))
   201  		}
   202  	} else if p.Constant() && o.Constant() && e.Constant() {
   203  		// Check that the constraint holds and report it as discovered.
   204  		prin, err := parseCompositePrin(p)
   205  		if err != nil {
   206  			return
   207  		}
   208  		oprin, eprin, err := parseRootExtPrins(o, e)
   209  		if err != nil {
   210  			return
   211  		}
   212  
   213  		// Extend the root principal with the extension from the ext principal
   214  		// and check identity. Make sure the constructed principal does
   215  		// not exceed the given maximum principal length.
   216  		oprin.Ext = append(oprin.Ext, eprin.Ext...)
   217  		if prin.Identical(oprin) {
   218  			discovered(datalog.NewClause(datalog.NewLiteral(sp, p, o, e)))
   219  		}
   220  	}
   221  }
   222  
   223  // NewTemporaryDatalogGuard returns a new datalog guard with a fresh, unsigned,
   224  // non-persistent rule set. It adds a custom predicate subprin(P, O, E) to check
   225  // if a principal P is a subprincipal O.E.
   226  func NewTemporaryDatalogGuard() Guard {
   227  	sp := &subprinPrim{max: 1}
   228  	sp.SetArity(3)
   229  	eng := dlengine.NewEngine()
   230  	eng.AddPred(sp)
   231  	return &DatalogGuard{dl: eng, sp: sp}
   232  }
   233  
   234  // NewDatalogGuardFromConfig returns a new datalog guard that uses a signed,
   235  // persistent rule set. ReloadIfModified() should be called to load the rule
   236  // set.
   237  func NewDatalogGuardFromConfig(verifier *Verifier, config DatalogGuardDetails) (*DatalogGuard, error) {
   238  	if verifier == nil || config.GetSignedRulesPath() == "" {
   239  		return nil, newError("datalog guard missing key or path")
   240  	}
   241  	dg := NewDatalogGuard(verifier)
   242  	dg.Config = config
   243  	return dg, nil
   244  }
   245  
   246  // NewDatalogGuard returns a new datalog guard without configuring a rules
   247  // file.
   248  func NewDatalogGuard(verifier *Verifier) *DatalogGuard {
   249  	sp := &subprinPrim{max: 1}
   250  	sp.SetArity(3)
   251  	eng := dlengine.NewEngine()
   252  	eng.AddPred(sp)
   253  	dg := &DatalogGuard{Key: verifier, dl: eng, sp: sp}
   254  	dg.Config.SignedRulesPath = nil
   255  	return dg
   256  }
   257  
   258  // Subprincipal returns subprincipal DatalogGuard, for temporary guards, or
   259  // DatalogGuard(<key>) for persistent guards.
   260  func (g *DatalogGuard) Subprincipal() auth.SubPrin {
   261  	if g.Key == nil {
   262  		rules, err := proto.Marshal(&g.db)
   263  		if err != nil {
   264  			return nil
   265  		}
   266  		hash := sha256.Sum256(rules)
   267  		e := auth.PrinExt{Name: "DatalogGuard", Arg: []auth.Term{auth.Bytes(hash[:])}}
   268  		return auth.SubPrin{e}
   269  	}
   270  	e := auth.PrinExt{Name: "DatalogGuard", Arg: []auth.Term{g.Key.ToPrincipal()}}
   271  	return auth.SubPrin{e}
   272  }
   273  
   274  // ReloadIfModified reads all persistent policy data from disk if the file
   275  // timestamp is more recent than the last time it was read.
   276  func (g *DatalogGuard) ReloadIfModified() error {
   277  	if g.Key == nil {
   278  		return nil
   279  	}
   280  	file, err := os.Open(g.Config.GetSignedRulesPath())
   281  	if err != nil {
   282  		return err
   283  	}
   284  	defer file.Close()
   285  
   286  	// before parsing, check the timestamp
   287  	info, err := file.Stat()
   288  	if err != nil {
   289  		return err
   290  	}
   291  	if !info.ModTime().After(g.modTime) {
   292  		return nil
   293  	}
   294  
   295  	serialized, err := ioutil.ReadAll(file)
   296  	if err != nil {
   297  		return err
   298  	}
   299  	var sdb SignedDatalogRules
   300  	if err := proto.Unmarshal(serialized, &sdb); err != nil {
   301  		return err
   302  	}
   303  	if ok, err := g.Key.Verify(sdb.SerializedRules, DatalogRulesSigningContext, sdb.Signature); !ok {
   304  		if err != nil {
   305  			return err
   306  		}
   307  		return newError("datalog rule signature did not verify")
   308  	}
   309  	var db DatalogRules
   310  	if err := proto.Unmarshal(sdb.SerializedRules, &db); err != nil {
   311  		return err
   312  	}
   313  	// Only clear the rules set, since g.assert already skips datalog rules that
   314  	// are already present in the engine.
   315  	g.db.Rules = nil
   316  	g.modTime = info.ModTime()
   317  	for _, rule := range db.Rules {
   318  		r, err := auth.UnmarshalForm(rule)
   319  		if err != nil {
   320  			return err
   321  		}
   322  		err = g.assert(r)
   323  		if err != nil {
   324  			return err
   325  		}
   326  	}
   327  	return nil
   328  }
   329  
   330  // GetSignedDatalogRules serializes and signs the datalog rules and returns
   331  // a SignedDatalogRules pointer.
   332  func (g *DatalogGuard) GetSignedDatalogRules(signer *Signer) (*SignedDatalogRules, error) {
   333  	if signer == nil {
   334  		return nil, newError("datalog temporary ruleset can't be saved")
   335  	}
   336  	rules, err := proto.Marshal(&g.db)
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  	sig, err := signer.Sign(rules, DatalogRulesSigningContext)
   341  	if err != nil {
   342  		return nil, err
   343  	}
   344  	sdb := &SignedDatalogRules{
   345  		SerializedRules: rules,
   346  		Signature:       sig,
   347  	}
   348  	return sdb, nil
   349  }
   350  
   351  // Save writes all persistent policy data to disk, signed by key.
   352  func (g *DatalogGuard) Save(signer *Signer) error {
   353  	sdb, err := g.GetSignedDatalogRules(signer)
   354  	if err != nil {
   355  		return err
   356  	}
   357  	serialized, err := proto.Marshal(sdb)
   358  	if err != nil {
   359  		return err
   360  	}
   361  	if err := util.WritePath(g.Config.GetSignedRulesPath(), serialized, 0777, 0666); err != nil {
   362  		return err
   363  	}
   364  	return nil
   365  }
   366  
   367  func setContains(vars []string, v string) bool {
   368  	for _, s := range vars {
   369  		if s == v {
   370  			return true
   371  		}
   372  	}
   373  	return false
   374  }
   375  
   376  func setRemove(vars *[]string, v string) {
   377  	if vars == nil {
   378  		return
   379  	}
   380  	for i := 0; i < len(*vars); i++ {
   381  		if (*vars)[i] == v {
   382  			(*vars)[i] = (*vars)[len(*vars)-1]
   383  			*vars = (*vars)[:len(*vars)-1]
   384  			i--
   385  		}
   386  	}
   387  }
   388  
   389  func stripQuantifiers(q auth.Form) (f auth.Form, vars []string) {
   390  	for {
   391  		var v string
   392  		switch f := q.(type) {
   393  		case auth.Forall:
   394  			v = f.Var
   395  			q = f.Body
   396  		case *auth.Forall:
   397  			v = f.Var
   398  			q = f.Body
   399  		default:
   400  			return q, vars
   401  		}
   402  		if !setContains(vars, v) {
   403  			vars = append(vars, v)
   404  		}
   405  	}
   406  }
   407  
   408  func flattenConjuncts(f ...auth.Form) (conjuncts []auth.Form) {
   409  	for _, f := range f {
   410  		switch f := f.(type) {
   411  		case auth.And:
   412  			conjuncts = append(conjuncts, flattenConjuncts(f.Conjunct...)...)
   413  		case *auth.And:
   414  			conjuncts = append(conjuncts, flattenConjuncts(f.Conjunct...)...)
   415  		default:
   416  			conjuncts = append(conjuncts, f)
   417  		}
   418  	}
   419  	return
   420  }
   421  
   422  func stripConditions(f auth.Form) (conds []auth.Form, consequent auth.Form) {
   423  	switch f := f.(type) {
   424  	case auth.Implies:
   425  		conds = flattenConjuncts(f.Antecedent)
   426  		consequent = f.Consequent
   427  	case *auth.Implies:
   428  		conds = flattenConjuncts(f.Antecedent)
   429  		consequent = f.Consequent
   430  	default:
   431  		consequent = f
   432  	}
   433  	return
   434  }
   435  
   436  func checkTermVarUsage(vars []string, unusedVars *[]string, e ...auth.Term) error {
   437  	for _, e := range e {
   438  		switch e := e.(type) {
   439  		case auth.TermVar, *auth.TermVar:
   440  			if !setContains(vars, e.String()) {
   441  				return fmt.Errorf("illegal quantification variable: %v\n", e)
   442  			}
   443  			setRemove(unusedVars, e.String())
   444  		case auth.Prin:
   445  			err := checkTermVarUsage(vars, unusedVars, e.KeyHash)
   446  			if err != nil {
   447  				return err
   448  			}
   449  			for _, ext := range e.Ext {
   450  				err := checkTermVarUsage(vars, unusedVars, ext.Arg...)
   451  				if err != nil {
   452  					return err
   453  				}
   454  			}
   455  		case *auth.Prin:
   456  			err := checkTermVarUsage(vars, unusedVars, e.KeyHash)
   457  			if err != nil {
   458  				return err
   459  			}
   460  			for _, ext := range e.Ext {
   461  				err := checkTermVarUsage(vars, unusedVars, ext.Arg...)
   462  				if err != nil {
   463  					return err
   464  				}
   465  			}
   466  		}
   467  	}
   468  	return nil
   469  }
   470  
   471  func checkFormVarUsage(vars []string, unusedVars *[]string, e ...auth.Form) error {
   472  	for _, e := range e {
   473  		switch e := e.(type) {
   474  		case auth.Pred:
   475  			err := checkTermVarUsage(vars, unusedVars, e.Arg...)
   476  			if err != nil {
   477  				return err
   478  			}
   479  		case *auth.Pred:
   480  			err := checkTermVarUsage(vars, unusedVars, e.Arg...)
   481  			if err != nil {
   482  				return err
   483  			}
   484  		}
   485  	}
   486  	return nil
   487  }
   488  
   489  func (g *DatalogGuard) stmtToDatalog(f auth.Form, vars []string, unusedVars *[]string) (string, error) {
   490  	speaker := "guard"
   491  	if g.Key != nil {
   492  		speaker = g.Key.ToPrincipal().String()
   493  	}
   494  	stmt, ok := f.(*auth.Says)
   495  	if !ok {
   496  		var val auth.Says
   497  		val, ok = (f).(auth.Says)
   498  		if ok {
   499  			stmt = &val
   500  		}
   501  	}
   502  	if ok {
   503  		err := checkTermVarUsage(vars, unusedVars, stmt.Speaker)
   504  		if err != nil {
   505  			return "", err
   506  		}
   507  	}
   508  	err := checkFormVarUsage(vars, unusedVars, f)
   509  	if err != nil {
   510  		return "", err
   511  	}
   512  	pred, ok := f.(*auth.Pred)
   513  	if !ok {
   514  		var val auth.Pred
   515  		val, ok = f.(auth.Pred)
   516  		if ok {
   517  			pred = &val
   518  		}
   519  	}
   520  	if !ok {
   521  		return "", fmt.Errorf("unsupported datalog statement: %v", f)
   522  	}
   523  	// Special-case: the principal named "Subprin" maps directly to subprinPrim.
   524  	var args []string
   525  	if pred.Name != "Subprin" {
   526  		args = []string{fmt.Sprintf("%q", speaker), fmt.Sprintf("%q", pred.Name)}
   527  	}
   528  
   529  	for _, arg := range pred.Arg {
   530  		if _, ok := arg.(auth.TermVar); ok {
   531  			// Don't quote variables, since otherwise they won't work as
   532  			// variables in the datalog representation.
   533  			args = append(args, fmt.Sprintf("%s", arg.String()))
   534  		} else {
   535  			args = append(args, fmt.Sprintf("%q", arg.String()))
   536  		}
   537  	}
   538  	if pred.Name == "Subprin" {
   539  		s := "subprin(" + strings.Join(args, ", ") + ")"
   540  		return s, nil
   541  
   542  	}
   543  	return "says(" + strings.Join(args, ", ") + ")", nil
   544  }
   545  
   546  // formToDatalogRule converts (a subset of) auth.Form to datalog syntax.
   547  func (g *DatalogGuard) formToDatalogRule(f auth.Form) (string, error) {
   548  	f, vars := stripQuantifiers(f)
   549  	conditions, consequent := stripConditions(f)
   550  	// vars must be upper-case
   551  	for _, v := range vars {
   552  		if len(v) == 0 || v[0] < 'A' || v[0] > 'Z' {
   553  			return "", fmt.Errorf("illegal quantification variable")
   554  		}
   555  	}
   556  	// convert the conditions
   557  	dcond := make([]string, len(conditions))
   558  	unusedVars := append([]string{}, vars...)
   559  	for i, cond := range conditions {
   560  		var err error
   561  		dcond[i], err = g.stmtToDatalog(cond, vars, &unusedVars)
   562  		if err != nil {
   563  			return "", err
   564  		}
   565  	}
   566  	// check for safety
   567  	if len(unusedVars) > 0 {
   568  		return "", fmt.Errorf("unsafe datalog variable usage: % s", unusedVars)
   569  	}
   570  	goal, err := g.stmtToDatalog(consequent, vars, nil)
   571  	if err != nil {
   572  		return "", err
   573  	}
   574  	if len(dcond) > 0 {
   575  		return goal + " :- " + strings.Join(dcond, ", "), nil
   576  	}
   577  	return goal, nil
   578  }
   579  
   580  func (g *DatalogGuard) findRule(f auth.Form) (string, int, error) {
   581  	rule, err := g.formToDatalogRule(f)
   582  	if err != nil {
   583  		return "", -1, err
   584  	}
   585  	for i, ser := range g.db.Rules {
   586  		f2, err := auth.UnmarshalForm(ser)
   587  		if err != nil {
   588  			continue
   589  		}
   590  		rule2, err := g.formToDatalogRule(f2)
   591  		if err != nil {
   592  			continue
   593  		}
   594  		if rule == rule2 {
   595  			return rule, i, nil
   596  		}
   597  	}
   598  	return rule, -1, nil
   599  }
   600  
   601  func (g *DatalogGuard) assert(f auth.Form) error {
   602  	rule, idx, err := g.findRule(f)
   603  	if err != nil {
   604  		return err
   605  	}
   606  	if idx >= 0 {
   607  		return nil
   608  	}
   609  	err = g.dl.Assert(rule)
   610  	if err != nil {
   611  		return err
   612  	}
   613  	g.db.Rules = append(g.db.Rules, auth.Marshal(f))
   614  	return nil
   615  }
   616  
   617  func (g *DatalogGuard) retract(f auth.Form) error {
   618  	rule, idx, err := g.findRule(f)
   619  	if err != nil {
   620  		return err
   621  	}
   622  	if idx < 0 {
   623  		return fmt.Errorf("no such rule")
   624  	}
   625  	err = g.dl.Retract(rule)
   626  	if err != nil {
   627  		return err
   628  	}
   629  	g.db.Rules = append(g.db.Rules[:idx], g.db.Rules[idx+1:]...)
   630  	return nil
   631  }
   632  
   633  func max(x, y int) int {
   634  	if x > y {
   635  		return x
   636  	}
   637  	return y
   638  }
   639  
   640  // Figure out the max length of a principal in a term, where the length of a
   641  // principal is one more than the length of the extensions of the principal.
   642  func getMaxTermLength(t auth.Term) int {
   643  	if t == nil {
   644  		return 0
   645  	}
   646  
   647  	switch t.(type) {
   648  	case auth.Prin:
   649  		// TODO(tmroeder): this and the next case are not fully
   650  		// general, since there might be an Arg that has a longer
   651  		// principal.
   652  		return 1 + len(t.(auth.Prin).Ext)
   653  	case *auth.Prin:
   654  		return 1 + len(t.(*auth.Prin).Ext)
   655  	case auth.PrinTail:
   656  		return len(t.(auth.PrinTail).Ext)
   657  	case *auth.PrinTail:
   658  		return len(t.(*auth.PrinTail).Ext)
   659  	case auth.Str, auth.Bytes, auth.Int, auth.TermVar:
   660  		return 0
   661  	default:
   662  		return 0
   663  	}
   664  }
   665  
   666  // Figure out the max length of a principal in a form, where the length of a
   667  // principal is one more than the length of the extensions of the principal.
   668  func getMaxFormLength(f auth.Form) int {
   669  	if f == nil {
   670  		return 0
   671  	}
   672  
   673  	m := 0
   674  	switch f.(type) {
   675  	case auth.Pred:
   676  		for _, t := range f.(auth.Pred).Arg {
   677  			m = max(m, getMaxTermLength(t))
   678  		}
   679  	case *auth.Pred:
   680  		for _, t := range f.(*auth.Pred).Arg {
   681  			m = max(m, getMaxTermLength(t))
   682  		}
   683  	case auth.Const, *auth.Const:
   684  		return 0
   685  	case auth.Not:
   686  		return getMaxFormLength(f.(auth.Not).Negand)
   687  	case *auth.Not:
   688  		return getMaxFormLength(f.(*auth.Not).Negand)
   689  	case auth.And:
   690  		for _, c := range f.(auth.And).Conjunct {
   691  			m = max(m, getMaxFormLength(c))
   692  		}
   693  	case *auth.And:
   694  		for _, c := range f.(*auth.And).Conjunct {
   695  			m = max(m, getMaxFormLength(c))
   696  		}
   697  	case auth.Or:
   698  		for _, d := range f.(auth.Or).Disjunct {
   699  			m = max(m, getMaxFormLength(d))
   700  		}
   701  	case *auth.Or:
   702  		for _, d := range f.(*auth.Or).Disjunct {
   703  			m = max(m, getMaxFormLength(d))
   704  		}
   705  	case auth.Implies:
   706  		first := getMaxFormLength(f.(auth.Implies).Antecedent)
   707  		second := getMaxFormLength(f.(auth.Implies).Consequent)
   708  		return max(first, second)
   709  	case *auth.Implies:
   710  		first := getMaxFormLength(f.(*auth.Implies).Antecedent)
   711  		second := getMaxFormLength(f.(*auth.Implies).Consequent)
   712  		return max(first, second)
   713  	case auth.Speaksfor:
   714  		first := getMaxTermLength(f.(auth.Speaksfor).Delegate)
   715  		second := getMaxTermLength(f.(auth.Speaksfor).Delegator)
   716  		return max(first, second)
   717  	case *auth.Speaksfor:
   718  		first := getMaxTermLength(f.(*auth.Speaksfor).Delegate)
   719  		second := getMaxTermLength(f.(*auth.Speaksfor).Delegator)
   720  		return max(first, second)
   721  	case auth.Says:
   722  		sl := getMaxTermLength(f.(auth.Says).Speaker)
   723  		ml := getMaxFormLength(f.(auth.Says).Message)
   724  		return max(sl, ml)
   725  	case *auth.Says:
   726  		sl := getMaxTermLength(f.(*auth.Says).Speaker)
   727  		ml := getMaxFormLength(f.(*auth.Says).Message)
   728  		return max(sl, ml)
   729  	case auth.Forall:
   730  		return getMaxFormLength(f.(auth.Forall).Body)
   731  	case *auth.Forall:
   732  		return getMaxFormLength(f.(*auth.Forall).Body)
   733  	case auth.Exists:
   734  		return getMaxFormLength(f.(auth.Exists).Body)
   735  	case *auth.Exists:
   736  		return getMaxFormLength(f.(*auth.Exists).Body)
   737  	default:
   738  		return 0
   739  	}
   740  
   741  	return m
   742  }
   743  
   744  func (g *DatalogGuard) query(f auth.Form) (bool, error) {
   745  	g.sp.max = getMaxFormLength(f)
   746  
   747  	q, err := g.stmtToDatalog(f, nil, nil)
   748  	if err != nil {
   749  		return false, err
   750  	}
   751  	ans, err := g.dl.Query(q)
   752  	if err != nil {
   753  		return false, err
   754  	}
   755  	return len(ans) > 0, nil
   756  }
   757  
   758  func makeDatalogPredicate(p auth.Prin, op string, args []string) auth.Pred {
   759  	a := []interface{}{p, op}
   760  	for _, s := range args {
   761  		a = append(a, s)
   762  	}
   763  	return auth.MakePredicate("Authorized", a...)
   764  }
   765  
   766  // Authorize adds an authorization for p to perform op(args).
   767  func (g *DatalogGuard) Authorize(p auth.Prin, op string, args []string) error {
   768  	return g.assert(makeDatalogPredicate(p, op, args))
   769  }
   770  
   771  // Retract removes an authorization for p to perform op(args).
   772  func (g *DatalogGuard) Retract(p auth.Prin, op string, args []string) error {
   773  	return g.retract(makeDatalogPredicate(p, op, args))
   774  }
   775  
   776  // IsAuthorized checks whether p is authorized to perform op(args).
   777  func (g *DatalogGuard) IsAuthorized(p auth.Prin, op string, args []string) bool {
   778  	ok, _ := g.query(makeDatalogPredicate(p, op, args))
   779  	return ok
   780  }
   781  
   782  // AddRule adds a policy rule.
   783  func (g *DatalogGuard) AddRule(rule string) error {
   784  	glog.Infof("Adding rule '%s'", rule)
   785  	var r auth.AnyForm
   786  	_, err := fmt.Sscanf("("+rule+")", "%v", &r)
   787  	if err != nil {
   788  		return err
   789  	}
   790  	return g.assert(r.Form)
   791  }
   792  
   793  // RetractRule removes a rule previously added via AddRule() or the
   794  // equivalent Authorize() call.
   795  func (g *DatalogGuard) RetractRule(rule string) error {
   796  	err := g.ReloadIfModified()
   797  	if err != nil {
   798  		return err
   799  	}
   800  	var r auth.AnyForm
   801  	_, err = fmt.Sscanf("("+rule+")", "%v", &r)
   802  	if err != nil {
   803  		return err
   804  	}
   805  	return g.retract(r.Form)
   806  }
   807  
   808  // Clear removes all rules.
   809  func (g *DatalogGuard) Clear() error {
   810  	g.db.Rules = nil
   811  	g.dl = dlengine.NewEngine()
   812  	return nil
   813  }
   814  
   815  // Query the policy. Implementations of this interface should support
   816  // at least queries of the form: Authorized(P, op, args...).
   817  func (g *DatalogGuard) Query(query string) (bool, error) {
   818  	err := g.ReloadIfModified()
   819  	if err != nil {
   820  		return false, err
   821  	}
   822  	var r auth.AnyForm
   823  	_, err = fmt.Sscanf("("+query+")", "%v", &r)
   824  	if err != nil {
   825  		return false, err
   826  	}
   827  
   828  	return g.query(r.Form)
   829  }
   830  
   831  // RuleCount returns a count of the total number of rules.
   832  func (g *DatalogGuard) RuleCount() int {
   833  	return len(g.db.Rules)
   834  }
   835  
   836  // GetRule returns the ith policy rule, if it exists.
   837  func (g *DatalogGuard) GetRule(i int) string {
   838  	if i < 0 || i >= len(g.db.Rules) {
   839  		return ""
   840  	}
   841  	rule := g.db.Rules[i]
   842  	r, err := auth.UnmarshalForm(rule)
   843  	if err != nil {
   844  		return ""
   845  	}
   846  	return r.String()
   847  }
   848  
   849  // RuleDebugString returns a debug string for the ith policy rule, if it exists.
   850  func (g *DatalogGuard) RuleDebugString(i int) string {
   851  	if i < 0 || i >= len(g.db.Rules) {
   852  		return ""
   853  	}
   854  	rule := g.db.Rules[i]
   855  	r, err := auth.UnmarshalForm(rule)
   856  	if err != nil {
   857  		return ""
   858  	}
   859  	return r.ShortString()
   860  }
   861  
   862  // String returns a string suitable for showing users authorization info.
   863  func (g *DatalogGuard) String() string {
   864  	rules := make([]string, len(g.db.Rules))
   865  	for i := range g.db.Rules {
   866  		rules[i] = g.GetRule(i)
   867  	}
   868  	return "DatalogGuard{\n" + strings.Join(rules, "\n") + "}\n"
   869  }