add option to specify custom user template path
This commit is contained in:
parent
05d7462a79
commit
fa9022ee1b
3 changed files with 320 additions and 282 deletions
24
.editorconfig
Normal file
24
.editorconfig
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
; https://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.md]
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
eclint_indent_style = unset
|
||||
|
||||
[Dockerfile]
|
||||
indent_size = 4
|
|
@ -94,6 +94,9 @@ Flags:
|
|||
path to easyrsa index file.
|
||||
--ccd Enable client-config-dir.
|
||||
--ccd.path="./ccd" path to client-config-dir
|
||||
--templates.clientconfig-path=""
|
||||
path to custom client.config.tpl file
|
||||
--templates.ccd-path="" path to custom ccd.tpl file
|
||||
--auth.password Enable additional password authorization.
|
||||
--auth.db="./easyrsa/pki/users.db"
|
||||
Database path fort password authorization.
|
||||
|
|
133
main.go
133
main.go
|
@ -5,9 +5,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -19,6 +16,10 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -32,26 +33,28 @@ const (
|
|||
indexTxtDateLayout = "060102150405Z"
|
||||
stringDateFormat = "2006-01-02 15:04:05"
|
||||
ovpnStatusDateLayout = "2006-01-02 15:04:05"
|
||||
version = "1.6.2"
|
||||
version = "1.6.3"
|
||||
)
|
||||
|
||||
var (
|
||||
listenHost = kingpin.Flag("listen.host","host for ovpn-admin").Default("0.0.0.0").String()
|
||||
listenPort = kingpin.Flag("listen.port","port for ovpn-admin").Default("8080").String()
|
||||
serverRole = kingpin.Flag("role","server role master or slave").Default("master").HintOptions("master", "slave").String()
|
||||
masterHost = kingpin.Flag("master.host","url for master server").Default("http://127.0.0.1").String()
|
||||
masterBasicAuthUser = kingpin.Flag("master.basic-auth.user","user for basic auth on master server url").Default("").String()
|
||||
masterBasicAuthPassword = kingpin.Flag("master.basic-auth.password","password for basic auth on master server url").Default("").String()
|
||||
listenHost = kingpin.Flag("listen.host", "host for ovpn-admin").Default("0.0.0.0").String()
|
||||
listenPort = kingpin.Flag("listen.port", "port for ovpn-admin").Default("8080").String()
|
||||
serverRole = kingpin.Flag("role", "server role master or slave").Default("master").HintOptions("master", "slave").String()
|
||||
masterHost = kingpin.Flag("master.host", "url for master server").Default("http://127.0.0.1").String()
|
||||
masterBasicAuthUser = kingpin.Flag("master.basic-auth.user", "user for basic auth on master server url").Default("").String()
|
||||
masterBasicAuthPassword = kingpin.Flag("master.basic-auth.password", "password for basic auth on master server url").Default("").String()
|
||||
masterSyncFrequency = kingpin.Flag("master.sync-frequency", "master host data sync frequency in seconds.").Default("600").Int()
|
||||
masterSyncToken = kingpin.Flag("master.sync-token", "master host data sync security token").Default("VerySecureToken").PlaceHolder("TOKEN").String()
|
||||
openvpnNetwork = kingpin.Flag("ovpn.network","network for openvpn server").Default("172.16.100.0/24").String()
|
||||
openvpnServer = kingpin.Flag("ovpn.server","comma separated addresses for openvpn servers").Default("127.0.0.1:7777:tcp").PlaceHolder("HOST:PORT:PROTOCOL").Strings()
|
||||
mgmtAddress = kingpin.Flag("mgmt","comma separated (alias=address) for openvpn servers mgmt interfaces").Default("main=127.0.0.1:8989").Strings()
|
||||
openvpnNetwork = kingpin.Flag("ovpn.network", "network for openvpn server").Default("172.16.100.0/24").String()
|
||||
openvpnServer = kingpin.Flag("ovpn.server", "comma separated addresses for openvpn servers").Default("127.0.0.1:7777:tcp").PlaceHolder("HOST:PORT:PROTOCOL").Strings()
|
||||
mgmtAddress = kingpin.Flag("mgmt", "comma separated (alias=address) for openvpn servers mgmt interfaces").Default("main=127.0.0.1:8989").Strings()
|
||||
metricsPath = kingpin.Flag("metrics.path", "URL path for surfacing collected metrics").Default("/metrics").String()
|
||||
easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("./easyrsa/").String()
|
||||
indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file.").Default("./easyrsa/pki/index.txt").String()
|
||||
ccdEnabled = kingpin.Flag("ccd", "Enable client-config-dir.").Default("false").Bool()
|
||||
ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").String()
|
||||
clientConfigTemplatePath = kingpin.Flag("templates.clientconfig-path", "path to custom client.conf.tpl").Default("").String()
|
||||
ccdTemplatePath = kingpin.Flag("templates.ccd-path", "path to custom ccd.tpl").Default("").String()
|
||||
authByPassword = kingpin.Flag("auth.password", "Enable additional password authorization.").Default("false").Bool()
|
||||
authDatabase = kingpin.Flag("auth.db", "Database path fort password authorization.").Default("./easyrsa/pki/users.db").String()
|
||||
debug = kingpin.Flag("debug", "Enable debug mode.").Default("false").Bool()
|
||||
|
@ -59,11 +62,9 @@ var (
|
|||
|
||||
certsArchivePath = "/tmp/" + certsArchiveFileName
|
||||
ccdArchivePath = "/tmp/" + ccdArchiveFileName
|
||||
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
ovpnServerCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "ovpn_server_cert_expire",
|
||||
Help: "openvpn server certificate expire time in days",
|
||||
|
@ -134,7 +135,6 @@ var (
|
|||
},
|
||||
[]string{"client"},
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
type OvpnAdmin struct {
|
||||
|
@ -271,7 +271,7 @@ func (oAdmin *OvpnAdmin) userChangePasswordHandler(w http.ResponseWriter, r *htt
|
|||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, `{"status":"error"}`, http.StatusNotImplemented )
|
||||
http.Error(w, `{"status":"error"}`, http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ func (oAdmin *OvpnAdmin) userShowConfigHandler(w http.ResponseWriter, r *http.Re
|
|||
|
||||
func (oAdmin *OvpnAdmin) userDisconnectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
// fmt.Fprintf(w, "%s", userDisconnect(r.FormValue("username")))
|
||||
// fmt.Fprintf(w, "%s", userDisconnect(r.FormValue("username")))
|
||||
fmt.Fprintf(w, "%s", r.FormValue("username"))
|
||||
}
|
||||
|
||||
|
@ -323,7 +323,7 @@ func (oAdmin *OvpnAdmin) userApplyCcdHandler(w http.ResponseWriter, r *http.Requ
|
|||
func (oAdmin *OvpnAdmin) serverSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
enabledModules, enabledModulesErr := json.Marshal(oAdmin.modules)
|
||||
if enabledModulesErr != nil {
|
||||
log.Printf("ERROR: %s\n",enabledModulesErr)
|
||||
log.Printf("ERROR: %s\n", enabledModulesErr)
|
||||
}
|
||||
fmt.Fprintf(w, `{"status":"ok", "serverRole": "%s", "modules": %s }`, oAdmin.role, string(enabledModules))
|
||||
}
|
||||
|
@ -350,8 +350,8 @@ func (oAdmin *OvpnAdmin) downloadCertsHandler(w http.ResponseWriter, r *http.Req
|
|||
}
|
||||
|
||||
archiveCerts()
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=" + certsArchiveFileName)
|
||||
http.ServeFile(w,r, certsArchivePath)
|
||||
w.Header().Set("Content-Disposition", "attachment; filename="+certsArchiveFileName)
|
||||
http.ServeFile(w, r, certsArchivePath)
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) downloadCcdHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -368,15 +368,14 @@ func (oAdmin *OvpnAdmin) downloadCcdHandler(w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
archiveCcd()
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=" + ccdArchiveFileName)
|
||||
http.ServeFile(w,r, ccdArchivePath)
|
||||
w.Header().Set("Content-Disposition", "attachment; filename="+ccdArchiveFileName)
|
||||
http.ServeFile(w, r, ccdArchivePath)
|
||||
}
|
||||
|
||||
func main() {
|
||||
kingpin.Version(version)
|
||||
kingpin.Parse()
|
||||
|
||||
|
||||
ovpnAdmin := new(OvpnAdmin)
|
||||
ovpnAdmin.lastSyncTime = "unknown"
|
||||
ovpnAdmin.role = *serverRole
|
||||
|
@ -388,7 +387,7 @@ func main() {
|
|||
ovpnAdmin.mgmtInterfaces = make(map[string]string)
|
||||
|
||||
for _, mgmtInterface := range *mgmtAddress {
|
||||
parts := strings.SplitN(mgmtInterface, "=",2)
|
||||
parts := strings.SplitN(mgmtInterface, "=", 2)
|
||||
ovpnAdmin.mgmtInterfaces[parts[0]] = parts[len(parts)-1]
|
||||
}
|
||||
|
||||
|
@ -447,7 +446,7 @@ func main() {
|
|||
})
|
||||
|
||||
fmt.Println("Bind: http://" + *listenHost + ":" + *listenPort)
|
||||
log.Fatal(http.ListenAndServe(*listenHost + ":" + *listenPort, nil))
|
||||
log.Fatal(http.ListenAndServe(*listenHost+":"+*listenPort, nil))
|
||||
}
|
||||
|
||||
func CacheControlWrapper(h http.Handler) http.Handler {
|
||||
|
@ -524,16 +523,28 @@ func renderIndexTxt(data []indexTxtLine) string {
|
|||
return indexTxt
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) getClientConfigTemplate() *template.Template {
|
||||
if *clientConfigTemplatePath != "" {
|
||||
return template.Must(template.ParseFiles(*clientConfigTemplatePath))
|
||||
} else {
|
||||
clientConfigTpl, clientConfigTplErr := oAdmin.templates.FindString("client.conf.tpl")
|
||||
if clientConfigTplErr != nil {
|
||||
log.Println("ERROR: clientConfigTpl not found in templates box")
|
||||
}
|
||||
return template.Must(template.New("client-config").Parse(clientConfigTpl))
|
||||
}
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
||||
if checkUserExist(username) {
|
||||
var hosts []OpenvpnServer
|
||||
|
||||
for _, server := range *openvpnServer {
|
||||
parts := strings.SplitN(server, ":",3)
|
||||
parts := strings.SplitN(server, ":", 3)
|
||||
hosts = append(hosts, OpenvpnServer{Host: parts[0], Port: parts[1], Protocol: parts[2]})
|
||||
}
|
||||
if *debug {
|
||||
log.Printf("WARNING: hosts for %s\n %v", username, hosts )
|
||||
log.Printf("WARNING: hosts for %s\n %v", username, hosts)
|
||||
}
|
||||
|
||||
conf := openvpnClientConfig{}
|
||||
|
@ -544,18 +555,14 @@ func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
|||
conf.TLS = fRead(*easyrsaDirPath + "/pki/ta.key")
|
||||
conf.PasswdAuth = *authByPassword
|
||||
|
||||
clientConfigTpl, clientConfigTplErr := oAdmin.templates.FindString("client.conf.tpl")
|
||||
if clientConfigTplErr != nil {
|
||||
log.Println("ERROR: clientConfigTpl not found in templates box")
|
||||
}
|
||||
t := oAdmin.getClientConfigTemplate()
|
||||
|
||||
t := template.Must(template.New("client-config").Parse(clientConfigTpl))
|
||||
var tmp bytes.Buffer
|
||||
err := t.Execute(&tmp, conf)
|
||||
if err != nil {
|
||||
log.Printf("WARNING: something goes wrong during rendering config for %s", username )
|
||||
log.Printf("WARNING: something goes wrong during rendering config for %s", username)
|
||||
if *debug {
|
||||
log.Printf("ERROR: rendering config for %s failed \n %v", username, err )
|
||||
log.Printf("ERROR: rendering config for %s failed \n %v", username, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,13 +575,25 @@ func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
|||
return fmt.Sprintf("User \"%s\" not found", username)
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) getCcdTemplate() *template.Template {
|
||||
if *ccdTemplatePath != "" {
|
||||
return template.Must(template.ParseFiles(*ccdTemplatePath))
|
||||
} else {
|
||||
ccdTpl, ccdTplErr := oAdmin.templates.FindString("ccd.tpl")
|
||||
if ccdTplErr != nil {
|
||||
log.Printf("ERROR: ccdTpl not found in templates box")
|
||||
}
|
||||
return template.Must(template.New("ccd").Parse(ccdTpl))
|
||||
}
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) parseCcd(username string) Ccd {
|
||||
ccd := Ccd{}
|
||||
ccd.User = username
|
||||
ccd.ClientAddress = "dynamic"
|
||||
ccd.CustomRoutes = []ccdRoute{}
|
||||
|
||||
txtLinesArray := strings.Split(fRead(*ccdDir + "/" + username), "\n")
|
||||
txtLinesArray := strings.Split(fRead(*ccdDir+"/"+username), "\n")
|
||||
|
||||
for _, v := range txtLinesArray {
|
||||
str := strings.Fields(v)
|
||||
|
@ -601,20 +620,13 @@ func (oAdmin *OvpnAdmin) modifyCcd(ccd Ccd) (bool, string) {
|
|||
}
|
||||
|
||||
if ccdValid {
|
||||
ccdTpl, ccdTplErr := oAdmin.templates.FindString("ccd.tpl")
|
||||
if ccdTplErr != nil {
|
||||
ccdErr = "ccdTpl not found in templates box"
|
||||
log.Printf("ERROR: %s\n",ccdErr)
|
||||
return false, ccdErr
|
||||
}
|
||||
|
||||
t := template.Must(template.New("ccd").Parse(ccdTpl))
|
||||
t := oAdmin.getCcdTemplate()
|
||||
var tmp bytes.Buffer
|
||||
tplErr := t.Execute(&tmp, ccd)
|
||||
if tplErr != nil {
|
||||
log.Println(tplErr)
|
||||
}
|
||||
fWrite(*ccdDir + "/" + ccd.User, tmp.String())
|
||||
fWrite(*ccdDir+"/"+ccd.User, tmp.String())
|
||||
return true, "ccd updated successfully"
|
||||
}
|
||||
}
|
||||
|
@ -631,7 +643,7 @@ func validateCcd(ccd Ccd) (bool, string) {
|
|||
log.Println(err)
|
||||
}
|
||||
|
||||
if ! checkStaticAddressIsFree(ccd.ClientAddress, ccd.User) {
|
||||
if !checkStaticAddressIsFree(ccd.ClientAddress, ccd.User) {
|
||||
ccdErr = fmt.Sprintf("ClientAddress \"%s\" already assigned to another user", ccd.ClientAddress)
|
||||
if *debug {
|
||||
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
||||
|
@ -647,7 +659,7 @@ func validateCcd(ccd Ccd) (bool, string) {
|
|||
return false, ccdErr
|
||||
}
|
||||
|
||||
if ! ovpnNet.Contains(net.ParseIP(ccd.ClientAddress)) {
|
||||
if !ovpnNet.Contains(net.ParseIP(ccd.ClientAddress)) {
|
||||
ccdErr = fmt.Sprintf("ClientAddress \"%s\" not belongs to openvpn server network", ccd.ClientAddress)
|
||||
if *debug {
|
||||
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
||||
|
@ -791,7 +803,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (bool, string) {
|
|||
return false, ucErr
|
||||
}
|
||||
|
||||
if ! validateUsername(username) {
|
||||
if !validateUsername(username) {
|
||||
ucErr = fmt.Sprintf("Username \"%s\" incorrect, you can use only %s\n", username, usernameRegexp)
|
||||
if *debug {
|
||||
log.Printf("ERROR: userCreate: %s", ucErr)
|
||||
|
@ -832,7 +844,7 @@ func (oAdmin *OvpnAdmin) userChangePassword(username, password string) (bool, st
|
|||
o := runBash(fmt.Sprintf("openvpn-user check --db.path %s --user %s | grep %s | wc -l", *authDatabase, username, username))
|
||||
fmt.Println(o)
|
||||
|
||||
if ! validatePassword(password) {
|
||||
if !validatePassword(password) {
|
||||
ucpErr := fmt.Sprintf("Password for too short, password length must be greater or equal %d", passwordMinLength)
|
||||
if *debug {
|
||||
log.Printf("ERROR: userChangePassword: %s\n", ucpErr)
|
||||
|
@ -924,7 +936,6 @@ func (oAdmin *OvpnAdmin) userUnrevoke(username string) string {
|
|||
return fmt.Sprintf("{\"msg\":\"User \"%s\" not found\"}", username)
|
||||
}
|
||||
|
||||
|
||||
func (oAdmin *OvpnAdmin) mgmtRead(conn net.Conn) string {
|
||||
buf := make([]byte, 32768)
|
||||
bufLen, _ := conn.Read(buf)
|
||||
|
@ -960,8 +971,8 @@ func (oAdmin *OvpnAdmin) mgmtConnectedUsersParser(text, serverName string) []cli
|
|||
|
||||
userName := user[0]
|
||||
userAddress := user[1]
|
||||
userBytesReceived:= user[2]
|
||||
userBytesSent:= user[3]
|
||||
userBytesReceived := user[2]
|
||||
userBytesSent := user[3]
|
||||
userConnectedSince := user[4]
|
||||
|
||||
userStatus := clientStatus{CommonName: userName, RealAddress: userAddress, BytesReceived: userBytesReceived, BytesSent: userBytesSent, ConnectedSince: userConnectedSince, ConnectedTo: serverName}
|
||||
|
@ -1029,7 +1040,7 @@ func (oAdmin *OvpnAdmin) downloadCerts() bool {
|
|||
if fExist(certsArchivePath) {
|
||||
fDelete(certsArchivePath)
|
||||
}
|
||||
err := fDownload(certsArchivePath, *masterHost + downloadCertsApiUrl + "?token=" + oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||
err := fDownload(certsArchivePath, *masterHost+downloadCertsApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
|
@ -1043,7 +1054,7 @@ func (oAdmin *OvpnAdmin) downloadCcd() bool {
|
|||
fDelete(ccdArchivePath)
|
||||
}
|
||||
|
||||
err := fDownload(ccdArchivePath, *masterHost + downloadCcdApiUrl + "?token=" + oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||
err := fDownload(ccdArchivePath, *masterHost+downloadCcdApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
|
@ -1053,24 +1064,24 @@ func (oAdmin *OvpnAdmin) downloadCcd() bool {
|
|||
}
|
||||
|
||||
func archiveCerts() {
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *easyrsaDirPath + "/pki", certsArchivePath ))
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *easyrsaDirPath+"/pki", certsArchivePath))
|
||||
fmt.Println(o)
|
||||
}
|
||||
|
||||
func archiveCcd() {
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *ccdDir, ccdArchivePath ))
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *ccdDir, ccdArchivePath))
|
||||
fmt.Println(o)
|
||||
}
|
||||
|
||||
func unArchiveCerts() {
|
||||
runBash(fmt.Sprintf("mkdir -p %s", *easyrsaDirPath + "/pki"))
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *easyrsaDirPath + "/pki", certsArchivePath ))
|
||||
runBash(fmt.Sprintf("mkdir -p %s", *easyrsaDirPath+"/pki"))
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *easyrsaDirPath+"/pki", certsArchivePath))
|
||||
fmt.Println(o)
|
||||
}
|
||||
|
||||
func unArchiveCcd() {
|
||||
runBash(fmt.Sprintf("mkdir -p %s", *ccdDir))
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *ccdDir, ccdArchivePath ))
|
||||
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *ccdDir, ccdArchivePath))
|
||||
fmt.Println(o)
|
||||
}
|
||||
|
||||
|
@ -1134,11 +1145,11 @@ func getOvpnCaCertExpireDate() time.Time {
|
|||
|
||||
// https://community.openvpn.net/openvpn/ticket/623
|
||||
func crlFix() {
|
||||
err1 := os.Chmod(*easyrsaDirPath + "/pki", 0755)
|
||||
err1 := os.Chmod(*easyrsaDirPath+"/pki", 0755)
|
||||
if err1 != nil {
|
||||
log.Println(err1)
|
||||
}
|
||||
err2 := os.Chmod(*easyrsaDirPath + "/pki/crl.pem", 0644)
|
||||
err2 := os.Chmod(*easyrsaDirPath+"/pki/crl.pem", 0644)
|
||||
if err2 != nil {
|
||||
log.Println(err2)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue