func (m *DeviceManager) doGenerateDeviceKey(t *state.Task, _ *tomb.Tomb) error { st := t.State() st.Lock() defer st.Unlock() device, err := auth.Device(st) if err != nil { return err } if device.KeyID != "" { // nothing to do return nil } keyPair, err := rsa.GenerateKey(rand.Reader, keyLength) if err != nil { return fmt.Errorf("cannot generate device key pair: %v", err) } privKey := asserts.RSAPrivateKey(keyPair) err = m.keypairMgr.Put(privKey) if err != nil { return fmt.Errorf("cannot store device key pair: %v", err) } device.KeyID = privKey.PublicKey().ID() err = auth.SetDevice(st, device) if err != nil { return err } t.SetStatus(state.DoneStatus) return nil }
func (m *SnapManager) undoLinkSnap(t *state.Task, _ *tomb.Tomb) error { st := t.State() st.Lock() defer st.Unlock() ss, snapst, err := snapSetupAndState(t) if err != nil { return err } var oldChannel string err = t.Get("old-channel", &oldChannel) if err != nil { return err } var oldTryMode bool err = t.Get("old-trymode", &oldTryMode) if err != nil { return err } var oldDevMode bool err = t.Get("old-devmode", &oldDevMode) if err != nil { return err } var oldJailMode bool err = t.Get("old-jailmode", &oldJailMode) if err != nil { return err } var oldCurrent snap.Revision err = t.Get("old-current", &oldCurrent) if err != nil { return err } var oldCandidateIndex int if err := t.Get("old-candidate-index", &oldCandidateIndex); err != nil { return err } isRevert := ss.Flags.Revert() // relinking of the old snap is done in the undo of unlink-current-snap currentIndex := snapst.LastIndex(snapst.Current) if currentIndex < 0 { return fmt.Errorf("internal error: cannot find revision %d in %v for undoing the added revision", ss.SideInfo.Revision, snapst.Sequence) } if oldCandidateIndex < 0 { snapst.Sequence = append(snapst.Sequence[:currentIndex], snapst.Sequence[currentIndex+1:]...) } else if !isRevert { oldCand := snapst.Sequence[currentIndex] copy(snapst.Sequence[oldCandidateIndex+1:], snapst.Sequence[oldCandidateIndex:]) snapst.Sequence[oldCandidateIndex] = oldCand } snapst.Current = oldCurrent snapst.Active = false snapst.Channel = oldChannel snapst.SetTryMode(oldTryMode) snapst.SetDevMode(oldDevMode) snapst.SetJailMode(oldJailMode) newInfo, err := readInfo(ss.Name(), ss.SideInfo) if err != nil { return err } pb := &TaskProgressAdapter{task: t} st.Unlock() // pb itself will ask for locking err = m.backend.UnlinkSnap(newInfo, pb) st.Lock() if err != nil { return err } // mark as inactive Set(st, ss.Name(), snapst) // Make sure if state commits and snapst is mutated we won't be rerun t.SetStatus(state.UndoneStatus) return nil }
func (m *SnapManager) doLinkSnap(t *state.Task, _ *tomb.Tomb) error { st := t.State() st.Lock() defer st.Unlock() ss, snapst, err := snapSetupAndState(t) if err != nil { return err } cand := ss.SideInfo m.backend.Candidate(cand) oldCandidateIndex := snapst.LastIndex(cand.Revision) if oldCandidateIndex < 0 { snapst.Sequence = append(snapst.Sequence, cand) } else if !ss.Flags.Revert() { // remove the old candidate from the sequence, add it at the end copy(snapst.Sequence[oldCandidateIndex:len(snapst.Sequence)-1], snapst.Sequence[oldCandidateIndex+1:]) snapst.Sequence[len(snapst.Sequence)-1] = cand } oldCurrent := snapst.Current snapst.Current = cand.Revision snapst.Active = true oldChannel := snapst.Channel if ss.Channel != "" { snapst.Channel = ss.Channel } oldTryMode := snapst.TryMode() snapst.SetTryMode(ss.TryMode()) oldDevMode := snapst.DevMode() snapst.SetDevMode(ss.DevMode()) oldJailMode := snapst.JailMode() snapst.SetJailMode(ss.JailMode()) newInfo, err := readInfo(ss.Name(), cand) if err != nil { return err } // record type snapst.SetType(newInfo.Type) st.Unlock() // XXX: this block is slightly ugly, find a pattern when we have more examples err = m.backend.LinkSnap(newInfo) if err != nil { pb := &TaskProgressAdapter{task: t} err := m.backend.UnlinkSnap(newInfo, pb) if err != nil { st.Lock() t.Errorf("cannot cleanup failed attempt at making snap %q available to the system: %v", ss.Name(), err) st.Unlock() } } st.Lock() if err != nil { return err } // save for undoLinkSnap t.Set("old-trymode", oldTryMode) t.Set("old-devmode", oldDevMode) t.Set("old-jailmode", oldJailMode) t.Set("old-channel", oldChannel) t.Set("old-current", oldCurrent) t.Set("old-candidate-index", oldCandidateIndex) // Do at the end so we only preserve the new state if it worked. Set(st, ss.Name(), snapst) // Make sure if state commits and snapst is mutated we won't be rerun t.SetStatus(state.DoneStatus) // if we just installed a core snap, request a restart // so that we switch executing its snapd if release.OnClassic && newInfo.Type == snap.TypeOS { t.Logf("Requested daemon restart.") st.Unlock() st.RequestRestart(state.RestartDaemon) st.Lock() } if !release.OnClassic && (newInfo.Type == snap.TypeOS || newInfo.Type == snap.TypeKernel) { t.Logf("Requested system restart.") st.Unlock() st.RequestRestart(state.RestartSystem) st.Lock() } return nil }
func (m *DeviceManager) doRequestSerial(t *state.Task, _ *tomb.Tomb) error { st := t.State() st.Lock() defer st.Unlock() cfg, err := getSerialRequestConfig(t) if err != nil { return err } device, err := auth.Device(st) if err != nil { return err } privKey, err := m.keyPair() if err == state.ErrNoState { return fmt.Errorf("internal error: cannot find device key pair") } if err != nil { return err } // make this idempotent, look if we have already a serial assertion // for privKey serials, err := assertstate.DB(st).FindMany(asserts.SerialType, map[string]string{ "brand-id": device.Brand, "model": device.Model, "device-key-sha3-384": privKey.PublicKey().ID(), }) if err != nil && err != asserts.ErrNotFound { return err } if len(serials) == 1 { // means we saved the assertion but didn't get to the end of the task device.Serial = serials[0].(*asserts.Serial).Serial() err := auth.SetDevice(st, device) if err != nil { return err } t.SetStatus(state.DoneStatus) return nil } if len(serials) > 1 { return fmt.Errorf("internal error: multiple serial assertions for the same device key") } serial, err := getSerial(t, privKey, device, cfg) if err == errPoll { t.Logf("Will poll for device serial assertion in 60 seconds") return &state.Retry{After: retryInterval} } if err != nil { // errors & retries return err } sto := snapstate.Store(st) // try to fetch the signing key of the serial st.Unlock() a, errAcctKey := sto.Assertion(asserts.AccountKeyType, []string{serial.SignKeyID()}, nil) st.Lock() if errAcctKey == nil { err := assertstate.Add(st, a) if err != nil { if !asserts.IsUnaccceptedUpdate(err) { return err } } } // add the serial assertion to the system assertion db err = assertstate.Add(st, serial) if err != nil { // if we had failed to fetch the signing key, retry in a bit if errAcctKey != nil { t.Errorf("cannot fetch signing key for the serial: %v", errAcctKey) return &state.Retry{After: retryInterval} } return err } if repeatRequestSerial == "after-add-serial" { // For testing purposes, ensure a crash in this state works. return &state.Retry{} } device.Serial = serial.Serial() err = auth.SetDevice(st, device) if err != nil { return err } t.SetStatus(state.DoneStatus) return nil }