github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/provider/azure/certfile.go (about) 1 package azure 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "math/rand" 7 "os" 8 "path" 9 10 "github.com/juju/errors" 11 ) 12 13 // tempCertFile is a temporary file containing an x509 certificate. 14 // It's possible to pass a certificate to libcurl in-memory, but much more 15 // complicated. We went with this hack for now. Call newTempCertFile to 16 // store a certificate in a temporary file, and once you're done with the 17 // file, invoke its Delete method to clean it up. 18 type tempCertFile struct { 19 tempDir string 20 filename string 21 } 22 23 // Path returns the full absolute path for the temporary certificate file. 24 func (certFile *tempCertFile) Path() string { 25 return path.Join(certFile.tempDir, certFile.filename) 26 } 27 28 // Delete cleans up a tempCertFile. You must call this after use, or you'll 29 // leave not just garbage but security-sensitive garbage. 30 // This method is idempotent. If called after it's already been run, it 31 // does nothing. 32 func (certFile *tempCertFile) Delete() { 33 if certFile.tempDir == "" { 34 // Either it wasn't constructed, or it's been deleted already. 35 return 36 } 37 err := os.RemoveAll(certFile.tempDir) 38 if err != nil { 39 panic(err) 40 } 41 // We no longer own a file that needs cleaning up. 42 certFile.filename = "" 43 certFile.tempDir = "" 44 } 45 46 // newTempCertFile stores the given x509 certificate in a temporary file, 47 // which only the current user will be allowed to access. 48 // You *must* clean up the file after use, by calling its Delete method. 49 func newTempCertFile(data []byte) (certFile *tempCertFile, err error) { 50 // Add context to any error we may return. 51 defer errors.Maskf(&err, "failed while writing temporary certificate file") 52 53 // Access permissions for these temporary files: 54 const ( 55 // Owner can read/write temporary files. Not backed up. 56 fileMode = 0600 | os.ModeTemporary | os.ModeExclusive 57 // Temporary dirs are like files, but owner also has "x" 58 // permission. 59 dirMode = fileMode | 0100 60 ) 61 62 certFile = &tempCertFile{} 63 64 // We'll randomize the file's name, so that even someone with access 65 // to the temporary directory (perhaps a group member sneaking in 66 // just before we close access to the directory) won't be able to 67 // guess its name and inject their own file. 68 certFile.filename = fmt.Sprintf("x509-%d.cert", rand.Int31()) 69 70 // To guarantee that nobody else will be able to access the file, even 71 // by predicting or guessing its name, we create the file in its own 72 // private directory. 73 certFile.tempDir, err = ioutil.TempDir("", "juju-azure") 74 if err != nil { 75 return nil, err 76 } 77 err = os.Chmod(certFile.tempDir, dirMode) 78 if err != nil { 79 return nil, err 80 } 81 82 // Now, at last, write the file. WriteFile could have done most of 83 // the work on its own, but it doesn't guarantee that nobody creates 84 // a file of the same name first. When that happens, you get a file 85 // but not with the requested permissions. 86 err = ioutil.WriteFile(certFile.Path(), data, fileMode) 87 if err != nil { 88 os.RemoveAll(certFile.tempDir) 89 return nil, err 90 } 91 92 return certFile, nil 93 }