Open opens the encrypted filesystem specified by path (usually a loop device, but any encrypted block device will do) using the given key and returns the name assigned to it that can be later used to close the device.
(key []byte, path string)
| 281 | // and returns the name assigned to it that can be later used to close |
| 282 | // the device. |
| 283 | func (crypt *Device) Open(key []byte, path string) (string, error) { |
| 284 | fd, err := lock.Exclusive("/dev/mapper") |
| 285 | if err != nil { |
| 286 | return "", fmt.Errorf("unable to acquire lock on /dev/mapper") |
| 287 | } |
| 288 | defer lock.Release(fd) |
| 289 | |
| 290 | maxRetries := 3 // Arbitrary number of retries. |
| 291 | |
| 292 | cryptsetup, err := bin.FindBin("cryptsetup") |
| 293 | if err != nil { |
| 294 | return "", err |
| 295 | } |
| 296 | if !fs.IsOwner(cryptsetup, 0) { |
| 297 | return "", fmt.Errorf("%s must be owned by root", cryptsetup) |
| 298 | } |
| 299 | |
| 300 | for i := 0; i < maxRetries; i++ { |
| 301 | nextCrypt, err := getNextAvailableCryptDevice() |
| 302 | if err != nil { |
| 303 | return "", fmt.Errorf("while getting next device: %v", err) |
| 304 | } |
| 305 | if nextCrypt == "" { |
| 306 | return "", errors.New("сrypt device not available") |
| 307 | } |
| 308 | |
| 309 | cmd := exec.Command(cryptsetup, "open", "--batch-mode", "--type", "luks2", "--key-file", "-", path, nextCrypt) |
| 310 | cmd.SysProcAttr = &syscall.SysProcAttr{} |
| 311 | cmd.SysProcAttr.Credential = &syscall.Credential{Uid: 0, Gid: 0} |
| 312 | sylog.Debugf("Running %s %s", cmd.Path, strings.Join(cmd.Args, " ")) |
| 313 | |
| 314 | cmd.Stdin = bytes.NewBuffer(key) |
| 315 | out, err := cmd.CombinedOutput() |
| 316 | if err != nil { |
| 317 | if strings.Contains(string(out), "Device already exists") { |
| 318 | continue |
| 319 | } |
| 320 | err = checkCryptsetupVersion(cryptsetup) |
| 321 | if err == ErrUnsupportedCryptsetupVersion { |
| 322 | // Special case of unsupported version of cryptsetup. We return the raw error |
| 323 | // so it can propagate up and a user-friendly message be displayed. This error |
| 324 | // should trigger an error at the CLI level. |
| 325 | return "", err |
| 326 | } |
| 327 | |
| 328 | if strings.Contains(string(out), "No key available") { |
| 329 | sylog.Debugf("Invalid password") |
| 330 | return "", ErrInvalidPassphrase |
| 331 | } |
| 332 | |
| 333 | return "", fmt.Errorf("cryptsetup open failed: %s: %v", string(out), err) |
| 334 | } |
| 335 | |
| 336 | for attempt := 0; true; attempt++ { |
| 337 | _, err := os.Stat("/dev/mapper/" + nextCrypt) |
| 338 | if err == nil { |
| 339 | break |
| 340 | } |