stream.go
changeset 82 7ce2432dd66a
parent 81 a74e7fc4ecee
child 83 a264cb0129e2
equal deleted inserted replaced
81:a74e7fc4ecee 82:7ce2432dd66a
     9 // those events to the client.
     9 // those events to the client.
    10 
    10 
    11 package xmpp
    11 package xmpp
    12 
    12 
    13 import (
    13 import (
       
    14 	"bytes"
    14 	"crypto/md5"
    15 	"crypto/md5"
    15 	"crypto/rand"
    16 	"crypto/rand"
    16 	"crypto/tls"
    17 	"crypto/tls"
    17 	"encoding/base64"
    18 	"encoding/base64"
    18 	"encoding/xml"
    19 	"encoding/xml"
   396 		cl.bind(fe.Bind)
   397 		cl.bind(fe.Bind)
   397 		return
   398 		return
   398 	}
   399 	}
   399 }
   400 }
   400 
   401 
       
   402 // BUG(cjyar): Server certificate is not checked against the provided
       
   403 // hostname.
       
   404 
   401 // readTransport() is running concurrently. We need to stop it,
   405 // readTransport() is running concurrently. We need to stop it,
   402 // negotiate TLS, then start it again. It calls waitForSocket() in
   406 // negotiate TLS, then start it again. It calls waitForSocket() in
   403 // its inner loop; see below.
   407 // its inner loop; see below.
   404 func (cl *Client) handleTls(t *starttls) {
   408 func (cl *Client) handleTls(t *starttls) {
   405 	tcp := cl.socket
   409 	tcp := cl.socket
   428 	}
   432 	}
   429 	cl.Features = nil
   433 	cl.Features = nil
   430 
   434 
   431 	// Now re-send the initial handshake message to start the new
   435 	// Now re-send the initial handshake message to start the new
   432 	// session.
   436 	// session.
   433 		hsOut := openStream()
   437 	hsOut := openStream(&cl.Jid)
   434 	cl.xmlOut <- hsOut
   438 	cl.xmlOut <- hsOut
   435 }
   439 }
   436 
   440 
   437 // Synchronize with handleTls(). Called from readTransport() when
   441 // Synchronize with handleTls(). Called from readTransport() when
   438 // cl.socket is nil.
   442 // cl.socket is nil.
   447 
   451 
   448 	// Signal that we're going back to the read loop.
   452 	// Signal that we're going back to the read loop.
   449 	cl.socketSync.Done()
   453 	cl.socketSync.Done()
   450 }
   454 }
   451 
   455 
   452 // BUG(cjyar): Doesn't implement TLS/SASL EXTERNAL.
       
   453 func (cl *Client) chooseSasl(fe *Features) {
   456 func (cl *Client) chooseSasl(fe *Features) {
   454 	var digestMd5 bool
   457 	var digestMd5, external bool
   455 	for _, m := range fe.Mechanisms.Mechanism {
   458 	for _, m := range fe.Mechanisms.Mechanism {
   456 		switch strings.ToLower(m) {
   459 		switch strings.ToLower(m) {
   457 		case "digest-md5":
   460 		case "digest-md5":
   458 			digestMd5 = true
   461 			digestMd5 = true
   459 		}
   462 		case "external":
   460 	}
   463 			external = true
   461 
   464 		}
   462 	if digestMd5 {
   465 	}
       
   466 
       
   467 	if external {
       
   468 		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local:
       
   469 				"auth"}, Mechanism: "EXTERNAL"}
       
   470 		cl.xmlOut <- auth
       
   471 	} else if digestMd5 {
   463 		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"}, Mechanism: "DIGEST-MD5"}
   472 		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"}, Mechanism: "DIGEST-MD5"}
   464 		cl.xmlOut <- auth
   473 		cl.xmlOut <- auth
       
   474 	} else {
       
   475 		if Log != nil {
       
   476 			buf := bytes.NewBuffer(nil)
       
   477 			xml.Marshal(buf, fe)
       
   478 			Log.Printf("No supported mechanisms: %s",
       
   479 				buf.String())
       
   480 		}
       
   481 		abort := Generic{XMLName: xml.Name{Local: "abort",
       
   482 			Space: NsSASL}}
       
   483 		cl.xmlOut <- abort
       
   484 		se := streamError{Any: Generic{XMLName:
       
   485 				xml.Name{Local: "undefined-condition",
       
   486 				Space: NsStreams}}, Text:
       
   487 			&errText{Lang: "en", Text: "No supported mechs"}}
       
   488 		cl.xmlOut <- se
       
   489 		close(cl.xmlOut)
   465 	}
   490 	}
   466 }
   491 }
   467 
   492 
   468 func (cl *Client) handleSasl(srv *auth) {
   493 func (cl *Client) handleSasl(srv *auth) {
   469 	switch strings.ToLower(srv.XMLName.Local) {
   494 	switch strings.ToLower(srv.XMLName.Local) {
   491 	case "success":
   516 	case "success":
   492 		if Log != nil && Loglevel >= syslog.LOG_INFO {
   517 		if Log != nil && Loglevel >= syslog.LOG_INFO {
   493 			Log.Println("Sasl authentication succeeded")
   518 			Log.Println("Sasl authentication succeeded")
   494 		}
   519 		}
   495 		cl.Features = nil
   520 		cl.Features = nil
   496 		cl.xmlOut <- openStream(cl.Jid)
   521 		cl.xmlOut <- openStream(&cl.Jid)
   497 	}
   522 	}
   498 }
   523 }
   499 
   524 
   500 func (cl *Client) saslDigest1(srvMap map[string]string) {
   525 func (cl *Client) saslDigest1(srvMap map[string]string) {
   501 	// Make sure it supports qop=auth
   526 	// Make sure it supports qop=auth
   522 	nonce := srvMap["nonce"]
   547 	nonce := srvMap["nonce"]
   523 	digestUri := "xmpp/" + cl.Jid.Domain
   548 	digestUri := "xmpp/" + cl.Jid.Domain
   524 	nonceCount := int32(1)
   549 	nonceCount := int32(1)
   525 	nonceCountStr := fmt.Sprintf("%08x", nonceCount)
   550 	nonceCountStr := fmt.Sprintf("%08x", nonceCount)
   526 
   551 
   527 	// Begin building the response. Username is
   552 	// Begin building the response. Username is user (with no
   528 	// user@domain or just domain.
   553 	// @domain) or just domain.
   529 	var username string
   554 	var username string
   530 	if cl.Jid.Node == "" {
   555 	if cl.Jid.Node == "" {
   531 		username = cl.Jid.Domain
   556 		username = cl.Jid.Domain
   532 	} else {
   557 	} else {
   533 		username = cl.Jid.Node
   558 		username = cl.Jid.Node