David K. Bainbridge | 528b318 | 2017-01-23 08:51:59 -0800 | [diff] [blame^] | 1 | // Copyright 2015 Canonical Ltd. |
| 2 | // Licensed under the LGPLv3, see LICENCE file for details. |
| 3 | |
| 4 | package utils |
| 5 | |
| 6 | import ( |
| 7 | "os" |
| 8 | "os/user" |
| 9 | |
| 10 | "github.com/juju/errors" |
| 11 | ) |
| 12 | |
| 13 | // ResolveSudo returns the original username if sudo was used. The |
| 14 | // original username is extracted from the OS environment. |
| 15 | func ResolveSudo(username string) string { |
| 16 | return resolveSudo(username, os.Getenv) |
| 17 | } |
| 18 | |
| 19 | func resolveSudo(username string, getenvFunc func(string) string) string { |
| 20 | if username != "root" { |
| 21 | return username |
| 22 | } |
| 23 | // sudo was probably called, get the original user. |
| 24 | if username := getenvFunc("SUDO_USER"); username != "" { |
| 25 | return username |
| 26 | } |
| 27 | return username |
| 28 | } |
| 29 | |
| 30 | // EnvUsername returns the username from the OS environment. |
| 31 | func EnvUsername() (string, error) { |
| 32 | return os.Getenv("USER"), nil |
| 33 | } |
| 34 | |
| 35 | // OSUsername returns the username of the current OS user (based on UID). |
| 36 | func OSUsername() (string, error) { |
| 37 | u, err := user.Current() |
| 38 | if err != nil { |
| 39 | return "", errors.Trace(err) |
| 40 | } |
| 41 | return u.Username, nil |
| 42 | } |
| 43 | |
| 44 | // ResolveUsername returns the username determined by the provided |
| 45 | // functions. The functions are tried in the same order in which they |
| 46 | // were passed in. An error returned from any of them is immediately |
| 47 | // returned. If an empty string is returned then that signals that the |
| 48 | // function did not find the username and the next function is tried. |
| 49 | // Once a username is found, the provided resolveSudo func (if any) is |
| 50 | // called with that username and the result is returned. If no username |
| 51 | // is found then errors.NotFound is returned. |
| 52 | func ResolveUsername(resolveSudo func(string) string, usernameFuncs ...func() (string, error)) (string, error) { |
| 53 | for _, usernameFunc := range usernameFuncs { |
| 54 | username, err := usernameFunc() |
| 55 | if err != nil { |
| 56 | return "", errors.Trace(err) |
| 57 | } |
| 58 | if username != "" { |
| 59 | if resolveSudo != nil { |
| 60 | if original := resolveSudo(username); original != "" { |
| 61 | username = original |
| 62 | } |
| 63 | } |
| 64 | return username, nil |
| 65 | } |
| 66 | } |
| 67 | return "", errors.NotFoundf("username") |
| 68 | } |
| 69 | |
| 70 | // LocalUsername determines the current username on the local host. |
| 71 | func LocalUsername() (string, error) { |
| 72 | username, err := ResolveUsername(ResolveSudo, EnvUsername, OSUsername) |
| 73 | if err != nil { |
| 74 | return "", errors.Annotatef(err, "cannot get current user from the environment: %v", os.Environ()) |
| 75 | } |
| 76 | return username, nil |
| 77 | } |