Esempio n. 1
0
func (s *snapassertsSuite) TestDeriveSideInfoHappy(c *C) {
	digest := makeDigest(42)
	size := uint64(len(fakeSnap(42)))
	headers := map[string]interface{}{
		"snap-id":       "snap-id-1",
		"snap-sha3-384": digest,
		"snap-size":     fmt.Sprintf("%d", size),
		"snap-revision": "42",
		"developer-id":  s.dev1Acct.AccountID(),
		"timestamp":     time.Now().Format(time.RFC3339),
	}
	snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "")
	c.Assert(err, IsNil)
	err = s.localDB.Add(snapRev)
	c.Assert(err, IsNil)

	tempdir := c.MkDir()
	snapPath := filepath.Join(tempdir, "anon.snap")
	err = ioutil.WriteFile(snapPath, fakeSnap(42), 0644)
	c.Assert(err, IsNil)

	si, err := snapasserts.DeriveSideInfo(snapPath, s.localDB)
	c.Assert(err, IsNil)
	c.Check(si, DeepEquals, &snap.SideInfo{
		RealName:    "foo",
		SnapID:      "snap-id-1",
		Revision:    snap.R(42),
		Channel:     "",
		DeveloperID: s.dev1Acct.AccountID(),
		Developer:   "developer1",
	})
}
Esempio n. 2
0
func (s *snapassertsSuite) TestDeriveSideInfoNoSignatures(c *C) {
	tempdir := c.MkDir()
	snapPath := filepath.Join(tempdir, "anon.snap")
	err := ioutil.WriteFile(snapPath, fakeSnap(42), 0644)
	c.Assert(err, IsNil)

	_, err = snapasserts.DeriveSideInfo(snapPath, s.localDB)
	// cannot find signatures with metadata for snap
	c.Assert(err, Equals, asserts.ErrNotFound)
}
Esempio n. 3
0
func (s *snapassertsSuite) TestDeriveSideInfoRevokedSnapDecl(c *C) {
	// revoked snap declaration (snap-name=="") !
	headers := map[string]interface{}{
		"series":       "16",
		"snap-id":      "snap-id-1",
		"snap-name":    "",
		"publisher-id": s.dev1Acct.AccountID(),
		"revision":     "1",
		"timestamp":    time.Now().Format(time.RFC3339),
	}
	snapDecl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
	c.Assert(err, IsNil)
	err = s.localDB.Add(snapDecl)
	c.Assert(err, IsNil)

	digest := makeDigest(42)
	size := uint64(len(fakeSnap(42)))
	headers = map[string]interface{}{
		"snap-id":       "snap-id-1",
		"snap-sha3-384": digest,
		"snap-size":     fmt.Sprintf("%d", size),
		"snap-revision": "42",
		"developer-id":  s.dev1Acct.AccountID(),
		"timestamp":     time.Now().Format(time.RFC3339),
	}
	snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "")
	c.Assert(err, IsNil)
	err = s.localDB.Add(snapRev)
	c.Assert(err, IsNil)

	tempdir := c.MkDir()
	snapPath := filepath.Join(tempdir, "anon.snap")
	err = ioutil.WriteFile(snapPath, fakeSnap(42), 0644)
	c.Assert(err, IsNil)

	_, err = snapasserts.DeriveSideInfo(snapPath, s.localDB)
	c.Check(err, ErrorMatches, fmt.Sprintf(`cannot install snap %q with a revoked snap declaration`, snapPath))
}
Esempio n. 4
0
func (s *snapassertsSuite) TestDeriveSideInfoSizeMismatch(c *C) {
	digest := makeDigest(42)
	size := uint64(len(fakeSnap(42)))
	headers := map[string]interface{}{
		"snap-id":       "snap-id-1",
		"snap-sha3-384": digest,
		"snap-size":     fmt.Sprintf("%d", size+5), // broken
		"snap-revision": "42",
		"developer-id":  s.dev1Acct.AccountID(),
		"timestamp":     time.Now().Format(time.RFC3339),
	}
	snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "")
	c.Assert(err, IsNil)
	err = s.localDB.Add(snapRev)
	c.Assert(err, IsNil)

	tempdir := c.MkDir()
	snapPath := filepath.Join(tempdir, "anon.snap")
	err = ioutil.WriteFile(snapPath, fakeSnap(42), 0644)
	c.Assert(err, IsNil)

	_, err = snapasserts.DeriveSideInfo(snapPath, s.localDB)
	c.Check(err, ErrorMatches, fmt.Sprintf(`snap %q does not have expected size according to signatures \(broken or tampered\): %d != %d`, snapPath, size, size+5))
}
Esempio n. 5
0
func populateStateFromSeedImpl(st *state.State) ([]*state.TaskSet, error) {
	// check that the state is empty
	var seeded bool
	err := st.Get("seeded", &seeded)
	if err != nil && err != state.ErrNoState {
		return nil, err
	}
	if seeded {
		return nil, fmt.Errorf("cannot populate state: already seeded")
	}

	// ack all initial assertions
	if err := importAssertionsFromSeed(st); err != nil {
		return nil, err
	}

	seed, err := snap.ReadSeedYaml(filepath.Join(dirs.SnapSeedDir, "seed.yaml"))
	if err != nil {
		return nil, err
	}

	tsAll := []*state.TaskSet{}
	for i, sn := range seed.Snaps {

		var flags snapstate.Flags
		if sn.DevMode {
			flags.DevMode = true
		}
		path := filepath.Join(dirs.SnapSeedDir, "snaps", sn.File)

		var sideInfo snap.SideInfo
		if sn.Unasserted {
			sideInfo.RealName = sn.Name
		} else {
			si, err := snapasserts.DeriveSideInfo(path, assertstate.DB(st))
			if err == asserts.ErrNotFound {
				return nil, fmt.Errorf("cannot find signatures with metadata for snap %q (%q)", sn.Name, path)
			}
			if err != nil {
				return nil, err
			}
			sideInfo = *si
			sideInfo.Private = sn.Private
		}

		ts, err := snapstate.InstallPath(st, &sideInfo, path, sn.Channel, flags)
		if i > 0 {
			ts.WaitAll(tsAll[i-1])
		}

		if err != nil {
			return nil, err
		}

		tsAll = append(tsAll, ts)
	}
	if len(tsAll) == 0 {
		return nil, nil
	}

	ts := tsAll[len(tsAll)-1]
	markSeeded := st.NewTask("mark-seeded", i18n.G("Mark system seeded"))
	markSeeded.WaitAll(ts)
	tsAll = append(tsAll, state.NewTaskSet(markSeeded))

	return tsAll, nil
}
Esempio n. 6
0
func populateStateFromSeed() error {
	if osutil.FileExists(dirs.SnapStateFile) {
		return fmt.Errorf("cannot create state: state %q already exists", dirs.SnapStateFile)
	}

	ovld, err := overlord.New()
	if err != nil {
		return err
	}
	st := ovld.State()

	// ack all initial assertions
	if err := importAssertionsFromSeed(st); err != nil {
		return err
	}

	seed, err := snap.ReadSeedYaml(filepath.Join(dirs.SnapSeedDir, "seed.yaml"))
	if err != nil {
		return err
	}

	tsAll := []*state.TaskSet{}
	for i, sn := range seed.Snaps {
		st.Lock()

		flags := snapstate.Flags(0)
		if sn.DevMode {
			flags |= snapstate.DevMode
		}
		path := filepath.Join(dirs.SnapSeedDir, "snaps", sn.File)

		var sideInfo snap.SideInfo
		if sn.Unasserted {
			sideInfo.RealName = sn.Name
		} else {
			si, err := snapasserts.DeriveSideInfo(path, assertstate.DB(st))
			if err == asserts.ErrNotFound {
				st.Unlock()
				return fmt.Errorf("cannot find signatures with metadata for snap %q (%q)", sn.Name, path)
			}
			if err != nil {
				st.Unlock()
				return err
			}
			sideInfo = *si
			sideInfo.Private = sn.Private
		}

		ts, err := snapstate.InstallPath(st, &sideInfo, path, sn.Channel, flags)
		if i > 0 {
			ts.WaitAll(tsAll[i-1])
		}
		st.Unlock()

		if err != nil {
			return err
		}

		tsAll = append(tsAll, ts)
	}
	if len(tsAll) == 0 {
		return nil
	}

	st.Lock()
	msg := fmt.Sprintf("First boot seeding")
	chg := st.NewChange("seed", msg)
	for _, ts := range tsAll {
		chg.AddAll(ts)
	}
	st.Unlock()

	// do it and wait for ready
	ovld.Loop()

	st.EnsureBefore(0)
	<-chg.Ready()

	st.Lock()
	status := chg.Status()
	err = chg.Err()
	st.Unlock()
	if status != state.DoneStatus {
		ovld.Stop()
		return fmt.Errorf("cannot run seed change: %s", err)

	}

	return ovld.Stop()
}
Esempio n. 7
0
func postSnaps(c *Command, r *http.Request, user *auth.UserState) Response {
	contentType := r.Header.Get("Content-Type")

	if contentType == "application/json" {
		return snapsOp(c, r, user)
	}

	if !strings.HasPrefix(contentType, "multipart/") {
		return BadRequest("unknown content type: %s", contentType)
	}

	route := c.d.router.Get(stateChangeCmd.Path)
	if route == nil {
		return InternalError("cannot find route for change")
	}

	// POSTs to sideload snaps must be a multipart/form-data file upload.
	_, params, err := mime.ParseMediaType(contentType)
	if err != nil {
		return BadRequest("cannot parse POST body: %v", err)
	}

	form, err := multipart.NewReader(r.Body, params["boundary"]).ReadForm(maxReadBuflen)
	if err != nil {
		return BadRequest("cannot read POST form: %v", err)
	}

	dangerousOK := isTrue(form, "dangerous")
	devmode := isTrue(form, "devmode")
	flags, err := modeFlags(devmode, isTrue(form, "jailmode"))
	if err != nil {
		return BadRequest(err.Error())
	}

	if len(form.Value["action"]) > 0 && form.Value["action"][0] == "try" {
		if len(form.Value["snap-path"]) == 0 {
			return BadRequest("need 'snap-path' value in form")
		}
		return trySnap(c, r, user, form.Value["snap-path"][0], flags)
	}

	// find the file for the "snap" form field
	var snapBody multipart.File
	var origPath string
out:
	for name, fheaders := range form.File {
		if name != "snap" {
			continue
		}
		for _, fheader := range fheaders {
			snapBody, err = fheader.Open()
			origPath = fheader.Filename
			if err != nil {
				return BadRequest(`cannot open uploaded "snap" file: %v`, err)
			}
			defer snapBody.Close()

			break out
		}
	}
	defer form.RemoveAll()

	if snapBody == nil {
		return BadRequest(`cannot find "snap" file field in provided multipart/form-data payload`)
	}

	tmpf, err := ioutil.TempFile("", "snapd-sideload-pkg-")
	if err != nil {
		return InternalError("cannot create temporary file: %v", err)
	}

	if _, err := io.Copy(tmpf, snapBody); err != nil {
		os.Remove(tmpf.Name())
		return InternalError("cannot copy request into temporary file: %v", err)
	}
	tmpf.Sync()

	tempPath := tmpf.Name()

	if len(form.Value["snap-path"]) > 0 {
		origPath = form.Value["snap-path"][0]
	}

	st := c.d.overlord.State()
	st.Lock()
	defer st.Unlock()

	var snapName string
	var sideInfo *snap.SideInfo

	if !dangerousOK {
		si, err := snapasserts.DeriveSideInfo(tempPath, assertstate.DB(st))
		switch err {
		case nil:
			snapName = si.RealName
			sideInfo = si
		case asserts.ErrNotFound:
			// with devmode we try to find assertions but it's ok
			// if they are not there (implies --dangerous)
			if !devmode {
				msg := "cannot find signatures with metadata for snap"
				if origPath != "" {
					msg = fmt.Sprintf("%s %q", msg, origPath)
				}
				return BadRequest(msg)
			}
			// TODO: set a warning if devmode
		default:
			return BadRequest(err.Error())
		}
	}

	if snapName == "" {
		// potentially dangerous but dangerous or devmode params were set
		info, err := unsafeReadSnapInfo(tempPath)
		if err != nil {
			return InternalError("cannot read snap file: %v", err)
		}
		snapName = info.Name()
		sideInfo = &snap.SideInfo{RealName: snapName}
	}

	msg := fmt.Sprintf(i18n.G("Install %q snap from file"), snapName)
	if origPath != "" {
		msg = fmt.Sprintf(i18n.G("Install %q snap from file %q"), snapName, origPath)
	}

	var userID int
	if user != nil {
		userID = user.ID
	}

	tsets, err := withEnsureUbuntuCore(st, snapName, userID,
		func() (*state.TaskSet, error) {
			return snapstateInstallPath(st, sideInfo, tempPath, "", flags)
		},
	)
	if err != nil {
		return InternalError("cannot install snap file: %v", err)
	}

	chg := newChange(st, "install-snap", msg, tsets, []string{snapName})
	chg.Set("api-data", map[string]string{"snap-name": snapName})

	ensureStateSoon(st)

	return AsyncResponse(nil, &Meta{Change: chg.ID()})
}