Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package smtp
  5. import (
  6. "crypto/hmac"
  7. "crypto/md5"
  8. "errors"
  9. "fmt"
  10. )
  11. // Auth is implemented by an SMTP authentication mechanism.
  12. type Auth interface {
  13. // Start begins an authentication with a server.
  14. // It returns the name of the authentication protocol
  15. // and optionally data to include in the initial AUTH message
  16. // sent to the server. It can return proto == "" to indicate
  17. // that the authentication should be skipped.
  18. // If it returns a non-nil error, the SMTP client aborts
  19. // the authentication attempt and closes the connection.
  20. Start(server *ServerInfo) (proto string, toServer []byte, err error)
  21. // Next continues the authentication. The server has just sent
  22. // the fromServer data. If more is true, the server expects a
  23. // response, which Next should return as toServer; otherwise
  24. // Next should return toServer == nil.
  25. // If Next returns a non-nil error, the SMTP client aborts
  26. // the authentication attempt and closes the connection.
  27. Next(fromServer []byte, more bool) (toServer []byte, err error)
  28. }
  29. // ServerInfo records information about an SMTP server.
  30. type ServerInfo struct {
  31. Name string // SMTP server name
  32. TLS bool // using TLS, with valid certificate for Name
  33. Auth []string // advertised authentication mechanisms
  34. }
  35. type plainAuth struct {
  36. identity, username, password string
  37. host string
  38. }
  39. // PlainAuth returns an Auth that implements the PLAIN authentication
  40. // mechanism as defined in RFC 4616. The returned Auth uses the given
  41. // username and password to authenticate to host and act as identity.
  42. // Usually identity should be the empty string, to act as username.
  43. //
  44. // PlainAuth will only send the credentials if the connection is using TLS
  45. // or is connected to localhost. Otherwise authentication will fail with an
  46. // error, without sending the credentials.
  47. func PlainAuth(identity, username, password, host string) Auth {
  48. return &plainAuth{identity, username, password, host}
  49. }
  50. func isLocalhost(name string) bool {
  51. return name == "localhost" || name == "127.0.0.1" || name == "::1"
  52. }
  53. func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
  54. // Must have TLS, or else localhost server.
  55. // Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo.
  56. // In particular, it doesn't matter if the server advertises PLAIN auth.
  57. // That might just be the attacker saying
  58. // "it's ok, you can trust me with your password."
  59. if !server.TLS && !isLocalhost(server.Name) {
  60. return "", nil, errors.New("unencrypted connection")
  61. }
  62. if server.Name != a.host {
  63. return "", nil, errors.New("wrong host name")
  64. }
  65. resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
  66. return "PLAIN", resp, nil
  67. }
  68. func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) {
  69. if more {
  70. // We've already sent everything.
  71. return nil, errors.New("unexpected server challenge")
  72. }
  73. return nil, nil
  74. }
  75. type cramMD5Auth struct {
  76. username, secret string
  77. }
  78. // CRAMMD5Auth returns an Auth that implements the CRAM-MD5 authentication
  79. // mechanism as defined in RFC 2195.
  80. // The returned Auth uses the given username and secret to authenticate
  81. // to the server using the challenge-response mechanism.
  82. func CRAMMD5Auth(username, secret string) Auth {
  83. return &cramMD5Auth{username, secret}
  84. }
  85. func (a *cramMD5Auth) Start(server *ServerInfo) (string, []byte, error) {
  86. return "CRAM-MD5", nil, nil
  87. }
  88. func (a *cramMD5Auth) Next(fromServer []byte, more bool) ([]byte, error) {
  89. if more {
  90. d := hmac.New(md5.New, []byte(a.secret))
  91. d.Write(fromServer)
  92. s := make([]byte, 0, d.Size())
  93. return []byte(fmt.Sprintf("%s %x", a.username, d.Sum(s))), nil
  94. }
  95. return nil, nil
  96. }