github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/interfaces/builtin/account_control.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package builtin
    21  
    22  import (
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/snapcore/snapd/interfaces"
    27  	"github.com/snapcore/snapd/interfaces/seccomp"
    28  	"github.com/snapcore/snapd/osutil"
    29  )
    30  
    31  const accountControlSummary = `allows managing non-system user accounts`
    32  
    33  const accountControlBaseDeclarationSlots = `
    34    account-control:
    35      allow-installation:
    36        slot-snap-type:
    37          - core
    38      deny-auto-connection: true
    39  `
    40  
    41  const accountControlConnectedPlugAppArmor = `
    42  /{,usr/}sbin/chpasswd ixr,
    43  /{,usr/}sbin/user{add,del} ixr,
    44  
    45  # Allow modifying the non-system extrausers NSS database. The extrausers
    46  # database is used on Ubuntu Core devices to manage both privileged and
    47  # unprivileged users (since /etc/passwd, /etc/group, etc are all read-only).
    48  /var/lib/extrausers/ r,
    49  /var/lib/extrausers/** rwkl,
    50  
    51  # Needed by useradd
    52  /etc/login.defs r,
    53  /etc/default/useradd r,
    54  /etc/default/nss r,
    55  /etc/pam.d/{,*} r,
    56  
    57  # Needed by chpasswd
    58  /lib/@{multiarch}/security/* ixr,
    59  
    60  # Useradd needs netlink
    61  network netlink raw,
    62  
    63  # Capabilities needed by useradd
    64  capability audit_write,
    65  capability chown,
    66  capability fsetid,
    67  
    68  # useradd writes the result in the log
    69  #include <abstractions/wutmp>
    70  /var/log/faillog rwk,
    71  `
    72  
    73  // Needed because useradd uses a netlink socket, {{group}} is used as a
    74  // placeholder argument for the actual ID of a group owning /etc/shadow
    75  const accountControlConnectedPlugSecCompTemplate = `
    76  # useradd requires chowning to 0:'{{group}}'
    77  fchown - u:root {{group}}
    78  fchown32 - u:root {{group}}
    79  
    80  # from libaudit1
    81  bind
    82  socket AF_NETLINK - NETLINK_AUDIT
    83  `
    84  
    85  type accountControlInterface struct {
    86  	commonInterface
    87  	secCompSnippet string
    88  }
    89  
    90  func makeAccountControlSecCompSnippet() (string, error) {
    91  	gid, err := osutil.FindGidOwning("/etc/shadow")
    92  	if err != nil {
    93  		return "", err
    94  	}
    95  
    96  	snippet := strings.Replace(accountControlConnectedPlugSecCompTemplate,
    97  		"{{group}}", strconv.FormatUint(gid, 10), -1)
    98  
    99  	return snippet, nil
   100  }
   101  
   102  func (iface *accountControlInterface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   103  	if iface.secCompSnippet == "" {
   104  		// Cache the snippet after it's successfully computed once
   105  		snippet, err := makeAccountControlSecCompSnippet()
   106  		if err != nil {
   107  			return err
   108  		}
   109  		iface.secCompSnippet = snippet
   110  	}
   111  	spec.AddSnippet(iface.secCompSnippet)
   112  	return nil
   113  }
   114  
   115  func init() {
   116  	registerIface(&accountControlInterface{commonInterface: commonInterface{
   117  		name:                  "account-control",
   118  		summary:               accountControlSummary,
   119  		implicitOnCore:        true,
   120  		implicitOnClassic:     true,
   121  		baseDeclarationSlots:  accountControlBaseDeclarationSlots,
   122  		connectedPlugAppArmor: accountControlConnectedPlugAppArmor,
   123  		// handled by SecCompConnectedPlug
   124  		connectedPlugSecComp: "",
   125  	}})
   126  }