gitee.com/mysnapcore/mysnapd@v0.1.0/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  	"gitee.com/mysnapcore/mysnapd/interfaces"
    27  	"gitee.com/mysnapcore/mysnapd/interfaces/seccomp"
    28  	"gitee.com/mysnapcore/mysnapd/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  /{,usr/}sbin/pam_tally2 ixr,
    57  
    58  # Needed by chpasswd
    59  /{,usr/}lib/@{multiarch}/security/* ixr,
    60  
    61  # Useradd needs netlink
    62  network netlink raw,
    63  
    64  # Capabilities needed by useradd
    65  capability audit_write,
    66  capability chown,
    67  capability fsetid,
    68  
    69  # useradd writes the result in the log
    70  #include <abstractions/wutmp>
    71  /var/log/faillog rwk,
    72  `
    73  
    74  // Needed because useradd uses a netlink socket, {{group}} is used as a
    75  // placeholder argument for the actual ID of a group owning /etc/shadow
    76  const accountControlConnectedPlugSecCompTemplate = `
    77  # useradd requires chowning to 0:'{{group}}'
    78  fchown - u:root {{group}}
    79  fchown32 - u:root {{group}}
    80  
    81  # from libaudit1
    82  bind
    83  socket AF_NETLINK - NETLINK_AUDIT
    84  `
    85  
    86  type accountControlInterface struct {
    87  	commonInterface
    88  	secCompSnippet string
    89  }
    90  
    91  func makeAccountControlSecCompSnippet() (string, error) {
    92  	gid, err := osutil.FindGidOwning("/etc/shadow")
    93  	if err != nil {
    94  		return "", err
    95  	}
    96  
    97  	snippet := strings.Replace(accountControlConnectedPlugSecCompTemplate,
    98  		"{{group}}", strconv.FormatUint(gid, 10), -1)
    99  
   100  	return snippet, nil
   101  }
   102  
   103  func (iface *accountControlInterface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   104  	if iface.secCompSnippet == "" {
   105  		// Cache the snippet after it's successfully computed once
   106  		snippet, err := makeAccountControlSecCompSnippet()
   107  		if err != nil {
   108  			return err
   109  		}
   110  		iface.secCompSnippet = snippet
   111  	}
   112  	spec.AddSnippet(iface.secCompSnippet)
   113  	return nil
   114  }
   115  
   116  func init() {
   117  	registerIface(&accountControlInterface{commonInterface: commonInterface{
   118  		name:                  "account-control",
   119  		summary:               accountControlSummary,
   120  		implicitOnCore:        true,
   121  		implicitOnClassic:     true,
   122  		baseDeclarationSlots:  accountControlBaseDeclarationSlots,
   123  		connectedPlugAppArmor: accountControlConnectedPlugAppArmor,
   124  		// handled by SecCompConnectedPlug
   125  		connectedPlugSecComp: "",
   126  	}})
   127  }