Beispiel #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
}
// Handles the message "CLMSG_save_fai_log".
//  buf: the decrypted message
func clmsg_save_fai_log(buf *bytes.Buffer) {
	macaddress := ""
	action := ""
	start := 0
	end := 0
	data := buf.Bytes()
	for i := 0; i < len(data)-19; i++ {
		if data[i] == '<' {
			if i+12+17 <= len(data) && match(data, i, "<macaddress>") {
				macaddress = string(data[i+12 : i+12+17])
			} else if match(data, i, "<fai_action>") {
				for k := i + 12; k < len(data); k++ {
					if data[k] == '<' {
						action = string(data[i+12 : k])
						i = k
						break
					}
				}
			} else if match(data, i, "<CLMSG_save_fai_log>") {
				start = i + 20
			} else if match(data, i, "</CLMSG_save_fai_log>") {
				end = i
			}
		}
	}

	if !macAddressRegexp.MatchString(macaddress) {
		util.Log(0, "ERROR! CLMSG_save_fai_log with illegal <macaddress> \"%v\"", macaddress)
		return
	}

	if !actionRegexp.MatchString(action) {
		util.Log(0, "ERROR! CLMSG_save_fai_log with illegal <fai_action> \"%v\"", action)
		return
	}

	util.Log(1, "INFO! Received log files from client %v. Assuming CLMSG_PROGRESS 100", macaddress)
	progress_msg := xml.NewHash("xml", "CLMSG_PROGRESS", "100")
	progress_msg.Add("macaddress", macaddress)
	clmsg_progress(progress_msg)

	timestamp := util.MakeTimestamp(time.Now())
	logname := action + "_" + timestamp[0:8] + "_" + timestamp[8:]
	logdir := path.Join(config.FAILogPath, strings.ToLower(macaddress), logname)

	// NOTE: 1kB = 1000B, 1kiB = 1024B
	util.Log(1, "INFO! Storing %vkB of %v log files from %v in %v", len(data)/1000, action, macaddress, logdir)

	err := os.MkdirAll(logdir, 0755)
	if err != nil {
		util.Log(0, "ERROR! Error creating log directory \"%v\": %v", logdir, err)
		return
	}

	// Create convenience symlink with the system's name as alias for MAC address.
	go util.WithPanicHandler(func() {
		if plainname := db.SystemPlainnameForMAC(macaddress); plainname != "none" {
			linkpath := path.Join(config.FAILogPath, strings.ToLower(plainname))
			link_target, err := os.Readlink(linkpath)
			if err != nil && !os.IsNotExist(err.(*os.PathError).Err) {
				util.Log(0, "ERROR! %v exists but is not a symlink: %v", linkpath, err)
				return
			}
			if err == nil {
				if link_target == strings.ToLower(macaddress) {
					return // symlink is already correct => nothing to do
				}

				util.Log(0, "WARNING! Machine %v has a new MAC %v . Removing old symlink %v => %v", plainname, macaddress, linkpath, link_target)
				err = os.Remove(linkpath)
				if err != nil {
					util.Log(0, "ERROR! Removing %v failed: %v", linkpath, err)
					// Don't bail out. Maybe we can create the new symlink anyway.
				}
			}
			err = os.Symlink(strings.ToLower(macaddress), linkpath)
			if err != nil && !os.IsExist(err.(*os.LinkError).Err) {
				util.Log(0, "ERROR! Could not create symlink %v => %v: %v", linkpath, strings.ToLower(macaddress), err)
			}
		}
	})

	files := []int{}
	for i := start; i < end; i++ {
		if data[i] == ':' && match(data, i-8, "log_file") {
			k := i
			i++
			for i < end {
				if data[i] == ':' {
					if k+1 < i {
						files = append(files, k+1, i)
					}
					break
				}
				i++
			}
		}
	}

	files = append(files, end+8)

	for i := 0; i < len(files)-1; i += 2 {
		fname := string(data[files[i]:files[i+1]])
		logdata := data[files[i+1]+1 : files[i+2]-8]
		util.Log(1, "INFO! Processing \"%v\" (%vkB)", fname, len(logdata)/1000)

		logdata = util.Base64DecodeInPlace(logdata)

		// As a precaution, make sure fname contains no slashes.
		fname = strings.Replace(fname, "/", "_", -1)
		err = ioutil.WriteFile(path.Join(logdir, fname), logdata, 0644)
		if err != nil {
			util.Log(0, "ERROR! Could not store \"%v\": %v", path.Join(logdir, fname), err)
			continue
		}
	}
}
Beispiel #3
0
func testBase64() {
	check(util.Base64DecodeString("", nil), []byte{})
	check(util.Base64DecodeInPlace([]byte{}), []byte{})
	check(util.Base64DecodeString("=", nil), []byte{})
	check(util.Base64DecodeInPlace([]byte("=")), []byte{})
	check(util.Base64DecodeString("  =  ", nil), []byte{})
	check(util.Base64DecodeInPlace([]byte("  =  ")), []byte{})
	check(util.Base64DecodeString("/+/+", nil), []byte{0xff, 0xef, 0xfe})
	check(util.Base64DecodeInPlace([]byte("/+/+")), []byte{0xff, 0xef, 0xfe})
	check(util.Base64DecodeString("_-_-", nil), []byte{0xff, 0xef, 0xfe})
	check(util.Base64DecodeInPlace([]byte("_-_-")), []byte{0xff, 0xef, 0xfe})
	var devnull int
	check(string(util.Base64DecodeString("SGFsbG8=", nil)), "Hallo")
	check(string(util.Base64DecodeInPlace([]byte("SGFsbG8="))), "Hallo")
	check(string(util.Base64DecodeString("SGFsbA==", nil)), "Hall")
	check(string(util.Base64DecodeInPlace([]byte("SGFsbA=="))), "Hall")
	check(string(util.Base64DecodeString("SGFsbG8", nil)), "Hallo")
	check(string(util.Base64DecodeInPlace([]byte("SGFsbG8"))), "Hallo")
	check(string(util.Base64DecodeString("SGFsbA=", nil)), "Hall")
	check(string(util.Base64DecodeInPlace([]byte("SGFsbA="))), "Hall")
	check(string(util.Base64DecodeString("SGFsbG8===", nil)), "Hallo")
	check(string(util.Base64DecodeInPlace([]byte("SGFsbG8==="))), "Hallo")
	check(string(util.Base64DecodeString("SGFsbA", nil)), "Hall")
	check(string(util.Base64DecodeInPlace([]byte("SGFsbA"))), "Hall")
	check(string(util.Base64DecodeString("SGFsbG8=", &devnull)), "Hallo")
	check(devnull, 0)
	check(string(util.Base64DecodeString("SGFsbA==", &devnull)), "Hall")
	check(devnull, 0)
	check(string(util.Base64DecodeString("SGFsbA=", &devnull)), "Hall")
	check(devnull, 0)
	check(string(util.Base64DecodeString("SGFsbG8===", &devnull)), "Hallo")
	check(devnull, 0)
	check(string(util.Base64DecodeString("AA", nil)), "\000")
	check(string(util.Base64DecodeInPlace([]byte("AA"))), "\000")
	check(string(util.Base64DecodeString("AAA", nil)), "\000\000")
	check(string(util.Base64DecodeInPlace([]byte("AAA"))), "\000\000")
	var zerocarry int
	check(string(util.Base64DecodeString("AA", &zerocarry)), "")
	check(zerocarry != 0, true)
	check(string(util.Base64DecodeString("=", &zerocarry)), "\000")
	check(zerocarry, 0)
	check(string(util.Base64DecodeString("AAA", &zerocarry)), "")
	check(zerocarry != 0, true)
	check(string(util.Base64DecodeString("=", &zerocarry)), "\000\000")
	check(zerocarry, 0)

	testbuf := make([]byte, 1024)
	for i := range testbuf {
		testbuf[i] = byte(i)
	}

	error_list := ""
	for length := 0; length <= 12; length++ {
		for eq := 0; eq <= 4; eq++ {
			for err := 0; err <= 12; err++ {
				b64_1 := base64.StdEncoding.EncodeToString(testbuf[0 : 512-length])

				testslice := b64_1[0:]
				errors := []int{0}
				for e := 0; e < err; e++ {
					errors = append(errors, errors[e]+rand.Intn(len(testslice)-errors[e]))
				}
				errors = append(errors, len(testslice))
				teststr := ""
				for i := 0; i < len(errors)-1; i++ {
					if i != 0 {
						teststr = teststr + "\000\n"
					}
					teststr = teststr + testslice[errors[i]:errors[i+1]]
				}

				for i := 0; i < eq; i++ {
					teststr += "="
				}
				// because we're concatenating we need at least 1 "=" if the
				// first string ends in an incomplete block
				if eq == 0 && (length&3) != 0 {
					teststr += "="
				}

				b64_2 := base64.URLEncoding.EncodeToString(testbuf[512-length:])

				testslice = b64_2[0:]
				errors = []int{0}
				for e := 0; e < err; e++ {
					errors = append(errors, errors[e]+rand.Intn(len(testslice)-errors[e]))
				}
				errors = append(errors, len(testslice))
				for i := 0; i < len(errors)-1; i++ {
					if i != 0 {
						teststr = teststr + " "
					}
					teststr = teststr + testslice[errors[i]:errors[i+1]]
				}

				for i := 0; i < eq; i++ {
					teststr += "="
				}

				for parts := 0; parts < 5; parts++ {
					stops := []int{0}
					for e := 0; e < parts; e++ {
						stops = append(stops, stops[e]+rand.Intn(len(teststr)-stops[e]))
					}
					stops = append(stops, len(teststr))

					decoded := ""
					carry := 0
					for i := 0; i < len(stops)-1; i++ {
						decoded += string(util.Base64DecodeString(teststr[stops[i]:stops[i+1]], &carry))
					}

					if decoded != string(testbuf) {
						error_list += fmt.Sprintf("(util.Base64DecodeString() failed for length=%v eq=%v err=%v parts=%v)\n", length, eq, err, parts)
					}

					buffy := []byte(string(teststr))
					decbuffy := util.Base64DecodeInPlace(buffy)
					if &(decbuffy[0]) != &(buffy[0]) || // verify the in-place property
						string(decbuffy) != string(testbuf) {
						error_list += fmt.Sprintf("(util.Base64DecodeInPlace() failed for length=%v eq=%v err=%v parts=%v)\n", length, eq, err, parts)
					}
				}
			}
		}
	}

	check(error_list, "")

	buffy := make([]byte, 1024)
	st := "Nehmt, esst. Dies ist mein Leib - sprach der Schokohase"
	copy(buffy[32:], st)
	result := util.Base64EncodeInPlace(buffy[:32+len(st)], 32)
	check(&(buffy[0]) == &(result[0]), true)
	check(cap(result), cap(buffy))
	check(string(result), "TmVobXQsIGVzc3QuIERpZXMgaXN0IG1laW4gTGVpYiAtIHNwcmFjaCBkZXIgU2Nob2tvaGFzZQ==")

	st = "Nehmt, esst. Dies ist mein Leib - sprach der Schokohase\n"
	copy(buffy[256:], st)
	result = util.Base64EncodeInPlace(buffy[:256+len(st)], 256)
	check(&(buffy[0]) == &(result[0]), true)
	check(cap(result), cap(buffy))
	check(string(result), "TmVobXQsIGVzc3QuIERpZXMgaXN0IG1laW4gTGVpYiAtIHNwcmFjaCBkZXIgU2Nob2tvaGFzZQo=")

	for n := 0; n <= 12; n++ {
		buffy = make([]byte, n)
		for i := range buffy {
			buffy[i] = byte(i)
		}
		check(string(util.Base64EncodeString(string(buffy))), base64.StdEncoding.EncodeToString(buffy))
	}
}