mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 00:11:04 +00:00 
			
		
		
		
	* Inital routes to git refs api * Git refs API implementation * Update swagger * Fix copyright * Make swagger happy add basic test * Fix test * Fix test again :)
		
			
				
	
	
		
			146 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			146 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
//
 | 
						|
// Copyright (c) 2014 David Mzareulyan
 | 
						|
//
 | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 | 
						|
// and associated documentation files (the "Software"), to deal in the Software without restriction,
 | 
						|
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
 | 
						|
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
 | 
						|
// is furnished to do so, subject to the following conditions:
 | 
						|
//
 | 
						|
// The above copyright notice and this permission notice shall be included in all copies or substantial
 | 
						|
// portions of the Software.
 | 
						|
//
 | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 | 
						|
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
						|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 | 
						|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
//
 | 
						|
 | 
						|
// +build windows
 | 
						|
 | 
						|
package sshagent
 | 
						|
 | 
						|
// see https://github.com/Yasushi/putty/blob/master/windows/winpgntc.c#L155
 | 
						|
// see https://github.com/paramiko/paramiko/blob/master/paramiko/win_pageant.py
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/binary"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"sync"
 | 
						|
	"syscall"
 | 
						|
	"unsafe"
 | 
						|
)
 | 
						|
 | 
						|
// Maximum size of message can be sent to pageant
 | 
						|
const MaxMessageLen = 8192
 | 
						|
 | 
						|
var (
 | 
						|
	ErrPageantNotFound = errors.New("pageant process not found")
 | 
						|
	ErrSendMessage     = errors.New("error sending message")
 | 
						|
 | 
						|
	ErrMessageTooLong       = errors.New("message too long")
 | 
						|
	ErrInvalidMessageFormat = errors.New("invalid message format")
 | 
						|
	ErrResponseTooLong      = errors.New("response too long")
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	agentCopydataID = 0x804e50ba
 | 
						|
	wmCopydata      = 74
 | 
						|
)
 | 
						|
 | 
						|
type copyData struct {
 | 
						|
	dwData uintptr
 | 
						|
	cbData uint32
 | 
						|
	lpData unsafe.Pointer
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	lock sync.Mutex
 | 
						|
 | 
						|
	winFindWindow         = winAPI("user32.dll", "FindWindowW")
 | 
						|
	winGetCurrentThreadID = winAPI("kernel32.dll", "GetCurrentThreadId")
 | 
						|
	winSendMessage        = winAPI("user32.dll", "SendMessageW")
 | 
						|
)
 | 
						|
 | 
						|
func winAPI(dllName, funcName string) func(...uintptr) (uintptr, uintptr, error) {
 | 
						|
	proc := syscall.MustLoadDLL(dllName).MustFindProc(funcName)
 | 
						|
	return func(a ...uintptr) (uintptr, uintptr, error) { return proc.Call(a...) }
 | 
						|
}
 | 
						|
 | 
						|
// Available returns true if Pageant is running
 | 
						|
func Available() bool { return pageantWindow() != 0 }
 | 
						|
 | 
						|
// Query sends message msg to Pageant and returns response or error.
 | 
						|
// 'msg' is raw agent request with length prefix
 | 
						|
// Response is raw agent response with length prefix
 | 
						|
func query(msg []byte) ([]byte, error) {
 | 
						|
	if len(msg) > MaxMessageLen {
 | 
						|
		return nil, ErrMessageTooLong
 | 
						|
	}
 | 
						|
 | 
						|
	msgLen := binary.BigEndian.Uint32(msg[:4])
 | 
						|
	if len(msg) != int(msgLen)+4 {
 | 
						|
		return nil, ErrInvalidMessageFormat
 | 
						|
	}
 | 
						|
 | 
						|
	lock.Lock()
 | 
						|
	defer lock.Unlock()
 | 
						|
 | 
						|
	paWin := pageantWindow()
 | 
						|
 | 
						|
	if paWin == 0 {
 | 
						|
		return nil, ErrPageantNotFound
 | 
						|
	}
 | 
						|
 | 
						|
	thID, _, _ := winGetCurrentThreadID()
 | 
						|
	mapName := fmt.Sprintf("PageantRequest%08x", thID)
 | 
						|
	pMapName, _ := syscall.UTF16PtrFromString(mapName)
 | 
						|
 | 
						|
	mmap, err := syscall.CreateFileMapping(syscall.InvalidHandle, nil, syscall.PAGE_READWRITE, 0, MaxMessageLen+4, pMapName)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer syscall.CloseHandle(mmap)
 | 
						|
 | 
						|
	ptr, err := syscall.MapViewOfFile(mmap, syscall.FILE_MAP_WRITE, 0, 0, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer syscall.UnmapViewOfFile(ptr)
 | 
						|
 | 
						|
	mmSlice := (*(*[MaxMessageLen]byte)(unsafe.Pointer(ptr)))[:]
 | 
						|
 | 
						|
	copy(mmSlice, msg)
 | 
						|
 | 
						|
	mapNameBytesZ := append([]byte(mapName), 0)
 | 
						|
 | 
						|
	cds := copyData{
 | 
						|
		dwData: agentCopydataID,
 | 
						|
		cbData: uint32(len(mapNameBytesZ)),
 | 
						|
		lpData: unsafe.Pointer(&(mapNameBytesZ[0])),
 | 
						|
	}
 | 
						|
 | 
						|
	resp, _, _ := winSendMessage(paWin, wmCopydata, 0, uintptr(unsafe.Pointer(&cds)))
 | 
						|
 | 
						|
	if resp == 0 {
 | 
						|
		return nil, ErrSendMessage
 | 
						|
	}
 | 
						|
 | 
						|
	respLen := binary.BigEndian.Uint32(mmSlice[:4])
 | 
						|
	if respLen > MaxMessageLen-4 {
 | 
						|
		return nil, ErrResponseTooLong
 | 
						|
	}
 | 
						|
 | 
						|
	respData := make([]byte, respLen+4)
 | 
						|
	copy(respData, mmSlice)
 | 
						|
 | 
						|
	return respData, nil
 | 
						|
}
 | 
						|
 | 
						|
func pageantWindow() uintptr {
 | 
						|
	nameP, _ := syscall.UTF16PtrFromString("Pageant")
 | 
						|
	h, _, _ := winFindWindow(uintptr(unsafe.Pointer(nameP)), uintptr(unsafe.Pointer(nameP)))
 | 
						|
	return h
 | 
						|
}
 |