// create a new KeyDB. func (ce *CryptEngine) dbCreate(homedir string, iterations int) error { keydbname := filepath.Join(homedir, "keys") // read passphrase log.Infof("read passphrase from fd %d", ce.fileTable.PassphraseFD) scanner := bufio.NewScanner(ce.fileTable.PassphraseFP) var passphrase []byte defer bzero.Bytes(passphrase) if scanner.Scan() { passphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } // read passphrase again log.Infof("read passphrase from fd %d again", ce.fileTable.PassphraseFD) var passphrase2 []byte defer bzero.Bytes(passphrase2) if scanner.Scan() { passphrase2 = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } // compare passphrases if !bytes.Equal(passphrase, passphrase2) { return log.Error("passphrases differ") } // create keyDB log.Infof("create keyDB '%s'", keydbname) if err := keydb.Create(keydbname, passphrase, iterations); err != nil { return err } return nil }
func (ce *CtrlEngine) openMsgDB( homedir string, ) error { // read passphrase, if necessary if ce.passphrase == nil { fmt.Fprintf(ce.fileTable.StatusFP, "read passphrase from fd %d (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read passphrase from fd %d (not echoed)", ce.fileTable.PassphraseFD) var err error ce.passphrase, err = util.Readline(ce.fileTable.PassphraseFP) if err != nil { return err } log.Info("done") } // open msgDB msgdbname := filepath.Join(homedir, "msgs") log.Infof("open msgDB %s", msgdbname) var err error ce.msgDB, err = msgdb.Open(msgdbname, ce.passphrase) if err != nil { return err } return nil }
// loop runs the crypt engine in a loop and reads commands from the file // descriptor command-fd. func (ce *CryptEngine) loop(c *cli.Context) { if len(c.Args()) > 0 { ce.err = fmt.Errorf("cryptengine: unknown command '%s', try 'help'", strings.Join(c.Args(), " ")) return } log.Info("cryptengine: starting") // run command(s) log.Infof("read commands from fd %d", ce.fileTable.CommandFD) scanner := bufio.NewScanner(ce.fileTable.CommandFP) for scanner.Scan() { args := []string{ce.app.Name} line := scanner.Text() if line == "" { log.Infof("read empty line") continue } log.Infof("read: %s", line) args = append(args, strings.Fields(line)...) if err := ce.app.Run(args); err != nil { // command execution failed -> issue status and continue log.Infof("command execution failed (app): %s", err) fmt.Fprintln(ce.fileTable.StatusFP, err) continue } if ce.err != nil { if ce.err == errExit { // exit requested -> return log.Info("cryptengine: stopping (exit requested)") fmt.Fprintln(ce.fileTable.StatusFP, "QUITTING") ce.err = nil return } // command execution failed -> issue status and continue log.Infof("command execution failed (cmd): %s", ce.err) fmt.Fprintln(ce.fileTable.StatusFP, ce.err) ce.err = nil } else { log.Info("command successful") } fmt.Fprintln(ce.fileTable.StatusFP, "READY.") } if err := scanner.Err(); err != nil { ce.err = log.Errorf("cryptengine: %s", err) } log.Info("cryptengine: stopping (error)") return }
func (ce *CryptEngine) openKeyDB() error { // read passphrase log.Infof("read passphrase from fd %d", ce.fileTable.PassphraseFD) passphrase, err := util.Readline(ce.fileTable.PassphraseFP) if err != nil { return err } defer bzero.Bytes(passphrase) log.Info("done") // open keyDB keydbname := filepath.Join(ce.homedir, "keys") log.Infof("open keyDB %s", keydbname) ce.keyDB, err = keydb.Open(keydbname, passphrase) if err != nil { return err } return nil }
func (ce *CtrlEngine) checkUpdates() error { commit := ce.config.Map["release.Commit"] log.Info("checkUpdates()") log.Infof("server: release.Commit: %s", commit) log.Infof("binary: release.Commit: %s", release.Commit) if release.Commit != commit { // parse release date tRelease, err := time.Parse(git.Date, ce.config.Map["release.Date"]) if err != nil { return err } // parse binary date tBinary, err := time.Parse(git.Date, release.Date) if err != nil { return err } // switch to UTC tRelease = tRelease.UTC() tBinary = tBinary.UTC() log.Infof("server: release.Date: %s", tRelease.Format(time.RFC3339)) log.Infof("binary: release.Date: %s", tBinary.Format(time.RFC3339)) // compare dates if !tBinary.Before(tRelease) { // binary is newer than release -> do nothing log.Info("binary is newer than release -> do nothing") } else if tBinary.Add(def.UpdateDuration).Before(tRelease) { // binary is totally outdated -> force update log.Info("binary is totally outdated -> force update") return log.Error("ctrlengine: software is outdated, you have to " + "update with `mutectrl upkeep update`") } else { // new version available -> inform user log.Info("new version available -> inform user") fmt.Fprintf(ce.fileTable.StatusFP, "ctrlengine: software "+ "available, please update with `mutectrl upkeep update`\n") } } return nil }
func (ce *CtrlEngine) upkeepFetchconf( msgDB *msgdb.MsgDB, homedir string, show bool, outfp, statfp io.Writer, ) error { netDomain, pubkeyStr, configURL := def.ConfigParams() log.Infof("fetch config for '%s'", netDomain) fmt.Fprintf(statfp, "fetch config for '%s'\n", netDomain) publicKey, err := hex.DecodeString(pubkeyStr) if err != nil { log.Error(err) } ce.config.PublicKey = publicKey ce.config.URLList = "10," + configURL ce.config.Timeout = 0 // use default timeout if err := ce.config.Update(); err != nil { return log.Error(err) } jsn, err := json.Marshal(ce.config) if err != nil { return log.Error(err) } if err := msgDB.AddValue(netDomain, string(jsn)); err != nil { return err } err = msgDB.AddValue("time."+netDomain, strconv.FormatInt(times.Now(), 10)) if err != nil { return err } // apply new configuration if err := def.InitMute(&ce.config); err != nil { return err } // format configuration nicely jsn, err = json.MarshalIndent(ce.config, "", " ") if err != nil { return log.Error(err) } // write new configuration file if err := writeConfigFile(homedir, netDomain, jsn); err != nil { return err } // show new configuration if show { fmt.Fprintf(outfp, string(jsn)+"\n") } return nil }
func (ce *CtrlEngine) uidActive( c *cli.Context, outputFD uintptr, outputFP io.Writer, ) error { active, err := ce.msgDB.GetValue(msgdb.ActiveUID) if err != nil { return err } if active == "" { return errors.New("ctrlengine: no active nym in DB") } log.Infof("write active nym to fd %d", outputFD) fmt.Fprintln(outputFP, active) return nil }
// generate a new nym and store it in keydb. func (ce *CryptEngine) generate( pseudonym string, keyserver bool, outputfp *os.File, ) error { // map pseudonym id, domain, err := identity.MapPlus(pseudonym) if err != nil { return err } // create new UID // TODO: allow different PFS preferences var lastEntry string if !keyserver { // no lastEntry, because this will be the first entry in hashchain lastEntry, err = ce.keyDB.GetLastHashChainEntry(domain) if err != nil { return err } } uid, err := uid.Create(id, false, "", "", uid.Strict, lastEntry, cipher.RandReader) if err != nil { return err } if !keyserver { // store UID in keyDB if err := ce.keyDB.AddPrivateUID(uid); err != nil { return err } } else { // a private key for the keyserver is not stored in the keyDB var out bytes.Buffer if err := json.Indent(&out, []byte(uid.JSON()), "", " "); err != nil { return err } fmt.Fprintln(outputfp, out.String()) if keyserver { fmt.Fprintf(outputfp, "{\"PRIVSIGKEY\": %q}\n", uid.PrivateSigKey()) } } log.Infof("nym '%s' generated successfully", id) return nil }
// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the // interruptChannel and invokes the registered interruptCallbacks accordingly. // It also listens for callback registration. It must be run as a goroutine. func mainInterruptHandler() { // interruptCallbacks is a list of callbacks to invoke when a // SIGINT (Ctrl+C) is received. var interruptCallbacks []func() for { select { case <-interruptChannel: log.Infof("received SIGINT (Ctrl+C). Shutting down...") for _, callback := range interruptCallbacks { callback() } // Signal the main goroutine to shutdown. ShutdownChannel <- nil case handler := <-addHandlerChannel: interruptCallbacks = append(interruptCallbacks, handler) } } }
func mutectrlMain() error { defer log.Flush() // create crypto engine ce := ctrlengine.New() defer ce.Close() // add interrupt handler interrupt.AddInterruptHandler(func() { log.Infof("gracefully shutting down...") ce.Close() }) // start crypto engine go func() { if err := ce.Start(os.Args); err != nil { interrupt.ShutdownChannel <- err return } interrupt.ShutdownChannel <- nil }() return <-interrupt.ShutdownChannel }
// loop runs the CtrlEngine in a loop and reads commands from the file // descriptor command-fd. // TODO: actually read from command-fd! func (ce *CtrlEngine) loop(c *cli.Context) { if len(c.Args()) > 0 { ce.err = fmt.Errorf("ctrlengine: unknown command '%s', try 'help'", strings.Join(c.Args(), " ")) return } log.Info("ctrlengine: starting") interactive = true // run command(s) line = liner.NewLiner() defer line.Close() line.SetCtrlCAborts(true) commands := buildCmdList(c.App.Commands, "") line.SetCompleter(func(line string) (c []string) { for _, command := range commands { if strings.HasPrefix(command, line) { c = append(c, command) } } return }) for { active, err := ce.msgDB.GetValue(msgdb.ActiveUID) if err != nil { util.Fatal(err) } if active == "" { active = "none" } fmt.Fprintf(ce.fileTable.StatusFP, "active user ID: %s\n", active) fmt.Fprintln(ce.fileTable.StatusFP, "READY.") ln, err := line.Prompt("") if err != nil { if err == liner.ErrPromptAborted { fmt.Fprintf(ce.fileTable.StatusFP, "aborting...\n") } log.Info("ctrlengine: stopping (error)") log.Error(err) return } line.AppendHistory(ln) args := []string{ce.app.Name} if ln == "" { log.Infof("read empty line") continue } log.Infof("read: %s", ln) // in the loop these global variables are reset, therefore we have to // pass them in again args = append(args, "--homedir", c.GlobalString("homedir"), "--logdir", c.GlobalString("logdir"), "--loglevel", c.GlobalString("loglevel"), ) args = append(args, strings.Fields(ln)...) if err := ce.app.Run(args); err != nil { // command execution failed -> issue status and continue log.Infof("command execution failed (app): %s", err) fmt.Fprintln(ce.fileTable.StatusFP, err) continue } if ce.err != nil { if ce.err == errExit { // exit requested -> return log.Info("ctrlengine: stopping (exit requested)") ce.err = nil return } // command execution failed -> issue status and continue fmt.Fprintln(ce.fileTable.StatusFP, ce.translateError(ce.err)) ce.err = nil } else { log.Info("command successful") } } }
func (ce *CtrlEngine) prepare( c *cli.Context, openMsgDB, checkUpdates bool, ) error { if !ce.prepared { // create the necessary directories if they don't already exist err := util.CreateDirs(c.GlobalString("homedir"), c.GlobalString("logdir")) if err != nil { return err } // initialize logging framework err = log.Init(c.GlobalString("loglevel"), "ctrl ", c.GlobalString("logdir"), c.GlobalBool("logconsole")) if err != nil { return err } // initialize file descriptors ce.fileTable, err = descriptors.NewTable(c) if err != nil { return err } ce.prepared = true } log.Infof("prepare(openMsgDB=%s)", strconv.FormatBool(openMsgDB)) // open MsgDB, if necessary if openMsgDB { homedir := c.GlobalString("homedir") offline := c.GlobalBool("offline") // open messsage DB, if necessary if ce.msgDB == nil { err := ce.openMsgDB(homedir) if err != nil { return err } } // get config if err := ce.getConfig(homedir, offline); err != nil { return err } // check for updates, if necessary if checkUpdates { if err := ce.checkUpdates(); err != nil { return err } } // start wallet var err error ce.client, err = startWallet(ce.msgDB, offline) if err != nil { return err } } return nil }
// create a new MsgDB and KeyDB. func (ce *CtrlEngine) dbCreate( w, statusfp io.Writer, homedir string, c *cli.Context, ) error { msgdbname := filepath.Join(c.GlobalString("homedir"), "msgs") // read passphrase fmt.Fprintf(statusfp, "read passphrase from fd %d (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read passphrase from fd %d (not echoed)", ce.fileTable.PassphraseFD) var ( scanner *bufio.Scanner passphrase []byte passphrase2 []byte err error ) defer bzero.Bytes(passphrase) defer bzero.Bytes(passphrase2) isTerminal := terminal.IsTerminal(int(ce.fileTable.PassphraseFD)) if isTerminal { passphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { scanner = bufio.NewScanner(ce.fileTable.PassphraseFP) if scanner.Scan() { passphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // read passphrase again fmt.Fprintf(statusfp, "read passphrase from fd %d again (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read passphrase from fd %d again (not echoed)", ce.fileTable.PassphraseFD) if isTerminal { passphrase2, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { if scanner.Scan() { passphrase2 = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // compare passphrases if !bytes.Equal(passphrase, passphrase2) { return log.Error(ErrPassphrasesDiffer) } // create msgDB log.Infof("create msgDB '%s'", msgdbname) if err := msgdb.Create(msgdbname, passphrase, c.Int("iterations")); err != nil { return err } // open msgDB msgDB, err := msgdb.Open(msgdbname, passphrase) if err != nil { return err } defer msgDB.Close() // configure to make sure mutecrypt has config file err = ce.upkeepFetchconf(msgDB, homedir, false, nil, statusfp) if err != nil { return err } // create keyDB log.Info("create keyDB") if err := createKeyDB(c, w, ce.fileTable.OutputFD, passphrase); err != nil { return err } // status fmt.Fprintf(statusfp, "database files created\n") log.Info("database files created") // determine private walletKey walletKey := c.String("walletkey") if walletKey == "" { // generate wallet key _, privateKey, err := ed25519.GenerateKey(cipher.RandReader) if err != nil { return err } walletKey = base64.Encode(privateKey[:]) } // store wallet key if err := msgDB.AddValue(msgdb.WalletKey, walletKey); err != nil { return err } // print wallet key if err := printWalletKey(w, walletKey); err != nil { return err } return nil }
func (ce *CryptEngine) registerOrUpdate( pseudonym, token, command, verb string, ) error { // map pseudonym id, domain, err := identity.MapPlus(pseudonym) if err != nil { return err } // TODO: check token? // get UID from keyDB msg, messageReply, err := ce.keyDB.GetPrivateUID(id, false) if err != nil { return err } if messageReply != nil { return log.Errorf("cryptengine: UID has already been %s", verb) } // get JSON-RPC client and capabilities client, caps, err := ce.cache.Get(domain, ce.keydPort, ce.keydHost, ce.homedir, "KeyRepository."+command) if err != nil { return err } // register/update UID with key server content := make(map[string]interface{}) content["UIDMessage"] = msg content["Token"] = token reply, err := client.JSONRPCRequest("KeyRepository."+command, content) if err != nil { return err } rep, ok := reply["UIDMessageReply"].(map[string]interface{}) if !ok { return log.Errorf("cryptengine: %s reply has the wrong type", command) } // marshal the unstructured UIDMessageReply into a JSON byte array jsn, err := json.Marshal(rep) if err != nil { return err } // unmarshal the JSON byte array back into a UIDMessageReply msgReply, err := uid.NewJSONReply(string(jsn)) if err != nil { return err } // store reply first to have proof, if the key server is cheating if err := ce.keyDB.AddPrivateUIDReply(msg, msgReply); err != nil { return err } // verify reply // TODO: keyserver can return more than one SIGPUBKEY if err := msgReply.VerifySrvSig(msg, caps.SIGPUBKEYS[0]); err != nil { return err } log.Infof("nym '%s' %s successfully", id, verb) return nil }
func (pe *ProtoEngine) fetch( output io.Writer, status io.Writer, server string, lastMessageTime int64, command io.Reader, ) error { // read passphrase log.Infof("read private key from fd %d", pe.fileTable.PassphraseFD) pks, err := util.Readline(pe.fileTable.PassphraseFP) if err != nil { return err } log.Info("done") pk, err := base64.Decode(string(pks)) if err != nil { return log.Error(err) } var privkey [ed25519.PrivateKeySize]byte copy(privkey[:], pk) log.Debugf("lastMessageTime=%d", lastMessageTime) messages, err := client.ListMessages(&privkey, lastMessageTime, server, def.CACert) if err != nil { // TODO: handle this better if err.Error() == "accountdb: Nothing found" { // no messages found log.Info("write: NONE") fmt.Fprintln(status, "NONE") return nil } return log.Error(err) } /* for _, message := range messages { messageID := base64.Encode(message.MessageID) log.Debugf("messageID=%s, ReceiveTime=%d, ReadTime=%d", messageID, message.ReceiveTime, message.ReadTime) } */ scanner := bufio.NewScanner(command) for _, message := range messages { msg, err := client.FetchMessage(&privkey, message.MessageID, server, def.CACert) if err != nil { return log.Error(err) } messageID := base64.Encode(message.MessageID) log.Debugf("write: MESSAGEID:\t%s", messageID) fmt.Fprintf(status, "MESSAGEID:\t%s\n", messageID) var command string if scanner.Scan() { command = scanner.Text() } else { return log.Error("protoengine: expecting command input") } if err := scanner.Err(); err != nil { fmt.Fprintln(os.Stderr, "reading standard input:", err) } if command == "NEXT" { log.Debug("read: NEXT") enc := base64.Encode(msg) if _, err := io.WriteString(output, enc); err != nil { return log.Error(err) } log.Debugf("write: LENGTH:\t%d", len(enc)) fmt.Fprintf(status, "LENGTH:\t%d\n", len(enc)) log.Debugf("write: RECEIVETIME:\t%d", message.ReceiveTime) fmt.Fprintf(status, "RECEIVETIME:\t%d\n", message.ReceiveTime) } else if command == "QUIT" { log.Debug("read: QUIT") return nil } else { return log.Errorf("protoengine: unknown command '%s'", command) } } // no more messages log.Info("write: NONE") fmt.Fprintln(status, "NONE") return nil }
func mutecryptNewUID( c *cli.Context, passphrase []byte, id, domain, host, mixaddress, nymaddress string, client *client.Client, ) error { log.Infof("mutecryptNewUID(): id=%s, domain=%s", id, domain) args := []string{ "--homedir", c.GlobalString("homedir"), "--loglevel", c.GlobalString("loglevel"), "--logdir", c.GlobalString("logdir"), } if host != "" { args = append(args, "--keyhost", host, "--keyport", ":8080") // TODO: remove keyport hack! } cmd := exec.Command("mutecrypt", args...) stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } scanner := bufio.NewScanner(stderr) passphraseReader, passphraseWriter, err := os.Pipe() if err != nil { return err } cmd.ExtraFiles = append(cmd.ExtraFiles, passphraseReader) commandReader, commandWriter, err := os.Pipe() if err != nil { return err } cmd.ExtraFiles = append(cmd.ExtraFiles, commandReader) // generate UID _, err = io.WriteString(commandWriter, strings.Join([]string{ "uid", "generate", "--id", id + "\n", }, " ")) if err != nil { return err } // start process if err := cmd.Start(); err != nil { return err } // write passphrase plen := len(passphrase) buf := make([]byte, plen+1) defer bzero.Bytes(buf) copy(buf, passphrase) copy(buf[plen:], []byte("\n")) if _, err := passphraseWriter.Write(buf); err != nil { return err } passphraseWriter.Close() // check for errors on stderr for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } // get capabilities args = []string{"caps", "show", "--domain", domain} if host := c.String("host"); host != "" { args = append(args, "--host", host) } args = append(args, "\n") _, err = io.WriteString(commandWriter, strings.Join(args, " ")) if err != nil { return err } for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } var caps capabilities.Capabilities decoder := json.NewDecoder(stdout) if err := decoder.Decode(&caps); err != nil { return err } /* // pretty-print capabilities jsn, err := json.MarshalIndent(caps, "", " ") if err != nil { return err } fmt.Println(string(jsn)) */ owner, err := decodeED25519PubKeyBase64(caps.TKNPUBKEY) if err != nil { return err } // get token from wallet token, err := wallet.GetToken(client, "UID", owner) if err != nil { return err } // try to register UID _, err = io.WriteString(commandWriter, strings.Join([]string{ "uid", "register", "--id", id, "--token", base64.Encode(token.Token) + "\n", }, " ")) if err != nil { client.UnlockToken(token.Hash) return err } var cryptErr error for scanner.Scan() { line := scanner.Text() if line != "READY." { cryptErr = errors.New(line) } else { break } } if err := scanner.Err(); err != nil { client.UnlockToken(token.Hash) return err } // delete UID, if registration was not successful if cryptErr != nil { client.UnlockToken(token.Hash) _, err = io.WriteString(commandWriter, strings.Join([]string{ "uid", "delete", "--force", "--id", id + "\n", }, " ")) if err != nil { return err } for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } } else { client.DelToken(token.Hash) } // add KeyInit messages token, err = wallet.GetToken(client, "Message", owner) if err != nil { return err } _, err = io.WriteString(commandWriter, strings.Join([]string{ "keyinit", "add", "--id", id, "--mixaddress", mixaddress, "--nymaddress", nymaddress, "--token", base64.Encode(token.Token) + "\n", }, " ")) if err != nil { client.UnlockToken(token.Hash) return err } for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { client.UnlockToken(token.Hash) return err } client.DelToken(token.Hash) // quit mutecrypt if _, err := io.WriteString(commandWriter, "quit\n"); err != nil { return err } for scanner.Scan() { line := scanner.Text() if line != "QUITTING" { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } if err := cmd.Wait(); err != nil { return err } // propagate error if cryptErr != nil { return cryptErr } return nil }
func (ce *CtrlEngine) upkeepUpdate( homedir string, /* source, binary bool, */ outfp, statfp io.Writer, ) error { log.Info("upkeepUpdate()") // make sure we have the most current config if err := ce.upkeepFetchconf(ce.msgDB, homedir, false, outfp, statfp); err != nil { return err } commit := ce.config.Map["release.Commit"] log.Infof("server: release.Commit: %s", commit) log.Infof("binary: release.Commit: %s", release.Commit) if release.Commit == commit { log.Info("Mute is up-to-date") fmt.Fprintf(statfp, "Mute is up-to-date\n") return nil } // parse release date tRelease, err := time.Parse(git.Date, ce.config.Map["release.Date"]) if err != nil { return err } // parse binary date tBinary, err := time.Parse(git.Date, release.Date) if err != nil { return err } // switch to UTC tRelease = tRelease.UTC() tBinary = tBinary.UTC() log.Infof("server: release.Date: %s", tRelease.Format(time.RFC3339)) log.Infof("binary: release.Date: %s", tBinary.Format(time.RFC3339)) // compare dates if tBinary.After(tRelease) { log.Info("commits differ, but binary is newer than release date") fmt.Fprintf(statfp, "commits differ, but binary is newer than release date\n") fmt.Fprintf(statfp, "are you running a developer version?\n") return nil } /* // commits differ and release date is more current than binary -> update if !source && !binary { // try to determine update mode via mutegenerate // (should only exist for source releases) dir, err := exec.LookPath(os.Args[0]) if err != nil { return err } dir = filepath.Join(dir, "..") cmd := exec.Command(filepath.Join(dir, "mutegenerate"), "-t") if err := cmd.Run(); err != nil { binary = true } else { source = true } } if source { */ log.Info("call updateMuteFromSource()") if err := updateMuteFromSource(outfp, statfp, commit); err != nil { return err } /* } else { if err := updateMuteBinaries(outfp, statfp); err != nil { return err } } */ // after a successful we exit return errExit }
// rekey MsgDB and KeyDB. func (ce *CtrlEngine) dbRekey(statusfp io.Writer, c *cli.Context) error { msgdbname := filepath.Join(c.GlobalString("homedir"), "msgs") // read old passphrase fmt.Fprintf(statusfp, "read old passphrase from fd %d (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read old passphrase from fd %d (not echoed)", ce.fileTable.PassphraseFD) var ( scanner *bufio.Scanner oldPassphrase []byte newPassphrase []byte newPassphrase2 []byte err error ) defer bzero.Bytes(oldPassphrase) defer bzero.Bytes(newPassphrase) defer bzero.Bytes(newPassphrase2) isTerminal := terminal.IsTerminal(int(ce.fileTable.PassphraseFD)) if isTerminal { oldPassphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { scanner = bufio.NewScanner(ce.fileTable.PassphraseFP) if scanner.Scan() { oldPassphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // read new passphrase fmt.Fprintf(statusfp, "read new passphrase from fd %d (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read new passphrase from fd %d (not echoed)", ce.fileTable.PassphraseFD) if isTerminal { newPassphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { if scanner.Scan() { newPassphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // read new passphrase again fmt.Fprintf(statusfp, "read new passphrase from fd %d again (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read new passphrase from fd %d again (not echoed)", ce.fileTable.PassphraseFD) if isTerminal { newPassphrase2, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { if scanner.Scan() { newPassphrase2 = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // compare new passphrases if !bytes.Equal(newPassphrase, newPassphrase2) { return log.Error(ErrPassphrasesDiffer) } // rekey msgDB log.Infof("rekey msgDB '%s'", msgdbname) if err := msgdb.Rekey(msgdbname, oldPassphrase, newPassphrase, c.Int("iterations")); err != nil { return err } // rekey keyDB log.Info("rekey keyDB") if err := rekeyKeyDB(c, oldPassphrase, newPassphrase); err != nil { return err } return nil }