Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

Please unblock package docker.io.  This is a new upstream backport
release with security (including CVE-2014-5277[1]) and minor
functionality fixes on top of 1.3.0, especially in the Dockerfile
parser relating to environment variable substitution[2].

Attached is the output of:
| debdiff docker.io_1.3.0~dfsg1-1.dsc docker.io_1.3.1~dfsg1-1.dsc > 
docker.io_1.3.1.debdiff
(from the version in Jessie to the version now in Sid)

unblock docker.io/1.3.1~dfsg1-1

♥,
- Tianon
  4096R / B42F 6819 007F 00F8 8E36  4FD4 036A 9C25 BF35 7DD4

[1]: https://groups.google.com/d/topic/docker-user/oYm0i3xShJU/discussion
[2]: https://github.com/docker/docker/blob/v1.3.1/CHANGELOG.md#131-2014-10-28
diff -Nru docker.io-1.3.0~dfsg1/CHANGELOG.md docker.io-1.3.1~dfsg1/CHANGELOG.md
--- docker.io-1.3.0~dfsg1/CHANGELOG.md  2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/CHANGELOG.md  2014-10-30 13:44:46.000000000 +0000
@@ -1,5 +1,23 @@
 # Changelog
 
+## 1.3.1 (2014-10-28)
+
+#### Security
+* Prevent fallback to SSL protocols < TLS 1.0 for client, daemon and registry
++ Secure HTTPS connection to registries with certificate verification and 
without HTTP fallback unless `--insecure-registry` is specified
+
+#### Runtime
+- Fix issue where volumes would not be shared
+
+#### Client
+- Fix issue with `--iptables=false` not automatically setting `--ip-masq=false`
+- Fix docker run output to non-TTY stdout
+
+#### Builder
+- Fix escaping `$` for environment variables
+- Fix issue with lowercase `onbuild` Dockerfile instruction
+- Restrict envrionment variable expansion to `ENV`, `ADD`, `COPY`, `WORKDIR`, 
`EXPOSE`, `VOLUME` and `USER`
+
 ## 1.3.0 (2014-10-14)
 
 #### Notable features since 1.2.0
diff -Nru docker.io-1.3.0~dfsg1/VERSION docker.io-1.3.1~dfsg1/VERSION
--- docker.io-1.3.0~dfsg1/VERSION       2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/VERSION       2014-10-30 13:44:46.000000000 +0000
@@ -1 +1 @@
-1.3.0
+1.3.1
diff -Nru docker.io-1.3.0~dfsg1/api/client/commands.go 
docker.io-1.3.1~dfsg1/api/client/commands.go
--- docker.io-1.3.0~dfsg1/api/client/commands.go        2014-10-15 
19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/api/client/commands.go        2014-10-30 
13:44:46.000000000 +0000
@@ -1986,6 +1986,10 @@
 }
 
 func (cli *DockerCli) pullImage(image string) error {
+       return cli.pullImageCustomOut(image, cli.out)
+}
+
+func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
        v := url.Values{}
        repos, tag := parsers.ParseRepositoryTag(image)
        // pull only the image tagged 'latest' if no tag was specified
@@ -2014,7 +2018,7 @@
        registryAuthHeader := []string{
                base64.URLEncoding.EncodeToString(buf),
        }
-       if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out, 
map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
+       if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, out, 
map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
                return err
        }
        return nil
@@ -2081,7 +2085,8 @@
        if statusCode == 404 {
                fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", 
config.Image)
 
-               if err = cli.pullImage(config.Image); err != nil {
+               // we don't want to write to stdout anything apart from 
container.ID
+               if err = cli.pullImageCustomOut(config.Image, cli.err); err != 
nil {
                        return nil, err
                }
                // Retry
diff -Nru docker.io-1.3.0~dfsg1/api/server/server.go 
docker.io-1.3.1~dfsg1/api/server/server.go
--- docker.io-1.3.0~dfsg1/api/server/server.go  2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/api/server/server.go  2014-10-30 13:44:46.000000000 
+0000
@@ -1439,6 +1439,8 @@
                tlsConfig := &tls.Config{
                        NextProtos:   []string{"http/1.1"},
                        Certificates: []tls.Certificate{cert},
+                       // Avoid fallback on insecure SSL protocols
+                       MinVersion: tls.VersionTLS10,
                }
                if job.GetenvBool("TlsVerify") {
                        certPool := x509.NewCertPool()
diff -Nru docker.io-1.3.0~dfsg1/builder/dispatchers.go 
docker.io-1.3.1~dfsg1/builder/dispatchers.go
--- docker.io-1.3.0~dfsg1/builder/dispatchers.go        2014-10-15 
19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/builder/dispatchers.go        2014-10-30 
13:44:46.000000000 +0000
@@ -11,6 +11,7 @@
        "fmt"
        "io/ioutil"
        "path/filepath"
+       "regexp"
        "strings"
 
        "github.com/docker/docker/nat"
@@ -129,7 +130,7 @@
                return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", 
triggerInstruction)
        }
 
-       original = strings.TrimSpace(strings.TrimLeft(original, "ONBUILD"))
+       original = 
regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "")
 
        b.Config.OnBuild = append(b.Config.OnBuild, original)
        return b.commit("", b.Config.Cmd, fmt.Sprintf("ONBUILD %s", original))
@@ -194,7 +195,7 @@
 
        defer func(cmd []string) { b.Config.Cmd = cmd }(cmd)
 
-       log.Debugf("Command to be executed: %v", b.Config.Cmd)
+       log.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)
 
        hit, err := b.probeCache()
        if err != nil {
@@ -233,7 +234,7 @@
 func cmd(b *Builder, args []string, attributes map[string]bool, original 
string) error {
        b.Config.Cmd = handleJsonArgs(args, attributes)
 
-       if !attributes["json"] && len(b.Config.Entrypoint) == 0 {
+       if !attributes["json"] {
                b.Config.Cmd = append([]string{"/bin/sh", "-c"}, 
b.Config.Cmd...)
        }
 
@@ -260,14 +261,14 @@
        parsed := handleJsonArgs(args, attributes)
 
        switch {
-       case len(parsed) == 0:
-               // ENTYRPOINT []
-               b.Config.Entrypoint = nil
        case attributes["json"]:
                // ENTRYPOINT ["echo", "hi"]
                b.Config.Entrypoint = parsed
+       case len(parsed) == 0:
+               // ENTRYPOINT []
+               b.Config.Entrypoint = nil
        default:
-               // ENTYRPOINT echo hi
+               // ENTRYPOINT echo hi
                b.Config.Entrypoint = []string{"/bin/sh", "-c", parsed[0]}
        }
 
diff -Nru docker.io-1.3.0~dfsg1/builder/evaluator.go 
docker.io-1.3.1~dfsg1/builder/evaluator.go
--- docker.io-1.3.0~dfsg1/builder/evaluator.go  2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/builder/evaluator.go  2014-10-30 13:44:46.000000000 
+0000
@@ -41,6 +41,17 @@
        ErrDockerfileEmpty = errors.New("Dockerfile cannot be empty")
 )
 
+// Environment variable interpolation will happen on these statements only.
+var replaceEnvAllowed = map[string]struct{}{
+       "env":     {},
+       "add":     {},
+       "copy":    {},
+       "workdir": {},
+       "expose":  {},
+       "volume":  {},
+       "user":    {},
+}
+
 var evaluateTable map[string]func(*Builder, []string, map[string]bool, string) 
error
 
 func init() {
@@ -149,7 +160,7 @@
        b.dockerfile = ast
 
        // some initializations that would not have been supplied by the caller.
-       b.Config = &runconfig.Config{Entrypoint: []string{}, Cmd: nil}
+       b.Config = &runconfig.Config{}
        b.TmpContainers = map[string]struct{}{}
 
        for i, n := range b.dockerfile.Children {
@@ -196,13 +207,18 @@
 
        if cmd == "onbuild" {
                ast = ast.Next.Children[0]
-               strs = append(strs, b.replaceEnv(ast.Value))
+               strs = append(strs, ast.Value)
                msg += " " + ast.Value
        }
 
        for ast.Next != nil {
                ast = ast.Next
-               strs = append(strs, b.replaceEnv(ast.Value))
+               var str string
+               str = ast.Value
+               if _, ok := replaceEnvAllowed[cmd]; ok {
+                       str = b.replaceEnv(ast.Value)
+               }
+               strs = append(strs, str)
                msg += " " + ast.Value
        }
 
diff -Nru docker.io-1.3.0~dfsg1/builder/parser/parser.go 
docker.io-1.3.1~dfsg1/builder/parser/parser.go
--- docker.io-1.3.0~dfsg1/builder/parser/parser.go      2014-10-15 
19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/builder/parser/parser.go      2014-10-30 
13:44:46.000000000 +0000
@@ -87,10 +87,11 @@
 
        if sexp.Value != "" || sexp.Next != nil || sexp.Children != nil {
                node.Next = sexp
-               node.Attributes = attrs
-               node.Original = line
        }
 
+       node.Attributes = attrs
+       node.Original = line
+
        return "", node, nil
 }
 
diff -Nru docker.io-1.3.0~dfsg1/builder/support.go 
docker.io-1.3.1~dfsg1/builder/support.go
--- docker.io-1.3.0~dfsg1/builder/support.go    2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/builder/support.go    2014-10-30 13:44:46.000000000 
+0000
@@ -10,13 +10,26 @@
        // `\$` - match literal $
        // `[[:alnum:]_]+` - match things like `$SOME_VAR`
        // `{[[:alnum:]_]+}` - match things like `${SOME_VAR}`
-       tokenEnvInterpolation = 
regexp.MustCompile(`(\\\\+|[^\\]|\b|\A)\$([[:alnum:]_]+|{[[:alnum:]_]+})`)
+       tokenEnvInterpolation = 
regexp.MustCompile(`(\\|\\\\+|[^\\]|\b|\A)\$([[:alnum:]_]+|{[[:alnum:]_]+})`)
        // this intentionally punts on more exotic interpolations like 
${SOME_VAR%suffix} and lets the shell handle those directly
 )
 
 // handle environment replacement. Used in dispatcher.
 func (b *Builder) replaceEnv(str string) string {
        for _, match := range tokenEnvInterpolation.FindAllString(str, -1) {
+               idx := strings.Index(match, "\\$")
+               if idx != -1 {
+                       if idx+2 >= len(match) {
+                               str = strings.Replace(str, match, "\\$", -1)
+                               continue
+                       }
+
+                       prefix := match[:idx]
+                       stripped := match[idx+2:]
+                       str = strings.Replace(str, match, prefix+"$"+stripped, 
-1)
+                       continue
+               }
+
                match = match[strings.Index(match, "$"):]
                matchKey := strings.Trim(match, "${}")
 
diff -Nru docker.io-1.3.0~dfsg1/builtins/builtins.go 
docker.io-1.3.1~dfsg1/builtins/builtins.go
--- docker.io-1.3.0~dfsg1/builtins/builtins.go  2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/builtins/builtins.go  2014-10-30 13:44:46.000000000 
+0000
@@ -10,7 +10,6 @@
        "github.com/docker/docker/engine"
        "github.com/docker/docker/events"
        "github.com/docker/docker/pkg/parsers/kernel"
-       "github.com/docker/docker/registry"
 )
 
 func Register(eng *engine.Engine) error {
@@ -26,7 +25,8 @@
        if err := eng.Register("version", dockerVersion); err != nil {
                return err
        }
-       return registry.NewService().Install(eng)
+
+       return nil
 }
 
 // remote: a RESTful api for cross-docker communication
diff -Nru docker.io-1.3.0~dfsg1/daemon/config.go 
docker.io-1.3.1~dfsg1/daemon/config.go
--- docker.io-1.3.0~dfsg1/daemon/config.go      2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/daemon/config.go      2014-10-30 13:44:46.000000000 
+0000
@@ -31,6 +31,7 @@
        BridgeIface                 string
        BridgeIP                    string
        FixedCIDR                   string
+       InsecureRegistries          []string
        InterContainerCommunication bool
        GraphDriver                 string
        GraphOptions                []string
@@ -55,6 +56,7 @@
        flag.StringVar(&config.BridgeIP, []string{"#bip", "-bip"}, "", "Use 
this CIDR notation address for the network bridge's IP, not compatible with -b")
        flag.StringVar(&config.BridgeIface, []string{"b", "-bridge"}, "", 
"Attach containers to a pre-existing network bridge\nuse 'none' to disable 
container networking")
        flag.StringVar(&config.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 
subnet for fixed IPs (ex: 10.20.0.0/16)\nthis subnet must be nested in the 
bridge subnet (which is defined by -b or --bip)")
+       opts.ListVar(&config.InsecureRegistries, 
[]string{"-insecure-registry"}, "Enable insecure communication with specified 
registries (no certificate verification for HTTPS and enable HTTP fallback)")
        flag.BoolVar(&config.InterContainerCommunication, []string{"#icc", 
"-icc"}, true, "Enable inter-container communication")
        flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, 
"", "Force the Docker runtime to use a specific storage driver")
        flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, 
"native", "Force the Docker runtime to use a specific exec driver")
diff -Nru docker.io-1.3.0~dfsg1/daemon/daemon.go 
docker.io-1.3.1~dfsg1/daemon/daemon.go
--- docker.io-1.3.0~dfsg1/daemon/daemon.go      2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/daemon/daemon.go      2014-10-30 13:44:46.000000000 
+0000
@@ -731,7 +731,7 @@
                return nil, fmt.Errorf("You specified --iptables=false with 
--icc=false. ICC uses iptables to function. Please set --icc or --iptables to 
true.")
        }
        if !config.EnableIptables && config.EnableIpMasq {
-               return nil, fmt.Errorf("You specified --iptables=false with 
--ipmasq=true. IP masquerading uses iptables to function. Please set --ipmasq 
to false or --iptables to true.")
+               config.EnableIpMasq = false
        }
        config.DisableNetwork = config.BridgeIface == disableNetworkBridge
 
@@ -831,7 +831,7 @@
        }
 
        log.Debugf("Creating repository list")
-       repositories, err := graph.NewTagStore(path.Join(config.Root, 
"repositories-"+driver.String()), g, config.Mirrors)
+       repositories, err := graph.NewTagStore(path.Join(config.Root, 
"repositories-"+driver.String()), g, config.Mirrors, config.InsecureRegistries)
        if err != nil {
                return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
        }
diff -Nru docker.io-1.3.0~dfsg1/daemon/volumes.go 
docker.io-1.3.1~dfsg1/daemon/volumes.go
--- docker.io-1.3.0~dfsg1/daemon/volumes.go     2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/daemon/volumes.go     2014-10-30 13:44:46.000000000 
+0000
@@ -133,6 +133,7 @@
        // Get the rest of the volumes
        for path := range container.Config.Volumes {
                // Check if this is already added as a bind-mount
+               path = filepath.Clean(path)
                if _, exists := mounts[path]; exists {
                        continue
                }
@@ -182,6 +183,8 @@
                return "", "", false, fmt.Errorf("cannot bind mount volume: %s 
volume paths must be absolute.", path)
        }
 
+       path = filepath.Clean(path)
+       mountToPath = filepath.Clean(mountToPath)
        return path, mountToPath, writable, nil
 }
 
diff -Nru docker.io-1.3.0~dfsg1/debian/changelog 
docker.io-1.3.1~dfsg1/debian/changelog
--- docker.io-1.3.0~dfsg1/debian/changelog      2014-10-17 06:56:10.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/debian/changelog      2014-11-03 15:26:38.000000000 
+0000
@@ -1,3 +1,11 @@
+docker.io (1.3.1~dfsg1-1) unstable; urgency=high
+
+  * Update to 1.3.1 upstream release
+    - fix for CVE-2014-5277
+    - https://groups.google.com/d/topic/docker-user/oYm0i3xShJU/discussion
+
+ -- Tianon Gravi <admwig...@gmail.com>  Mon, 03 Nov 2014 08:26:29 -0700
+
 docker.io (1.3.0~dfsg1-1) unstable; urgency=medium
 
   * Updated to 1.3.0 upstream release.
diff -Nru docker.io-1.3.0~dfsg1/debian/upstream-version-gitcommits 
docker.io-1.3.1~dfsg1/debian/upstream-version-gitcommits
--- docker.io-1.3.0~dfsg1/debian/upstream-version-gitcommits    2014-10-17 
06:34:38.000000000 +0000
+++ docker.io-1.3.1~dfsg1/debian/upstream-version-gitcommits    2014-10-31 
21:26:53.000000000 +0000
@@ -33,3 +33,4 @@
 1.1.2: d84a070
 1.2.0: fa7b24f
 1.3.0: c78088f
+1.3.1: 4e9bbfa
diff -Nru docker.io-1.3.0~dfsg1/docker/daemon.go 
docker.io-1.3.1~dfsg1/docker/daemon.go
--- docker.io-1.3.0~dfsg1/docker/daemon.go      2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/docker/daemon.go      2014-10-30 13:44:46.000000000 
+0000
@@ -14,6 +14,7 @@
        "github.com/docker/docker/engine"
        flag "github.com/docker/docker/pkg/mflag"
        "github.com/docker/docker/pkg/signal"
+       "github.com/docker/docker/registry"
 )
 
 const CanDaemon = true
@@ -33,11 +34,17 @@
        }
        eng := engine.New()
        signal.Trap(eng.Shutdown)
+
        // Load builtins
        if err := builtins.Register(eng); err != nil {
                log.Fatal(err)
        }
 
+       // load registry service
+       if err := 
registry.NewService(daemonCfg.InsecureRegistries).Install(eng); err != nil {
+               log.Fatal(err)
+       }
+
        // load the daemon in the background so we can immediately start
        // the http api so that connections don't fail while the daemon
        // is booting
diff -Nru docker.io-1.3.0~dfsg1/docker/docker.go 
docker.io-1.3.1~dfsg1/docker/docker.go
--- docker.io-1.3.0~dfsg1/docker/docker.go      2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/docker/docker.go      2014-10-30 13:44:46.000000000 
+0000
@@ -93,6 +93,8 @@
                        }
                        tlsConfig.Certificates = []tls.Certificate{cert}
                }
+               // Avoid fallback to SSL protocols < TLS1.0
+               tlsConfig.MinVersion = tls.VersionTLS10
        }
 
        if *flTls || *flTlsVerify {
diff -Nru docker.io-1.3.0~dfsg1/docs/mkdocs.yml 
docker.io-1.3.1~dfsg1/docs/mkdocs.yml
--- docker.io-1.3.0~dfsg1/docs/mkdocs.yml       2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/docs/mkdocs.yml       2014-10-30 13:44:46.000000000 
+0000
@@ -26,6 +26,7 @@
 
 # Introduction:
 - ['index.md', 'About', 'Docker']
+- ['release-notes.md', 'About', 'Release Notes']
 - ['introduction/index.md', '**HIDDEN**']
 - ['introduction/understanding-docker.md', 'About', 'Understanding Docker']
 
diff -Nru docker.io-1.3.0~dfsg1/graph/pull.go 
docker.io-1.3.1~dfsg1/graph/pull.go
--- docker.io-1.3.0~dfsg1/graph/pull.go 2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/graph/pull.go 2014-10-30 13:44:46.000000000 +0000
@@ -113,7 +113,9 @@
                return job.Error(err)
        }
 
-       endpoint, err := registry.NewEndpoint(hostname)
+       secure := registry.IsSecure(hostname, s.insecureRegistries)
+
+       endpoint, err := registry.NewEndpoint(hostname, secure)
        if err != nil {
                return job.Error(err)
        }
diff -Nru docker.io-1.3.0~dfsg1/graph/push.go 
docker.io-1.3.1~dfsg1/graph/push.go
--- docker.io-1.3.0~dfsg1/graph/push.go 2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/graph/push.go 2014-10-30 13:44:46.000000000 +0000
@@ -214,7 +214,9 @@
                return job.Error(err)
        }
 
-       endpoint, err := registry.NewEndpoint(hostname)
+       secure := registry.IsSecure(hostname, s.insecureRegistries)
+
+       endpoint, err := registry.NewEndpoint(hostname, secure)
        if err != nil {
                return job.Error(err)
        }
diff -Nru docker.io-1.3.0~dfsg1/graph/tags.go 
docker.io-1.3.1~dfsg1/graph/tags.go
--- docker.io-1.3.0~dfsg1/graph/tags.go 2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/graph/tags.go 2014-10-30 13:44:46.000000000 +0000
@@ -23,10 +23,11 @@
 )
 
 type TagStore struct {
-       path         string
-       graph        *Graph
-       mirrors      []string
-       Repositories map[string]Repository
+       path               string
+       graph              *Graph
+       mirrors            []string
+       insecureRegistries []string
+       Repositories       map[string]Repository
        sync.Mutex
        // FIXME: move push/pull-related fields
        // to a helper type
@@ -54,18 +55,20 @@
        return true
 }
 
-func NewTagStore(path string, graph *Graph, mirrors []string) (*TagStore, 
error) {
+func NewTagStore(path string, graph *Graph, mirrors []string, 
insecureRegistries []string) (*TagStore, error) {
        abspath, err := filepath.Abs(path)
        if err != nil {
                return nil, err
        }
+
        store := &TagStore{
-               path:         abspath,
-               graph:        graph,
-               mirrors:      mirrors,
-               Repositories: make(map[string]Repository),
-               pullingPool:  make(map[string]chan struct{}),
-               pushingPool:  make(map[string]chan struct{}),
+               path:               abspath,
+               graph:              graph,
+               mirrors:            mirrors,
+               insecureRegistries: insecureRegistries,
+               Repositories:       make(map[string]Repository),
+               pullingPool:        make(map[string]chan struct{}),
+               pushingPool:        make(map[string]chan struct{}),
        }
        // Load the json file if it exists, otherwise create it.
        if err := store.reload(); os.IsNotExist(err) {
diff -Nru docker.io-1.3.0~dfsg1/graph/tags_unit_test.go 
docker.io-1.3.1~dfsg1/graph/tags_unit_test.go
--- docker.io-1.3.0~dfsg1/graph/tags_unit_test.go       2014-10-15 
19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/graph/tags_unit_test.go       2014-10-30 
13:44:46.000000000 +0000
@@ -53,7 +53,7 @@
        if err != nil {
                t.Fatal(err)
        }
-       store, err := NewTagStore(path.Join(root, "tags"), graph, nil)
+       store, err := NewTagStore(path.Join(root, "tags"), graph, nil, nil)
        if err != nil {
                t.Fatal(err)
        }
diff -Nru docker.io-1.3.0~dfsg1/hack/release.sh 
docker.io-1.3.1~dfsg1/hack/release.sh
--- docker.io-1.3.0~dfsg1/hack/release.sh       2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/hack/release.sh       2014-10-30 13:44:46.000000000 
+0000
@@ -270,7 +270,7 @@
        done
 
        # Upload keys
-       s3cmd sync /.gnupg/ s3://$BUCKET/ubuntu/.gnupg/
+       s3cmd sync $HOME/.gnupg/ s3://$BUCKET/ubuntu/.gnupg/
        gpg --armor --export releasedocker > bundles/$VERSION/ubuntu/gpg
        s3cmd --acl-public put bundles/$VERSION/ubuntu/gpg s3://$BUCKET/gpg
 
@@ -355,8 +355,8 @@
 
 setup_gpg() {
        # Make sure that we have our keys
-       mkdir -p /.gnupg/
-       s3cmd sync s3://$BUCKET/ubuntu/.gnupg/ /.gnupg/ || true
+       mkdir -p $HOME/.gnupg/
+       s3cmd sync s3://$BUCKET/ubuntu/.gnupg/ $HOME/.gnupg/ || true
        gpg --list-keys releasedocker >/dev/null || {
                gpg --gen-key --batch <<EOF
 Key-Type: RSA
diff -Nru docker.io-1.3.0~dfsg1/integration-cli/docker_cli_build_test.go 
docker.io-1.3.1~dfsg1/integration-cli/docker_cli_build_test.go
--- docker.io-1.3.0~dfsg1/integration-cli/docker_cli_build_test.go      
2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/integration-cli/docker_cli_build_test.go      
2014-10-30 13:44:46.000000000 +0000
@@ -2,6 +2,7 @@
 
 import (
        "archive/tar"
+       "encoding/json"
        "fmt"
        "io/ioutil"
        "os"
@@ -15,6 +16,396 @@
        "github.com/docker/docker/pkg/archive"
 )
 
+func TestBuildShCmdJSONEntrypoint(t *testing.T) {
+       name := "testbuildshcmdjsonentrypoint"
+       defer deleteImages(name)
+
+       _, err := buildImage(
+               name,
+               `
+    FROM busybox
+    ENTRYPOINT ["/bin/echo"]
+    CMD echo test
+    `,
+               true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       out, _, err := runCommandWithOutput(
+               exec.Command(
+                       dockerBinary,
+                       "run",
+                       name))
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if strings.TrimSpace(out) != "/bin/sh -c echo test" {
+               t.Fatal("CMD did not contain /bin/sh -c")
+       }
+
+       logDone("build - CMD should always contain /bin/sh -c when specified 
without JSON")
+}
+
+func TestBuildEnvironmentReplacementUser(t *testing.T) {
+       name := "testbuildenvironmentreplacement"
+       defer deleteImages(name)
+
+       _, err := buildImage(name, `
+  FROM scratch
+  ENV user foo
+  USER ${user}
+  `, true)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       res, err := inspectFieldJSON(name, "Config.User")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if res != `"foo"` {
+               t.Fatal("User foo from environment not in Config.User on image")
+       }
+
+       logDone("build - user environment replacement")
+}
+
+func TestBuildEnvironmentReplacementVolume(t *testing.T) {
+       name := "testbuildenvironmentreplacement"
+       defer deleteImages(name)
+
+       _, err := buildImage(name, `
+  FROM scratch
+  ENV volume /quux
+  VOLUME ${volume}
+  `, true)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       res, err := inspectFieldJSON(name, "Config.Volumes")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var volumes map[string]interface{}
+
+       if err := json.Unmarshal([]byte(res), &volumes); err != nil {
+               t.Fatal(err)
+       }
+
+       if _, ok := volumes["/quux"]; !ok {
+               t.Fatal("Volume /quux from environment not in Config.Volumes on 
image")
+       }
+
+       logDone("build - volume environment replacement")
+}
+
+func TestBuildEnvironmentReplacementExpose(t *testing.T) {
+       name := "testbuildenvironmentreplacement"
+       defer deleteImages(name)
+
+       _, err := buildImage(name, `
+  FROM scratch
+  ENV port 80
+  EXPOSE ${port}
+  `, true)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       res, err := inspectFieldJSON(name, "Config.ExposedPorts")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var exposedPorts map[string]interface{}
+
+       if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
+               t.Fatal(err)
+       }
+
+       if _, ok := exposedPorts["80/tcp"]; !ok {
+               t.Fatal("Exposed port 80 from environment not in 
Config.ExposedPorts on image")
+       }
+
+       logDone("build - expose environment replacement")
+}
+
+func TestBuildEnvironmentReplacementWorkdir(t *testing.T) {
+       name := "testbuildenvironmentreplacement"
+       defer deleteImages(name)
+
+       _, err := buildImage(name, `
+  FROM busybox
+  ENV MYWORKDIR /work
+  RUN mkdir ${MYWORKDIR}
+  WORKDIR ${MYWORKDIR}
+  `, true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       logDone("build - workdir environment replacement")
+}
+
+func TestBuildEnvironmentReplacementAddCopy(t *testing.T) {
+       name := "testbuildenvironmentreplacement"
+       defer deleteImages(name)
+
+       ctx, err := fakeContext(`
+  FROM scratch
+  ENV baz foo
+  ENV quux bar
+  ENV dot .
+
+  ADD ${baz} ${dot}
+  COPY ${quux} ${dot}
+  `,
+               map[string]string{
+                       "foo": "test1",
+                       "bar": "test2",
+               })
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if _, err := buildImageFromContext(name, ctx, true); err != nil {
+               t.Fatal(err)
+       }
+
+       logDone("build - add/copy environment replacement")
+}
+
+func TestBuildEnvironmentReplacementEnv(t *testing.T) {
+       name := "testbuildenvironmentreplacement"
+
+       defer deleteImages(name)
+
+       _, err := buildImage(name,
+               `
+  FROM scratch
+  ENV foo foo
+  ENV bar ${foo}
+  `, true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       res, err := inspectFieldJSON(name, "Config.Env")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       envResult := []string{}
+
+       if err = unmarshalJSON([]byte(res), &envResult); err != nil {
+               t.Fatal(err)
+       }
+
+       found := false
+
+       for _, env := range envResult {
+               parts := strings.SplitN(env, "=", 2)
+               if parts[0] == "bar" {
+                       found = true
+                       if parts[1] != "foo" {
+                               t.Fatal("Could not find replaced var for env 
`bar`: got %q instead of `foo`", parts[1])
+                       }
+               }
+       }
+
+       if !found {
+               t.Fatal("Never found the `bar` env variable")
+       }
+
+       logDone("build - env environment replacement")
+}
+
+func TestBuildHandleEscapes(t *testing.T) {
+       name := "testbuildhandleescapes"
+
+       defer deleteImages(name)
+
+       _, err := buildImage(name,
+               `
+  FROM scratch
+  ENV FOO bar
+  VOLUME ${FOO}
+  `, true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var result map[string]map[string]struct{}
+
+       res, err := inspectFieldJSON(name, "Config.Volumes")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if err = unmarshalJSON([]byte(res), &result); err != nil {
+               t.Fatal(err)
+       }
+
+       if _, ok := result["bar"]; !ok {
+               t.Fatal("Could not find volume bar set from env foo in volumes 
table")
+       }
+
+       _, err = buildImage(name,
+               `
+  FROM scratch
+  ENV FOO bar
+  VOLUME \${FOO}
+  `, true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       res, err = inspectFieldJSON(name, "Config.Volumes")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if err = unmarshalJSON([]byte(res), &result); err != nil {
+               t.Fatal(err)
+       }
+
+       if _, ok := result["${FOO}"]; !ok {
+               t.Fatal("Could not find volume ${FOO} set from env foo in 
volumes table")
+       }
+
+       // this test in particular provides *7* backslashes and expects 6 to 
come back.
+       // Like above, the first escape is swallowed and the rest are treated as
+       // literals, this one is just less obvious because of all the character 
noise.
+
+       _, err = buildImage(name,
+               `
+  FROM scratch
+  ENV FOO bar
+  VOLUME \\\\\\\${FOO}
+  `, true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       res, err = inspectFieldJSON(name, "Config.Volumes")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if err = unmarshalJSON([]byte(res), &result); err != nil {
+               t.Fatal(err)
+       }
+
+       if _, ok := result[`\\\\\\${FOO}`]; !ok {
+               t.Fatal(`Could not find volume \\\\\\${FOO} set from env foo in 
volumes table`)
+       }
+
+       logDone("build - handle escapes")
+}
+
+func TestBuildOnBuildLowercase(t *testing.T) {
+       name := "testbuildonbuildlowercase"
+       name2 := "testbuildonbuildlowercase2"
+
+       defer deleteImages(name, name2)
+
+       _, err := buildImage(name,
+               `
+  FROM busybox
+  onbuild run echo quux
+  `, true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       _, out, err := buildImageWithOut(name2, fmt.Sprintf(`
+  FROM %s
+  `, name), true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if !strings.Contains(out, "quux") {
+               t.Fatalf("Did not receive the expected echo text, got %s", out)
+       }
+
+       if strings.Contains(out, "ONBUILD ONBUILD") {
+               t.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", 
out)
+       }
+
+       logDone("build - handle case-insensitive onbuild statement")
+}
+
+func TestBuildEnvEscapes(t *testing.T) {
+       name := "testbuildenvescapes"
+       defer deleteAllContainers()
+       defer deleteImages(name)
+       _, err := buildImage(name,
+               `
+    FROM busybox
+    ENV TEST foo
+    CMD echo \$
+    `,
+               true)
+
+       out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", 
"-t", name))
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if strings.TrimSpace(out) != "$" {
+               t.Fatalf("Env TEST was not overwritten with bar when foo was 
supplied to dockerfile: was %q", strings.TrimSpace(out))
+       }
+
+       logDone("build - env should handle \\$ properly")
+}
+
+func TestBuildEnvOverwrite(t *testing.T) {
+       name := "testbuildenvoverwrite"
+       defer deleteAllContainers()
+       defer deleteImages(name)
+
+       _, err := buildImage(name,
+               `
+    FROM busybox
+    ENV TEST foo
+    CMD echo ${TEST}
+    `,
+               true)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", 
"-e", "TEST=bar", "-t", name))
+
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if strings.TrimSpace(out) != "bar" {
+               t.Fatalf("Env TEST was not overwritten with bar when foo was 
supplied to dockerfile: was %q", strings.TrimSpace(out))
+       }
+
+       logDone("build - env should overwrite builder ENV during run")
+}
+
 func TestBuildOnBuildForbiddenMaintainerInSourceImage(t *testing.T) {
        name := "testbuildonbuildforbiddenmaintainerinsourceimage"
        defer deleteImages(name)
@@ -1272,6 +1663,49 @@
        logDone("build - expose")
 }
 
+func TestBuildEmptyEntrypointInheritance(t *testing.T) {
+       name := "testbuildentrypointinheritance"
+       name2 := "testbuildentrypointinheritance2"
+       defer deleteImages(name, name2)
+
+       _, err := buildImage(name,
+               `FROM busybox
+        ENTRYPOINT ["/bin/echo"]`,
+               true)
+       if err != nil {
+               t.Fatal(err)
+       }
+       res, err := inspectField(name, "Config.Entrypoint")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       expected := "[/bin/echo]"
+       if res != expected {
+               t.Fatalf("Entrypoint %s, expected %s", res, expected)
+       }
+
+       _, err = buildImage(name2,
+               fmt.Sprintf(`FROM %s
+        ENTRYPOINT []`, name),
+               true)
+       if err != nil {
+               t.Fatal(err)
+       }
+       res, err = inspectField(name2, "Config.Entrypoint")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       expected = "[]"
+
+       if res != expected {
+               t.Fatalf("Entrypoint %s, expected %s", res, expected)
+       }
+
+       logDone("build - empty entrypoint inheritance")
+}
+
 func TestBuildEmptyEntrypoint(t *testing.T) {
        name := "testbuildentrypoint"
        defer deleteImages(name)
@@ -2328,6 +2762,7 @@
        name := "testbuildenvusage"
        defer deleteImages(name)
        dockerfile := `FROM busybox
+ENV    HOME /root
 ENV    PATH $HOME/bin:$PATH
 ENV    PATH /tmp:$PATH
 RUN    [ "$PATH" = 
"/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]
diff -Nru docker.io-1.3.0~dfsg1/integration-cli/docker_cli_daemon_test.go 
docker.io-1.3.1~dfsg1/integration-cli/docker_cli_daemon_test.go
--- docker.io-1.3.0~dfsg1/integration-cli/docker_cli_daemon_test.go     
2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/integration-cli/docker_cli_daemon_test.go     
2014-10-30 13:44:46.000000000 +0000
@@ -82,3 +82,13 @@
 
        logDone("daemon - volume refs are restored")
 }
+
+func TestDaemonStartIptablesFalse(t *testing.T) {
+       d := NewDaemon(t)
+       if err := d.Start("--iptables=false"); err != nil {
+               t.Fatalf("we should have been able to start the daemon with 
passing iptables=false: %v", err)
+       }
+       d.Stop()
+
+       logDone("daemon - started daemon with iptables=false")
+}
diff -Nru docker.io-1.3.0~dfsg1/integration-cli/docker_cli_run_test.go 
docker.io-1.3.1~dfsg1/integration-cli/docker_cli_run_test.go
--- docker.io-1.3.0~dfsg1/integration-cli/docker_cli_run_test.go        
2014-10-15 19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/integration-cli/docker_cli_run_test.go        
2014-10-30 13:44:46.000000000 +0000
@@ -2,6 +2,7 @@
 
 import (
        "bufio"
+       "bytes"
        "fmt"
        "io/ioutil"
        "net"
@@ -2374,3 +2375,68 @@
 
        logDone("run - volumes not recreated on start")
 }
+
+func TestRunNoOutputFromPullInStdout(t *testing.T) {
+       defer deleteAllContainers()
+       // just run with unknown image
+       cmd := exec.Command(dockerBinary, "run", "asdfsg")
+       stdout := bytes.NewBuffer(nil)
+       cmd.Stdout = stdout
+       if err := cmd.Run(); err == nil {
+               t.Fatal("Run with unknown image should fail")
+       }
+       if stdout.Len() != 0 {
+               t.Fatalf("Stdout contains output from pull: %s", stdout)
+       }
+       logDone("run - no output from pull in stdout")
+}
+
+func TestRunVolumesCleanPaths(t *testing.T) {
+       defer deleteAllContainers()
+
+       if _, err := buildImage("run_volumes_clean_paths",
+               `FROM busybox
+                VOLUME /foo/`,
+               true); err != nil {
+               t.Fatal(err)
+       }
+       defer deleteImages("run_volumes_clean_paths")
+
+       cmd := exec.Command(dockerBinary, "run", "-v", "/foo", "-v", "/bar/", 
"--name", "dark_helmet", "run_volumes_clean_paths")
+       if out, _, err := runCommandWithOutput(cmd); err != nil {
+               t.Fatal(err, out)
+       }
+
+       out, err := inspectFieldMap("dark_helmet", "Volumes", "/foo/")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if out != "<no value>" {
+               t.Fatalf("Found unexpected volume entry for '/foo/' in 
volumes\n%q", out)
+       }
+
+       out, err = inspectFieldMap("dark_helmet", "Volumes", "/foo")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if !strings.Contains(out, volumesStoragePath) {
+               t.Fatalf("Volume was not defined for /foo\n%q", out)
+       }
+
+       out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar/")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if out != "<no value>" {
+               t.Fatalf("Found unexpected volume entry for '/bar/' in 
volumes\n%q", out)
+       }
+       out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if !strings.Contains(out, volumesStoragePath) {
+               t.Fatalf("Volume was not defined for /bar\n%q", out)
+       }
+
+       logDone("run - volume paths are cleaned")
+}
diff -Nru docker.io-1.3.0~dfsg1/integration-cli/docker_test_vars.go 
docker.io-1.3.1~dfsg1/integration-cli/docker_test_vars.go
--- docker.io-1.3.0~dfsg1/integration-cli/docker_test_vars.go   2014-10-15 
19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/integration-cli/docker_test_vars.go   2014-10-30 
13:44:46.000000000 +0000
@@ -16,8 +16,10 @@
        // the private registry to use for tests
        privateRegistryURL = "127.0.0.1:5000"
 
-       execDriverPath    = "/var/lib/docker/execdriver/native"
-       volumesConfigPath = "/var/lib/docker/volumes"
+       dockerBasePath     = "/var/lib/docker"
+       execDriverPath     = dockerBasePath + "/execdriver/native"
+       volumesConfigPath  = dockerBasePath + "/volumes"
+       volumesStoragePath = dockerBasePath + "/vfs/dir"
 
        workingDirectory string
 )
diff -Nru docker.io-1.3.0~dfsg1/integration-cli/docker_utils.go 
docker.io-1.3.1~dfsg1/integration-cli/docker_utils.go
--- docker.io-1.3.0~dfsg1/integration-cli/docker_utils.go       2014-10-15 
19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/integration-cli/docker_utils.go       2014-10-30 
13:44:46.000000000 +0000
@@ -507,6 +507,16 @@
        return strings.TrimSpace(out), nil
 }
 
+func inspectFieldMap(name, path, field string) (string, error) {
+       format := fmt.Sprintf("{{index .%s %q}}", path, field)
+       inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
+       out, exitCode, err := runCommandWithOutput(inspectCmd)
+       if err != nil || exitCode != 0 {
+               return "", fmt.Errorf("failed to inspect %s: %s", name, out)
+       }
+       return strings.TrimSpace(out), nil
+}
+
 func getIDByName(name string) (string, error) {
        return inspectField(name, "Id")
 }
diff -Nru docker.io-1.3.0~dfsg1/registry/endpoint.go 
docker.io-1.3.1~dfsg1/registry/endpoint.go
--- docker.io-1.3.0~dfsg1/registry/endpoint.go  2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/registry/endpoint.go  2014-10-30 13:44:46.000000000 
+0000
@@ -2,7 +2,6 @@
 
 import (
        "encoding/json"
-       "errors"
        "fmt"
        "io/ioutil"
        "net/http"
@@ -34,9 +33,9 @@
        return hostname, DefaultAPIVersion
 }
 
-func NewEndpoint(hostname string) (*Endpoint, error) {
+func NewEndpoint(hostname string, secure bool) (*Endpoint, error) {
        var (
-               endpoint        Endpoint
+               endpoint        = Endpoint{secure: secure}
                trimmedHostname string
                err             error
        )
@@ -49,14 +48,27 @@
                return nil, err
        }
 
+       // Try HTTPS ping to registry
        endpoint.URL.Scheme = "https"
        if _, err := endpoint.Ping(); err != nil {
-               log.Debugf("Registry %s does not work (%s), falling back to 
http", endpoint, err)
-               // TODO: Check if http fallback is enabled
+
+               //TODO: triggering highland build can be done there without 
"failing"
+
+               if secure {
+                       // If registry is secure and HTTPS failed, show user 
the error and tell them about `--insecure-registry`
+                       // in case that's what they need. DO NOT accept unknown 
CA certificates, and DO NOT fallback to HTTP.
+                       return nil, fmt.Errorf("Invalid registry endpoint %s: 
%v. If this private registry supports only HTTP or HTTPS with an unknown CA 
certificate, please add `--insecure-registry %s` to the daemon's arguments. In 
the case of HTTPS, if you have access to the registry's CA certificate, no need 
for the flag; simply place the CA certificate at 
/etc/docker/certs.d/%s/ca.crt", endpoint, err, endpoint.URL.Host, 
endpoint.URL.Host)
+               }
+
+               // If registry is insecure and HTTPS failed, fallback to HTTP.
+               log.Debugf("Error from registry %q marked as insecure: %v. 
Insecurely falling back to HTTP", endpoint, err)
                endpoint.URL.Scheme = "http"
-               if _, err = endpoint.Ping(); err != nil {
-                       return nil, errors.New("Invalid Registry endpoint: " + 
err.Error())
+               _, err2 := endpoint.Ping()
+               if err2 == nil {
+                       return &endpoint, nil
                }
+
+               return nil, fmt.Errorf("Invalid registry endpoint %q. HTTPS 
attempt: %v. HTTP attempt: %v", endpoint, err, err2)
        }
 
        return &endpoint, nil
@@ -65,6 +77,7 @@
 type Endpoint struct {
        URL     *url.URL
        Version APIVersion
+       secure  bool
 }
 
 // Get the formated URL for the root of this registry Endpoint
@@ -88,7 +101,7 @@
                return RegistryInfo{Standalone: false}, err
        }
 
-       resp, _, err := doRequest(req, nil, ConnectTimeout)
+       resp, _, err := doRequest(req, nil, ConnectTimeout, e.secure)
        if err != nil {
                return RegistryInfo{Standalone: false}, err
        }
@@ -127,3 +140,19 @@
        log.Debugf("RegistryInfo.Standalone: %t", info.Standalone)
        return info, nil
 }
+
+// IsSecure returns false if the provided hostname is part of the list of 
insecure registries.
+// Insecure registries accept HTTP and/or accept HTTPS with certificates from 
unknown CAs.
+func IsSecure(hostname string, insecureRegistries []string) bool {
+       if hostname == IndexServerAddress() {
+               return true
+       }
+
+       for _, h := range insecureRegistries {
+               if hostname == h {
+                       return false
+               }
+       }
+
+       return true
+}
diff -Nru docker.io-1.3.0~dfsg1/registry/registry.go 
docker.io-1.3.1~dfsg1/registry/registry.go
--- docker.io-1.3.0~dfsg1/registry/registry.go  2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/registry/registry.go  2014-10-30 13:44:46.000000000 
+0000
@@ -14,6 +14,7 @@
        "strings"
        "time"
 
+       "github.com/docker/docker/pkg/log"
        "github.com/docker/docker/utils"
 )
 
@@ -35,13 +36,21 @@
        ConnectTimeout
 )
 
-func newClient(jar http.CookieJar, roots *x509.CertPool, cert 
*tls.Certificate, timeout TimeoutType) *http.Client {
-       tlsConfig := tls.Config{RootCAs: roots}
+func newClient(jar http.CookieJar, roots *x509.CertPool, cert 
*tls.Certificate, timeout TimeoutType, secure bool) *http.Client {
+       tlsConfig := tls.Config{
+               RootCAs: roots,
+               // Avoid fallback to SSL protocols < TLS1.0
+               MinVersion: tls.VersionTLS10,
+       }
 
        if cert != nil {
                tlsConfig.Certificates = append(tlsConfig.Certificates, *cert)
        }
 
+       if !secure {
+               tlsConfig.InsecureSkipVerify = true
+       }
+
        httpTransport := &http.Transport{
                DisableKeepAlives: true,
                Proxy:             http.ProxyFromEnvironment,
@@ -78,69 +87,76 @@
        }
 }
 
-func doRequest(req *http.Request, jar http.CookieJar, timeout TimeoutType) 
(*http.Response, *http.Client, error) {
-       hasFile := func(files []os.FileInfo, name string) bool {
-               for _, f := range files {
-                       if f.Name() == name {
-                               return true
-                       }
-               }
-               return false
-       }
-
-       hostDir := path.Join("/etc/docker/certs.d", req.URL.Host)
-       fs, err := ioutil.ReadDir(hostDir)
-       if err != nil && !os.IsNotExist(err) {
-               return nil, nil, err
-       }
-
+func doRequest(req *http.Request, jar http.CookieJar, timeout TimeoutType, 
secure bool) (*http.Response, *http.Client, error) {
        var (
                pool  *x509.CertPool
                certs []*tls.Certificate
        )
 
-       for _, f := range fs {
-               if strings.HasSuffix(f.Name(), ".crt") {
-                       if pool == nil {
-                               pool = x509.NewCertPool()
-                       }
-                       data, err := ioutil.ReadFile(path.Join(hostDir, 
f.Name()))
-                       if err != nil {
-                               return nil, nil, err
-                       }
-                       pool.AppendCertsFromPEM(data)
+       if secure && req.URL.Scheme == "https" {
+               hasFile := func(files []os.FileInfo, name string) bool {
+                       for _, f := range files {
+                               if f.Name() == name {
+                                       return true
+                               }
+                       }
+                       return false
                }
-               if strings.HasSuffix(f.Name(), ".cert") {
-                       certName := f.Name()
-                       keyName := certName[:len(certName)-5] + ".key"
-                       if !hasFile(fs, keyName) {
-                               return nil, nil, fmt.Errorf("Missing key %s for 
certificate %s", keyName, certName)
-                       }
-                       cert, err := tls.LoadX509KeyPair(path.Join(hostDir, 
certName), path.Join(hostDir, keyName))
-                       if err != nil {
-                               return nil, nil, err
-                       }
-                       certs = append(certs, &cert)
+
+               hostDir := path.Join("/etc/docker/certs.d", req.URL.Host)
+               log.Debugf("hostDir: %s", hostDir)
+               fs, err := ioutil.ReadDir(hostDir)
+               if err != nil && !os.IsNotExist(err) {
+                       return nil, nil, err
                }
-               if strings.HasSuffix(f.Name(), ".key") {
-                       keyName := f.Name()
-                       certName := keyName[:len(keyName)-4] + ".cert"
-                       if !hasFile(fs, certName) {
-                               return nil, nil, fmt.Errorf("Missing 
certificate %s for key %s", certName, keyName)
+
+               for _, f := range fs {
+                       if strings.HasSuffix(f.Name(), ".crt") {
+                               if pool == nil {
+                                       pool = x509.NewCertPool()
+                               }
+                               log.Debugf("crt: %s", hostDir+"/"+f.Name())
+                               data, err := ioutil.ReadFile(path.Join(hostDir, 
f.Name()))
+                               if err != nil {
+                                       return nil, nil, err
+                               }
+                               pool.AppendCertsFromPEM(data)
+                       }
+                       if strings.HasSuffix(f.Name(), ".cert") {
+                               certName := f.Name()
+                               keyName := certName[:len(certName)-5] + ".key"
+                               log.Debugf("cert: %s", hostDir+"/"+f.Name())
+                               if !hasFile(fs, keyName) {
+                                       return nil, nil, fmt.Errorf("Missing 
key %s for certificate %s", keyName, certName)
+                               }
+                               cert, err := 
tls.LoadX509KeyPair(path.Join(hostDir, certName), path.Join(hostDir, keyName))
+                               if err != nil {
+                                       return nil, nil, err
+                               }
+                               certs = append(certs, &cert)
+                       }
+                       if strings.HasSuffix(f.Name(), ".key") {
+                               keyName := f.Name()
+                               certName := keyName[:len(keyName)-4] + ".cert"
+                               log.Debugf("key: %s", hostDir+"/"+f.Name())
+                               if !hasFile(fs, certName) {
+                                       return nil, nil, fmt.Errorf("Missing 
certificate %s for key %s", certName, keyName)
+                               }
                        }
                }
        }
 
        if len(certs) == 0 {
-               client := newClient(jar, pool, nil, timeout)
+               client := newClient(jar, pool, nil, timeout, secure)
                res, err := client.Do(req)
                if err != nil {
                        return nil, nil, err
                }
                return res, client, nil
        }
+
        for i, cert := range certs {
-               client := newClient(jar, pool, cert, timeout)
+               client := newClient(jar, pool, cert, timeout, secure)
                res, err := client.Do(req)
                // If this is the last cert, otherwise, continue to next cert 
if 403 or 5xx
                if i == len(certs)-1 || err == nil && res.StatusCode != 403 && 
res.StatusCode < 500 {
diff -Nru docker.io-1.3.0~dfsg1/registry/registry_test.go 
docker.io-1.3.1~dfsg1/registry/registry_test.go
--- docker.io-1.3.0~dfsg1/registry/registry_test.go     2014-10-15 
19:15:24.000000000 +0000
+++ docker.io-1.3.1~dfsg1/registry/registry_test.go     2014-10-30 
13:44:46.000000000 +0000
@@ -18,7 +18,7 @@
 
 func spawnTestRegistrySession(t *testing.T) *Session {
        authConfig := &AuthConfig{}
-       endpoint, err := NewEndpoint(makeURL("/v1/"))
+       endpoint, err := NewEndpoint(makeURL("/v1/"), false)
        if err != nil {
                t.Fatal(err)
        }
@@ -30,7 +30,7 @@
 }
 
 func TestPingRegistryEndpoint(t *testing.T) {
-       ep, err := NewEndpoint(makeURL("/v1/"))
+       ep, err := NewEndpoint(makeURL("/v1/"), false)
        if err != nil {
                t.Fatal(err)
        }
diff -Nru docker.io-1.3.0~dfsg1/registry/service.go 
docker.io-1.3.1~dfsg1/registry/service.go
--- docker.io-1.3.0~dfsg1/registry/service.go   2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/registry/service.go   2014-10-30 13:44:46.000000000 
+0000
@@ -13,12 +13,15 @@
 //  'pull': Download images from any registry (TODO)
 //  'push': Upload images to any registry (TODO)
 type Service struct {
+       insecureRegistries []string
 }
 
 // NewService returns a new instance of Service ready to be
 // installed no an engine.
-func NewService() *Service {
-       return &Service{}
+func NewService(insecureRegistries []string) *Service {
+       return &Service{
+               insecureRegistries: insecureRegistries,
+       }
 }
 
 // Install installs registry capabilities to eng.
@@ -32,15 +35,12 @@
 // and returns OK if authentication was sucessful.
 // It can be used to verify the validity of a client's credentials.
 func (s *Service) Auth(job *engine.Job) engine.Status {
-       var (
-               err        error
-               authConfig = &AuthConfig{}
-       )
+       var authConfig = new(AuthConfig)
 
        job.GetenvJson("authConfig", authConfig)
-       // TODO: this is only done here because auth and registry need to be 
merged into one pkg
+
        if addr := authConfig.ServerAddress; addr != "" && addr != 
IndexServerAddress() {
-               endpoint, err := NewEndpoint(addr)
+               endpoint, err := NewEndpoint(addr, IsSecure(addr, 
s.insecureRegistries))
                if err != nil {
                        return job.Error(err)
                }
@@ -49,11 +49,13 @@
                }
                authConfig.ServerAddress = endpoint.String()
        }
+
        status, err := Login(authConfig, HTTPRequestFactory(nil))
        if err != nil {
                return job.Error(err)
        }
        job.Printf("%s\n", status)
+
        return engine.StatusOK
 }
 
@@ -89,7 +91,10 @@
        if err != nil {
                return job.Error(err)
        }
-       endpoint, err := NewEndpoint(hostname)
+
+       secure := IsSecure(hostname, s.insecureRegistries)
+
+       endpoint, err := NewEndpoint(hostname, secure)
        if err != nil {
                return job.Error(err)
        }
diff -Nru docker.io-1.3.0~dfsg1/registry/session.go 
docker.io-1.3.1~dfsg1/registry/session.go
--- docker.io-1.3.0~dfsg1/registry/session.go   2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/registry/session.go   2014-10-30 13:44:46.000000000 
+0000
@@ -64,7 +64,7 @@
 }
 
 func (r *Session) doRequest(req *http.Request) (*http.Response, *http.Client, 
error) {
-       return doRequest(req, r.jar, r.timeout)
+       return doRequest(req, r.jar, r.timeout, r.indexEndpoint.secure)
 }
 
 // Retrieve the history of a given image from the Registry.
diff -Nru docker.io-1.3.0~dfsg1/runconfig/merge.go 
docker.io-1.3.1~dfsg1/runconfig/merge.go
--- docker.io-1.3.0~dfsg1/runconfig/merge.go    2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/runconfig/merge.go    2014-10-30 13:44:46.000000000 
+0000
@@ -88,7 +88,10 @@
                if len(userConf.Cmd) == 0 {
                        userConf.Cmd = imageConf.Cmd
                }
-               userConf.Entrypoint = imageConf.Entrypoint
+
+               if userConf.Entrypoint == nil {
+                       userConf.Entrypoint = imageConf.Entrypoint
+               }
        }
        if userConf.WorkingDir == "" {
                userConf.WorkingDir = imageConf.WorkingDir
diff -Nru docker.io-1.3.0~dfsg1/volumes/repository.go 
docker.io-1.3.1~dfsg1/volumes/repository.go
--- docker.io-1.3.0~dfsg1/volumes/repository.go 2014-10-15 19:15:24.000000000 
+0000
+++ docker.io-1.3.1~dfsg1/volumes/repository.go 2014-10-30 13:44:46.000000000 
+0000
@@ -55,6 +55,7 @@
                        return nil, err
                }
        }
+       path = filepath.Clean(path)
 
        path, err = filepath.EvalSymlinks(path)
        if err != nil {
@@ -126,7 +127,7 @@
        if err != nil {
                return nil
        }
-       return r.volumes[path]
+       return r.volumes[filepath.Clean(path)]
 }
 
 func (r *Repository) Add(volume *Volume) error {
@@ -160,7 +161,7 @@
        if err != nil {
                return err
        }
-       volume := r.get(path)
+       volume := r.get(filepath.Clean(path))
        if volume == nil {
                return fmt.Errorf("Volume %s does not exist", path)
        }

Reply via email to