github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/daemon/access.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2021 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 daemon 21 22 import ( 23 "net/http" 24 "strconv" 25 26 "github.com/snapcore/snapd/client" 27 "github.com/snapcore/snapd/dirs" 28 "github.com/snapcore/snapd/logger" 29 "github.com/snapcore/snapd/overlord/auth" 30 "github.com/snapcore/snapd/polkit" 31 ) 32 33 var polkitCheckAuthorization = polkit.CheckAuthorization 34 35 var checkPolkitAction = checkPolkitActionImpl 36 37 func checkPolkitActionImpl(r *http.Request, ucred *ucrednet, action string) *apiError { 38 var flags polkit.CheckFlags 39 allowHeader := r.Header.Get(client.AllowInteractionHeader) 40 if allowHeader != "" { 41 if allow, err := strconv.ParseBool(allowHeader); err != nil { 42 logger.Noticef("error parsing %s header: %s", client.AllowInteractionHeader, err) 43 } else if allow { 44 flags |= polkit.CheckAllowInteraction 45 } 46 } 47 // Pass both pid and uid from the peer ucred to avoid pid race 48 switch authorized, err := polkitCheckAuthorization(ucred.Pid, ucred.Uid, action, nil, flags); err { 49 case nil: 50 if authorized { 51 // polkit says user is authorised 52 return nil 53 } 54 case polkit.ErrDismissed: 55 return AuthCancelled("cancelled") 56 default: 57 logger.Noticef("polkit error: %s", err) 58 } 59 return Unauthorized("access denied") 60 } 61 62 // accessChecker checks whether a particular request is allowed. 63 // 64 // An access checker will either allow a request, deny it, or return 65 // accessUnknown, which indicates the decision should be delegated to 66 // the next access checker. 67 type accessChecker interface { 68 CheckAccess(d *Daemon, r *http.Request, ucred *ucrednet, user *auth.UserState) *apiError 69 } 70 71 // requireSnapdSocket ensures the request was received via snapd.socket. 72 func requireSnapdSocket(ucred *ucrednet) *apiError { 73 if ucred == nil { 74 return Forbidden("access denied") 75 } 76 77 if ucred.Socket != dirs.SnapdSocket { 78 return Forbidden("access denied") 79 } 80 81 return nil 82 } 83 84 // openAccess allows requests without authentication, provided they 85 // have peer credentials and were not received on snapd-snap.socket 86 type openAccess struct{} 87 88 func (ac openAccess) CheckAccess(d *Daemon, r *http.Request, ucred *ucrednet, user *auth.UserState) *apiError { 89 return requireSnapdSocket(ucred) 90 } 91 92 // authenticatedAccess allows requests from authenticated users, 93 // provided they were not received on snapd-snap.socket 94 // 95 // A user is considered authenticated if they provide a macaroon, are 96 // the root user according to peer credentials, or granted access by 97 // Polkit. 98 type authenticatedAccess struct { 99 Polkit string 100 } 101 102 func (ac authenticatedAccess) CheckAccess(d *Daemon, r *http.Request, ucred *ucrednet, user *auth.UserState) *apiError { 103 if rspe := requireSnapdSocket(ucred); rspe != nil { 104 return rspe 105 } 106 107 if user != nil { 108 return nil 109 } 110 111 if ucred.Uid == 0 { 112 return nil 113 } 114 115 // We check polkit last because it may result in the user 116 // being prompted for authorisation. This should be avoided if 117 // access is otherwise granted. 118 if ac.Polkit != "" { 119 return checkPolkitAction(r, ucred, ac.Polkit) 120 } 121 122 return Unauthorized("access denied") 123 } 124 125 // rootAccess allows requests from the root uid, provided they 126 // were not received on snapd-snap.socket 127 type rootAccess struct{} 128 129 func (ac rootAccess) CheckAccess(d *Daemon, r *http.Request, ucred *ucrednet, user *auth.UserState) *apiError { 130 if rspe := requireSnapdSocket(ucred); rspe != nil { 131 return rspe 132 } 133 134 if ucred.Uid == 0 { 135 return nil 136 } 137 return Forbidden("access denied") 138 } 139 140 // snapAccess allows requests from the snapd-snap.socket 141 type snapAccess struct{} 142 143 func (ac snapAccess) CheckAccess(d *Daemon, r *http.Request, ucred *ucrednet, user *auth.UserState) *apiError { 144 if ucred == nil { 145 return Forbidden("access denied") 146 } 147 148 if ucred.Socket == dirs.SnapSocket { 149 return nil 150 } 151 // FIXME: should snapctl access be allowed on the main socket? 152 return Forbidden("access denied") 153 }