Compare commits

..

7 Commits

Author SHA1 Message Date
Mohammed Al Sahaf 15faeacb60 cmd: fix auto-detetction of .caddyfile extension (#6356)
* cmd: fix auto-detetction of .caddyfile extension

Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>

* move conditions around and add clarifying comment

Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>

* reject ambiguous config file name

Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>

---------

Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>
2024-06-02 03:49:38 +00:00
Will Norris f8a2c60297 caddyhttp: properly sanitize requests for root path (#6360)
SanitizePathJoin protects against directory traversal attacks by
checking for requests whose URL path look like they are trying to
request something other than a local file, and returns the root
directory in those cases.

The method is also careful to ensure that requests which contain a
trailing slash include a trailing slash in the returned value.  However,
for requests that contain only a slash (requests for the root path), the
IsLocal check returns early before the matching trailing slash is
re-added.

This change updates SanitizePathJoin to only perform the
filepath.IsLocal check if the cleaned request URL path is non-empty.

---

This change also updates the existing SanitizePathJoin tests to use
filepath.FromSlash rather than filepath.Join. This makes the expected
value a little easier to read, but also has the advantage of not being
processed by filepath.Clean like filepath.Join is. This means that the
exact expect value will be compared, not the result of first cleaning
it.

Fixes #6352
2024-06-02 03:40:59 +00:00
Matthew Holt 01308b4bae I'm so tired of typos 2024-06-01 20:43:35 -06:00
Matthew Holt b7280e6949 caddytls: Implement certmagic.RenewalInfoGetter
Fixes ARI errors reported here:
https://caddy.community/t/error-in-logs-with-updating-ari-after-upgrading-to-caddy-v2-8-1/24320
2024-06-01 18:02:49 -06:00
dependabot[bot] a63767d3f8 build(deps): bump golangci/golangci-lint-action from 5 to 6 (#6361)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 5 to 6.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-02 02:26:31 +03:00
Francis Lavoie 40c582ce82 caddyhttp: Fix merging consecutive client_ip or remote_ip matchers (#6350) 2024-05-30 07:32:17 -06:00
Anton Kovalenko a52917a37d core: MkdirAll appDataDir in InstanceID with 0o700 (#6340)
appDataDir components should be searchable (u+x) when they are
created, or else Caddy is unable to start with an empty HOME.
2024-05-30 10:38:09 +00:00
10 changed files with 121 additions and 45 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
check-latest: true
- name: golangci-lint
uses: golangci/golangci-lint-action@v5
uses: golangci/golangci-lint-action@v6
with:
version: v1.55
+1 -1
View File
@@ -869,7 +869,7 @@ func InstanceID() (uuid.UUID, error) {
if err != nil {
return uuid, err
}
err = os.MkdirAll(appDataDir, 0o600)
err = os.MkdirAll(appDataDir, 0o700)
if err != nil {
return uuid, err
}
@@ -46,6 +46,18 @@
@matcher12 client_ip private_ranges
respond @matcher12 "client_ip matcher with private ranges"
@matcher13 {
remote_ip 1.1.1.1
remote_ip 2.2.2.2
}
respond @matcher13 "remote_ip merged"
@matcher14 {
client_ip 1.1.1.1
client_ip 2.2.2.2
}
respond @matcher14 "client_ip merged"
}
----------
{
@@ -279,6 +291,42 @@
"handler": "static_response"
}
]
},
{
"match": [
{
"remote_ip": {
"ranges": [
"1.1.1.1",
"2.2.2.2"
]
}
}
],
"handle": [
{
"body": "remote_ip merged",
"handler": "static_response"
}
]
},
{
"match": [
{
"client_ip": {
"ranges": [
"1.1.1.1",
"2.2.2.2"
]
}
}
],
"handle": [
{
"body": "client_ip merged",
"handler": "static_response"
}
]
}
]
}
+12 -3
View File
@@ -163,9 +163,18 @@ func loadConfigWithLogger(logger *zap.Logger, configFile, adapterName string) ([
// caddyfile adapter for convenience
baseConfig := strings.ToLower(filepath.Base(configFile))
baseConfigExt := filepath.Ext(baseConfig)
if (strings.HasPrefix(baseConfig, "caddyfile") ||
strings.HasSuffix(baseConfig, ".caddyfile")) &&
(len(baseConfigExt) == 0 || caddyconfig.GetAdapter(baseConfigExt[1:]) == nil) &&
startsOrEndsInCaddyfile := strings.HasPrefix(baseConfig, "caddyfile") || strings.HasSuffix(baseConfig, ".caddyfile")
// If the adapter is not specified, the config file is not starts with "caddyfile", and isn't a JSON file (e.g. Caddyfile.yaml),
// then we don't know what the config format is.
if adapterName == "" && startsOrEndsInCaddyfile && baseConfigExt != ".caddyfile" && baseConfigExt != ".json" {
return nil, "", fmt.Errorf("ambiguous config file format; please specify adapter (use --adapter)")
}
// If the config file starts or ends with "caddyfile",
// the extension of the config file is not ".json", AND
// the user did not specify an adapter, then we assume it's Caddyfile.
if startsOrEndsInCaddyfile &&
baseConfigExt != ".json" &&
adapterName == "" {
adapterName = "caddyfile"
+1 -1
View File
@@ -9,7 +9,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/alecthomas/chroma/v2 v2.13.0
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
github.com/caddyserver/certmagic v0.21.2
github.com/caddyserver/certmagic v0.21.3
github.com/caddyserver/zerossl v0.1.3
github.com/dustin/go-humanize v1.0.1
github.com/go-chi/chi/v5 v5.0.12
+2 -2
View File
@@ -73,8 +73,8 @@ github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/caddyserver/certmagic v0.21.2 h1:O18LtaYBGDooyy257cYePnhp4lPfz6TaJELil6Q1fDg=
github.com/caddyserver/certmagic v0.21.2/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0=
github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+1 -1
View File
@@ -239,7 +239,7 @@ func SanitizedPathJoin(root, reqPath string) string {
}
relPath := path.Clean("/" + reqPath)[1:] // clean path and trim the leading /
if !filepath.IsLocal(relPath) {
if relPath != "" && !filepath.IsLocal(relPath) {
// path is unsafe (see https://github.com/golang/go/issues/56336#issuecomment-1416214885)
return root
}
+18 -10
View File
@@ -26,22 +26,28 @@ func TestSanitizedPathJoin(t *testing.T) {
inputPath: "/",
expect: ".",
},
{
// fileserver.MatchFile passes an inputPath of "//" for some try_files values.
// See https://github.com/caddyserver/caddy/issues/6352
inputPath: "//",
expect: filepath.FromSlash("./"),
},
{
inputPath: "/foo",
expect: "foo",
},
{
inputPath: "/foo/",
expect: "foo" + separator,
expect: filepath.FromSlash("foo/"),
},
{
inputPath: "/foo/bar",
expect: filepath.Join("foo", "bar"),
expect: filepath.FromSlash("foo/bar"),
},
{
inputRoot: "/a",
inputPath: "/foo/bar",
expect: filepath.Join("/", "a", "foo", "bar"),
expect: filepath.FromSlash("/a/foo/bar"),
},
{
inputPath: "/foo/../bar",
@@ -50,32 +56,34 @@ func TestSanitizedPathJoin(t *testing.T) {
{
inputRoot: "/a/b",
inputPath: "/foo/../bar",
expect: filepath.Join("/", "a", "b", "bar"),
expect: filepath.FromSlash("/a/b/bar"),
},
{
inputRoot: "/a/b",
inputPath: "/..%2fbar",
expect: filepath.Join("/", "a", "b", "bar"),
expect: filepath.FromSlash("/a/b/bar"),
},
{
inputRoot: "/a/b",
inputPath: "/%2e%2e%2fbar",
expect: filepath.Join("/", "a", "b", "bar"),
expect: filepath.FromSlash("/a/b/bar"),
},
{
// inputPath fails the IsLocal test so only the root is returned,
// but with a trailing slash since one was included in inputPath
inputRoot: "/a/b",
inputPath: "/%2e%2e%2f%2e%2e%2f",
expect: "/a/b", // inputPath fails the IsLocal test so only the root is returned
expect: filepath.FromSlash("/a/b/"),
},
{
inputRoot: "/a/b",
inputPath: "/foo%2fbar",
expect: filepath.Join("/", "a", "b", "foo", "bar"),
expect: filepath.FromSlash("/a/b/foo/bar"),
},
{
inputRoot: "/a/b",
inputPath: "/foo%252fbar",
expect: filepath.Join("/", "a", "b", "foo%2fbar"),
expect: filepath.FromSlash("/a/b/foo%2fbar"),
},
{
inputRoot: "C:\\www",
@@ -92,7 +100,7 @@ func TestSanitizedPathJoin(t *testing.T) {
// https://github.com/golang/go/issues/56336#issuecomment-1416214885
inputRoot: "root",
inputPath: "/a/b/../../c",
expect: filepath.Join("root", "c"),
expect: filepath.FromSlash("root/c"),
},
} {
// we don't *need* to use an actual parsed URL, but it
+24 -20
View File
@@ -72,19 +72,21 @@ func (MatchRemoteIP) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
d.Next() // consume matcher name
for d.NextArg() {
if d.Val() == "forwarded" {
return d.Err("the 'forwarded' option is no longer supported; use the 'client_ip' matcher instead")
// iterate to merge multiple matchers into one
for d.Next() {
for d.NextArg() {
if d.Val() == "forwarded" {
return d.Err("the 'forwarded' option is no longer supported; use the 'client_ip' matcher instead")
}
if d.Val() == "private_ranges" {
m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
continue
}
m.Ranges = append(m.Ranges, d.Val())
}
if d.Val() == "private_ranges" {
m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
continue
if d.NextBlock(0) {
return d.Err("malformed remote_ip matcher: blocks are not supported")
}
m.Ranges = append(m.Ranges, d.Val())
}
if d.NextBlock(0) {
return d.Err("malformed remote_ip matcher: blocks are not supported")
}
return nil
}
@@ -164,16 +166,18 @@ func (MatchClientIP) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchClientIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
d.Next() // consume matcher name
for d.NextArg() {
if d.Val() == "private_ranges" {
m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
continue
// iterate to merge multiple matchers into one
for d.Next() {
for d.NextArg() {
if d.Val() == "private_ranges" {
m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
continue
}
m.Ranges = append(m.Ranges, d.Val())
}
if d.NextBlock(0) {
return d.Err("malformed client_ip matcher: blocks are not supported")
}
m.Ranges = append(m.Ranges, d.Val())
}
if d.NextBlock(0) {
return d.Err("malformed client_ip matcher: blocks are not supported")
}
return nil
}
+13 -6
View File
@@ -264,6 +264,12 @@ func (iss *ACMEIssuer) Revoke(ctx context.Context, cert certmagic.CertificateRes
// to be accessed and manipulated.
func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss }
// GetRenewalInfo wraps the underlying GetRenewalInfo method and satisfies
// the CertMagic interface for ARI support.
func (iss *ACMEIssuer) GetRenewalInfo(ctx context.Context, cert certmagic.Certificate) (acme.RenewalInfo, error) {
return iss.issuer.GetRenewalInfo(ctx, cert)
}
// generateZeroSSLEABCredentials generates ZeroSSL EAB credentials for the primary contact email
// on the issuer. It should only be usedif the CA endpoint is ZeroSSL. An email address is required.
func (iss *ACMEIssuer) generateZeroSSLEABCredentials(ctx context.Context, acct acme.Account) (*acme.EAB, acme.Account, error) {
@@ -649,10 +655,11 @@ type ChainPreference struct {
// Interface guards
var (
_ certmagic.PreChecker = (*ACMEIssuer)(nil)
_ certmagic.Issuer = (*ACMEIssuer)(nil)
_ certmagic.Revoker = (*ACMEIssuer)(nil)
_ caddy.Provisioner = (*ACMEIssuer)(nil)
_ ConfigSetter = (*ACMEIssuer)(nil)
_ caddyfile.Unmarshaler = (*ACMEIssuer)(nil)
_ certmagic.PreChecker = (*ACMEIssuer)(nil)
_ certmagic.Issuer = (*ACMEIssuer)(nil)
_ certmagic.Revoker = (*ACMEIssuer)(nil)
_ certmagic.RenewalInfoGetter = (*ACMEIssuer)(nil)
_ caddy.Provisioner = (*ACMEIssuer)(nil)
_ ConfigSetter = (*ACMEIssuer)(nil)
_ caddyfile.Unmarshaler = (*ACMEIssuer)(nil)
)