Example #1
0
// Like GosaDecrypt() but operates in-place on buf.
// Returns true if decryption successful and false if not.
// If false is returned, the buffer contents may be destroyed, but only
// if further decryption attempts with other keys would be pointless anyway,
// because of some fatal condition (such as the data not being a multiple of
// the cipher's block size).
func GosaDecryptBuffer(buf *bytes.Buffer, key string) bool {
	buf.TrimSpace()

	if buf.Len() < 11 {
		return false
	} // minimum length of unencrypted <xml></xml>

	data := buf.Bytes()
	if string(data[0:5]) == "<xml>" {
		return true
	}

	// Fixes the following:
	// * gosa-si bug in the following line:
	//     if( $client_answer =~ s/session_id=(\d+)$// ) {
	//   This leaves the "." before "session_id" which breaks base64
	// * new gosa-si protocol has ";IP:PORT" appended to message
	//   which also breaks base64
	for semicolon_period := 0; semicolon_period < len(data); semicolon_period++ {
		if data[semicolon_period] == ';' || data[semicolon_period] == '.' {
			buf.Trim(0, semicolon_period)
			data = buf.Bytes()
			break
		}
	}

	aescipher, _ := aes.NewCipher([]byte(util.Md5sum(key)))
	crypter := cipher.NewCBCDecrypter(aescipher, config.InitializationVector)

	cryptotest := make([]byte, (((3*aes.BlockSize)+2)/3)<<2)
	n := copy(cryptotest, data)
	cryptotest = cryptotest[0:n]
	cryptotest = util.Base64DecodeInPlace(cryptotest)
	n = (len(cryptotest) / aes.BlockSize) * aes.BlockSize
	cryptotest = cryptotest[0:n]
	crypter.CryptBlocks(cryptotest, cryptotest)
	if !strings.Contains(string(cryptotest), "<xml>") {
		return false
	}

	data = util.Base64DecodeInPlace(data)
	buf.Trim(0, len(data))
	data = buf.Bytes()

	if buf.Len()%aes.BlockSize != 0 {
		// this condition is fatal => further decryption attempts are pointless
		buf.Reset()
		return false
	}

	crypter = cipher.NewCBCDecrypter(aescipher, config.InitializationVector)
	crypter.CryptBlocks(data, data)

	buf.TrimSpace() // removes 0 padding, too

	return true
}
Example #2
0
func faiConnection(conn *net.TCPConn) {
	defer conn.Close()
	var err error

	err = conn.SetKeepAlive(true)
	if err != nil {
		util.Log(0, "ERROR! SetKeepAlive: %v", err)
	}

	var buf bytes.Buffer
	defer buf.Reset()
	readbuf := make([]byte, 4096)
	n := 1
	for n != 0 {
		n, err = conn.Read(readbuf)
		if err != nil && err != io.EOF {
			util.Log(0, "ERROR! Read: %v", err)
		}
		if n == 0 && err == nil {
			util.Log(0, "ERROR! Read 0 bytes but no error reported")
		}

		// Find complete lines terminated by '\n' and process them.
		for start := 0; ; {
			eol := start
			for ; eol < n; eol++ {
				if readbuf[eol] == '\n' {
					break
				}
			}

			// no \n found, append to buf and continue reading
			if eol == n {
				buf.Write(readbuf[start:n])
				break
			}

			// append to rest of line to buffered contents
			buf.Write(readbuf[start:eol])
			start = eol + 1

			buf.TrimSpace()

			util.Log(2, "DEBUG! FAI monitor message from %v: %v", conn.RemoteAddr(), buf.String())
			buf.Reset()
		}
	}

	if buf.Len() != 0 {
		util.Log(2, "DEBUG! Incomplete FAI monitor message (i.e. not terminated by \"\\n\") from %v: %v", conn.RemoteAddr(), buf.String())
	}
}
Example #3
0
func testBuffer() {
	var b bytes.Buffer
	check(b.String(), "") // String() on fresh variable
	b.Reset()             // Reset() on fresh variable
	check(b.String(), "") // String() after Reset()
	b.Reset()             // Reset() after Reset()
	check(b.String(), "")
	check(b.Len(), 0)

	// same tests as above with pointer
	b2 := &bytes.Buffer{}
	check(b2.String(), "")
	b2.Reset()
	check(b2.String(), "")
	b2.Reset()
	check(b2.String(), "")
	check(b2.Len(), 0)

	b2.WriteString("Dies ist ein Test!")
	check(b2.String(), "Dies ist ein Test!")
	check(b2.Len(), 18)

	n, err := b.Write(nil)
	check(n, 0)
	check(err, nil)
	check(b.String(), "")

	n, err = b.Write([]byte{})
	check(n, 0)
	check(err, nil)
	check(b.String(), "")
	check(b.Pointer(), nil)
	check(b.Capacity(), 0)
	check(b.Len(), 0)

	func() {
		defer func() {
			check(recover(), bytes.ErrTooLarge)
		}()
		b.Grow(-1)
	}()

	n, err = b.Write([]byte{'a'})
	check(n, 1)
	check(err, nil)
	check(b.String(), "a")
	check(b.Capacity() >= 1, true)
	check(b.Len(), 1)
	check(b.Pointer() != nil, true)

	check(b.Grow(11), 1)
	check(b.Capacity() >= 12, true)
	c := b.Capacity()
	p := b.Pointer()
	check(b.Grow(11), 1) // should not cause actual growth
	check(b.Pointer(), p)
	check(b.Capacity(), c)
	check(b.Len(), 1)
	((*[2]byte)(b.Pointer()))[1] = 'z'
	check(b.Contains("z"), false)

	n, err = b.WriteString("Hallo")
	check(n, 5)
	check(err, nil)
	check(b.String(), "aHallo")
	check(b.Pointer(), p)
	check(b.Capacity(), c)
	check(b.Len(), 6)

	b.Reset()
	check(b.String(), "")
	check(b.Pointer(), nil)
	check(b.Capacity(), 0)
	check(b.Contains(""), true)
	check(b.Contains("a"), false)

	b.WriteString("Hallo")
	b.WriteByte(' ')
	b.Write([]byte{'d', 'i', 'e', 's'})
	b.WriteByte(' ')
	b.WriteString("ist ")
	b.WriteString("ein ")
	b.Write([]byte("Test"))
	check(b.String(), "Hallo dies ist ein Test")
	check(b.Contains("Hallo dies ist ein Test"), true)
	check(b.Contains("Test"), true)
	check(b.Contains("Hallo"), true)
	check(b.Contains("allo"), true)
	check(b.Contains(""), true)

	check(b.Split(" "), []string{"Hallo", "dies", "ist", "ein", "Test"})
	check(b.Split("X"), []string{"Hallo dies ist ein Test"})
	check(b.Split("Hallo dies ist ein Test"), []string{"", ""})
	check(b.Split("H"), []string{"", "allo dies ist ein Test"})
	check(b.Split("Test"), []string{"Hallo dies ist ein ", ""})
	check(b.Split("es"), []string{"Hallo di", " ist ein T", "t"})

	b.Reset()
	b.WriteString("  \n\t Hallo  \t\v\n")
	check(b.Len(), 15)
	p = b.Pointer()
	b.TrimSpace()
	check(b.String(), "Hallo")
	check(b.Len(), 5)
	check(b.Pointer(), p)

	b.Reset()
	b.WriteString("  \n\t   \t\v\n")
	check(b.Len(), 10)
	b.TrimSpace()
	check(b.Pointer(), nil)
	check(b.Len(), 0)
	check(b.Capacity(), 0)
	b.TrimSpace()
	check(b.Pointer(), nil)
	check(b.Len(), 0)
	check(b.Capacity(), 0)

	b.Reset()
	b.WriteString("  \n\t Hallo")
	check(b.Len(), 10)
	p = b.Pointer()
	b.TrimSpace()
	check(b.String(), "Hallo")
	check(b.Len(), 5)
	check(b.Pointer(), p)

	b.Reset()
	b.WriteString("Hallo  \t\v\n")
	check(b.Len(), 10)
	p = b.Pointer()
	b.TrimSpace()
	check(b.String(), "Hallo")
	check(b.Len(), 5)
	check(b.Pointer(), p)

	b.Reset()
	b.WriteString(" ")
	check(b.Len(), 1)
	b.TrimSpace()
	check(b.Pointer(), nil)
	check(b.Len(), 0)
	check(b.Capacity(), 0)

	b.Reset()
	b.WriteString("Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotzkasten")
	n = b.Len()
	c = b.Capacity()
	p = b.Pointer()
	b.Trim(-10, 2000)
	check(b.Len(), n)
	check(b.Capacity(), c)
	check(b.Pointer(), p)

	b.Trim(2000, -10)
	check(b.Len(), 0)
	check(b.Capacity(), 0)
	check(b.Pointer(), nil)

	b.WriteString("Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotzkasten")
	b.Trim(4, 4)
	check(b.Len(), 0)
	check(b.Capacity(), 0)
	check(b.Pointer(), nil)

	b.WriteString("Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotzkasten")
	n = b.Len()
	c = b.Capacity()
	p = b.Pointer()
	b.Trim(0, b.Len()-6)
	check(b.Len(), n-6)
	check(b.Capacity(), c)
	check(b.Pointer(), p)
	check(b.String(), "Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotz")

	b.Trim(27, b.Len())
	check(b.Len(), n-6-27)
	check(b.Capacity(), c)
	check(b.Pointer(), p)
	check(b.String(), "kotzt in den Cottbuser Postkotz")

	b.Trim(1, b.Len()-1)
	check(b.Len(), n-6-27-2)
	check(b.Capacity(), c)
	check(b.Pointer(), p)
	check(b.String(), "otzt in den Cottbuser Postkot")

	b.Reset()
	b.Write0(-1)
	b.Write0(-100)
	b.Write0(0)
	check(b.Len(), 0)
	check(b.Capacity(), 0)
	check(b.Pointer(), nil)

	b.Write0(1)
	check(b.Len(), 1)
	check(b.Capacity(), 1)
	check(b.Bytes(), []byte{0})

	b.WriteByte(111)
	b.Write0(1)
	b.WriteByte(222)
	b.Write0(2)
	b.WriteByte(99)
	check(b.Len(), 7)
	check(b.Bytes(), []byte{0, 111, 0, 222, 0, 0, 99})

	b2.Reset()
	slices := [][]byte{}
	total := 0
	numfakeerrs := 0
	for total < 100000 {
		c = rand.Intn(30000)
		total += c

		sl := make([]byte, c)
		for i := range sl {
			sl[i] = byte(rand.Intn(256))
		}
		slices = append(slices, sl)
		b2.Write(sl)

		if total/30000 > numfakeerrs {
			slices = append(slices, nil)
			numfakeerrs++
		}
	}

	check(numfakeerrs, 3)

	slcopy := make([][]byte, len(slices))
	copy(slcopy, slices)
	slret := &sliceReturner{Slices: slcopy}
	b.Reset()
	check(b.Capacity(), 0)
	check(b.Len(), 0)
	check(b.Pointer(), nil)
	n = 0
	for i := 0; i < numfakeerrs; i++ {
		n64, err := b.ReadFrom(slret)
		n += int(n64)
		check(err, FakeError)
	}
	n64, err := b.ReadFrom(slret)
	n += int(n64)
	check(err, nil)
	check(n, total)
	check(b.Capacity() > b.Len(), true)
	check(b.Len(), total)

	contents := b.Bytes()
	contents2 := b2.Bytes()
	check(len(contents), len(contents2))
	n = 0
	for i := range contents {
		if contents[i] != contents2[i] {
			break
		}
		n++
	}
	check(n, total)

	b2.Reset()
	for i := range slices {
		for k := range slices[i] {
			slices[i][k] = 11
		}
		n, err = b.Read(slices[i])
		check(n, len(slices[i]))
		check(err, nil)
		b2.Write(slices[i])
	}

	check(b2.Len(), total)

	n, err = b.Read(slices[0])
	check(n, 0)
	check(err, io.EOF)

	contents = b.Bytes()
	contents2 = b2.Bytes()
	check(len(contents), len(contents2))
	n = 0
	for i := range contents {
		if contents[i] != contents2[i] {
			break
		}
		n++
	}
	check(n, total)

	b.WriteString("foo")
	foo := make([]byte, 10)
	n, err = b.Read(foo)
	check(n, 3)
	check(err, nil)
	check(string(foo[0:3]), "foo")

	n64, err = b.Seek(6700, 0)
	check(n64, 6700)
	check(err, nil)

	n64, err = b.Seek(-6000, 1)
	check(n64, 700)
	check(err, nil)

	n64, err = b.Seek(815, 1)
	check(n64, 1515)
	check(err, nil)
	n, err = b.Read(foo)
	check(n, len(foo))
	check(err, nil)
	check(foo, b2.Bytes()[1515:1515+len(foo)])

	n64, err = b.Seek(-3, 2)
	check(n64, total)
	check(err, nil)
	n, err = b.Read(foo)
	check(n, 3)
	check(err, nil)
	check(string(foo[0:3]), "foo")

	n64, err = b.Seek(999999, 0)
	check(n64, b.Len())
	check(err, nil)
	n64, err = b.Seek(-3, 1)
	check(n64, total)
	check(err, nil)
	n, err = b.Read(foo)
	check(n, 3)
	check(err, nil)
	check(string(foo[0:3]), "foo")

	n64, err = b.Seek(-815, 0)
	check(n64, 0)
	check(err, nil)
	n, err = b.Read(foo)
	check(n, len(foo))
	check(err, nil)
	check(foo, b2.Bytes()[0:len(foo)])
}
Example #4
0
// Handles one or more messages received over conn. Each message is a single
// line terminated by \n. The message may be encrypted as by security.GosaEncrypt().
func handle_request(tcpconn *net.TCPConn) {
	defer tcpconn.Close()
	defer atomic.AddInt32(&ActiveConnections, -1)

	//  defer util.Log(2, "DEBUG! Connection to %v closed", tcpconn.RemoteAddr())
	//  util.Log(2, "DEBUG! Connection from %v", tcpconn.RemoteAddr())

	var err error

	err = tcpconn.SetKeepAlive(true)
	if err != nil {
		util.Log(0, "ERROR! SetKeepAlive: %v", err)
	}

	var buf bytes.Buffer
	defer buf.Reset()
	readbuf := make([]byte, 4096)

	var conn net.Conn
	conn = tcpconn
	n := 1

	if config.TLSServerConfig != nil {
		// If TLS is required, we need to see a STARTTLS before the timeout.
		// If TLS is optional we need to accept idle connections for backwards compatibility
		if config.TLSRequired {
			conn.SetDeadline(time.Now().Add(config.TimeoutTLS))
		}

		for i := range starttls {
			n, err = conn.Read(readbuf[0:1])
			if n == 0 {
				if i != 0 { // Do not log an error for a port scan that just opens a connection and closes it immediately
					util.Log(0, "ERROR! Read error while looking for STARTTLS from %v: %v", conn.RemoteAddr(), err)
				}
				return
			}
			buf.Write(readbuf[0:1])
			if readbuf[0] == '\r' && starttls[i] == '\n' {
				// Read the \n that must follow \r (we don't support lone CR line endings)
				conn.Read(readbuf[0:1]) // ignore error. It will pop up again further down the line.
			}
			if readbuf[0] != starttls[i] {
				if config.TLSRequired {
					util.Log(0, "ERROR! No STARTTLS from %v, but TLS is required", conn.RemoteAddr())
					util.WriteAll(conn, []byte(message.ErrorReply("STARTTLS is required to connect")))
					return
				}
				break
			}
			if readbuf[0] == '\n' {
				buf.Reset() // purge STARTTLS\n from buffer
				conn = tls.Server(conn, config.TLSServerConfig)
			}
		}
	}

	context := security.ContextFor(conn)
	if context == nil {
		return
	}

	for n != 0 {
		//util.Log(2, "DEBUG! Receiving from %v", conn.RemoteAddr())
		n, err = conn.Read(readbuf)

		if err != nil && err != io.EOF {
			util.Log(0, "ERROR! Read: %v", err)
		}
		if err == io.EOF {
			util.Log(2, "DEBUG! Connection closed by %v", conn.RemoteAddr())
		}
		if n == 0 && err == nil {
			util.Log(0, "ERROR! Read 0 bytes but no error reported")
		}

		// Find complete lines terminated by '\n' and process them.
		for start := 0; ; {
			eol := start
			for ; eol < n; eol++ {
				if readbuf[eol] == '\n' {
					break
				}
			}

			// no \n found, append to buf and continue reading
			if eol == n {
				buf.Write(readbuf[start:n])
				break
			}

			// append to rest of line to buffered contents
			buf.Write(readbuf[start:eol])
			start = eol + 1

			buf.TrimSpace()

			// process the message and get a reply (if applicable)
			if buf.Len() > 0 { // ignore empty lines
				request_start := time.Now()
				reply, disconnect := message.ProcessEncryptedMessage(&buf, context)
				buf.Reset()
				request_time := time.Since(request_start)
				RequestProcessingTimes.Push(request_time)
				request_time -= RequestProcessingTimes.Next().(time.Duration)
				atomic.AddInt64(&message.RequestProcessingTime, int64(request_time))

				if reply.Len() > 0 {
					util.Log(2, "DEBUG! Sending %v bytes reply to %v", reply.Len(), conn.RemoteAddr())

					var deadline time.Time // zero value means "no deadline"
					if config.Timeout >= 0 {
						deadline = time.Now().Add(config.Timeout)
					}
					conn.SetWriteDeadline(deadline)

					_, err := util.WriteAll(conn, reply.Bytes())
					if err != nil {
						util.Log(0, "ERROR! WriteAll: %v", err)
					}
					reply.Reset()
					util.WriteAll(conn, []byte{'\r', '\n'})
				}

				if disconnect {
					util.Log(1, "INFO! Forcing disconnect of %v because of error", conn.RemoteAddr())
					return
				}

				if Shutdown {
					util.Log(1, "INFO! Forcing disconnect of %v because of go-susi shutdown", conn.RemoteAddr())
					return
				}
			}
		}
	}

	if buf.Len() != 0 {
		util.Log(0, "ERROR! Incomplete message from %v (i.e. not terminated by \"\\n\") of %v bytes: %v", conn.RemoteAddr(), buf.Len(), buf.String())
	}
}