예제 #1
0
파일: redirector.go 프로젝트: hlandau/acme
func enforceGID(gid, path string) error {
	newGID, err := passwd.ParseGID(gid)
	if err != nil {
		return err
	}

	// So this is a surprisingly complicated dance if we want to be free of
	// potentially hazardous race conditions. We have a path. We can't assume
	// anything about its ownership, or mode, whether it's a symlink, etc.
	//
	// The big risk is that someone is able to create a symlink pointing to
	// something they want to illicitly access. Note that since /var/run will
	// commonly be used and because this directory is world-writeable, ala /tmp,
	// this is a real risk.
	//
	// So we have to make sure we don't follow symlinks. Assume we are running
	// as root (necessary, since we're chowning), and that nothing running as
	// root is malicious.
	//
	// We open the directory as a file so we can modify it using that reference
	// without worrying about the resolution of the path changing under us. But
	// we need to make sure we don't follow symlinks. This requires special OS
	// support, alas.
	dir, err := deos.OpenNoSymlinks(path)
	if err != nil {
		return err
	}

	defer dir.Close()

	fi, err := dir.Stat()
	if err != nil {
		return err
	}

	// Attributes of the directory can still change, but its type certainly
	// can't. This guarantee is enough for our purposes.
	if (fi.Mode() & os.ModeType) != os.ModeDir {
		return fmt.Errorf("challenge path %#v is not a directory", path)
	}

	curUID, err := deos.GetFileUID(fi)
	if err != nil {
		return err
	}

	dir.Chmod((fi.Mode() | 0070) & ^os.ModeType) // Ignore errors.
	dir.Chown(curUID, newGID)                    // Ignore errors.
	return nil
}
예제 #2
0
파일: fdb.go 프로젝트: hlandau/acme
// Change all directory permissions to be correct.
func (db *DB) conformPermissions() error {
	err := filepath.Walk(db.path, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		rpath, err := filepath.Rel(db.path, path)
		if err != nil {
			return err
		}

		mode := info.Mode()
		switch mode & os.ModeType {
		case 0:
		case os.ModeDir:
			db.extantDirs[rpath] = struct{}{}
		case os.ModeSymlink:
			l, err := os.Readlink(path)
			if err != nil {
				return err
			}

			if filepath.IsAbs(l) {
				return fmt.Errorf("database symlinks must not have absolute targets: %v: %v", path, l)
			}

			ll := filepath.Join(filepath.Dir(path), l)
			ll, err = filepath.Abs(ll)
			if err != nil {
				return err
			}

			ok, err := pathIsWithin(ll, db.path)
			if err != nil {
				return err
			}
			if !ok {
				return fmt.Errorf("database symlinks must point to within the database directory: %v: %v", path, ll)
			}

			_, err = os.Stat(ll)
			if os.IsNotExist(err) {
				log.Warnf("broken symlink, removing: %v -> %v", path, l)
				err := os.Remove(path)
				if err != nil {
					return err
				}
			} else if err != nil {
				log.Errore(err, "stat symlink")
				return err
			}

		default:
			return fmt.Errorf("unexpected file type in state directory: %s", mode)
		}

		perm := db.longestMatching(rpath)
		if perm == nil {
			log.Warnf("object without any permissions specified: %v", rpath)
		} else {
			correctPerm := perm.FileMode
			if (mode & os.ModeType) == os.ModeDir {
				correctPerm = perm.DirMode
			}

			if (mode & os.ModeType) != os.ModeSymlink {
				if fperm := mode.Perm(); fperm != correctPerm {
					log.Warnf("%#v has wrong mode %v, changing to %v", rpath, fperm, correctPerm)

					err := os.Chmod(path, correctPerm)
					if err != nil {
						return err
					}
				}
			}

			correctUID, correctGID, err := resolveUIDGID(perm)
			if err != nil {
				return err
			}

			if correctUID >= 0 || correctGID >= 0 {
				curUID, err := deos.GetFileUID(info)
				if err != nil {
					return err
				}

				curGID, err := deos.GetFileGID(info)
				if err != nil {
					return err
				}

				if correctUID < 0 {
					correctUID = curUID
				}

				if correctGID < 0 {
					correctGID = curGID
				}

				if curUID != correctUID || curGID != correctGID {
					log.Warnf("%#v has wrong UID/GID %v/%v, changing to %v/%v", rpath, curUID, curGID, correctUID, correctGID)

					err := os.Lchown(path, correctUID, correctGID)
					// Can't chown if not root so be a bit forgiving, but always moan
					log.Errore(err, "could not lchown file ", rpath)
				}
			}
		}

		return nil
	})
	if err != nil {
		return err
	}

	return nil
}