github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/daemon/ucrednet.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2015 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 "errors" 24 "fmt" 25 "net" 26 "regexp" 27 "strconv" 28 "sync" 29 sys "syscall" 30 ) 31 32 var errNoID = errors.New("no pid/uid found") 33 34 const ( 35 ucrednetNoProcess = int32(0) 36 ucrednetNobody = uint32((1 << 32) - 1) 37 ) 38 39 var raddrRegexp = regexp.MustCompile(`^pid=(\d+);uid=(\d+);socket=([^;]*);$`) 40 41 var ucrednetGet = ucrednetGetImpl 42 43 func ucrednetGetImpl(remoteAddr string) (pid int32, uid uint32, socket string, err error) { 44 // NOTE treat remoteAddr at one point included a user-controlled 45 // string. In case that happens again by accident, treat it as tainted, 46 // and be very suspicious of it. 47 pid = ucrednetNoProcess 48 uid = ucrednetNobody 49 subs := raddrRegexp.FindStringSubmatch(remoteAddr) 50 if subs != nil { 51 if v, err := strconv.ParseInt(subs[1], 10, 32); err == nil { 52 pid = int32(v) 53 } 54 if v, err := strconv.ParseUint(subs[2], 10, 32); err == nil { 55 uid = uint32(v) 56 } 57 socket = subs[3] 58 } 59 if pid == ucrednetNoProcess || uid == ucrednetNobody { 60 err = errNoID 61 } 62 63 return pid, uid, socket, err 64 } 65 66 type ucrednet struct { 67 pid int32 68 uid uint32 69 socket string 70 } 71 72 func (un *ucrednet) String() string { 73 if un == nil { 74 return "pid=;uid=;socket=;" 75 } 76 return fmt.Sprintf("pid=%d;uid=%d;socket=%s;", un.pid, un.uid, un.socket) 77 } 78 79 type ucrednetAddr struct { 80 net.Addr 81 *ucrednet 82 } 83 84 func (wa *ucrednetAddr) String() string { 85 // NOTE we drop the original (user-supplied) net.Addr from the 86 // serialization entirely. We carry it this far so it helps debugging 87 // (via %#v logging), but from here on in it's not helpful. 88 return wa.ucrednet.String() 89 } 90 91 type ucrednetConn struct { 92 net.Conn 93 *ucrednet 94 } 95 96 func (wc *ucrednetConn) RemoteAddr() net.Addr { 97 return &ucrednetAddr{wc.Conn.RemoteAddr(), wc.ucrednet} 98 } 99 100 type ucrednetListener struct { 101 net.Listener 102 103 idempotClose sync.Once 104 closeErr error 105 } 106 107 var getUcred = sys.GetsockoptUcred 108 109 func (wl *ucrednetListener) Accept() (net.Conn, error) { 110 con, err := wl.Listener.Accept() 111 if err != nil { 112 return nil, err 113 } 114 115 var unet *ucrednet 116 if ucon, ok := con.(*net.UnixConn); ok { 117 f, err := ucon.File() 118 if err != nil { 119 return nil, err 120 } 121 // File() is a dup(); needs closing 122 defer f.Close() 123 124 ucred, err := getUcred(int(f.Fd()), sys.SOL_SOCKET, sys.SO_PEERCRED) 125 if err != nil { 126 return nil, err 127 } 128 129 unet = &ucrednet{ 130 pid: ucred.Pid, 131 uid: ucred.Uid, 132 socket: ucon.LocalAddr().String(), 133 } 134 } 135 136 return &ucrednetConn{con, unet}, nil 137 } 138 139 func (wl *ucrednetListener) Close() error { 140 wl.idempotClose.Do(func() { 141 wl.closeErr = wl.Listener.Close() 142 }) 143 return wl.closeErr 144 }