github.com/pelicanplatform/pelican@v1.0.5/web_ui/ui_unix.go (about) 1 //go:build !windows 2 3 /*************************************************************** 4 * 5 * Copyright (C) 2023, Pelican Project, Morgridge Institute for Research 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); you 8 * may not use this file except in compliance with the License. You may 9 * obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 ***************************************************************/ 20 21 package web_ui 22 23 import ( 24 "bufio" 25 "fmt" 26 "os" 27 "path/filepath" 28 "strings" 29 "syscall" 30 31 "github.com/pelicanplatform/pelican/param" 32 "github.com/pkg/errors" 33 log "github.com/sirupsen/logrus" 34 "golang.org/x/crypto/bcrypt" 35 ) 36 37 func doReload() error { 38 db := authDB.Load() 39 if db == nil { 40 log.Debug("Cannot reload auth database - not configured") 41 return nil 42 } 43 fileName := param.Server_UIPasswordFile.GetString() 44 fp, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0600) 45 if err != nil { 46 log.Warning("Failed to open auth database for reload:", err) 47 return err 48 } 49 defer fp.Close() 50 if err = syscall.Flock(int(fp.Fd()), syscall.LOCK_SH); err != nil { 51 log.Warning("Failed to lock the auth database for read:", err) 52 return err 53 } 54 defer func() { 55 if err := syscall.Flock(int(fp.Fd()), syscall.LOCK_UN); err != nil { 56 log.Warning("Failed to unlock the auth database:", err) 57 } 58 }() 59 60 err = db.Reload(nil) 61 if err != nil { 62 log.Warningln("Failed to reload auth database:", err) 63 return err 64 } 65 log.Debug("Successfully reloaded the auth database") 66 return nil 67 } 68 69 func writePasswordEntryImpl(user, password string) error { 70 fileName := param.Server_UIPasswordFile.GetString() 71 passwordBytes := []byte(password) 72 if len(passwordBytes) > 72 { 73 return errors.New("Password too long") 74 } 75 hashed, err := bcrypt.GenerateFromPassword(passwordBytes, bcrypt.DefaultCost) 76 if err != nil { 77 return err 78 } 79 80 directory := filepath.Dir(fileName) 81 err = os.MkdirAll(directory, 0750) 82 if err != nil { 83 return err 84 } 85 fp, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0600) 86 if err != nil { 87 return err 88 } 89 defer fp.Close() 90 91 if _, err := fp.Seek(0, 0); err != nil { 92 log.Warning("Failed to seek to the beginning of the auth database:", err) 93 return err 94 } 95 96 if err = syscall.Flock(int(fp.Fd()), syscall.LOCK_EX); err != nil { 97 log.Warning("Failed to lock the auth database for read:", err) 98 return err 99 } 100 defer func() { 101 if err := syscall.Flock(int(fp.Fd()), syscall.LOCK_UN); err != nil { 102 log.Warning("Failed to unlock the auth database:", err) 103 } 104 }() 105 106 credentials := make(map[string]string) 107 scanner := bufio.NewScanner(fp) 108 scanner.Split(bufio.ScanLines) 109 for scanner.Scan() { 110 info := strings.SplitN(scanner.Text(), ":", 2) 111 if len(info) == 1 { 112 log.Warning("Invalid line in the authdb file:", scanner.Text()) 113 continue 114 } 115 credentials[info[0]] = info[1] 116 } 117 credentials[user] = string(hashed) 118 119 fp2, err := os.OpenFile(fileName, os.O_RDWR|os.O_TRUNC|os.O_APPEND, 0600) 120 if err != nil { 121 return err 122 } 123 defer fp2.Close() 124 125 for user, pass := range credentials { 126 entry := fmt.Sprintf("%s:%s\n", user, pass) 127 if _, err = fp2.Write([]byte(entry)); err != nil { 128 return err 129 } 130 } 131 132 return nil 133 } 134 135 func WritePasswordEntry(user, password string) error { 136 if err := writePasswordEntryImpl(user, password); err != nil { 137 return err 138 } 139 140 db := authDB.Load() 141 if db != nil { 142 if err := db.Reload(nil); err != nil { 143 return err 144 } 145 } 146 return nil 147 }