Loading batch/batch.go +53 −6 Original line number Diff line number Diff line Loading @@ -217,6 +217,7 @@ Match User %s X11Forwarding no AllowTcpForwarding no PermitTunnel no AuthorizedKeysFile none ForceCommand /usr/sbin/nologin AuthorizedKeysCommand %s authorized-keys %%u %%t %%k AuthorizedKeysCommandUser %s Loading Loading @@ -286,7 +287,9 @@ func MigrateKeys() int { } // MigrateKeysWithQueries migrates authorized_keys entries into the // ssh_keys database table using the provided query handle. // ssh_keys database table using the provided query handle. It also // rewrites the authorized_keys file so that all bulletin entries use // the current secure format (--user and restrict). func MigrateKeysWithQueries(q *storage.Queries) error { ctx := storage.Context() Loading @@ -304,6 +307,8 @@ func MigrateKeysWithQueries(q *storage.Queries) error { migrated := 0 skipped := 0 var nonBulletinLines []string var rewriteLines []string scanner := bufio.NewScanner(f) for scanner.Scan() { line := bytes.TrimSpace(scanner.Bytes()) Loading @@ -313,29 +318,57 @@ func MigrateKeysWithQueries(q *storage.Queries) error { pubKey, _, options, _, err := ssh.ParseAuthorizedKey(line) if err != nil { fmt.Printf("WARNING: skipping unparseable line: %s\n", err) skipped++ fmt.Printf("WARNING: keeping unparseable line as-is: %s\n", err) nonBulletinLines = append(nonBulletinLines, string(line)) continue } // Extract login from the command= option. // Extract login from the command= option. Accept both the // old format (-u LOGIN) and the new format (--user LOGIN). login := "" isBulletin := false for _, opt := range options { parts := strings.SplitN(opt, "=", 2) if len(parts) != 2 || parts[0] != "command" { continue } cmd := strings.Split(strings.Trim(parts[1], "\" "), " ") if len(cmd) >= 3 && cmd[0] == bulletin && cmd[1] == "-u" { if len(cmd) >= 3 && cmd[0] == bulletin { if cmd[1] == "-u" || cmd[1] == "--user" { login = cmd[2] isBulletin = true } } break } if !isBulletin { nonBulletinLines = append(nonBulletinLines, string(line)) continue } if login == "" { skipped++ continue } // Ensure the user exists in the DB. u, err := q.GetUser(ctx, login) if err != nil { fmt.Printf("WARNING: skipping key for %s: %s\n", login, err) skipped++ continue } if u.Login == "" { _, err = q.AddUser(ctx, storage.AddUserParams{ Login: login, }) if err != nil { fmt.Printf("WARNING: could not create user %s: %s\n", login, err) skipped++ continue } fmt.Printf("Created user %s.\n", login) } // Compute fingerprint and key details. h := sha256.Sum256(pubKey.Marshal()) fp := "SHA256:" + base64.RawStdEncoding.EncodeToString(h[:]) Loading Loading @@ -364,12 +397,26 @@ func MigrateKeysWithQueries(q *storage.Queries) error { skipped++ continue } // Write this entry back in the new secure format. newLine := fmt.Sprintf("command=\"%s --user %s\",restrict %s", bulletin, login, keyLine) rewriteLines = append(rewriteLines, newLine) migrated++ } if err := scanner.Err(); err != nil { return fmt.Errorf("error reading authorized_keys: %w", err) } // Rewrite the authorized_keys file with upgraded entries. allLines := append(nonBulletinLines, rewriteLines...) newContent := strings.Join(allLines, "\n") + "\n" err = os.WriteFile(keyfile, []byte(newContent), 0600) // #nosec G703 -- path is constructed from xdg.Home if err != nil { return fmt.Errorf("failed to rewrite %s: %w", keyfile, err) } fmt.Printf("Migrated %d keys, skipped %d.\n", migrated, skipped) fmt.Println("The authorized_keys file has been rewritten with secure entries.") return nil } Loading
batch/batch.go +53 −6 Original line number Diff line number Diff line Loading @@ -217,6 +217,7 @@ Match User %s X11Forwarding no AllowTcpForwarding no PermitTunnel no AuthorizedKeysFile none ForceCommand /usr/sbin/nologin AuthorizedKeysCommand %s authorized-keys %%u %%t %%k AuthorizedKeysCommandUser %s Loading Loading @@ -286,7 +287,9 @@ func MigrateKeys() int { } // MigrateKeysWithQueries migrates authorized_keys entries into the // ssh_keys database table using the provided query handle. // ssh_keys database table using the provided query handle. It also // rewrites the authorized_keys file so that all bulletin entries use // the current secure format (--user and restrict). func MigrateKeysWithQueries(q *storage.Queries) error { ctx := storage.Context() Loading @@ -304,6 +307,8 @@ func MigrateKeysWithQueries(q *storage.Queries) error { migrated := 0 skipped := 0 var nonBulletinLines []string var rewriteLines []string scanner := bufio.NewScanner(f) for scanner.Scan() { line := bytes.TrimSpace(scanner.Bytes()) Loading @@ -313,29 +318,57 @@ func MigrateKeysWithQueries(q *storage.Queries) error { pubKey, _, options, _, err := ssh.ParseAuthorizedKey(line) if err != nil { fmt.Printf("WARNING: skipping unparseable line: %s\n", err) skipped++ fmt.Printf("WARNING: keeping unparseable line as-is: %s\n", err) nonBulletinLines = append(nonBulletinLines, string(line)) continue } // Extract login from the command= option. // Extract login from the command= option. Accept both the // old format (-u LOGIN) and the new format (--user LOGIN). login := "" isBulletin := false for _, opt := range options { parts := strings.SplitN(opt, "=", 2) if len(parts) != 2 || parts[0] != "command" { continue } cmd := strings.Split(strings.Trim(parts[1], "\" "), " ") if len(cmd) >= 3 && cmd[0] == bulletin && cmd[1] == "-u" { if len(cmd) >= 3 && cmd[0] == bulletin { if cmd[1] == "-u" || cmd[1] == "--user" { login = cmd[2] isBulletin = true } } break } if !isBulletin { nonBulletinLines = append(nonBulletinLines, string(line)) continue } if login == "" { skipped++ continue } // Ensure the user exists in the DB. u, err := q.GetUser(ctx, login) if err != nil { fmt.Printf("WARNING: skipping key for %s: %s\n", login, err) skipped++ continue } if u.Login == "" { _, err = q.AddUser(ctx, storage.AddUserParams{ Login: login, }) if err != nil { fmt.Printf("WARNING: could not create user %s: %s\n", login, err) skipped++ continue } fmt.Printf("Created user %s.\n", login) } // Compute fingerprint and key details. h := sha256.Sum256(pubKey.Marshal()) fp := "SHA256:" + base64.RawStdEncoding.EncodeToString(h[:]) Loading Loading @@ -364,12 +397,26 @@ func MigrateKeysWithQueries(q *storage.Queries) error { skipped++ continue } // Write this entry back in the new secure format. newLine := fmt.Sprintf("command=\"%s --user %s\",restrict %s", bulletin, login, keyLine) rewriteLines = append(rewriteLines, newLine) migrated++ } if err := scanner.Err(); err != nil { return fmt.Errorf("error reading authorized_keys: %w", err) } // Rewrite the authorized_keys file with upgraded entries. allLines := append(nonBulletinLines, rewriteLines...) newContent := strings.Join(allLines, "\n") + "\n" err = os.WriteFile(keyfile, []byte(newContent), 0600) // #nosec G703 -- path is constructed from xdg.Home if err != nil { return fmt.Errorf("failed to rewrite %s: %w", keyfile, err) } fmt.Printf("Migrated %d keys, skipped %d.\n", migrated, skipped) fmt.Println("The authorized_keys file has been rewritten with secure entries.") return nil }