github.com/cs3org/reva/v2@v2.27.7/pkg/storage/utils/decomposedfs/usermapper/usermapper_linux.go (about)

     1  // Copyright 2018-2021 CERN
     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  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package usermapper
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"os/user"
    25  	"runtime"
    26  	"strconv"
    27  
    28  	"golang.org/x/sys/unix"
    29  
    30  	revactx "github.com/cs3org/reva/v2/pkg/ctx"
    31  )
    32  
    33  // UnixMapper is a user mapper that maps users to unix uids and gids
    34  type UnixMapper struct {
    35  	baseUid int
    36  	baseGid int
    37  }
    38  
    39  // New returns a new user mapper
    40  func NewUnixMapper() *UnixMapper {
    41  	baseUid, _ := unix.SetfsuidRetUid(-1)
    42  	baseGid, _ := unix.SetfsgidRetGid(-1)
    43  
    44  	return &UnixMapper{
    45  		baseUid: baseUid,
    46  		baseGid: baseGid,
    47  	}
    48  }
    49  
    50  // RunInUserScope runs the given function in the scope of the base user
    51  func (um *UnixMapper) RunInBaseScope(f func() error) error {
    52  	unscope, err := um.ScopeBase()
    53  	if err != nil {
    54  		return err
    55  	}
    56  	defer func() { _ = unscope() }()
    57  
    58  	return f()
    59  }
    60  
    61  // ScopeBase returns to the base uid and gid returning a function that can be used to restore the previous scope
    62  func (um *UnixMapper) ScopeBase() (func() error, error) {
    63  	return um.ScopeUserByIds(-1, um.baseGid)
    64  }
    65  
    66  // ScopeUser returns to the base uid and gid returning a function that can be used to restore the previous scope
    67  func (um *UnixMapper) ScopeUser(ctx context.Context) (func() error, error) {
    68  	u := revactx.ContextMustGetUser(ctx)
    69  
    70  	uid, gid, err := um.mapUser(u.Username)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	return um.ScopeUserByIds(uid, gid)
    75  }
    76  
    77  // ScopeUserByIds scopes the current user to the given uid and gid returning a function that can be used to restore the previous scope
    78  func (um *UnixMapper) ScopeUserByIds(uid, gid int) (func() error, error) {
    79  	runtime.LockOSThread() // Lock this Goroutine to the current OS thread
    80  
    81  	var err error
    82  	var prevUid int
    83  	var prevGid int
    84  	if uid >= 0 {
    85  		prevUid, err = unix.SetfsuidRetUid(uid)
    86  		if err != nil {
    87  			return nil, err
    88  		}
    89  		if testUid, _ := unix.SetfsuidRetUid(-1); testUid != uid {
    90  			return nil, fmt.Errorf("failed to setfsuid to %d", uid)
    91  		}
    92  	}
    93  	if gid >= 0 {
    94  		prevGid, err = unix.SetfsgidRetGid(gid)
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  		if testGid, _ := unix.SetfsgidRetGid(-1); testGid != gid {
    99  			return nil, fmt.Errorf("failed to setfsgid to %d", gid)
   100  		}
   101  	}
   102  
   103  	return func() error {
   104  		if uid >= 0 {
   105  			_ = unix.Setfsuid(prevUid)
   106  		}
   107  		if gid >= 0 {
   108  			_ = unix.Setfsgid(prevGid)
   109  		}
   110  		runtime.UnlockOSThread()
   111  		return nil
   112  	}, nil
   113  }
   114  
   115  func (u *UnixMapper) mapUser(username string) (int, int, error) {
   116  	userDetails, err := user.Lookup(username)
   117  	if err != nil {
   118  		return 0, 0, err
   119  	}
   120  
   121  	uid, err := strconv.Atoi(userDetails.Uid)
   122  	if err != nil {
   123  		return 0, 0, err
   124  	}
   125  	gid, err := strconv.Atoi(userDetails.Gid)
   126  	if err != nil {
   127  		return 0, 0, err
   128  	}
   129  
   130  	return uid, gid, nil
   131  }