5
5
package main
6
6
7
7
import (
8
+ "bytes"
8
9
"log"
9
10
"os"
10
11
"os/exec"
@@ -83,8 +84,8 @@ func (m *mkcert) checkNSS() bool {
83
84
func (m * mkcert ) installNSS () bool {
84
85
if m .forEachNSSProfile (func (profile string ) {
85
86
cmd := exec .Command (certutilPath , "-A" , "-d" , profile , "-t" , "C,," , "-n" , m .caUniqueName (), "-i" , filepath .Join (m .CAROOT , rootName ))
86
- out , err := cmd . CombinedOutput ( )
87
- fatalIfCmdErr (err , "certutil -A" , out )
87
+ out , err := execCertutil ( cmd )
88
+ fatalIfCmdErr (err , "certutil -A -d " + profile , out )
88
89
}) == 0 {
89
90
log .Printf ("ERROR: no %s security databases found" , NSSBrowsers )
90
91
return false
@@ -104,11 +105,24 @@ func (m *mkcert) uninstallNSS() {
104
105
return
105
106
}
106
107
cmd := exec .Command (certutilPath , "-D" , "-d" , profile , "-n" , m .caUniqueName ())
107
- out , err := cmd . CombinedOutput ( )
108
- fatalIfCmdErr (err , "certutil -D" , out )
108
+ out , err := execCertutil ( cmd )
109
+ fatalIfCmdErr (err , "certutil -D -d " + profile , out )
109
110
})
110
111
}
111
112
113
+ // execCertutil will execute a "certutil" command and if needed re-execute
114
+ // the command with commandWithSudo to work around file permissions.
115
+ func execCertutil (cmd * exec.Cmd ) ([]byte , error ) {
116
+ out , err := cmd .CombinedOutput ()
117
+ if err != nil && bytes .Contains (out , []byte ("SEC_ERROR_READ_ONLY" )) && runtime .GOOS != "windows" {
118
+ origArgs := cmd .Args [1 :]
119
+ cmd = commandWithSudo (cmd .Path )
120
+ cmd .Args = append (cmd .Args , origArgs ... )
121
+ out , err = cmd .CombinedOutput ()
122
+ }
123
+ return out , err
124
+ }
125
+
112
126
func (m * mkcert ) forEachNSSProfile (f func (profile string )) (found int ) {
113
127
profiles , _ := filepath .Glob (FirefoxProfile )
114
128
profiles = append (profiles , nssDBs ... )
0 commit comments