Просмотр исходного кода

update deltachat-core to 0.32.0 (a8a3c533e7572e76e22b659e7832601f4aae3aa4)

dignifiedquire 6 лет назад
Родитель
Сommit
9748e8373b
100 измененных файлов с 36785 добавлено и 1182 удалено
  1. 7 7
      Pods/MessageKit/Sources/Controllers/MessagesViewController+Keyboard.swift
  2. 4 4
      Pods/MessageKit/Sources/Controllers/MessagesViewController+Menu.swift
  3. 4 4
      Pods/MessageKit/Sources/Controllers/MessagesViewController.swift
  4. 1 1
      Pods/MessageKit/Sources/Layout/MessagesCollectionViewFlowLayout.swift
  5. 1 1
      Pods/MessageKit/Sources/Models/MessageKitDateFormatter.swift
  6. 1 1
      Pods/MessageKit/Sources/Models/MessageStyle.swift
  7. 2 2
      Pods/MessageKit/Sources/Protocols/MessagesDisplayDelegate.swift
  8. 1 1
      Pods/MessageKit/Sources/Views/AvatarView.swift
  9. 2 2
      Pods/MessageKit/Sources/Views/Cells/LocationMessageCell.swift
  10. 1 1
      Pods/MessageKit/Sources/Views/InputBarItem.swift
  11. 1 1
      Pods/MessageKit/Sources/Views/InputStackView.swift
  12. 7 7
      Pods/MessageKit/Sources/Views/InputTextView.swift
  13. 1 1
      Pods/MessageKit/Sources/Views/InsetLabel.swift
  14. 9 9
      Pods/MessageKit/Sources/Views/MessageInputBar.swift
  15. 13 13
      Pods/MessageKit/Sources/Views/MessageLabel.swift
  16. 4 4
      Pods/MessageKit/Sources/Views/MessagesCollectionView.swift
  17. 1 1
      Pods/MessageKit/Sources/Views/PlayButtonView.swift
  18. 15 11
      Pods/Pods.xcodeproj/project.pbxproj
  19. 23 5
      deltachat-ios.xcodeproj/project.pbxproj
  20. 23 8
      deltachat-ios/ChatViewController.swift
  21. 1 1
      deltachat-ios/Wrapper.swift
  22. 40 0
      deltachat-ios/libraries/deltachat-core/.scripts/deploy.sh
  23. 66 0
      deltachat-ios/libraries/deltachat-core/.travis.yml
  24. 136 0
      deltachat-ios/libraries/deltachat-core/CHANGELOG.md
  25. 378 621
      deltachat-ios/libraries/deltachat-core/LICENSE
  26. 116 72
      deltachat-ios/libraries/deltachat-core/README.md
  27. 0 172
      deltachat-ios/libraries/deltachat-core/cmdline/SNIPPETS.txt
  28. 75 90
      deltachat-ios/libraries/deltachat-core/cmdline/cmdline.c
  29. 0 22
      deltachat-ios/libraries/deltachat-core/cmdline/cmdline.h
  30. 104 40
      deltachat-ios/libraries/deltachat-core/cmdline/main.c
  31. 1 2
      deltachat-ios/libraries/deltachat-core/cmdline/meson.build
  32. 144 25
      deltachat-ios/libraries/deltachat-core/cmdline/stress.c
  33. 0 22
      deltachat-ios/libraries/deltachat-core/cmdline/stress.h
  34. 7 4
      deltachat-ios/libraries/deltachat-core/deltachat-core.cbp
  35. 3 3
      deltachat-ios/libraries/deltachat-core/docs/Doxyfile
  36. 2 3
      deltachat-ios/libraries/deltachat-core/docs/README.md
  37. BIN
      deltachat-ios/libraries/deltachat-core/docs/logo.png
  38. 23 0
      deltachat-ios/libraries/deltachat-core/docs/release-checklist.md
  39. 0 21
      deltachat-ios/libraries/deltachat-core/docs/update.sh
  40. 9 0
      deltachat-ios/libraries/deltachat-core/libs/README.md
  41. 48 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/AUTHORS
  42. 44 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/COPYING
  43. 3440 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/ChangeLog
  44. 302 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/INSTALL
  45. 1 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/INSTALL.TXT
  46. 503 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/NEWS
  47. 21 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/README
  48. 65 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/Makefile.am
  49. 65 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/NTMakefile
  50. 607 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/config.h
  51. 118 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/exits.h
  52. 108 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/gai.h
  53. 59 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/hmac-md5.h
  54. 246 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/makemd5.c
  55. 42 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/md5.h
  56. 38 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/md5global.h
  57. 186 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/prop.h
  58. 1321 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/sasl.h
  59. 986 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/saslplug.h
  60. 99 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/saslutil.h
  61. 104 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/Makefile.am
  62. 128 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/NTMakefile
  63. 1198 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/auxprop.c
  64. 462 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/canonusr.c
  65. 1097 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/checkpw.c
  66. 1349 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/client.c
  67. 2622 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/common.c
  68. 168 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/config.c
  69. 562 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/dlopen.c
  70. 410 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/external.c
  71. 254 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/getaddrinfo.c
  72. 108 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/getnameinfo.c
  73. 114 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/getsubopt.c
  74. 527 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/md5.c
  75. 528 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/saslint.h
  76. 812 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/saslutil.c
  77. 2398 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/server.c
  78. 263 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/seterror.c
  79. 784 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/snprintf.c
  80. 184 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/staticopen.h
  81. 330 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/windlopen.c
  82. 93 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/meson.build
  83. 6 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/meson_options.txt
  84. 158 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/Makefile.am
  85. 325 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/NTMakefile
  86. 390 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/anonymous.c
  87. 43 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/anonymous_init.c
  88. 689 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/cram.c
  89. 43 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/crammd5_init.c
  90. 4655 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/digestmd5.c
  91. 43 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/digestmd5_init.c
  92. 1851 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2.c
  93. 43 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2_init.c
  94. 324 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2_token.c
  95. 58 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2_token.h
  96. 2076 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gssapi.c
  97. 43 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gssapiv2_init.c
  98. 1406 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/kerberos4.c
  99. 43 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/kerberos4_init.c
  100. 569 0
      deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/ldapdb.c

+ 7 - 7
Pods/MessageKit/Sources/Controllers/MessagesViewController+Keyboard.swift

@@ -29,15 +29,15 @@ extension MessagesViewController {
     // MARK: - Register / Unregister Observers
 
     internal func addKeyboardObservers() {
-        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleKeyboardDidChangeState(_:)), name: .UIKeyboardWillChangeFrame, object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleTextViewDidBeginEditing(_:)), name: .UITextViewTextDidBeginEditing, object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.adjustScrollViewInset), name: .UIDeviceOrientationDidChange, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleKeyboardDidChangeState(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleTextViewDidBeginEditing(_:)), name: UITextView.textDidBeginEditingNotification, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.adjustScrollViewInset), name: UIDevice.orientationDidChangeNotification, object: nil)
     }
 
     internal func removeKeyboardObservers() {
-        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillChangeFrame, object: nil)
-        NotificationCenter.default.removeObserver(self, name: .UITextViewTextDidBeginEditing, object: nil)
-        NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
     }
 
     // MARK: - Notification Handlers
@@ -52,7 +52,7 @@ extension MessagesViewController {
 
     @objc
     private func handleKeyboardDidChangeState(_ notification: Notification) {
-        guard let keyboardEndFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return }
+        guard let keyboardEndFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
         
         guard !isMessagesControllerBeingDismissed else { return }
         

+ 4 - 4
Pods/MessageKit/Sources/Controllers/MessagesViewController+Menu.swift

@@ -29,11 +29,11 @@ extension MessagesViewController {
     // MARK: - Register / Unregister Observers
 
     internal func addMenuControllerObservers() {
-        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.menuControllerWillShow(_:)), name: .UIMenuControllerWillShowMenu, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.menuControllerWillShow(_:)), name: UIMenuController.willShowMenuNotification, object: nil)
     }
 
     internal func removeMenuControllerObservers() {
-        NotificationCenter.default.removeObserver(self, name: .UIMenuControllerWillShowMenu, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UIMenuController.willShowMenuNotification, object: nil)
     }
 
     // MARK: - Notification Handlers
@@ -45,11 +45,11 @@ extension MessagesViewController {
         guard let currentMenuController = notification.object as? UIMenuController,
             let selectedIndexPath = selectedIndexPathForMenu else { return }
 
-        NotificationCenter.default.removeObserver(self, name: .UIMenuControllerWillShowMenu, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UIMenuController.willShowMenuNotification, object: nil)
         defer {
             NotificationCenter.default.addObserver(self,
                                                    selector: #selector(MessagesViewController.menuControllerWillShow(_:)),
-                                                   name: .UIMenuControllerWillShowMenu, object: nil)
+                                                   name: UIMenuController.willShowMenuNotification, object: nil)
             selectedIndexPathForMenu = nil
         }
 

+ 4 - 4
Pods/MessageKit/Sources/Controllers/MessagesViewController.swift

@@ -205,9 +205,9 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
         }
 
         switch kind {
-        case UICollectionElementKindSectionHeader:
+        case UICollectionView.elementKindSectionHeader:
             return displayDelegate.messageHeaderView(for: indexPath, in: messagesCollectionView)
-        case UICollectionElementKindSectionFooter:
+        case UICollectionView.elementKindSectionFooter:
             return displayDelegate.messageFooterView(for: indexPath, in: messagesCollectionView)
         default:
             fatalError(MessageKitError.unrecognizedSectionKind)
@@ -282,11 +282,11 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
     
     private func addObservers() {
         NotificationCenter.default.addObserver(
-            self, selector: #selector(clearMemoryCache), name: .UIApplicationDidReceiveMemoryWarning, object: nil)
+            self, selector: #selector(clearMemoryCache), name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
     }
     
     private func removeObservers() {
-        NotificationCenter.default.removeObserver(self, name: .UIApplicationDidReceiveMemoryWarning, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
     }
     
     @objc private func clearMemoryCache() {

+ 1 - 1
Pods/MessageKit/Sources/Layout/MessagesCollectionViewFlowLayout.swift

@@ -69,7 +69,7 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
 
         sectionInset = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
 
-        NotificationCenter.default.addObserver(self, selector: #selector(MessagesCollectionViewFlowLayout.handleOrientationChange(_:)), name: .UIDeviceOrientationDidChange, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(MessagesCollectionViewFlowLayout.handleOrientationChange(_:)), name: UIDevice.orientationDidChangeNotification, object: nil)
     }
 
     required public init?(coder aDecoder: NSCoder) {

+ 1 - 1
Pods/MessageKit/Sources/Models/MessageKitDateFormatter.swift

@@ -43,7 +43,7 @@ open class MessageKitDateFormatter {
         return formatter.string(from: date)
     }
 
-    public func attributedString(from date: Date, with attributes: [NSAttributedStringKey: Any]) -> NSAttributedString {
+    public func attributedString(from date: Date, with attributes: [NSAttributedString.Key: Any]) -> NSAttributedString {
         let dateString = string(from: date)
         return NSAttributedString(string: dateString, attributes: attributes)
     }

+ 1 - 1
Pods/MessageKit/Sources/Models/MessageStyle.swift

@@ -35,7 +35,7 @@ public enum MessageStyle {
         case topRight
         case bottomRight
 
-        internal var imageOrientation: UIImageOrientation {
+        internal var imageOrientation: UIImage.Orientation {
             switch self {
             case .bottomRight: return .up
             case .bottomLeft: return .upMirrored

+ 2 - 2
Pods/MessageKit/Sources/Protocols/MessagesDisplayDelegate.swift

@@ -118,7 +118,7 @@ public protocol MessagesDisplayDelegate: AnyObject {
     ///   - detector: The `DetectorType` for the applied attributes.
     ///   - message: A `MessageType` with a `MessageKind` case of `.text` or `.attributedText` to which the detectors will apply.
     ///   - indexPath: The `IndexPath` of the cell.
-    func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedStringKey: Any]
+    func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedString.Key: Any]
 
     // MARK: - Location Messages
 
@@ -207,7 +207,7 @@ public extension MessagesDisplayDelegate {
         return []
     }
 
-    func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedStringKey: Any] {
+    func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedString.Key: Any] {
         return MessageLabel.defaultAttributes
     }
 

+ 1 - 1
Pods/MessageKit/Sources/Views/AvatarView.swift

@@ -105,7 +105,7 @@ open class AvatarView: UIImageView {
 
         let textStyle = NSMutableParagraphStyle()
         textStyle.alignment = .center
-        let textFontAttributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: placeholderTextColor, NSAttributedStringKey.paragraphStyle: textStyle]
+        let textFontAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: placeholderTextColor, NSAttributedString.Key.paragraphStyle: textStyle]
 
         let textTextHeight: CGFloat = initials.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height
         context.saveGState()

+ 2 - 2
Pods/MessageKit/Sources/Views/Cells/LocationMessageCell.swift

@@ -29,7 +29,7 @@ import MapKit
 open class LocationMessageCell: MessageContentCell {
 
     /// The activity indicator to be displayed while the map image is loading.
-    open var activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
+    open var activityIndicator = UIActivityIndicatorView(style: .gray)
 
     /// The image view holding the map image.
     open var imageView = UIImageView()
@@ -68,7 +68,7 @@ open class LocationMessageCell: MessageContentCell {
 
         activityIndicator.startAnimating()
 
-        let snapshotOptions = MKMapSnapshotOptions()
+        let snapshotOptions = MKMapSnapshotter.Options()
         snapshotOptions.region = MKCoordinateRegion(center: locationItem.location.coordinate, span: options.span)
         snapshotOptions.showsBuildings = options.showsBuildings
         snapshotOptions.showsPointsOfInterest = options.showsPointsOfInterest

+ 1 - 1
Pods/MessageKit/Sources/Views/InputBarItem.swift

@@ -309,7 +309,7 @@ open class InputBarButtonItem: UIButton {
     // MARK: - Static Spacers
     
     /// An InputBarButtonItem that's spacing property is set to be .flexible
-    open static var flexibleSpace: InputBarButtonItem {
+    public static var flexibleSpace: InputBarButtonItem {
         let item = InputBarButtonItem()
         item.setSize(.zero, animated: false)
         item.spacing = .flexible

+ 1 - 1
Pods/MessageKit/Sources/Views/InputStackView.swift

@@ -46,7 +46,7 @@ open class InputStackView: UIStackView {
     
     // MARK: Initialization
     
-    public convenience init(axis: UILayoutConstraintAxis, spacing: CGFloat) {
+    public convenience init(axis: NSLayoutConstraint.Axis, spacing: CGFloat) {
         self.init(frame: .zero)
         self.axis = axis
         self.spacing = spacing

+ 7 - 7
Pods/MessageKit/Sources/Views/InputTextView.swift

@@ -63,7 +63,7 @@ open class InputTextView: UITextView {
     open var isImagePasteEnabled: Bool = true
     
     /// A UILabel that holds the InputTextView's placeholder text
-    open let placeholderLabel: UILabel = {
+    public let placeholderLabel: UILabel = {
         let label = UILabel()
         label.numberOfLines = 0
         label.textColor = .lightGray
@@ -190,7 +190,7 @@ open class InputTextView: UITextView {
         
         NotificationCenter.default.addObserver(self,
                                                selector: #selector(InputTextView.redrawTextAttachments),
-                                               name: .UIDeviceOrientationDidChange, object: nil)
+                                               name: UIDevice.orientationDidChangeNotification, object: nil)
     }
     
     /// Updates the placeholderLabels constraint constants to match the placeholderLabelInsets
@@ -205,7 +205,7 @@ open class InputTextView: UITextView {
     // MARK: - Notification
     
     private func postTextViewDidChangeNotification() {
-        NotificationCenter.default.post(name: .UITextViewTextDidChange, object: self)
+        NotificationCenter.default.post(name: UITextView.textDidChangeNotification, object: self)
     }
     
     // MARK: - Image Paste Support
@@ -244,9 +244,9 @@ open class InputTextView: UITextView {
         newAttributedStingComponent.append(NSAttributedString(string: "\n"))
         
         // The attributes that should be applied to the new NSAttributedString to match the current attributes
-        let attributes: [NSAttributedStringKey: Any] = [
-            NSAttributedStringKey.font: font ?? UIFont.preferredFont(forTextStyle: .body),
-            NSAttributedStringKey.foregroundColor: textColor ?? .black
+        let attributes: [NSAttributedString.Key: Any] = [
+            NSAttributedString.Key.font: font ?? UIFont.preferredFont(forTextStyle: .body),
+            NSAttributedString.Key.foregroundColor: textColor ?? .black
             ]
         newAttributedStingComponent.addAttributes(attributes, range: NSRange(location: 0, length: newAttributedStingComponent.length))
         
@@ -260,7 +260,7 @@ open class InputTextView: UITextView {
         selectedRange = NSRange(location: location, length: 0)
     
         // Broadcast a notification to recievers such as the MessageInputBar which will handle resizing
-        NotificationCenter.default.post(name: .UITextViewTextDidChange, object: self)
+        NotificationCenter.default.post(name: UITextView.textDidChangeNotification, object: self)
     }
     
     /// Returns an NSTextAttachment the provided image that will fit inside the NSTextContainer

+ 1 - 1
Pods/MessageKit/Sources/Views/InsetLabel.swift

@@ -31,7 +31,7 @@ open class InsetLabel: UILabel {
     }
 
     open override func drawText(in rect: CGRect) {
-        let insetRect = UIEdgeInsetsInsetRect(rect, textInsets)
+        let insetRect = rect.inset(by: textInsets)
         super.drawText(in: insetRect)
     }
 

+ 9 - 9
Pods/MessageKit/Sources/Views/MessageInputBar.swift

@@ -76,7 +76,7 @@ open class MessageInputBar: UIView {
     }
     
     /// A SeparatorLine that is anchored at the top of the MessageInputBar with a height of 1
-    open let separatorLine = SeparatorLine()
+    public let separatorLine = SeparatorLine()
     
     /**
      The InputStackView at the InputStackView.top position
@@ -85,7 +85,7 @@ open class MessageInputBar: UIView {
      1. It's axis is initially set to .vertical
      2. It's alignment is initially set to .fill
      */
-    open let topStackView: InputStackView = {
+    public let topStackView: InputStackView = {
         let stackView = InputStackView(axis: .vertical, spacing: 0)
         stackView.alignment = .fill
         return stackView
@@ -97,7 +97,7 @@ open class MessageInputBar: UIView {
      ## Important Notes ##
      1. It's axis is initially set to .horizontal
      */
-    open let leftStackView = InputStackView(axis: .horizontal, spacing: 0)
+    public let leftStackView = InputStackView(axis: .horizontal, spacing: 0)
     
     /**
      The InputStackView at the InputStackView.right position
@@ -105,7 +105,7 @@ open class MessageInputBar: UIView {
      ## Important Notes ##
      1. It's axis is initially set to .horizontal
      */
-    open let rightStackView = InputStackView(axis: .horizontal, spacing: 0)
+    public let rightStackView = InputStackView(axis: .horizontal, spacing: 0)
     
     /**
      The InputStackView at the InputStackView.bottom position
@@ -114,7 +114,7 @@ open class MessageInputBar: UIView {
      1. It's axis is initially set to .horizontal
      2. It's spacing is initially set to 15
      */
-    open let bottomStackView = InputStackView(axis: .horizontal, spacing: 15)
+    public let bottomStackView = InputStackView(axis: .horizontal, spacing: 15)
     
     /// The InputTextView a user can input a message in
     open lazy var inputTextView: InputTextView = {
@@ -312,13 +312,13 @@ open class MessageInputBar: UIView {
         
         NotificationCenter.default.addObserver(self,
                                                selector: #selector(MessageInputBar.textViewDidChange),
-                                               name: .UITextViewTextDidChange, object: inputTextView)
+                                               name: UITextView.textDidChangeNotification, object: inputTextView)
         NotificationCenter.default.addObserver(self,
                                                selector: #selector(MessageInputBar.textViewDidBeginEditing),
-                                               name: .UITextViewTextDidBeginEditing, object: inputTextView)
+                                               name: UITextView.textDidBeginEditingNotification, object: inputTextView)
         NotificationCenter.default.addObserver(self,
                                                selector: #selector(MessageInputBar.textViewDidEndEditing),
-                                               name: .UITextViewTextDidEndEditing, object: inputTextView)
+                                               name: UITextView.textDidEndEditingNotification, object: inputTextView)
     }
     
     /// Adds all of the subviews
@@ -412,7 +412,7 @@ open class MessageInputBar: UIView {
             guard UIScreen.main.nativeBounds.height == 2436 else { return }
             if let window = window {
                 windowAnchor?.isActive = false
-                windowAnchor = contentView.bottomAnchor.constraintLessThanOrEqualToSystemSpacingBelow(window.safeAreaLayoutGuide.bottomAnchor, multiplier: 1)
+                windowAnchor = contentView.bottomAnchor.constraint(lessThanOrEqualToSystemSpacingBelow: window.safeAreaLayoutGuide.bottomAnchor, multiplier: 1)
                 windowAnchor?.constant = -padding.bottom
                 windowAnchor?.priority = UILayoutPriority(rawValue: 750)
                 windowAnchor?.isActive = true

+ 13 - 13
Pods/MessageKit/Sources/Views/MessageLabel.swift

@@ -117,25 +117,25 @@ open class MessageLabel: UILabel {
 
     private var attributesNeedUpdate = false
 
-    public static var defaultAttributes: [NSAttributedStringKey: Any] = {
+    public static var defaultAttributes: [NSAttributedString.Key: Any] = {
         return [
-            NSAttributedStringKey.foregroundColor: UIColor.darkText,
-            NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue,
-            NSAttributedStringKey.underlineColor: UIColor.darkText
+            NSAttributedString.Key.foregroundColor: UIColor.darkText,
+            NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue,
+            NSAttributedString.Key.underlineColor: UIColor.darkText
         ]
     }()
 
-    open internal(set) var addressAttributes: [NSAttributedStringKey: Any] = defaultAttributes
+    open internal(set) var addressAttributes: [NSAttributedString.Key: Any] = defaultAttributes
 
-    open internal(set) var dateAttributes: [NSAttributedStringKey: Any] = defaultAttributes
+    open internal(set) var dateAttributes: [NSAttributedString.Key: Any] = defaultAttributes
 
-    open internal(set) var phoneNumberAttributes: [NSAttributedStringKey: Any] = defaultAttributes
+    open internal(set) var phoneNumberAttributes: [NSAttributedString.Key: Any] = defaultAttributes
 
-    open internal(set) var urlAttributes: [NSAttributedStringKey: Any] = defaultAttributes
+    open internal(set) var urlAttributes: [NSAttributedString.Key: Any] = defaultAttributes
     
-    open internal(set) var transitInformationAttributes: [NSAttributedStringKey: Any] = defaultAttributes
+    open internal(set) var transitInformationAttributes: [NSAttributedString.Key: Any] = defaultAttributes
 
-    public func setAttributes(_ attributes: [NSAttributedStringKey: Any], detector: DetectorType) {
+    public func setAttributes(_ attributes: [NSAttributedString.Key: Any], detector: DetectorType) {
         switch detector {
         case .phoneNumber:
             phoneNumberAttributes = attributes
@@ -171,7 +171,7 @@ open class MessageLabel: UILabel {
 
     open override func drawText(in rect: CGRect) {
 
-        let insetRect = UIEdgeInsetsInsetRect(rect, textInsets)
+        let insetRect = rect.inset(by: textInsets)
         textContainer.size = CGSize(width: insetRect.width, height: rect.height)
 
         let origin = insetRect.origin
@@ -263,7 +263,7 @@ open class MessageLabel: UILabel {
         }
     }
 
-    private func detectorAttributes(for detectorType: DetectorType) -> [NSAttributedStringKey: Any] {
+    private func detectorAttributes(for detectorType: DetectorType) -> [NSAttributedString.Key: Any] {
 
         switch detectorType {
         case .address:
@@ -280,7 +280,7 @@ open class MessageLabel: UILabel {
 
     }
 
-    private func detectorAttributes(for checkingResultType: NSTextCheckingResult.CheckingType) -> [NSAttributedStringKey: Any] {
+    private func detectorAttributes(for checkingResultType: NSTextCheckingResult.CheckingType) -> [NSAttributedString.Key: Any] {
         switch checkingResultType {
         case .address:
             return addressAttributes

+ 4 - 4
Pods/MessageKit/Sources/Views/MessagesCollectionView.swift

@@ -65,8 +65,8 @@ open class MessagesCollectionView: UICollectionView {
         register(TextMessageCell.self)
         register(MediaMessageCell.self)
         register(LocationMessageCell.self)
-        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader)
-        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter)
+        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader)
+        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter)
     }
     
     private func setupGestureRecognizers() {
@@ -133,7 +133,7 @@ open class MessagesCollectionView: UICollectionView {
 
     /// Generically dequeues a header of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
     public func dequeueReusableHeaderView<T: UICollectionReusableView>(_ viewClass: T.Type, for indexPath: IndexPath) -> T {
-        let view = dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: String(describing: T.self), for: indexPath)
+        let view = dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: String(describing: T.self), for: indexPath)
         guard let viewType = view as? T else {
             fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(String(describing: T.self))")
         }
@@ -142,7 +142,7 @@ open class MessagesCollectionView: UICollectionView {
 
     /// Generically dequeues a footer of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
     public func dequeueReusableFooterView<T: UICollectionReusableView>(_ viewClass: T.Type, for indexPath: IndexPath) -> T {
-        let view = dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: String(describing: T.self), for: indexPath)
+        let view = dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: String(describing: T.self), for: indexPath)
         guard let viewType = view as? T else {
             fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(String(describing: T.self))")
         }

+ 1 - 1
Pods/MessageKit/Sources/Views/PlayButtonView.swift

@@ -28,7 +28,7 @@ open class PlayButtonView: UIView {
 
     // MARK: - Properties
 
-    open let triangleView = UIView()
+    public let triangleView = UIView()
 
     private var triangleCenterXConstraint: NSLayoutConstraint?
     private var cacheFrame: CGRect = .zero

+ 15 - 11
Pods/Pods.xcodeproj/project.pbxproj

@@ -3,7 +3,7 @@
 	archiveVersion = 1;
 	classes = {
 	};
-	objectVersion = 48;
+	objectVersion = 46;
 	objects = {
 
 /* Begin PBXBuildFile section */
@@ -156,7 +156,7 @@
 		752607C53B782FEDB730DF8C28BE30FA /* buffer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = buffer.h; path = opensslIncludes/openssl/buffer.h; sourceTree = "<group>"; };
 		756A57CC49BAE0C5D3614FB107B3C555 /* Pods-deltachat-ios-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-deltachat-ios-frameworks.sh"; sourceTree = "<group>"; };
 		75937D2ED93565773D091329E4BEEC39 /* cast.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = cast.h; path = opensslIncludes/openssl/cast.h; sourceTree = "<group>"; };
-		75A94351D2191958479B156D019624ED /* Pods_deltachat_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_deltachat_ios.framework; path = "Pods-deltachat-ios.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+		75A94351D2191958479B156D019624ED /* Pods_deltachat_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_deltachat_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		77BFCDBCCD9988431D09A2867C83CC6D /* kssl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = kssl.h; path = opensslIncludes/openssl/kssl.h; sourceTree = "<group>"; };
 		78BA79B24D7D3E923B65BDEB1C7097B6 /* MessageInputBarDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MessageInputBarDelegate.swift; path = Sources/Protocols/MessageInputBarDelegate.swift; sourceTree = "<group>"; };
 		7AA664D2FF7A7858AF14A6BE8C2CD40E /* aes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = aes.h; path = opensslIncludes/openssl/aes.h; sourceTree = "<group>"; };
@@ -170,10 +170,10 @@
 		8655BEF30E1DE72EAF670E821F92AEBF /* MessageKit.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MessageKit.modulemap; sourceTree = "<group>"; };
 		873F0064CC07C18ADDBC078592004241 /* MediaItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MediaItem.swift; path = Sources/Protocols/MediaItem.swift; sourceTree = "<group>"; };
 		8BE747517D7C957DD8A9DF9B4045D7E4 /* rand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = rand.h; path = opensslIncludes/openssl/rand.h; sourceTree = "<group>"; };
-		8CE3B99EA5F5EF0CDA1AF942D824C8C8 /* MessageKitAssets.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = MessageKitAssets.bundle; path = "MessageKit-MessageKitAssets.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
+		8CE3B99EA5F5EF0CDA1AF942D824C8C8 /* MessageKitAssets.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MessageKitAssets.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
 		8D558540E34072F6CE829EE45147C6E6 /* LocationMessageCell.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LocationMessageCell.swift; path = Sources/Views/Cells/LocationMessageCell.swift; sourceTree = "<group>"; };
 		8FF3053F586F77496940DFC57819C061 /* ecdsa.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ecdsa.h; path = opensslIncludes/openssl/ecdsa.h; sourceTree = "<group>"; };
-		93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
+		93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
 		9538E95F86220B69EA9E5DA8C641C640 /* ssl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ssl.h; path = opensslIncludes/openssl/ssl.h; sourceTree = "<group>"; };
 		9560E6E6DBD8C9CE67667F7455DAF160 /* seed.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = seed.h; path = opensslIncludes/openssl/seed.h; sourceTree = "<group>"; };
 		9792E2AA8D29DF31F5FC7A469E029A08 /* lhash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lhash.h; path = opensslIncludes/openssl/lhash.h; sourceTree = "<group>"; };
@@ -219,7 +219,7 @@
 		D2C6430CE04EE991F3B36175FCEBDF5F /* cmac.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = cmac.h; path = opensslIncludes/openssl/cmac.h; sourceTree = "<group>"; };
 		D419476EA4A3C99BB714FFEF382703F8 /* dh.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = dh.h; path = opensslIncludes/openssl/dh.h; sourceTree = "<group>"; };
 		D47E09627B3BA6FF604F331EBB00779C /* bio.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bio.h; path = opensslIncludes/openssl/bio.h; sourceTree = "<group>"; };
-		DB210F2617C91BE19ACAFC8B28EFFCE0 /* Images */ = {isa = PBXFileReference; includeInIndex = 1; name = Images; path = Assets/MessageKitAssets.bundle/Images; sourceTree = "<group>"; };
+		DB210F2617C91BE19ACAFC8B28EFFCE0 /* Images */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder; name = Images; path = Assets/MessageKitAssets.bundle/Images; sourceTree = "<group>"; };
 		DC50E236DF4CC99910B1389F06F6ADAC /* libcrypto.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libcrypto.a; path = lib/libcrypto.a; sourceTree = "<group>"; };
 		DE323A84B5DF687EE686DD2A9F605338 /* hmac.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = hmac.h; path = opensslIncludes/openssl/hmac.h; sourceTree = "<group>"; };
 		E046138CB860AA13C60DA07BF0C23F17 /* libssl.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libssl.a; path = lib/libssl.a; sourceTree = "<group>"; };
@@ -234,7 +234,7 @@
 		EABA7A22F98D7625193D9D65ED567EEE /* MessagesDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MessagesDataSource.swift; path = Sources/Protocols/MessagesDataSource.swift; sourceTree = "<group>"; };
 		EDEB9B0B07723F2B401C8B8314E2A1A8 /* comp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = comp.h; path = opensslIncludes/openssl/comp.h; sourceTree = "<group>"; };
 		EE846444A54DEFD38EB50752AA4EE52F /* ocsp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ocsp.h; path = opensslIncludes/openssl/ocsp.h; sourceTree = "<group>"; };
-		F10CE7D6533BF029BD0A556B8CB7C8AD /* MessageKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = MessageKit.framework; path = MessageKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		F10CE7D6533BF029BD0A556B8CB7C8AD /* MessageKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MessageKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		F2728A8E0297A65F4AE45C4E2079D488 /* MessageKit-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MessageKit-umbrella.h"; sourceTree = "<group>"; };
 		F27B6EC43C60472B9B8450EEBB427AF4 /* MessagesViewController+Menu.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "MessagesViewController+Menu.swift"; path = "Sources/Controllers/MessagesViewController+Menu.swift"; sourceTree = "<group>"; };
 		F3C71D33F69CC82E0824B6C945B7A028 /* LocationMessageSizeCalculator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LocationMessageSizeCalculator.swift; path = Sources/Layout/LocationMessageSizeCalculator.swift; sourceTree = "<group>"; };
@@ -378,7 +378,6 @@
 				26C04DC4E9D5A64ECAB35FFFD854552D /* Resources */,
 				97FA7C3FFBD96A14F717045EEF8129D6 /* Support Files */,
 			);
-			name = MessageKit;
 			path = MessageKit;
 			sourceTree = "<group>";
 		};
@@ -494,7 +493,6 @@
 				0BF5400C86DE6670D3E7CEB496B9D437 /* x509v3.h */,
 				BAD97EA68E223E8F269F7C799574ADFE /* Frameworks */,
 			);
-			name = "openssl-ios-bitcode";
 			path = "openssl-ios-bitcode";
 			sourceTree = "<group>";
 		};
@@ -607,7 +605,12 @@
 			isa = PBXProject;
 			attributes = {
 				LastSwiftUpdateCheck = 0930;
-				LastUpgradeCheck = 0930;
+				LastUpgradeCheck = 1010;
+				TargetAttributes = {
+					9FF7D45F060B1C2B29487F13C7CC8EA9 = {
+						LastSwiftMigration = 1010;
+					};
+				};
 			};
 			buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -797,6 +800,7 @@
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				STRIP_INSTALLED_PRODUCT = NO;
+				SWIFT_COMPILATION_MODE = wholemodule;
 				SYMROOT = "${SRCROOT}/../build";
 			};
 			name = Release;
@@ -862,7 +866,7 @@
 				SKIP_INSTALL = YES;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
 				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
-				SWIFT_VERSION = 4.0;
+				SWIFT_VERSION = 4.2;
 				TARGETED_DEVICE_FAMILY = "1,2";
 				VALIDATE_PRODUCT = YES;
 				VERSIONING_SYSTEM = "apple-generic";
@@ -911,7 +915,7 @@
 				SKIP_INSTALL = YES;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
-				SWIFT_VERSION = 4.0;
+				SWIFT_VERSION = 4.2;
 				TARGETED_DEVICE_FAMILY = "1,2";
 				VERSIONING_SYSTEM = "apple-generic";
 				VERSION_INFO_PREFIX = "";

+ 23 - 5
deltachat-ios.xcodeproj/project.pbxproj

@@ -29,7 +29,6 @@
 		7070FB6C20FF345F000DC258 /* dc_keyring.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB5120FF345D000DC258 /* dc_keyring.c */; };
 		7070FB6D20FF345F000DC258 /* dc_imex.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB5220FF345D000DC258 /* dc_imex.c */; };
 		7070FB6E20FF345F000DC258 /* dc_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB5320FF345D000DC258 /* dc_openssl.c */; };
-		7070FB6F20FF345F000DC258 /* dc_uudecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB5420FF345D000DC258 /* dc_uudecode.c */; };
 		7070FB7020FF345F000DC258 /* dc_lot.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB5520FF345D000DC258 /* dc_lot.c */; };
 		7070FB7120FF345F000DC258 /* dc_receive_imf.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB5620FF345D000DC258 /* dc_receive_imf.c */; };
 		7070FB7220FF345F000DC258 /* dc_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB5720FF345E000DC258 /* dc_key.c */; };
@@ -52,6 +51,10 @@
 		7092474120B3869500AF8799 /* ContactProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7092474020B3869500AF8799 /* ContactProfileViewController.swift */; };
 		70B08FCD21073B910097D3EA /* NewGroupMemberChoiceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B08FCC21073B910097D3EA /* NewGroupMemberChoiceController.swift */; };
 		70B8882E2091B8550074812E /* ContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B8882D2091B8550074812E /* ContactCell.swift */; };
+		78E45E2921D176C400D4B15E /* dc_jobthread.h in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E2821D176C300D4B15E /* dc_jobthread.h */; };
+		78E45E2B21D176FB00D4B15E /* dc_jobthread.c in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E2A21D176FB00D4B15E /* dc_jobthread.c */; };
+		78E45E2F21D1774200D4B15E /* dc_context.h in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E2D21D1774200D4B15E /* dc_context.h */; };
+		78E45E3021D1774200D4B15E /* dc_move.c in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E2E21D1774200D4B15E /* dc_move.c */; };
 		7A0052A11FBC50C40048C3BF /* CredentialsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0052A01FBC50C40048C3BF /* CredentialsController.swift */; };
 		7A0052C81FBE6CB40048C3BF /* NewContactController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0052C71FBE6CB40048C3BF /* NewContactController.swift */; };
 		7A451D941FB1B1DB00177250 /* wrapper.c in Sources */ = {isa = PBXBuildFile; fileRef = 7A451D921FB1B1DB00177250 /* wrapper.c */; };
@@ -165,6 +168,12 @@
 		7092474020B3869500AF8799 /* ContactProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactProfileViewController.swift; sourceTree = "<group>"; };
 		70B08FCC21073B910097D3EA /* NewGroupMemberChoiceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGroupMemberChoiceController.swift; sourceTree = "<group>"; };
 		70B8882D2091B8550074812E /* ContactCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactCell.swift; sourceTree = "<group>"; };
+		78E45E2121D1768900D4B15E /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = "deltachat-ios/libraries/deltachat-core/src"; sourceTree = "<group>"; };
+		78E45E2821D176C300D4B15E /* dc_jobthread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dc_jobthread.h; path = "deltachat-ios/libraries/deltachat-core/src/dc_jobthread.h"; sourceTree = "<group>"; };
+		78E45E2A21D176FB00D4B15E /* dc_jobthread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dc_jobthread.c; path = "deltachat-ios/libraries/deltachat-core/src/dc_jobthread.c"; sourceTree = "<group>"; };
+		78E45E2C21D1774200D4B15E /* dc_context.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dc_context.c; path = "deltachat-ios/libraries/deltachat-core/src/dc_context.c"; sourceTree = "<group>"; };
+		78E45E2D21D1774200D4B15E /* dc_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dc_context.h; path = "deltachat-ios/libraries/deltachat-core/src/dc_context.h"; sourceTree = "<group>"; };
+		78E45E2E21D1774200D4B15E /* dc_move.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dc_move.c; path = "deltachat-ios/libraries/deltachat-core/src/dc_move.c"; sourceTree = "<group>"; };
 		7A0052A01FBC50C40048C3BF /* CredentialsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsController.swift; sourceTree = "<group>"; };
 		7A0052C71FBE6CB40048C3BF /* NewContactController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewContactController.swift; sourceTree = "<group>"; };
 		7A451D921FB1B1DB00177250 /* wrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wrapper.c; sourceTree = "<group>"; };
@@ -331,6 +340,12 @@
 		7A9FB1371FB061E2001FEA36 = {
 			isa = PBXGroup;
 			children = (
+				78E45E2C21D1774200D4B15E /* dc_context.c */,
+				78E45E2D21D1774200D4B15E /* dc_context.h */,
+				78E45E2E21D1774200D4B15E /* dc_move.c */,
+				78E45E2A21D176FB00D4B15E /* dc_jobthread.c */,
+				78E45E2821D176C300D4B15E /* dc_jobthread.h */,
+				78E45E2121D1768900D4B15E /* src */,
 				7A451D9A1FB1F4BF00177250 /* libetpan.xcodeproj */,
 				7A9FB1421FB061E2001FEA36 /* deltachat-ios */,
 				7A9FB1411FB061E2001FEA36 /* Products */,
@@ -606,6 +621,11 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				7070FB6320FF345F000DC258 /* dc_context.c in Sources */,
+				78E45E2F21D1774200D4B15E /* dc_context.h in Sources */,
+				78E45E3021D1774200D4B15E /* dc_move.c in Sources */,
+				78E45E2B21D176FB00D4B15E /* dc_jobthread.c in Sources */,
+				78E45E2921D176C400D4B15E /* dc_jobthread.h in Sources */,
 				7A79236E1FB0A2C800BC2DE5 /* misc.c in Sources */,
 				AEACE2E91FB34D9100DCDD78 /* ContactViewController.swift in Sources */,
 				7A0052A11FBC50C40048C3BF /* CredentialsController.swift in Sources */,
@@ -628,7 +648,6 @@
 				7A7923721FB0A2C800BC2DE5 /* reader.c in Sources */,
 				7070FB9220FF4118000DC258 /* dc_imap.c in Sources */,
 				7070FB3D20FDD9FE000DC258 /* NewGroupViewController.swift in Sources */,
-				7070FB6320FF345F000DC258 /* dc_context.c in Sources */,
 				7070FB7720FF345F000DC258 /* dc_qr.c in Sources */,
 				7A7923701FB0A2C800BC2DE5 /* packet-parse.c in Sources */,
 				70B08FCD21073B910097D3EA /* NewGroupMemberChoiceController.swift in Sources */,
@@ -645,7 +664,6 @@
 				7070FB6920FF345F000DC258 /* dc_mimeparser.c in Sources */,
 				7A0052C81FBE6CB40048C3BF /* NewContactController.swift in Sources */,
 				7070FB6020FF345F000DC258 /* dc_hash.c in Sources */,
-				7070FB6F20FF345F000DC258 /* dc_uudecode.c in Sources */,
 				AEACE2DD1FB323CA00DCDD78 /* ChatViewController.swift in Sources */,
 				7070FB4020FF3421000DC258 /* dc_chat.c in Sources */,
 				7070FB7320FF345F000DC258 /* dc_aheader.c in Sources */,
@@ -813,7 +831,7 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				DEVELOPMENT_TEAM = 9M4M75R59J;
+				DEVELOPMENT_TEAM = EEQW58QXHC;
 				HEADER_SEARCH_PATHS = "deltachat-ios/libraries/deltachat-core/libs/netpgp/include";
 				INFOPLIST_FILE = "deltachat-ios/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
@@ -839,7 +857,7 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				DEVELOPMENT_TEAM = 9M4M75R59J;
+				DEVELOPMENT_TEAM = EEQW58QXHC;
 				HEADER_SEARCH_PATHS = "deltachat-ios/libraries/deltachat-core/libs/netpgp/include";
 				INFOPLIST_FILE = "deltachat-ios/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 11.0;

+ 23 - 8
deltachat-ios/ChatViewController.swift

@@ -33,11 +33,13 @@ class ChatViewController: MessagesViewController {
     }
     
     var textDraft:String? {
-        let chat = MRChat(id: chatId)
         // FIXME: need to free pointer
-        if let textDraft = dc_chat_get_text_draft(chat.chatPointer) {
-            let s = String(validatingUTF8: textDraft)!
-            return s
+        if let draft = dc_get_draft(mailboxPointer, UInt32(chatId)) {
+            if let text = dc_msg_get_text(draft) {
+                let s = String(validatingUTF8: text)!
+                return s
+            }
+            return nil
         }
         return nil
     }
@@ -84,7 +86,12 @@ class ChatViewController: MessagesViewController {
     
     func setTextDraft() {
         if let text = self.messageInputBar.inputTextView.text {
-            dc_set_text_draft(mailboxPointer, UInt32(chatId), text.cString(using: .utf8))
+            let draft = dc_msg_new(mailboxPointer, DC_MSG_TEXT)
+            dc_msg_set_text(draft, text.cString(using: .utf8))
+            dc_set_draft(mailboxPointer, UInt32(chatId), draft)
+            
+            // cleanup
+            dc_msg_unref(draft)
         }
     }
     
@@ -385,10 +392,12 @@ extension ChatViewController: MessagesLayoutDelegate {
     }
     
     @objc func didPressPhotoButton() {
+        // TODO: don't panic in simulator, when the camera is not available
         let imagePicker = UIImagePickerController()
-        imagePicker.delegate = self
         imagePicker.sourceType = .camera
         imagePicker.cameraDevice = .rear
+        imagePicker.delegate = self
+        imagePicker.allowsEditing = true
         self.present(imagePicker, animated: true, completion: nil)
     }
     
@@ -434,7 +443,13 @@ extension ChatViewController: UIImagePickerControllerDelegate, UINavigationContr
                 let width = Int32(exactly: pickedImage.size.width),
                 let height = Int32(exactly: pickedImage.size.height),
                 let path = self.saveImage(image: pickedImage) {
-                dc_send_image_msg(mailboxPointer, UInt32(self.chatId), path, "image/jpeg", width, height)
+                let msg = dc_msg_new(mailboxPointer, DC_MSG_IMAGE)
+                dc_msg_set_file(msg, path, "image/jpeg")
+                dc_msg_set_dimension(msg, width, height)
+                dc_send_msg(mailboxPointer, UInt32(self.chatId), msg)
+                
+                // cleanup
+                dc_msg_unref(msg)
             }
         }
         
@@ -455,7 +470,7 @@ extension ChatViewController: MessageCellDelegate {
     
     }
     
-    func didTapTopLabel(in cell: MessageCollectionViewCell) {
+    @objc(didTapCellTopLabelIn:) func didTapCellTopLabel(in cell: MessageCollectionViewCell) {
         print("Top label tapped")
     }
 

+ 1 - 1
deltachat-ios/Wrapper.swift

@@ -74,7 +74,7 @@ class MRMessage {
     
     lazy var image: UIImage? = { [unowned self] in
         guard let documents = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) else { return nil }
-        let filetype = dc_msg_get_type(messagePointer)
+        let filetype = dc_msg_get_viewtype(messagePointer)
         let file = dc_msg_get_filename(messagePointer)
         if let cFile = file, filetype == DC_MSG_IMAGE {
             let filename = String(cString: cFile)

+ 40 - 0
deltachat-ios/libraries/deltachat-core/.scripts/deploy.sh

@@ -0,0 +1,40 @@
+#!/bin/bash
+
+set -e
+set -u
+set -x
+set -v
+
+
+#Only attempt to deploy if we know the ssh key secrets, username and server
+if test -z ${encrypted_49475b8073e9_key:+decryp_key} ; then exit 0; fi
+if test -z ${encrypted_49475b8073e9_iv:+decrypt_iv} ; then exit 0; fi
+if test -z ${DEPLOY_USER:+username} ; then exit 0; fi
+if test -z ${DEPLOY_SERVER:+server} ; then exit 0; fi
+
+# Prepare the ssh homedir.
+#
+# Decrypting the ssh private key for deploying to the server.
+# See https://docs.travis-ci.com/user/encrypting-files/ for details.
+mkdir -p -m 0700 ~/.ssh
+openssl aes-256-cbc \
+  -K $encrypted_49475b8073e9_key \
+  -iv $encrypted_49475b8073e9_iv \
+  -in $TRAVIS_BUILD_DIR/.credentials/delta.id_rsa.enc \
+  -out ~/.ssh/id_rsa -d
+chmod 600 ~/.ssh/id_rsa
+printf "Host *\n" >> ~/.ssh/config
+printf " %sAuthentication no\n" ChallengeResponse Password KbdInteractive >> ~/.ssh/config
+
+
+# Perform the actual deploy to py.delta.chat
+rsync -avz \
+  -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
+  $TRAVIS_BUILD_DIR/python/doc/_build/html/ \
+  ${DEPLOY_USER}@${DEPLOY_SERVER}:build/${TRAVIS_BRANCH/\//_}
+
+# Perform the actual deploy to c.delta.chat
+rsync -avz \
+  -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
+  $TRAVIS_BUILD_DIR/docs/html/ \
+  ${DEPLOY_USER}@${DEPLOY_SERVER}:build-c/${TRAVIS_BRANCH/\//_}

+ 66 - 0
deltachat-ios/libraries/deltachat-core/.travis.yml

@@ -0,0 +1,66 @@
+sudo: required
+language: c
+
+env:
+  global:
+    - DEPLOY_USER=delta DEPLOY_SERVER="py.delta.chat"
+
+  matrix:
+    - MESONARGS="" DOCS=t TESTS=t
+    - MESONARGS="-Dmonolith=true" TESTS=t
+    - MESONARGS="--default-library=static"
+    - MESONARGS="--wrap-mode=forcefallback --default-library=static"
+
+addons:
+  apt:
+    sources:
+    - ubuntu-toolchain-r-test
+    # for newer doxygen: - sourceline: 'ppa:libreoffice/ppa'
+    packages:
+    - python3-pip
+    - python3.5
+    - g++-7
+    - libssl-dev
+    - libsqlite3-dev
+    - libbz2-dev
+    - zlib1g-dev
+    - python3.5-dev
+    - python-software-properties
+    - doxygen
+
+install:
+  - export CC=gcc-7
+  - export CXX=g++-7
+  - sudo ln -sf /usr/bin/python3.5 /usr/bin/python3
+  - sudo pip3 install meson
+  - wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip
+  - unzip ninja-linux.zip
+  - sudo cp ninja /usr/bin
+  - wget http://http.debian.net/debian/pool/main/c/cyrus-sasl2/cyrus-sasl2_2.1.27~101-g0780600+dfsg.orig.tar.xz
+  - tar xfv cyrus-sasl2_2.1.27~101-g0780600+dfsg.orig.tar.xz
+  - pushd cyrus-sasl2-2.1.27~101-g0780600+dfsg.orig && ./autogen.sh && make && sudo make install && popd
+
+script:
+  - doxygen --version
+  - mkdir -p builddir && pushd builddir
+  - meson $MESONARGS && ninja -v && sudo ninja install
+  - export LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
+  - sudo ldconfig -v
+  - popd && pushd docs
+  - if [ -n "$DOCS" ]; then doxygen; fi
+  - popd && pushd python
+  - virtualenv -p /usr/bin/python3.5 venv
+  - source venv/bin/activate
+  - pip install tox
+  - if [ -e /usr/local/lib/x86_64-linux-gnu/libdeltachat.so ]; then ldd /usr/local/lib/x86_64-linux-gnu/libdeltachat.so; fi
+  - if [ -n "$TESTS" ]; then tox; fi
+  - if [ -n "$DOCS" ]; then tox -e doc; fi
+  - popd
+
+deploy:
+  provider: script
+  skip_cleanup: true
+  script: bash $TRAVIS_BUILD_DIR/.scripts/deploy.sh
+  on:
+    all_branches: true
+    condition: $DOCS

+ 136 - 0
deltachat-ios/libraries/deltachat-core/CHANGELOG.md

@@ -0,0 +1,136 @@
+# API changes
+
+This file mainly documents changes in the API of deltachat-core.
+
+For a full list of changes in deltachat-core, please have a look at the commits at
+https://github.com/deltachat/deltachat-core/commits/master
+
+For a high-level overview about changes anywhere in the Delta Chat ecosystem,
+see https://delta.chat/en/changelog
+
+## v0.32.0
+
+* add function to add a thread watching the Send folder
+* add config-options inbox_watch and sendbox_watch
+* move chat messages from inbox/sent to DeltaChat folder
+
+The changes have been done by Björn Petersen and Holger Krekel
+
+## v0.31.1
+2018-12-20
+
+* bugfix release
+
+## v0.31.0
+
+* add config-options mvbox_watch and mvbox_move
+* remove config-options imap_folder, mvbox_enabled
+
+The changes have been done by Björn Petersen and Holger Krekel,
+Lars-Magnus Skog
+
+## v0.30.0
+
+* the core can second folder simultanous to the INBOX now;
+  for this purposes, users shoud create a 3rd thread calling
+  the new functions dc_perform_mvbox_fetch() and dc_perform_mvbox_idle()
+* add config-option mvbox_enabled
+
+The changes have been done by Björn Petersen and Holger Krekel
+
+## v0.29.0
+
+* add dc_chat_get_color() and dc_contact_get_color()
+
+The changes have been done by Björn Petersen
+
+## v0.28.0
+
+* allow any messages as drafts
+* enhance profile image api, add dc_contact_get_profile_image()
+* dc_msg_get_filemime() returns the mimetype for incoming messages
+
+The changes have been done by Björn Petersen, Holger Krekel,
+Lars-Magnus Skog
+
+## v0.27.0
+
+* use '...' as the subject-fallback-text
+* empty messages are returned as such
+* build improvements, bug fixes
+
+The changes have been done by Björn Petersen, Floris Bruynooghe,
+Holger Krekel, Lars-Magnus Skog
+
+## v0.26.1
+2018-11-23
+
+* bugfix release
+
+## v0.26.0
+2018-11-18
+
+* remove DC_EVENT_IS_OFFLINE
+* remove error code from DC_EVENT_ERROR
+* add DC_EVENT_ERROR_SELF_NOT_IN_GROUP
+* add flag to DC_EVENT_ERROR_NETWORK to differ between first/subsequent errors
+* block concurrent calls to dc_configure()
+
+The changes have been done by Björn Petersen, Holger Krekel, Lars-Magnus Skog
+
+## v0.25.1
+2018-11-14
+
+* bugfix release
+
+The changes have been done by Björn Petersen, Lars-Magnus Skog
+
+## v0.25.0
+2018-11-12
+
+* use a single folder for all incoming and outgoing messages;
+  defaults to INBOX and can be configured using
+  dc_set_config(context, "imap_folder", folder)
+* dc_set_config() and dc_get_config() check for correct key
+* new function dc_maybe_network() to trigger jobs (as sending messages)
+  and bypass the new exponential backoff algorithm
+
+The changes have been done by Azul, Björn Petersen, Borys Piddubnyi,
+Floris Bruynooghe, Holger Krekel, Stefan Strogin
+
+## v0.24.1
+2018-11-01
+
+* Re-licensed files in src, doc, cmdline and python directories to MPL 2.0. 
+  For confirmations from contributors see the thus finalized issue
+  https://github.com/deltachat/deltachat-core/issues/403.
+
+## v0.24.0
+2018-10-29
+
+* removed DC_EVENT_GET_QUANTITY_STRING
+* added quantity parameter to DC_EVENT_GET_STRING
+
+## v0.23.0
+2018-10-17
+
+* add dc_get_received_timestamp()
+* dc_send_X_msg() functions removed in favor to dc_send_msg()
+* removed deprcated mrmailbox.h
+
+
+## v0.22.0
+2018-10-11
+
+* dc_send_msg() creates a copy of passed files before returning
+* the event DC_EVENT_FILE_COPIED is no longer used
+
+
+## v0.21.0
+2018-10-11
+
+* default parameter removed from dc_get_config().
+  if the requested value was not set before, 
+  the core returns an appropriate default value on its own.
+* messages of all types can contain text now;
+  use dc_msg_get_text() to check.

+ 378 - 621
deltachat-ios/libraries/deltachat-core/LICENSE

@@ -1,624 +1,381 @@
 
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     END OF TERMS AND CONDITIONS
+The files in this directory and under the "src", "python", "doc" and "cmdline" subdirectories
+are (c) 2018 by Bjoern Petersen and contributors and released under the 
+Mozilla Public License Version 2.0, see below for a copy. 
+
+NOTE that the files in the "libs" directory are copyrighted by third parties 
+and come with their own respective licenses. 
 
+Mozilla Public License Version 2.0
+==================================
 
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in 
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.

+ 116 - 72
deltachat-ios/libraries/deltachat-core/README.md

@@ -1,71 +1,84 @@
-Delta Chat Core Library
-================================================================================
+# Delta Chat Core Library
 
-You can use the _Delta Chat Core Library_ to build **your own messenger** or
-plugin that is completely **compatible** with the existing email infrastructure.
+[![Build Status](https://travis-ci.org/deltachat/deltachat-core.svg?branch=master)](https://travis-ci.org/deltachat/deltachat-core)
 
-![Logo](https://delta.chat/assets/features/start-img4.png)
+The _Delta Chat Core Library_ is written in cross-platform **C**,
+documented at <https://c.delta.chat>.  
 
-Using this library in your app, you get the **ease** of well-known messengers
-with the **reach** of email. Moreover, you're **independent** from other companies or
-services as your data is not relayed through Delta Chat, only your email
-provider. That means that there are no Delta Chat servers, only clients made compatible via Delta Chat Core.
+The ``deltachat`` Python bindings can be found in the 
+[python subdirectory](https://github.com/deltachat/deltachat-core/tree/master/python)
+and are documented at <https://py.delta.chat>.
 
-The library is used eg. in the [Delta Chat Android Frontend](https://github.com/deltachat/deltachat-android)
-and in the [Delta Chat iOS Frontend](https://github.com/deltachat/deltachat-ios), but can also be used for
-completely different messenger projects.
+## binary/distribution packages  (work-in-progress)
 
-Some features at a glance:
+There are work-in-progress efforts for creating (binary) packages which
+do not require that you build the library manually:
 
-- **Secure** with automatic end-to-end-encryption, supporting the new
-  [Autocrypt](https://autocrypt.org/) standard
-- **Fast** by the use of Push-IMAP
-- **Read receipts**
-- **Largest userbase** - recipients _not_ using Delta Chat can be reached as well
-- **Compatible** - not only to itself
-- **Elegant** and **simple** user interface
-- **Distributed** system
-- **No Spam** - only messages of known users are shown by default
-- **Reliable** - safe for professional use
-- **Trustworthy** - can even be used for business messages
-- **Libre software** and [standards-based](https://delta.chat/en/standards)
+- [libdeltachat-core-git archlinux package](https://aur.archlinux.org/packages/libdeltachat-core-git/>)
 
+- [Debian packaging](https://github.com/deltachat/deltachat-core/issues/299)
 
-API Documentation
---------------------------------------------------------------------------------
+- [Windows building](https://github.com/deltachat/deltachat-core/issues/306)
 
-The C-API is documented at <https://deltachat.github.io/api/>.
+If you can help with advancing or adding to these efforts, be our guest. 
+Otherwise read on for how to get ``libdeltachat.so`` and ``deltachat.h``
+installed into your system. 
 
-Please keep in mind, that your derived work must be released under a
-GPL-compatible licence.  For details, please have a look at the [LICENSE file](https://github.com/deltachat/deltachat-core/blob/master/LICENSE) accompanying the source code.
+## building your own ``libdeltachat.so``
 
+### getting a recent enough ``meson`` for building 
 
-Build
---------------------------------------------------------------------------------
+If you have installed ``meson`` in your environment check the version::
 
-Delta Chat Core can be built as a library using the
-[meson](http://mesonbuild.com) build system. It depends on a number
-of external libraries, most of which are detected using
+    meson --version
+   
+You need to have version ``0.47.2`` at least. If the version
+is older there is a recommended way of getting a better version:
+
+1. uninstall your system-level ``meson`` package (if possible)
+
+2. ensure you have at least ``python3.5`` installed and type:
+   ```
+       python3 -m pip 
+   ```
+
+   to check that you have "pip" installed. If not available, you
+   might get it as a ``python3-pip`` package or you could follow
+   [installing pip](https://pip.pypa.io/en/stable/installing/).
+
+3. then pip-install meson into your home-directory:
+   ```
+       python3 -u -m pip install meson
+   ```
+
+   the ``-u`` causes the pip-install to put a ``meson`` command line tool into
+   ``~/.local/`` or %APPDATA%\Python on Windows.  
+
+4. run ``meson --version`` to verify it's at at least version 0.48.0 now.
+   If the ``meson`` command is not found, add ``~/.local/bin`` to ``PATH``
+   and try again (``export PATH=~/.local/bin:$PATH`` on many unix-y terminals).
+
+
+### installing "ninja-build" 
+
+On Linux and Mac you need to install 'ninja-build' (debian package name)
+to be able to actually build/compile things. 
+
+Note that most dependencies below are detected using
 [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/).
-Usually this just works automatically, provided the depending libraries are
-installed correctly.
-
-By default a few stripped-down versions of these libraries are bundled
-with Delta Chat Core and these will be used.  They are marked as
-optional in the list below.  It is possible to use system-provided
-versions of these libraries using a configure option to meson.
-
-Otherwise installing all of these using your system libraries is the
-easiest route.  Please note that you may need "development" packages
-installed for these to work.
-
-- [LibEtPan](https://github.com/dinhviethoa/libetpan); **optional** A
-  stripped-down version of this library is vendored and used by
-  default.  Use the `system-etpan=true` option to use a
-  system-provided version instead.  Note that this does not use
-  pkg-config so the system-provided version will be looked up by using
-  `libetpan-config` which must be in the PATH.  Version 1.8 or newer
-  is required.
+Usually this just works automatically, provided the depending libraries
+are installed correctly.  
+
+### installing c-level dependencies 
+
+The deltachat core library depends on a number of external libraries,
+which you may need to install (we have some fallbacks if you don't):
+
+- [LibEtPan](https://github.com/dinhviethoa/libetpan); Note that this
+  library does not use pkg-config so the system-provided version will
+  be looked up by using `libetpan-config` which must be in the PATH.
+  Version 1.8 or newer is required. LibEtPan must be compiled with
+  SASL support enabled.
 
 - [OpenSSL](https://www.openssl.org/)
 
@@ -73,19 +86,18 @@ installed for these to work.
 
 - [zlib](https://zlib.net)
 
-- libsasl
-
-- [bzip2](http://bzip.org)
+- [libsasl](https://cyrusimap.org/sasl/)
 
-To build you need to have [meson](http://mesonbuild.com) (at least version 0.36.0) and
-[ninja](https://ninja-build.org) installed as well.
+To install these on debian you can type:
+```
+    sudo apt install libetpan-dev libssl-dev libsqlite3-dev libsasl2-dev libbz2-dev zlib1g-dev
+```
 
-On Linux (e.g. Debian Stretch) you can install all these using:
 
-`sudo apt install libetpan-dev libssl-dev libsqlite3-dev libsasl2-dev libbz2-dev zlib1g-dev meson ninja-build`.
+### performing the actual build 
 
 Once all dependencies are installed, creating a build is as follows,
-starting from the project's root directory:
+starting from a [deltachat-core github checkout](https://github.com/deltachat/deltachat-core):
 
 ```
 mkdir builddir
@@ -93,7 +105,7 @@ cd builddir
 meson
 # Optionally configure some other parameters
 # run `meson configure` to see the options, e.g.
-#    meson configure -Dsystem-etpan=true
+#    meson configure --default-library=static
 ninja
 sudo ninja install
 sudo ldconfig
@@ -104,26 +116,58 @@ is thus also supported:
 ```
 sudo ninja uninstall
 ```
-
-Note that the above assumes `/usr/local/lib` is configured somewhere
+**NOTE** that the above assumes `/usr/local/lib` is configured somewhere
 in `/etc/ld.so.conf` or `/etc/ld.so.conf.d/*`, which is fairly
 standard.  It is possible your system uses
 `/usr/local/lib/x86_64-linux-gnu` which should be auto-detected and
 just work as well.
 
 
-Testing program
---------------------------------------------------------------------------------
+### Building without system-level dependencies 
+
+By default stripped-down versions of the dependencies are bundled with
+Delta Chat Core and these will be used when a dependency is missing.
+You can choose to always use the bundled version of the dependencies
+by invoking meson with the `--wrap-mode=forcefallback` option.
+Likewise you can forbid using the bundled dependencies using
+`--wrap-mode=nofallback`.
+
+There also is an experimental feature where you can build a version of the
+shared `libdeltachat.so` library with no further external
+dependencies.  This can be done by passing the `-Dmonolith=true`
+option to meson.  Note that this implies `--wrap-mode=forcefallback`
+since this will always use all the bundled dependencies.
+
+
+## Language bindings and frontend Projects
+
+Language bindings are available for:
+
+- [Node.js](https://www.npmjs.com/package/deltachat-node)
+- [Python](https://py.delta.chat)
+- **Java** and **Swift** (contained in the Android/iOS repos) 
+
+The following "frontend" project make use of the C-library
+or its language bindings: 
+
+- [Android](https://github.com/deltachat/deltachat-android)
+- [iOS](https://github.com/deltachat/deltachat-ios) 
+- [Desktop](https://github.com/deltachat/deltachat-desktop)
+- [Pidgin](https://gitlab.com/lupine/purple-plugin-delta)
+
+## Testing program
 
 After a successful build there is also a little testing program in `builddir/cmdline`.
 You start the program with `./delta <database-file>`
 (if the database file does not exist, it is created).
-The program then shows a promt and typing `help` gives some help about the available commands.
+The program then shows a prompt and typing `help` gives some help about the available commands.
+
+New tests are currently developed using Python, see 
+https://github.com/deltachat/deltachat-core/tree/master/python/tests
 
 
-License
---------------------------------------------------------------------------------
+## License
 
-Licensed under the GPLv3, see LICENSE file for details.
+Licensed under the MPL 2.0 see [LICENSE](./LICENSE) file for details.
 
-Copyright © 2017, 2018 Delta Chat contributors
+Copyright © 2017, 2018 Björn Petersen and Delta Chat contributors.

+ 0 - 172
deltachat-ios/libraries/deltachat-core/cmdline/SNIPPETS.txt

@@ -1,172 +0,0 @@
-/*******************************************************************************
- * Restoring
- ******************************************************************************/
-
-mrimap_t: ...
-	pthread_t             m_restore_thread;
-	int                   m_restore_thread_created;
-	int                   m_restore_do_exit;
-
-
-mrimap_disconnect: ...
-		if( ths->m_restore_thread_created )
-		{
-			mrmailbox_log_info(ths->m_mailbox, 0, "Stopping IMAP-restore-thread...");
-				ths->m_restore_do_exit = 1;
-				pthread_join(ths->m_restore_thread, NULL);
-			mrmailbox_log_info(ths->m_mailbox, 0, "IMAP-restore-thread stopped.");
-		}
-
-static void* restore_thread_entry_point(void* entry_arg)
-{
-	mrimap_t*  ths = (mrimap_t*)entry_arg;
-	mrosnative_setup_thread(ths->m_mailbox); /* must be very first */
-
-	int        r, handle_locked = 0, idle_blocked = 0;
-	clist      *folder_list = NULL, *fetch_result = NULL;
-	clistiter  *folder_iter, *fetch_iter;
-	#define    CHECK_EXIT if( ths->m_restore_do_exit ) { goto exit_; }
-
-	mrmailbox_log_info(ths->m_mailbox, 0, "IMAP-restore-thread started.");
-
-	LOCK_HANDLE
-	BLOCK_IDLE
-		INTERRUPT_IDLE
-		mrmailbox_log_info(ths->m_mailbox, 0, "IMAP-restore-thread gets folders.");
-		if( !setup_handle_if_needed__(ths)
-		 || (folder_list=list_folders__(ths))==NULL ) {
-			goto exit_;
-		}
-	UNBLOCK_IDLE
-	UNLOCK_HANDLE
-
-	for( folder_iter = clist_begin(folder_list); folder_iter != NULL ; folder_iter = clist_next(folder_iter) )
-	{
-		mrimapfolder_t* folder = (mrimapfolder_t*)clist_content(folder_iter);
-
-		CHECK_EXIT
-
-		LOCK_HANDLE
-		BLOCK_IDLE
-			INTERRUPT_IDLE
-			setup_handle_if_needed__(ths);
-			mrmailbox_log_info(ths->m_mailbox, 0, "IMAP-restore-thread gets messages in \"%s\".", folder->m_name_utf8);
-			if( select_folder__(ths, folder->m_name_to_select)
-			 && ths->m_hEtpan->imap_selection_info->sel_has_exists )
-			{
-				/* fetch the last 200 messages by one-based-index. TODO: we should regard the given timespan somehow */
-				int32_t i_last  = ths->m_hEtpan->imap_selection_info->sel_exists;
-				int32_t i_first = MR_MAX(i_last-200, 1);
-
-				struct mailimap_set* set = mailimap_set_new_interval(i_first, i_last);
-					r = mailimap_fetch(ths->m_hEtpan, set, ths->m_fetch_type_uid, &fetch_result); /* execute FETCH from:to command, result includes the given index */
-				mailimap_set_free(set);
-			}
-		UNBLOCK_IDLE
-		UNLOCK_HANDLE
-
-		if( !is_error(ths, r) && fetch_result != NULL )
-		{
-			for( fetch_iter = clist_begin(fetch_result); fetch_iter != NULL ; fetch_iter = clist_next(fetch_iter) )
-			{
-				CHECK_EXIT
-
-				struct mailimap_msg_att* msg_att = (struct mailimap_msg_att*)clist_content(fetch_iter); /* mailimap_msg_att is a list of attributes: list is a list of message attributes */
-				uint32_t cur_uid = peek_uid(msg_att);
-				if( cur_uid )
-				{
-					fetch_single_msg(ths, folder->m_name_to_select, cur_uid, 1);
-				}
-			}
-
-			mailimap_fetch_list_free(fetch_result);
-			fetch_result = NULL;
-		}
-	}
-
-	mrmailbox_log_info(ths->m_mailbox, 0, "IMAP-restore-thread finished.");
-
-exit_:
-	UNBLOCK_IDLE
-	UNLOCK_HANDLE /* needed before the follow lock as the handle may be locked or unlocked when arriving in exit_*/
-
-	if( fetch_result ) {
-		mailimap_fetch_list_free(fetch_result);
-	}
-
-	if( folder_list ) {
-		free_folders(folder_list);
-	}
-
-	LOCK_HANDLE
-		ths->m_restore_thread_created = 0;
-	UNLOCK_HANDLE
-	mrosnative_unsetup_thread(ths->m_mailbox); /* must be very last */
-	return NULL;
-}
-
-
-int mrimap_restore(mrimap_t* ths, time_t seconds_to_restore)
-{
-	int success = 0, handle_locked = 0;
-
-	if( ths==NULL || !ths->m_connected || seconds_to_restore <= 0 ) {
-		goto cleanup;
-	}
-
-	LOCK_HANDLE
-		if( ths->m_restore_thread_created ) {
-			goto cleanup;
-		}
-		ths->m_restore_thread_created = 1;
-		ths->m_restore_do_exit = 0;
-	UNLOCK_HANDLE
-
-	pthread_create(&ths->m_restore_thread, NULL, restore_thread_entry_point, ths);
-
-	success = 1;
-
-cleanup:
-	return success;
-}
-
-
-/* in cmdline ... */
-	else if( strcmp(cmd, "restore")==0 )
-	{
-		if( arg1 ) {
-			int days = atoi(arg1);
-			ret = mrmailbox_restore(mailbox, days*24*60*60)? COMMAND_SUCCEEDED : COMMAND_FAILED;
-		}
-		else {
-			ret = safe_strdup("ERROR: Argument <days> missing.");
-		}
-	}
-	
-/* restore old data from the IMAP server, not really implemented. */
-int mrmailbox_restore(mrmailbox_t* ths, time_t seconds_to_restore)
-{
-	if( ths == NULL ) {
-		return 0;
-	}
-
-	return mrimap_restore(ths->m_imap, seconds_to_restore);
-}
-	
-
-static char* get_file_disposition_suffix_(struct mailmime_disposition* file_disposition)
-{
-	if( file_disposition ) {
-		clistiter* cur;
-		for( cur = clist_begin(file_disposition->dsp_parms); cur != NULL; cur = clist_next(cur) ) {
-			struct mailmime_disposition_parm* dsp_param = (struct mailmime_disposition_parm*)clist_content(cur);
-			if( dsp_param ) {
-				if( dsp_param->pa_type==MAILMIME_DISPOSITION_PARM_FILENAME ) {
-					return mr_get_filesuffix_lc(dsp_param->pa_data.pa_filename);
-				}
-			}
-		}
-	}
-	return NULL;
-}
-

+ 75 - 90
deltachat-ios/libraries/deltachat-core/cmdline/cmdline.c

@@ -1,25 +1,3 @@
-/*******************************************************************************
- *
- *                              Delta Chat Core
- *                      Copyright (C) 2017 Björn Petersen
- *                   Contact: r10s@b44t.com, http://b44t.com
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see http://www.gnu.org/licenses/ .
- *
- ******************************************************************************/
-
-
 /* If you do not want to use dc_cmdline(), this file MAY NOT included to
 your library */
 
@@ -113,7 +91,7 @@ static int dc_poke_eml_file(dc_context_t* context, const char* filename)
 		return 0;
 	}
 
-	if (dc_read_file(filename, (void**)&data, &data_bytes, context) == 0) {
+	if (dc_read_file(context, filename, (void**)&data, &data_bytes) == 0) {
 		goto cleanup;
 	}
 
@@ -265,6 +243,42 @@ cleanup:
 }
 
 
+static void log_msg(dc_context_t* context, const char* prefix, dc_msg_t* msg)
+{
+	dc_contact_t* contact = dc_get_contact(context, dc_msg_get_from_id(msg));
+	char* contact_name = dc_contact_get_name(contact);
+	int contact_id = dc_contact_get_id(contact);
+
+	const char* statestr = "";
+	switch (dc_msg_get_state(msg)) {
+		case DC_STATE_OUT_PENDING:   statestr = " o";   break;
+		case DC_STATE_OUT_DELIVERED: statestr = " √";   break;
+		case DC_STATE_OUT_MDN_RCVD:  statestr = " √√";  break;
+		case DC_STATE_OUT_FAILED:    statestr = " !!";  break;
+	}
+
+	char* temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg));
+	char* msgtext = dc_msg_get_text(msg);
+		dc_log_info(context, 0, "%s#%i%s: %s (Contact#%i): %s %s%s%s%s [%s]",
+			prefix,
+			(int)dc_msg_get_id(msg),
+			dc_msg_get_showpadlock(msg)? "\xF0\x9F\x94\x92" : "",
+			contact_name,
+			contact_id,
+			msgtext,
+			dc_msg_is_starred(msg)? " \xE2\x98\x85" : "",
+			dc_msg_get_from_id(msg)==1? "" : (dc_msg_get_state(msg)==DC_STATE_IN_SEEN? "[SEEN]" : (dc_msg_get_state(msg)==DC_STATE_IN_NOTICED? "[NOTICED]":"[FRESH]")),
+			dc_msg_is_info(msg)? "[INFO]" : "",
+			statestr,
+			temp2);
+	free(msgtext);
+	free(temp2);
+	free(contact_name);
+
+	dc_contact_unref(contact);
+}
+
+
 static void log_msglist(dc_context_t* context, dc_array_t* msglist)
 {
 	int i, cnt = dc_array_get_cnt(msglist), lines_out = 0;
@@ -278,36 +292,7 @@ static void log_msglist(dc_context_t* context, dc_array_t* msglist)
 			if (lines_out==0) { dc_log_info(context, 0, "--------------------------------------------------------------------------------"); lines_out++; }
 
 			dc_msg_t* msg = dc_get_msg(context, msg_id);
-			dc_contact_t* contact = dc_get_contact(context, dc_msg_get_from_id(msg));
-			char* contact_name = dc_contact_get_name(contact);
-			int contact_id = dc_contact_get_id(contact);
-
-			const char* statestr = "";
-			switch (dc_msg_get_state(msg)) {
-				case DC_STATE_OUT_PENDING:   statestr = " o";   break;
-				case DC_STATE_OUT_DELIVERED: statestr = " √";   break;
-				case DC_STATE_OUT_MDN_RCVD:  statestr = " √√";  break;
-				case DC_STATE_OUT_FAILED:    statestr = " !!";  break;
-			}
-
-			char* temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg));
-			char* msgtext = dc_msg_get_text(msg);
-				dc_log_info(context, 0, "Msg#%i%s: %s (Contact#%i): %s %s%s%s%s [%s]",
-					(int)dc_msg_get_id(msg),
-					dc_msg_get_showpadlock(msg)? "\xF0\x9F\x94\x92" : "",
-					contact_name,
-					contact_id,
-					msgtext,
-					dc_msg_is_starred(msg)? " \xE2\x98\x85" : "",
-					dc_msg_get_from_id(msg)==1? "" : (dc_msg_get_state(msg)==DC_STATE_IN_SEEN? "[SEEN]" : (dc_msg_get_state(msg)==DC_STATE_IN_NOTICED? "[NOTICED]":"[FRESH]")),
-					dc_msg_is_info(msg)? "[INFO]" : "",
-					statestr,
-					temp2);
-			free(msgtext);
-			free(temp2);
-			free(contact_name);
-
-			dc_contact_unref(contact);
+			log_msg(context, "Msg", msg);
 			dc_msg_unref(msg);
 		}
 	}
@@ -433,7 +418,7 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 				"configure\n"
 				"connect\n"
 				"disconnect\n"
-				"poll\n"
+				"maybenetwork\n"
 				"help imex (Import/Export)\n"
 				"==============================Chat commands==\n"
 				"listchats [<query>]\n"
@@ -449,7 +434,7 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 				"groupimage [<file>]\n"
 				"chatinfo\n"
 				"send <text>\n"
-				"sendimage <file>\n"
+				"sendimage <file> [<text>]\n"
 				"sendfile <file>\n"
 				"draft [<text>]\n"
 				"listmedia\n"
@@ -487,7 +472,7 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 	else if (!s_is_auth)
 	{
 		if (strcmp(cmd, "auth")==0) {
-			char* is_pw = dc_get_config(context, "mail_pw", "");
+			char* is_pw = dc_get_config(context, "mail_pw");
 			if (strcmp(arg1, is_pw)==0) {
 				s_is_auth = 1;
 				ret = COMMAND_SUCCEEDED;
@@ -600,7 +585,7 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 		char* file_name = dc_mprintf("%s/autocrypt-setup-message.html", context->blobdir);
 		char* file_content = NULL;
 			if ((file_content=dc_render_setup_file(context, setup_code)) != NULL
-			 && dc_write_file(file_name, file_content, strlen(file_content), context)) {
+			 && dc_write_file(context, file_name, file_content, strlen(file_content))) {
 				ret = dc_mprintf("Setup message written to: %s\nSetup code: %s", file_name, setup_code);
 			}
 			else {
@@ -646,14 +631,9 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 	else if (strcmp(cmd, "get")==0)
 	{
 		if (arg1) {
-			char* val = dc_get_config(context, arg1, "<unset>");
-			if (val) {
-				ret = dc_mprintf("%s=%s", arg1, val);
-				free(val);
-			}
-			else {
-				ret = COMMAND_FAILED;
-			}
+			char* val = dc_get_config(context, arg1);
+			ret = dc_mprintf("%s=%s", arg1, val);
+			free(val);
 		}
 		else {
 			ret = dc_strdup("ERROR: Argument <key> missing.");
@@ -666,6 +646,11 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 			ret = COMMAND_FAILED;
 		}
 	}
+	else if (strcmp(cmd, "maybenetwork")==0)
+	{
+		dc_maybe_network(context);
+		ret = COMMAND_SUCCEEDED;
+	}
 
 	/*******************************************************************************
 	 * Chat commands
@@ -755,12 +740,10 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 				log_msglist(context, msglist);
 				dc_array_unref(msglist);
 			}
-			if (dc_chat_get_draft_timestamp(sel_chat)) {
-				char* timestr = dc_timestamp_to_str(dc_chat_get_draft_timestamp(sel_chat));
-				char* drafttext = dc_chat_get_text_draft(sel_chat);
-					dc_log_info(context, 0, "Draft: %s [%s]", drafttext, timestr);
-				free(drafttext);
-				free(timestr);
+			dc_msg_t* draft = dc_get_draft(context, dc_chat_get_id(sel_chat));
+			if (draft) {
+				log_msg(context, "Draft", draft);
+				dc_msg_unref(draft);
 			}
 			ret = dc_mprintf("%i messages.", dc_get_msg_cnt(context, dc_chat_get_id(sel_chat)));
 			dc_marknoticed_chat(context, dc_chat_get_id(sel_chat));
@@ -917,35 +900,34 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 			ret = dc_strdup("No chat selected.");
 		}
 	}
-	else if (strcmp(cmd, "sendimage")==0)
+	else if (strcmp(cmd, "sendempty")==0)
 	{
 		if (sel_chat) {
-			if (arg1 && arg1[0]) {
-				if (dc_send_image_msg(context, dc_chat_get_id(sel_chat), arg1, NULL, 0, 0)) {
-					ret = dc_strdup("Image sent.");
-				}
-				else {
-					ret = dc_strdup("ERROR: Sending image failed.");
-				}
+			if (dc_send_text_msg(context, dc_chat_get_id(sel_chat), "")) {
+				ret = dc_strdup("Message sent.");
 			}
 			else {
-				ret = dc_strdup("ERROR: No image given.");
+				ret = dc_strdup("ERROR: Sending failed.");
 			}
 		}
 		else {
 			ret = dc_strdup("No chat selected.");
 		}
 	}
-	else if (strcmp(cmd, "sendfile")==0)
+	else if (strcmp(cmd, "sendimage")==0 || strcmp(cmd, "sendfile")==0)
 	{
 		if (sel_chat) {
 			if (arg1 && arg1[0]) {
-				if (dc_send_file_msg(context, dc_chat_get_id(sel_chat), arg1, NULL)) {
-					ret = dc_strdup("File sent.");
-				}
-				else {
-					ret = dc_strdup("ERROR: Sending file failed.");
-				}
+				char* arg2 = strchr(arg1, ' ');
+				if (arg2) { *arg2 = 0; arg2++; }
+
+				dc_msg_t* msg = dc_msg_new(context,
+					strcmp(cmd, "sendimage")==0? DC_MSG_IMAGE : DC_MSG_FILE);
+				dc_msg_set_file(msg, arg1, NULL);
+				dc_msg_set_text(msg, arg2);
+				dc_send_msg(context, dc_chat_get_id(sel_chat), msg);
+				dc_msg_unref(msg);
+				ret = COMMAND_SUCCEEDED;
 			}
 			else {
 				ret = dc_strdup("ERROR: No file given.");
@@ -973,11 +955,14 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 	{
 		if (sel_chat) {
 			if (arg1 && arg1[0]) {
-				dc_set_text_draft(context, dc_chat_get_id(sel_chat), arg1);
+				dc_msg_t* draft = dc_msg_new(context, DC_MSG_TEXT);
+				dc_msg_set_text(draft, arg1);
+				dc_set_draft(context, dc_chat_get_id(sel_chat), draft);
+				dc_msg_unref(draft);
 				ret = dc_strdup("Draft saved.");
 			}
 			else {
-				dc_set_text_draft(context, dc_chat_get_id(sel_chat), NULL);
+				dc_set_draft(context, dc_chat_get_id(sel_chat), NULL);
 				ret = dc_strdup("Draft deleted.");
 			}
 		}
@@ -1222,7 +1207,7 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
 	{
 		if (arg1) {
 			unsigned char* buf = NULL; size_t buf_bytes; uint32_t w, h;
-			if (dc_read_file(arg1, (void**)&buf, &buf_bytes, context)) {
+			if (dc_read_file(context, arg1, (void**)&buf, &buf_bytes)) {
 				dc_get_filemeta(buf, buf_bytes, &w, &h);
 				ret = dc_mprintf("width=%i, height=%i", (int)w, (int)h);
 			}

+ 0 - 22
deltachat-ios/libraries/deltachat-core/cmdline/cmdline.h

@@ -1,25 +1,3 @@
-/*******************************************************************************
- *
- *                              Delta Chat Core
- *                      Copyright (C) 2017 Björn Petersen
- *                   Contact: r10s@b44t.com, http://b44t.com
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see http://www.gnu.org/licenses/ .
- *
- ******************************************************************************/
-
-
 #ifndef __DC_CMDLINE_H__
 #define __DC_CMDLINE_H__
 #ifdef __cplusplus

+ 104 - 40
deltachat-ios/libraries/deltachat-core/cmdline/main.c

@@ -1,25 +1,3 @@
-/*******************************************************************************
- *
- *                              Delta Chat Core
- *                      Copyright (C) 2017 Björn Petersen
- *                   Contact: r10s@b44t.com, http://b44t.com
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see http://www.gnu.org/licenses/ .
- *
- ******************************************************************************/
-
-
 /* This is a CLI program and a little testing frame.  This file must not be
 included when using Delta Chat Core as a library.
 
@@ -52,7 +30,6 @@ static uintptr_t receive_event(dc_context_t* context, int event, uintptr_t data1
 	switch (event)
 	{
 		case DC_EVENT_GET_STRING:
-		case DC_EVENT_GET_QUANTITY_STRING:
 			break; /* do not show the event as this would fill the screen */
 
 		case DC_EVENT_INFO:
@@ -61,23 +38,43 @@ static uintptr_t receive_event(dc_context_t* context, int event, uintptr_t data1
 			}
 			break;
 
+		case DC_EVENT_SMTP_CONNECTED:
+			printf("[DC_EVENT_SMTP_CONNECTED] %s\n", (char*)data2);
+			break;
+
+		case DC_EVENT_IMAP_CONNECTED:
+			printf("[DC_EVENT_IMAP_CONNECTED] %s\n", (char*)data2);
+			break;
+
+		case DC_EVENT_SMTP_MESSAGE_SENT:
+			printf("[DC_EVENT_SMTP_MESSAGE_SENT] %s\n", (char*)data2);
+			break;
+
 		case DC_EVENT_WARNING:
 			printf("[Warning] %s\n", (char*)data2);
 			break;
 
 		case DC_EVENT_ERROR:
-			printf(ANSI_RED "[ERROR #%i] %s" ANSI_NORMAL "\n", (int)data1, (char*)data2);
+			printf(ANSI_RED "[DC_EVENT_ERROR] %s" ANSI_NORMAL "\n", (char*)data2);
+			break;
+
+		case DC_EVENT_ERROR_NETWORK:
+			printf(ANSI_RED "[DC_EVENT_ERROR_NETWORK] first=%i, msg=%s" ANSI_NORMAL "\n", (int)data1, (char*)data2);
+			break;
+
+		case DC_EVENT_ERROR_SELF_NOT_IN_GROUP:
+			printf(ANSI_RED "[DC_EVENT_ERROR_SELF_NOT_IN_GROUP] %s" ANSI_NORMAL "\n", (char*)data2);
 			break;
 
 		case DC_EVENT_HTTP_GET:
 			{
 				char* ret = NULL;
-				char* tempFile = dc_get_fine_pathNfilename(context->blobdir, "curl.result");
+				char* tempFile = dc_get_fine_pathNfilename(context, context->blobdir, "curl.result");
 				char* cmd = dc_mprintf("curl --silent --location --fail --insecure %s > %s", (char*)data1, tempFile); /* --location = follow redirects */
 				int error = system(cmd);
 				if (error == 0) { /* -1=system() error, !0=curl errors forced by -f, 0=curl success */
 					size_t bytes = 0;
-					dc_read_file(tempFile, (void**)&ret, &bytes, context);
+					dc_read_file(context, tempFile, (void**)&ret, &bytes);
 				}
 				free(cmd);
 				free(tempFile);
@@ -108,6 +105,10 @@ static uintptr_t receive_event(dc_context_t* context, int event, uintptr_t data1
 			printf(ANSI_YELLOW "{{Received DC_EVENT_IMEX_FILE_WRITTEN(%s)}}\n" ANSI_NORMAL, (char*)data1);
 			break;
 
+		case DC_EVENT_FILE_COPIED:
+			printf(ANSI_YELLOW "{{Received DC_EVENT_FILE_COPIED(%s)}}\n" ANSI_NORMAL, (char*)data1);
+			break;
+
 		case DC_EVENT_CHAT_MODIFIED:
 			printf(ANSI_YELLOW "{{Received DC_EVENT_CHAT_MODIFIED(%i)}}\n" ANSI_NORMAL, (int)data1);
 			break;
@@ -125,21 +126,58 @@ static uintptr_t receive_event(dc_context_t* context, int event, uintptr_t data1
  ******************************************************************************/
 
 
-static pthread_t imap_thread = 0;
+static pthread_t inbox_thread = 0;
 static int       run_threads = 0;
-static void* imap_thread_entry_point (void* entry_arg)
+static void* inbox_thread_entry_point (void* entry_arg)
 {
 	dc_context_t* context = (dc_context_t*)entry_arg;
 
 	while (run_threads) {
-		// jobs(), fetch() and idle()
-		// MUST be called from the same single thread and MUST be called sequentially.
+		// jobs(), fetch() and idle() MUST be called from the same single thread
+		// and MUST be called sequentially.
 		dc_perform_imap_jobs(context);
 		dc_perform_imap_fetch(context);
-		dc_perform_imap_idle(context); // this may take hours ...
+		if (run_threads) {
+			dc_perform_imap_idle(context); // this may take hours ...
+		}
+	}
+
+	return NULL;
+}
+
+
+static pthread_t mvbox_thread = 0;
+static void* mvbox_thread_entry_point (void* entry_arg)
+{
+	dc_context_t* context = (dc_context_t*)entry_arg;
+
+	while (run_threads) {
+		// fetch() and idle() MUST be called from the same single thread
+		// and MUST be called sequentially.
+		dc_perform_mvbox_fetch(context);
+		if (run_threads) {
+			dc_perform_mvbox_idle(context); // this may take hours ...
+		}
+	}
+
+	return NULL;
+}
+
+
+static pthread_t sentbox_thread = 0;
+static void* sentbox_thread_entry_point (void* entry_arg)
+{
+	dc_context_t* context = (dc_context_t*)entry_arg;
+
+	while (run_threads) {
+		// fetch() and idle() MUST be called from the same single thread
+		// and MUST be called sequentially.
+		dc_perform_sentbox_fetch(context);
+		if (run_threads) {
+			dc_perform_sentbox_idle(context); // this may take hours ...
+		}
 	}
 
-	imap_thread = 0;
 	return NULL;
 }
 
@@ -150,11 +188,14 @@ static void* smtp_thread_entry_point (void* entry_arg)
 	dc_context_t* context = (dc_context_t*)entry_arg;
 
 	while (run_threads) {
+		// jobs() and idle() MUST be called from the same single thread
+		// and MUST be called sequentially.
 		dc_perform_smtp_jobs(context);
-		dc_perform_smtp_idle(context); // this may take hours ...
+		if (run_threads) {
+			dc_perform_smtp_idle(context); // this may take hours ...
+		}
 	}
 
-	smtp_thread = 0;
 	return NULL;
 }
 
@@ -162,8 +203,16 @@ static void* smtp_thread_entry_point (void* entry_arg)
 static void start_threads(dc_context_t* context)
 {
 	run_threads = 1;
-	if (!imap_thread) {
-		pthread_create(&imap_thread, NULL, imap_thread_entry_point, context);
+	if (!inbox_thread) {
+		pthread_create(&inbox_thread, NULL, inbox_thread_entry_point, context);
+	}
+
+	if (!mvbox_thread) {
+		pthread_create(&mvbox_thread, NULL, mvbox_thread_entry_point, context);
+	}
+
+	if (!sentbox_thread) {
+		pthread_create(&sentbox_thread, NULL, sentbox_thread_entry_point, context);
 	}
 
 	if (!smtp_thread) {
@@ -176,12 +225,19 @@ static void stop_threads(dc_context_t* context)
 {
 	run_threads = 0;
 	dc_interrupt_imap_idle(context);
+	dc_interrupt_mvbox_idle(context);
+	dc_interrupt_sentbox_idle(context);
 	dc_interrupt_smtp_idle(context);
 
-	// wait until the threads are finished
-	while (imap_thread || smtp_thread) {
-		usleep(100*1000);
-	}
+	pthread_join(inbox_thread, NULL);
+	pthread_join(mvbox_thread, NULL);
+	pthread_join(sentbox_thread, NULL);
+	pthread_join(smtp_thread, NULL);
+
+	inbox_thread = 0;
+	mvbox_thread = 0;
+	sentbox_thread = 0;
+	smtp_thread = 0;
 }
 
 
@@ -227,6 +283,14 @@ int main(int argc, char ** argv)
 	stress_functions(context);
 	s_do_log_info = 1;
 
+	#if 0
+	for(int i=0; i<10000;i++) {
+		printf("--%i--\n", i);
+		start_threads(context);
+		stop_threads(context);
+	}
+	#endif
+
 	printf("Delta Chat Core is awaiting your commands.\n");
 
 	/* wait for command */

+ 1 - 2
deltachat-ios/libraries/deltachat-core/cmdline/meson.build

@@ -9,7 +9,6 @@ inc = include_directories('.')
 
 exe = executable(
   'delta', src,
-  dependencies: [pthreads, etpan],
-  link_with: lib,
+  dependencies: [dep],
   install: true,
 )

+ 144 - 25
deltachat-ios/libraries/deltachat-core/cmdline/stress.c

@@ -1,25 +1,3 @@
-/*******************************************************************************
- *
- *                              Delta Chat Core
- *                      Copyright (C) 2017 Björn Petersen
- *                   Contact: r10s@b44t.com, http://b44t.com
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see http://www.gnu.org/licenses/ .
- *
- ******************************************************************************/
-
-
 /* Stress some functions for testing; if used as a lib, this file is obsolete.
 For memory checking, use eg.
 $ valgrind --leak-check=full --tool=memcheck ./deltachat-core <db>
@@ -214,6 +192,64 @@ void stress_functions(dc_context_t* context)
 		dc_simplify_unref(simplify);
 	}
 
+	/* test file functions
+	 **************************************************************************/
+
+	if (dc_is_open(context))
+	{
+		if (dc_file_exist(context, "$BLOBDIR/foobar")
+		 || dc_file_exist(context, "$BLOBDIR/dada")
+		 || dc_file_exist(context, "$BLOBDIR/foobar.dadada")
+		 || dc_file_exist(context, "$BLOBDIR/foobar-folder")) {
+			dc_delete_file(context, "$BLOBDIR/foobar");
+			dc_delete_file(context, "$BLOBDIR/dada");
+			dc_delete_file(context, "$BLOBDIR/foobar.dadada");
+			dc_delete_file(context, "$BLOBDIR/foobar-folder");
+		}
+
+		dc_write_file(context, "$BLOBDIR/foobar", "content", 7);
+		assert( dc_file_exist(context, "$BLOBDIR/foobar") );
+		assert( !dc_file_exist(context, "$BLOBDIR/foobarx") );
+		assert( dc_get_filebytes(context, "$BLOBDIR/foobar")==7 );
+
+		char* absPath = dc_mprintf("%s/%s", context->blobdir, "foobar");
+		assert(  dc_is_blobdir_path(context, absPath) );
+		assert(  dc_is_blobdir_path(context, "$BLOBDIR/fofo") );
+		assert( !dc_is_blobdir_path(context, "/BLOBDIR/fofo") );
+		assert( dc_file_exist(context, absPath) );
+		free(absPath);
+
+		assert( dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada") );
+		assert( dc_get_filebytes(context, "$BLOBDIR/dada")==7 );
+
+		void* buf;
+		size_t buf_bytes;
+		assert( dc_read_file(context, "$BLOBDIR/dada", &buf, &buf_bytes) );
+		assert( buf_bytes==7 );
+		assert( strcmp(buf, "content")==0 );
+		free(buf);
+
+		assert( dc_delete_file(context, "$BLOBDIR/foobar") );
+		assert( dc_delete_file(context, "$BLOBDIR/dada") );
+
+		assert( dc_create_folder(context, "$BLOBDIR/foobar-folder") );
+		assert( dc_file_exist(context, "$BLOBDIR/foobar-folder") );
+		assert( dc_delete_file(context, "$BLOBDIR/foobar-folder") );
+
+		char* fn0 = dc_get_fine_pathNfilename(context, "$BLOBDIR", "foobar.dadada");
+		assert( fn0 );
+		assert( strcmp(fn0, "$BLOBDIR/foobar.dadada")==0 );
+		dc_write_file(context, fn0, "content", 7);
+
+		char* fn1 = dc_get_fine_pathNfilename(context, "$BLOBDIR", "foobar.dadada");
+		assert( fn1 );
+		assert( strcmp(fn1, "$BLOBDIR/foobar-1.dadada")==0 );
+
+		assert( dc_delete_file(context, fn0) );
+		free(fn0);
+		free(fn1);
+	}
+
 	/* test mailmime
 	**************************************************************************/
 
@@ -305,6 +341,23 @@ void stress_functions(dc_context_t* context)
 	 **************************************************************************/
 
 	{
+		assert( atol("")==0 ); /* we rely on this eg. in dc_sqlite3_get_config() */
+		assert( atoi("")==0 );
+
+		assert( !dc_may_be_valid_addr(NULL) );
+		assert( !dc_may_be_valid_addr("") );
+		assert(  dc_may_be_valid_addr("user@domain.tld") );
+		assert( !dc_may_be_valid_addr("uuu") );
+		assert( !dc_may_be_valid_addr("dd.tt") );
+		assert( !dc_may_be_valid_addr("tt.dd@uu") );
+		assert( !dc_may_be_valid_addr("uu") );
+		assert( !dc_may_be_valid_addr("u@d") );
+		assert( !dc_may_be_valid_addr("u@d.") );
+		assert( !dc_may_be_valid_addr("u@d.t") );
+		assert(  dc_may_be_valid_addr("u@d.tt") );
+		assert( !dc_may_be_valid_addr("u@.tt") );
+		assert( !dc_may_be_valid_addr("@d.tt") );
+
 		char* str = strdup("aaa");
 		int replacements = dc_str_replace(&str, "a", "ab"); /* no endless recursion here! */
 		assert( strcmp(str, "ababab")==0 );
@@ -359,6 +412,29 @@ void stress_functions(dc_context_t* context)
 		assert( strcmp(str, "")==0 );
 		free(str);
 
+		clist* list = dc_str_to_clist(NULL, " ");
+		assert( clist_count(list)==0 );
+		clist_free_content(list);
+		clist_free(list);
+
+		list = dc_str_to_clist("", " ");
+		assert( clist_count(list)==1 );
+		clist_free_content(list);
+		clist_free(list);
+
+		list = dc_str_to_clist(" ", " ");
+		assert( clist_count(list)==2 );
+		clist_free_content(list);
+		clist_free(list);
+
+		list = dc_str_to_clist("foo bar test", " ");
+		assert(clist_count(list)==3);
+		str = dc_str_from_clist(list, " ");
+		assert( strcmp(str, "foo bar test")==0 );
+		clist_free_content(list);
+		clist_free(list);
+		free(str);
+
 		assert( strcmp("fresh="     DC_STRINGIFY(DC_STATE_IN_FRESH),      "fresh=10")==0 ); /* these asserts check the values, the existance of the macros and also DC_STRINGIFY() */
 		assert( strcmp("noticed="   DC_STRINGIFY(DC_STATE_IN_NOTICED),    "noticed=13")==0 );
 		assert( strcmp("seen="      DC_STRINGIFY(DC_STATE_IN_SEEN),       "seen=16")==0 );
@@ -395,8 +471,6 @@ void stress_functions(dc_context_t* context)
 		assert( DC_PARAM_HEIGHT == 'h' );
 		assert( DC_PARAM_DURATION == 'd' );
 		assert( DC_PARAM_MIMETYPE == 'm' );
-		assert( DC_PARAM_AUTHORNAME == 'N' );
-		assert( DC_PARAM_TRACKNAME == 'n' );
 		assert( DC_PARAM_FORWARDED == 'a' );
 		assert( DC_PARAM_UNPROMOTED == 'U' );
 
@@ -497,6 +571,7 @@ void stress_functions(dc_context_t* context)
 		free(buf2);
 
 		assert(  DC_EVENT_DATA1_IS_STRING(2100) );
+		assert(  DC_EVENT_DATA1_IS_STRING(2052) );
 		assert( !DC_EVENT_DATA1_IS_STRING(100) );
 		assert( !DC_EVENT_DATA1_IS_STRING(300) );
 		assert( !DC_EVENT_DATA1_IS_STRING(400) );
@@ -507,7 +582,6 @@ void stress_functions(dc_context_t* context)
 		assert( !DC_EVENT_DATA2_IS_STRING(2010) );
 
 		assert(  DC_EVENT_RETURNS_STRING(2091) );
-		assert(  DC_EVENT_RETURNS_STRING(2092) );
 		assert(  DC_EVENT_RETURNS_STRING(2100) );
 		assert( !DC_EVENT_RETURNS_STRING(100) );
 		assert( !DC_EVENT_RETURNS_STRING(300) );
@@ -602,6 +676,51 @@ void stress_functions(dc_context_t* context)
 		dc_param_unref(p1);
 	}
 
+	/* test keys for dc_set_config() and dc_get_config()
+	 **************************************************************************/
+
+	{
+		char* keys = dc_get_config(context, "sys.config_keys");
+		assert( keys && keys[0] );
+
+		dc_strbuilder_t sb;
+		dc_strbuilder_init(&sb, 200);
+		dc_strbuilder_catf(&sb, " %s ", keys);
+		free(keys);
+		keys = sb.buf;
+
+		assert( strstr(keys, " probably_never_a_key ")==NULL );
+		assert( strstr(keys, " addr ")!=NULL );
+		assert( strstr(keys, " mail_server ")!=NULL );
+		assert( strstr(keys, " mail_user ")!=NULL );
+		assert( strstr(keys, " mail_pw ")!=NULL );
+		assert( strstr(keys, " mail_port ")!=NULL );
+		assert( strstr(keys, " send_server ")!=NULL );
+		assert( strstr(keys, " send_user ")!=NULL );
+		assert( strstr(keys, " send_pw ")!=NULL );
+		assert( strstr(keys, " send_port ")!=NULL );
+		assert( strstr(keys, " server_flags ")!=NULL );
+		assert( strstr(keys, " imap_folder ")!=NULL );
+		assert( strstr(keys, " displayname ")!=NULL );
+		assert( strstr(keys, " selfstatus ")!=NULL );
+		assert( strstr(keys, " selfavatar ")!=NULL );
+		assert( strstr(keys, " e2ee_enabled ")!=NULL );
+		assert( strstr(keys, " mdns_enabled ")!=NULL );
+		assert( strstr(keys, " save_mime_headers ")!=NULL );
+		assert( strstr(keys, " configured_addr ")!=NULL );
+		assert( strstr(keys, " configured_mail_server ")!=NULL );
+		assert( strstr(keys, " configured_mail_user ")!=NULL );
+		assert( strstr(keys, " configured_mail_pw ")!=NULL );
+		assert( strstr(keys, " configured_mail_port ")!=NULL );
+		assert( strstr(keys, " configured_send_server ")!=NULL );
+		assert( strstr(keys, " configured_send_user ")!=NULL );
+		assert( strstr(keys, " configured_send_pw ")!=NULL );
+		assert( strstr(keys, " configured_send_port ")!=NULL );
+		assert( strstr(keys, " configured_server_flags ")!=NULL );
+
+		free(keys);
+	}
+
 	/* test Autocrypt header parsing functions
 	 **************************************************************************/
 

+ 0 - 22
deltachat-ios/libraries/deltachat-core/cmdline/stress.h

@@ -1,25 +1,3 @@
-/*******************************************************************************
- *
- *                              Delta Chat Core
- *                      Copyright (C) 2017 Björn Petersen
- *                   Contact: r10s@b44t.com, http://b44t.com
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see http://www.gnu.org/licenses/ .
- *
- ******************************************************************************/
-
-
 #ifndef __STRESS_H__
 #define __STRESS_H__
 #ifdef __cplusplus

+ 7 - 4
deltachat-ios/libraries/deltachat-core/deltachat-core.cbp

@@ -34,7 +34,7 @@
 		</Build>
 		<Compiler>
 			<Add option="-Wall" />
-			<Add option="-fexceptions" />
+			<Add option="-fexceptions -Wno-unused-function -Wno-misleading-indentation -Wno-deprecated-declarations" />
 			<Add option="-DHAVE_CONFIG_H" />
 			<Add option="-DDC_USE_MIME_DEBUG" />
 			<Add option="-DHAVE_ICONV" />
@@ -464,6 +464,9 @@
 		<Unit filename="src/dc_job.c">
 			<Option compilerVar="CC" />
 		</Unit>
+		<Unit filename="src/dc_jobthread.c">
+			<Option compilerVar="CC" />
+		</Unit>
 		<Unit filename="src/dc_key.c">
 			<Option compilerVar="CC" />
 		</Unit>
@@ -488,6 +491,9 @@
 		<Unit filename="src/dc_mimeparser.c">
 			<Option compilerVar="CC" />
 		</Unit>
+		<Unit filename="src/dc_move.c">
+			<Option compilerVar="CC" />
+		</Unit>
 		<Unit filename="src/dc_msg.c">
 			<Option compilerVar="CC" />
 		</Unit>
@@ -536,9 +542,6 @@
 		<Unit filename="src/dc_tools.c">
 			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/dc_uudecode.c">
-			<Option compilerVar="CC" />
-		</Unit>
 		<Unit filename="src/deltachat.h" />
 		<Extensions>
 			<envvars />

+ 3 - 3
deltachat-ios/libraries/deltachat-core/docs/Doxyfile

@@ -53,7 +53,7 @@ PROJECT_BRIEF          =
 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
 # the logo to the output directory.
 
-PROJECT_LOGO           =
+PROJECT_LOGO           = logo.png
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
 # into which the generated documentation will be written. If a relative path is
@@ -852,7 +852,7 @@ EXCLUDE_PATTERNS       =
 # exclude all test directories use the pattern */test/*
 
 ######################################################
-EXCLUDE_SYMBOLS        = dc_aheader_t dc_apeerstate_t dc_e2ee_helper_t dc_imap_t dc_job_t dc_key_t dc_keyring_t dc_loginparam_t dc_mime*_t 
+EXCLUDE_SYMBOLS        = dc_aheader_t dc_apeerstate_t dc_e2ee_helper_t dc_imap_t dc_job*_t dc_key_t dc_keyring_t dc_loginparam_t dc_mime*_t
 EXCLUDE_SYMBOLS       += dc_saxparser_t dc_simplify_t dc_smtp_t dc_sqlite3_t dc_strbuilder_t dc_param_t dc_hash_t dc_hashelem_t
 EXCLUDE_SYMBOLS       += _dc_chat _dc_chatlist _dc_contact _dc_msg _dc_context _dc_lot _dc_array
 ######################################################
@@ -1911,7 +1911,7 @@ MAN_LINKS              = NO
 # captures the structure of the code including all documentation.
 # The default value is: NO.
 
-GENERATE_XML           = NO
+GENERATE_XML           = YES
 
 # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
 # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of

+ 2 - 3
deltachat-ios/libraries/deltachat-core/docs/README.md

@@ -1,5 +1,4 @@
 to get the api documentation,
 
-- call doxygen in this directory
-- or read it online at <https://deltachat.github.io/api/>
-- or clone `https://github.com/deltachat/api`
+- call doxygen in this directory and browse the `html` subdirectory
+- or read it online at <https://c.delta.chat>

BIN
deltachat-ios/libraries/deltachat-core/docs/logo.png


+ 23 - 0
deltachat-ios/libraries/deltachat-core/docs/release-checklist.md

@@ -0,0 +1,23 @@
+
+# release new core version
+
+1. deltachat-core: bump version, check CHANGELOG.md, commit
+2. $ VERSION=1.2.3
+3. $ git tag -s -m "Release v${VERSION}" v${VERSION} # create signed tag
+4. $ git tag -v v${VERSION} # verify tag signature
+5. $ git push origin master
+6. $ git push --tags origin
+
+
+# create the github release with signed binaries
+
+1. "draft a new release" with v${VERSION} on github.com
+2. publish release
+3. download zip and tar.gz files
+4. verify content
+5. sign content (to get the key overview, use gpg --list-secret-keys)  
+   $ gpg -a --detach-sign -u FINGERPRINT deltachat-core-${VERSION}.zip  
+   $ gpg -a --detach-sign -u FINGERPRINT deltachat-core-${VERSION}.tar.gz
+6. upload created signatures to github,
+   rename to v${VERSION}.zip.asc and v${VERSION}.tar.gz.asc
+

+ 0 - 21
deltachat-ios/libraries/deltachat-core/docs/update.sh

@@ -1,21 +0,0 @@
-# this script generates the c-api html-help-pages
-# from the c-core-source using `doxygen`
-
-UPLOADDIR="../../api"
-
-doxygen
-mkdir -p ${UPLOADDIR}/docs/
-cp -r html/* ${UPLOADDIR}/docs/
-read -p "if not errors are printed above, press ENTER to commit and push the changes"
-
-pushd . > /dev/null
-
-cd ${UPLOADDIR}
-git add docs/
-git commit -am "update docs"
-git push
-
-popd > /dev/null
-
-
-

+ 9 - 0
deltachat-ios/libraries/deltachat-core/libs/README.md

@@ -14,3 +14,12 @@ Linux repositories.
 Moreover, we've fixed some bugs here and there; these lines are marked by
 `EDIT BY MR` then (as soon as we find the time, we should check if such changes
 could form a pull request to the used library).
+
+
+# OpenSSL
+
+- OpenSSL was take from Telegram-FOSS-master-3.10.1(821)
+  and has the version 1.0.1t
+- removed the following configuration options:
+  OPENSSL_NO_CAMELLIA -DOPENSSL_NO_CAST
+  as Camellia as well as CAST is needed in PGP

+ 48 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/AUTHORS

@@ -0,0 +1,48 @@
+Rob Siemborski <rjs3+@andrew.cmu.edu> wrote and tested the conversion
+to the SASLv2 API.
+
+Ken Murchison <murch@andrew.cmu.edu> worked on the OTP, NTLM, SRP and SQL
+plugins, as well as helping to track down bugs as they appear. He also
+added support for HTTP authentication.
+
+Rob Earhart <earhart@cmu.edu> wrote the build/installation procedure,
+wrote and tested some of the code, and provided general guidance and
+coding advice.
+
+Leif Johansson <leifj@matematik.su.se> wrote the GSSAPI plugin, with
+contributions from Sam Hartman <hartmans@fundsxpress.com>.
+
+Leandro Santi <lesanti@sinectis.com.ar> added Courier authdaemon support.
+
+Alexey Melnikov <alexey.melnikov@isode.com> wrote the first pass of the
+DIGEST-MD5 plugin and continues to work on it.  He also wrote
+a good deal of the current Windows support.
+
+Rainer Schoepf <schoepf@uni-mainz.de> contributed the LOGIN plugin,
+based on Tim Martin's PLAIN plugin.
+
+Simon Loader <simon@surf.org.uk> wrote the MySQL auxprop module.
+
+Rolf Braun <rbraun@andrew.cmu.edu> wrote the MacOS ports.
+
+Howard Chu <hyc@highlandsun.com> put a good deal of work into OS/390
+portability, correct building of static libraries, and a slew
+of misc. bugfixes.
+
+Tim Martin <tmartin@andrew.cmu.edu> wrote, debugged, and tested
+most of the SASLv1 code.
+
+Larry Greenfield <leg+sasl@andrew.cmu.edu> complained. a lot.
+
+Chris Newman <chris.newman@oracle.com> wrote the initial version of the
+SASL API, as well as the version 2 SASL API (documented in sasl.h,
+saslutil.h, saslplug.h, and prop.h).
+
+Ryan Troll <ryan@andrew.cmu.edu> started the Windows port,
+and both Larry Greenfield and Alexey Melnikov have done more work on it.
+
+getaddrinfo.c was written by Hajimu UMEMOTO <ume@mahoroba.org>
+which is based on the IPv6 code written by KIKUCHI Takahiro
+<kick@kyoto.wide.ad.jp>
+
+$Id: AUTHORS,v 1.18 2006/12/01 17:34:58 mel Exp $

+ 44 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/COPYING

@@ -0,0 +1,44 @@
+/* CMU libsasl
+ * Tim Martin
+ * Rob Earhart
+ * Rob Siemborski
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */

+ 3440 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/ChangeLog

@@ -0,0 +1,3440 @@
+2012-10-12  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Getting ready for 2.1.25.
+
+2012-07-06  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_krb5.c: Fixed a crash in the auth_krb5.c
+	  (bug # 2706). Patch by Nalin Dahyabhai.
+
+2012-07-03  Alexey Melnikov <alexey.melnikov@isode.com>
+	* config/ltconfig: Fixed incorrect Darwin version matching in ltconfig
+	  (bug # 3713). Patch by Joshua Root.
+
+2012-06-08  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Fixed PLAIN/LOGIN authentication failure when using saslauthd
+	  with no auxprop plugins (bug # 3590).
+
+2012-06-08  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Added generation of pkg-config .pc file for Cyrus SASL.
+	  Patch by Dilyan Palauzov.
+
+2012-06-03  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Correctly updated libtool version for libsasl and its plugins due
+	  to ABI changes (bug # 3692).
+
+2012-06-02  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Better error reporting from auth_getpwent.c/auth_shadow.c
+	  (bug # 3134). Based on a patch by Greg A. Woods.
+
+2012-06-02  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Improved error logging on failure to load plugins.
+	  Patch by Greg A. Woods.
+
+2012-05-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/otp.c, plugins/srp.c: Removed calling of EVP_cleanup()
+	  on SRP/OTP plugin shutdown
+
+2012-05-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_httpform.c: Encode the parameter values passed to
+	  auth_httpform, not the whole POST data.
+
+2012-05-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/config.c, saslauthd/cfile.c: Fixed file descriptor leaks
+	  throughout the code (bug # 3702). Slightly reformatted patch
+	  by Manfred Weichel.
+
+2012-05-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* bug in "saslauthd -a rimap" - not reading the whole IMAP greeting
+	  (bug # 3211). Patch from Lutz Mark (via Red Hat)
+
+2012-05-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Modernize SASL malloc/realloc callback prototypes
+
+2012-05-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslutil.c: Fixed broken logic in get_fqhostname() when
+	  abort_if_no_fqdn is 0 (bug # 3589). Patch by baggins@pld-linux.org
+
+2012-05-28  Alexey Melnikov <alexey.melnikov@isode.com>
+	* sasldb/db_berkeley.c, utils/dbconverter-2.c: Added support for
+	  BerkleyDB 5.X or later (Patch by Howard Chu)
+
+2012-04-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/client.c, lib/server.c, lib/saslint.h: Make server and client
+	  side global callbacks private to server.c/client.c respectively
+
+2012-02-10  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/digestmd5.c: better handling of HTTP reauth cases.
+
+2012-01-28  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/digestmd5.c: Correctly send "stale" directive to prevent
+	  clients from (re)promtping for password
+
+2011-11-25  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gs2.c: Updated GS2 plugin not to lose minor GSS-API
+	  status codes on errors (based on a patch from Ralf Haferkamp
+	  <rhafer@suse.de>)
+
+2011-11-21  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gssapi.c: Only check out_flags once authentication is
+	  successfully completed
+
+2011-11-09  Ken Murchison <murch@andrew.cmu.edu>
+	* cmulocal/sasl2.m4, plugins/gssapi.c, utils/testsuite.c:
+	  Added GSS-SPNEGO plugin which can also be used for HTTP
+	  Negotiate authentication (RFC 4559)
+
+2011-11-08  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/ntlm.c: Flag client-side of NTLM plugin as HTTP-ready
+
+2011-11-08  Ken Murchison <murch@andrew.cmu.edu>
+	* include/saslutil.h, lib/config.c, lib/server.c
+	  Added sasl_config_done() to plug a memory leak when using an
+	  application specific config file
+
+2011-10-07  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gssapi.c: Fixed a segfault in gssapi.c
+	  (patch by Phil Pennock)
+
+2011-09-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* config/ltconfig, saslauthd/config/ltconfig: Fixed Cyrus SASL
+	  build on some versions of Mac OS.
+
+2011-09-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_rimap.c: qstring incorrectly appending
+	  the closing double quote. (Merge from RedHat)
+
+2011-09-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: unlock the mutex in sasl_dispose if the context
+	  was freed by another thread. (Merge from RedHat)
+
+2011-09-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* Makefile.am: "lib" should be built before "plugins"
+	  (Patch from marcandre.lureau@redhat.com)
+
+2011-09-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslutil.c: MINGW32 doesn't have rand_s
+	  (Patch from marcandre.lureau@redhat.com)
+
+2011-09-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in: Various build fixes for MINGW32
+	  (including defining sleep())
+	  (Patch from marcandre.lureau@redhat.com)
+
+2011-09-15  Alexey Melnikov <alexey.melnikov@isode.com>
+	* sample/client.c: Added additional typecasts to kill warnings
+	  about incompatible callback types
+
+2011-09-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in, config/ltconfig, config/ltmain.sh:
+	  MacOS X related build fixes: use .plugin when building
+	  SASL plugins, fixed version number calculation,
+	  don't generate multiple symlinks.
+	  Also use LD_RUN_PATH as rpath. (patches by Chris Ridd)
+
+2011-09-12  Alexey Melnikov <alexey.melnikov@isode.com>
+	* win32/common.mak: Add _CRT_SECURE_NO_DEPRECATE define
+	to suppress warnings about use of strdup, snprintf, etc.
+
+2011-09-12  Alexey Melnikov <alexey.melnikov@isode.com>
+	* sasldb/db_berkeley.c:
+	  Fixed warnings about incompatible callback types.
+
+2011-09-12  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/NTMakefile plugins/NTMakefile:
+	  Make sure that copied .c files are only rebuilt when changed.
+
+2011-09-07  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/scram.c:
+	  Fixed 3 memory leaks in SCRAM. Final 2.1.25.
+
+2011-09-07  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in, plugins/NTMakefile, plugins/cram.c:
+	  Allow use of cmusaslsecretCRAM-MD5 property to be disabled.
+
+2011-09-02  Alexey Melnikov <alexey.melnikov@isode.com>
+	* config/config.guess, config/config.sub,
+	  saslauthd/config/config.guess, saslauthd/config/config.sub:
+	  Updated config to the latest GNU snapshot.
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: Make sure that a failed authorization doesn't preclude
+	  further SASL authentication attempts from working.
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: Fixed some aspects of mech_avail callback handling
+	  in the server side SASL code.
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* config/ltconfig, saslauthd/config/ltconfig: Fix SASL's libtool
+	  MacOS/X 64-bit file magic. (Patch by Kurt Zeilenga)
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/scram.c: Fixed some additional Windows warnings and
+	  a memory leak in SCRAM.
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/scram.c: Fix size_t * v. unsigned * bug.
+	  (Patch by Kurt Zeilenga)
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: Fixed a crash caused by aborted SASL authentication
+	  and initiation of another one using the same SASL context.
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/md5.h, include/sasl.h, include/saslplug.h, lib/auxprop.c,
+	  lib/canonusr.c, lib/client.c, lib/common.c, lib/saslint.h, lib/server.c,
+	  lib/seterror.c, plugins/otp.c, plugins/plugin_common.c,
+	  sasldb/db_berkeley.c, sample/sample-client.c, sample/sample-server.c,
+	  utils/pluginviewer.c, utils/sasldblistusers.c, utils/saslpasswd.c,
+	  utils/testsuite.c: Many of the SASL includes define function pointers
+	  without specifying arguments. In C, the () is treated as unspecified,
+	  rather than (void), hence this is technically not a prototype,
+	  and gcc warns about it. (Patch by Dave Cridland and Alexey Melnikov)
+
+2011-09-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: Better server plugin API mismatch reporting
+
+2011-05-23  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gs2.c, plugins/gs2_token.c, plugins/gs2_token.h,
+	  cmulocal/sasl2.m4: Use draft-josefsson-gss-capsulate-01 if present.
+	  Negative SASL errors are fatal. (Patch from Luke Howard.)
+
+2011-05-13  Ken Murchison <murch@andrew.cmu.edu>
+	* include/sasl.h, plugins/digest-md5.c:
+	  Allow for non-persistent connections when using DIGEST-MD5 plugin
+	  for server-side HTTP Digest (RFC 2617).  Also make sure that an
+	  HTTP request is handed to plugin when required.
+
+2011-04-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gssapi.c: Fix to build GSSAPI with Heimdal (patch from
+	  Russ Allbery from Debian)
+
+2011-04-18  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gs2_token.h: Added gs2_token.h for the "make dist" target
+	  (patch by Dan White)
+
+2011-04-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* cmulocal/sasl2.m4: Only enable GS2 plugin if
+	  gss_inquire_mech_for_saslname is defined in gssapi.h
+
+2011-04-12  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/Makefile.am, plugins/makeinit.sh, plugins/ldapdb.c:
+	  LDAPDB build fixes from Dan White
+
+2011-04-05  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in, plugins/Makefile.am, plugins/NTMakefile,
+	  plugins/makeinit.sh, lib/staticopen.h, win32/include/config.h:
+	  Enabled SCRAM plugin build
+
+2011-03-25  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/Makefile.am, plugins/makeinit.sh, plugins/gs2_token.h,
+	  plugins/gs2_token.c, README.GS2, cmulocal/sasl2.m4: GS2 plugin
+	  from Luke Howard
+
+2011-01-25  Ken Murchison <murch@andrew.cmu.edu>
+	* include/sasl.h, include/saslplug.h, lib/client.c, lib/common.c,
+	  plugins/digest-md5.c sample/http_digest_client.c:
+	  Allow DIGEST-MD5 plugin to be used for client-side 
+	  HTTP Digest (RFC 2617)
+
+2011-01-21  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/scram.c: Added support for channel bindings to SCRAM-SHA-1.
+
+2011-01-21  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/client.c, lib/server.c, lib/common.c, lib/saslint.h: Fixed libsasl
+	  to accept *-PLUS SASL mechanism names in client_mech_list/mech_list
+	  options. As *-PLUS mechanism names were synthesized and didn't
+	  correspond to real plugin names, setting client_mech_list to
+	  "SCRAM-SHA-1-PLUS" (for example) was resulting in authentication
+	  failure due to inability to find a matching SASL plugin.
+
+2011-01-21  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/saslplug.h, lib/client.c: Fixed handling of channel bindings
+	  on the client side. The client side was failing to select a suitable
+	  SASL mechanism when the application specified channel bindings, but
+	  didn't make them mandatory to use. In such a configuration, if a
+	  non channel binding capable mechanism was selected through
+	  "client_mech_list" SASL option, sasl_client_start would fail.
+	  For example if the server supports both SCRAM-SHA-1[-PLUS] and
+	  PLAIN and "client_mech_list" was set to "PLAIN", authentication
+	  would never work.
+
+2011-01-21  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/client.c, lib/server.c: Better default ordering of SASL mechanisms.
+	  Ordering by plugins max_ssf produces wrong result in case an application
+	  using SASL doesn't care about SASL security layers. Before this change
+	  DIGEST-MD5 was always preferred over SCRAM-SHA-1[-PLUS]. In particular
+	  this change takes support for channel bindings into considerations.
+
+2011-01-19  Ken Murchison <murch@andrew.cmu.edu>
+	* include/sasl.h, include/saslplug.h,
+	  lib/common.c, lib/server.c, plugins/digest-md5.c:
+	  Changed server-side of HTTP Digest so that the application
+	  must pass an HTTP Request structure (Method/URI/Entity-Body)
+	  rather than just the HTTP Method
+
+2011-01-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: Server side SASL context should list *-PLUS SASL
+	  mechanisms before the corresponding non-PLUS mechanisms for naive
+	  SASL clients.
+
+2011-01-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: Fixed some Windows warnings in SASL security layer
+	  handling.
+
+2011-01-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/scram.c: Made the default number of SCRAM hash iterations
+	  configurable using a new SASL option called "scram_iteration_counter".
+	  Also fixed a couple of error messages.
+
+2011-01-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/pluginviewer.c: Fixed some Linux warnings in pluginviewer.
+
+2011-01-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/scram.c: Added support for storing SCRAM secrets in
+	  authPassword attribute. Also added the "scram_secret_generate" option
+	  for controlling if authPassword SCRAM secret should be generated
+	  or not. By default (when not specified) the authPassword SCRAM secret
+	  is NOT generated.
+
+2011-01-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/scram.c: Updated the SCRAM plugin not to use the hardcoded
+	  SCRAM-SHA-1 plugin name in logging.
+
+2011-01-18  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Use the same username for reauthentication
+	  cache lookup and update. Thanks to Ken for pointing out the
+	  problem.
+
+2011-01-14  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/ntlm.c: Flag NTLM plugin as HTTP-ready
+
+2011-01-14  Ken Murchison <murch@andrew.cmu.edu>
+	* include/sasl.h, include/saslplug.h,
+	  lib/common.c, lib/server.c, plugins/digest-md5.c:
+	  Allow DIGEST-MD5 plugin to be used for server-side 
+	  HTTP Digest (RFC 2617)
+
+2010-12-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: Some reformatting and safer handling of 'free
+	  after SASL server shutdown' condition in server_dispose.
+
+2010-12-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: server_idle needs to obey server's SASL mechanism
+	  list from the server context.
+
+2010-12-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/client.c, lib/saslint.h: Added support for ordering
+	  SASL mechanisms by strength (on the client side),
+	  or using the client_mech_list option.
+
+2010-12-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h, include/saslplug.h, lib/client.c, lib/common.c,
+	  lib/saslint.h, lib/server.c, sample/Makefile.am, sample/client.c,
+	  sample/server.c: Added support for channel bindings
+	  (patch by Luke Howard).
+
+2010-12-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslutil.c: Fixed the random number generator on Windows
+	  to actually produce random output on each run.
+
+2010-12-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: Updated textual representations of some error
+	  messages
+
+2010-11-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Eliminated some "signed/unsigned mismatch"
+	  warnings.
+
+2010-11-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c, plugins/srp.c, plugins/otp.c,
+	  plugins/ntlm.c, plugins/login.c, plugins/cram.c:
+	  Be protective against calling sasl_server_step
+	  once authentication has failed.
+
+2010-11-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Minimize the number of auxprop lookups
+	  in the server side DIGEST-MD5 plugin for the most common
+	  case when authentication and authorization identities are
+	  the same.
+
+2010-11-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Updated digestmd5_server_mech_step2()
+	  to be more defensive against empty client input.
+
+2010-11-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Fixed some memory leaks on failed
+	  plugin initialization. Prevent potential race condition
+	  when freeding plugin state. Set the freed reauthentication
+	  cache mutex to NULL, to make errors due to mutex access
+	  after free more obvious.
+
+2010-11-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Test against broken UTF-8 based hashes
+	  if calculation using special ISO-8859-1 code fails.
+	  This affected some XMPP clients. Patch by Dave Cridland
+	  <dave.cridland@isode.com>.
+
+2010-11-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Fixed an interop problem with some
+	  LDAP clients ignoring server advertised realm
+	  and providing their own.
+
+2009-08-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_shadow.c: Rolled back the previous commit
+	  (#define _XOPEN_SOURCE before including unistd.h),
+	  as this seems to break Solaris 8 build. Note that crypt.h
+	  should be present on a Solaris 8 machine, as well is on Debian,
+	  so this shouldn't be a problem.
+
+2009-08-04  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gssapi.c: Properly set serveroutlen to 0 in one place.
+	  Don't send empty challenge once server context establishment is done,
+	  as this is in violation of the RFC 2222 and its successor.
+
+2009-07-24  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gssapi.c: Don't send maxbuf, if no security layer
+	  can be established. Added additional checks for buffer lengths.
+
+2009-05-20  Ken Murchison <murch@andrew.cmu.edu>
+	* configure.in, cmulocal/sasl2.m4,
+	  config/kerberos_v4.m4, config/plain.m4, config/sasldb.m4,
+	  lib/Makefile.am: Fixes to allow static libs to be built in the
+	  CMU build environment
+
+2009-05-07  Ken Murchison <murch@andrew.cmu.edu>
+	* configure.in, include/sasl.h, lib/Makefile.am,
+	  plugins/Makefile.am, saslauthd/configure.in, sasldb/Makefile.am,
+	  win32/common.mak, win32/include/config.h: 2.1.24
+
+2009-05-03  Alexey Melnikov <alexey.melnikov@isode.com>
+	* sample/sample-client.c, sample/sample-server.c, utils/smtptest.c:
+	  Fixed bug # 2895 (passing LF to sasl_decode64)
+
+2009-05-03  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/NTMakefile: Disabled annoying warnings about use of
+	  deprecated standard C library functions, enabled
+	  warnings about Windows64 portability
+
+2009-05-03  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in: Added support for SQLite3
+	  (patch by Maxim Gorbachyov)
+
+2009-04-27  Ken Murchison <murch@andrew.cmu.edu>
+	* lib/saslutil.c: Fixed CERT VU#238019 (make sure sasl_encode64()
+	  always NUL terminates output or returns SASL_BUFOVER).
+
+2009-04-11  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/sql.c: Fixed SQLite lookup function.
+	  Also fixed SASL PLAIN authentication when used with
+	  SQLite auxprop backend.
+
+2009-04-11  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/dlopen.c: Updated to use .plugin extension on MacOS
+
+2009-04-08  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/client.c, lib/server.c: Removed unused mutexes
+	  (bug # 3141)
+
+2009-03-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h, include/saslplug.h, lib/canonusr.c,
+	  lib/checkpw.c, plugins/sasldb.c, plugins/sql.c:
+	  Added direct support for hashed password to auxprop API
+
+2009-03-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h, lib/canonusr.c, lib/external.c,
+	  plugins/gssapi.c, plugins/kerberos4.c: Make auxprop lookup
+	  calls in SASL GSSAPI/EXTERNAL optional
+
+2009-03-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/sasldb.c: A better fix for spurious 'user not found'
+	  errors caused by an attempt to delete a non-existent property
+
+2009-02-21  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/saslutil.h, lib/saslint.h: Made sasl_config_init public
+
+2009-02-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslint.h, lib/client.c, lib/common.c, lib/server.c:
+	  Make sure that sasl_set_alloc() has no effect once sasl_client_init()
+	  or sasl_server_init() is called [patch from Debian by
+	  fabbe@debian.org]
+
+2009-02-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: GCC 4.4 requires that the #elif
+	  preprocessor directive have a test condition [patch from Debian by
+	  fabbe@paniq.net]
+
+2009-02-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/lak.c: Define LDAP_DEPRECATED so that ldap_get_values
+	  is properly defined when compiling [patch from Debian by
+	  Dann Frazier <dannf@debian.org>]
+
+2009-02-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_sasldb.c: pid_file_lock is created with a mask
+	  of 644 instead of 0644 [patch from Debian by Sam Hocevar <sam@zoy.org>]
+
+2009-02-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_sasldb.c: Include config.h so that MAXHOSTNAMELEN
+	  is available when building on hurd-i386 [patch from Debian
+	  by mbanck@debian.org]
+
+2009-02-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_shadow.c: Define _XOPEN_SOURCE before including
+	  unistd.h, so that crypt is correctly defined [patch from Debian
+	  by dannf@debian.org]
+
+2009-02-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/pluginviewer.c: Code cleanup, improved human readable messages
+
+2009-02-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/config.c: Strip trailing spaces from config file option
+	  values (bug # 3139, bug # 3041)
+
+2009-02-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/otp.c: Don't use a stack variable for an OTP prompt
+	  (bug # 2822)
+
+2009-02-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_getpwent.c: Fixed Solaris build (patch by Leena
+	  Heino for bug # 2666)
+
+2009-02-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/saslplug.h, lib/server.c, plugins/anonymous.c,
+	  plugins/gssapi.c, plugins/otp.c: Partial support for the
+	  SASL_FEAT_DONTUSE_USERPASSWD feature
+
+2009-01-28  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h, lib/auxprop.c, lib/common.c, lib/server.c:
+	  Don't treat a constraint violation as an error to store an auxprop
+	  property
+
+2009-01-28  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h, lib/server.c: Extended libsasl (auxprop) to support
+	  user deletion
+
+2009-01-28  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/otp.c: Downgrade the failure to store OTP secret to debug level
+
+2009-01-25  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/windlopen.c: Free handles of shared libraries on Windows
+	  that were loaded but are not SASL plugins (patch by Petr Prazak)
+	  [Bug # 2089].
+
+2008-11-23  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/NTMakefile, win32/common.mak: Added support for building
+	  SQLite3 on Windows.
+
+2008-11-23  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/ldapdb.c: Updated LDAPDB lookup function to match auxprop
+	  API changes
+
+2008-11-15  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/sql.c: Added SQLITE3 support (patch by Maxim Gorbachyov)
+
+2008-10-31  Ken Murchison <murch@andrew.cmu.edu>
+	* lib/saslint.h, lib/server.c: order advertised mechanisms
+	  per the specified 'mech_list' option or by relative "strength"
+
+2008-10-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Fixed more portability warnings.
+	  Fixed some rare memory leaks. More detailed error reporting.
+
+2008-10-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* win32/include/config.h, lib/canonusr.c, lib/config.c,
+	  sasldb/allockey.c, utils/saslpasswd.c, utils/testsuite.c,
+	  sample/sample-server.c, plugins/anonymous.c, plugins/digestmd5.c,
+	  plugins/login.c, plugins/ntlm.c, plugins/otp.c:
+	  Fixed Windows 64 portability and other types of warnings
+
+2008-10-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* win32/common.mak: Added support for building libraries.
+	  Added support for Windows64.
+
+2008-10-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: Prevent freeing of common state on a subsequent
+	  call to _sasl_common_init. Make sure that the last global callback
+	  always wins.
+
+2008-10-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslint.h, lib/canonusr.c, lib/checkpw.c, lib/client.c,
+	  lib/server.c: Further fixes to auxprop lookup and _sasl_canon_user
+	  cleanup
+
+2008-10-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/saslplug.h, lib/auxprop.c, lib/canonusr.c, lib/saslint.h,
+	  plugins/sasldb.c, plugins/sql.c:
+	  Extended SASL auxprop_lookup to return error code
+
+2008-10-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslutil.c: Fixed Mac OS X 10.3 build.
+
+2008-10-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/sql.c: Uninitialized variables cause crash when
+	  the searched user is not found (patch from
+	  Maxim Gorbachyov <maxim.gorbachyov@gmail.com>)
+
+2008-10-23  Alexey Melnikov <alexey.melnikov@isode.com>
+	* sasldb/db_berkeley.c:  Return SASL_NOUSER instead of SASL_FAIL
+	  when the database file doesn't exist
+
+2008-10-23  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/checkpw.c: Updated sasl_user_exists so that it can handle
+	  passwordless accounts (e.g. disabled)
+
+2008-10-23  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/saslutil.h, lib/saslint.h, lib/client.c, lib/common.c,
+	  lib/saslutil.c, lib/server.c: Added hostname canonicalization
+
+2008-10-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/NTMakefile, utils/NTMakefile, sample/NTMakefile,
+	  plugins/NTMakefile: Updated to build with VC 8.0 (VC++ 2005)
+
+2008-10-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/NTMakefile: Don't install .exp and .manifest files.
+	  Updated build dependencies.
+
+2008-10-21  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslint.h, lib/client.c, lib/common.c, lib/server.c:
+	  Implemented sasl_client_done/sasl_server_done
+
+2008-10-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/login.c, plugins/plain.c: Advertise
+	  SASL_SEC_PASS_CREDENTIALS feature in PLAIN and LOGIN
+
+2008-10-02  Ken Murchison <murch@andrew.cmu.edu>
+	* lib/checkpw.c: Fixed potential buffer overflow in
+	  saslautd_verify_password().
+
+2008-09-30  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: Fixed sasl_set_mutex() to disallow changing
+	  mutex management functions once sasl_server_init/
+	  sasl_client_init is called. Failure to do this is causing
+	  a crash while locking mutexes. [Bug # 3083]
+
+2008-01-24  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/ntlm.c: Fixed crash in calculating NTv2 reponse
+	  (patch from Tim Costen from Isode)
+
+2008-01-23  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/ntlm.c, doc/options.html: allow a comma separated
+	  list of servernames in 'ntlm_server' option
+	  (patch from Enrico Persiani <enrico@ninfea-soft.org>)
+
+2008-01-23  Ken Murchison <murch@andrew.cmu.edu>
+	* plugins/ldapdb.c, plugins/makeinit.sh, doc/options.html:
+	  Added code to extend ldapdb into a canon_user plugin
+	  in addition to its existing auxprop plugin functionality
+	  (patch from Howard Chu <hyc@symas.com>
+	   and Torsten Schlabach <tschlabach@gmx.net>)
+
+2008-01-23  Ken Murchison <murch@andrew.cmu.edu>
+	* saslauthd/auth_rimap.c: fixed bug counting double-quotes in
+	  username/password.  Also fixed bug zeroing password.
+	  (patch from Robert Sanderson <rwsiv1@gmail.com>)
+
+2008-01-23  Ken Murchison <murch@andrew.cmu.edu>
+	* saslauthd/auth_krb.c: improved diagnostic in the
+	  k5support_verify_tgt() function. Now, detailed krb5 error
+	  information will be given out in the LOG_DEBUG syslog
+	  channel (based on patch from Enrico Scholz
+	  <enrico.scholz@informatik.tu-chemnitz.de>)
+
+2007-06-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/dlopen.c: 64bit HP-UX uses .so for shared libraries
+	  (patch by Nathan Kinder <nkinder@redhat.com>).
+
+2007-06-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Fixed a memory leak in the DIGEST-MD5
+	  security layer (based on patch from Nathan Kinder
+	  <nkinder@redhat.com>).
+
+2007-05-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* man/*: updated to reference RFC 4422 instead of
+	  RFC 2222.
+
+2007-03-02  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/sasldb.c, plugins/sql.c: Ignore properties
+	  starting with '*' in the auxprop store function.
+
+2007-02-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Fixed parsing of challenges/
+	  responses with extra commas.
+
+2007-01-29  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/gssapi.c: Check that params->serverFQDN is
+	  not NULL before using strlen on it (reported by
+	  Steven Simon <simon.s@apple.com>)
+	
+2006-12-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: Typecast iov_base to (char *),
+	  in case it is defined as "void *" on a platform
+	  like HPUX (Olaf Flebbe).
+
+2006-11-27  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Cleaned up comments and
+	  some error messages.
+
+2006-08-24  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/dlopen.c: Fixed segfault in dlclose on HPUX,
+	  based on feedback from <biswatosh2001@yahoo.com>.
+
+2006-07-16  Alexey Melnikov <alexey.melnikov@isode.com>
+	* win32/common.mak: Abstracted out compiler command
+	  line options for exception handling.
+
+2006-07-04  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/auth_shadow.c: Include crypt.h, so that crypt()
+	  is defined. This fixes crash on x64 Suse where
+	  sizeof(int) != sizeof(char *). Based on patch from
+	  rhafer@suse.de.
+
+2006-06-26  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Allow for multiple qop options
+	  from the server and require a single qop option
+	  from the client.
+
+2006-05-19  Ken Murchison <murch@andrew.cmu.edu>
+	* Makefile.am: include INSTALL.TXT in distro
+	*** Ready for 2.1.22
+
+2006-05-18  Ken Murchison <murch@andrew.cmu.edu>
+	* cmulocal/sasl2.m4: patch to compile with MIT krb5 1.4.3
+	  (Philip Guenther <guenther@sendmail.com>)
+
+2006-05-18  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in: Fixed default value in help for the
+	  --with-authdaemond command line option (Philip Guenther).
+
+2006-05-17  Alexey Melnikov <alexey.melnikov@isode.com>
+	* NEWS: Ready for 2.1.22
+
+2006-05-17  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/Makefile.am: enable pluginviewer in the default build.
+
+2006-04-26  Ken Murchison <murch@andrew.cmu.edu>
+	* lib/server.c: call do_authorization() after successful APOP
+
+2006-04-26  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: If neither DES nor RC4 cipher is selected,
+	  advertise maxssf of 1 (integrity protection).
+
+2006-04-26  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/pluginviewer.c: Must set fully qualified domain name
+	  in sasl_client_new, or some plugins will not be shown.
+
+2006-04-26  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/client.c: Replaced wrong "break" statement with
+	  "continue" in the client side list function.
+
+2006-04-25  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/NTMakefile: Enable RC4 cipher in Windows build.
+
+2006-04-25  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Make sure that SASL packets
+	  shorter than 16 bytes don't cause buffer overrun.
+	  Also prevent an error report from BoundsChecker
+	  regarding pointer being out of range.
+
+2006-04-25  Alexey Melnikov <alexey.melnikov@isode.com>
+	* win32/common.mak: Fixed bug of not setting CODEGEN
+	  (code generation option) if STATIC is set.
+
+2006-04-24  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/passdss.c, plugins/srp.c: Added include files required
+	  by OpenSSL 0.9.8 (original patch by Dan Nicholson).
+
+2006-04-24  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/NTMakefile: testsuite.exe doesn't depend on saslSASLDB.dll.
+
+2006-04-24  Alexey Melnikov <alexey.melnikov@isode.com>
+	* doc/windows.html: Updated Windows build instructions.
+
+2006-04-20  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/testsuite.c: Removed sasl_encode test which is no longer
+	  valid due to changed in sasl_encodev.
+	  Also properly terminated all property request lists with NULL.
+
+2006-04-19  Ken Murchison <murch@andrew.cmu.edu>
+	* saslauthd/auth_shadow.c, saslauthd/configure.in: Check for 4/5
+	argument versions of getXXname_r().
+
+2006-04-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: Andrey V. Malyshev pointed out that the SASL
+	  context is always NULL when the default logging callback
+	  _sasl_syslog is called. In particular this means that
+	  the log_level configuration option is always ignored.
+
+2006-04-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in: Search for application configuration
+	  files in /usr/lib/sasl2 by default and fall back to
+	  /etc/sasl2 if not found.
+
+2006-04-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/digestmd5.c: Handle missing realm option from
+	  the client as the empty string. This match the behavior
+	  prescribed in RFC 2831.
+
+2006-04-19  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/Makefile.am: Enable testsaslauthd build
+	  by default.
+
+2006-04-18  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslint.h, lib/common.c: Added support for spliting
+	  big data blocks (bigger than maxbuf) into multiple SASL
+	  packets in sasl_encodev.
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/Makefile.am: Added the pluginviewer man page.
+	  Reordered link dependencies for saslpasswds/sasldblistusers2.
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/pluginviewer.8: Added man page for pluginviewer.
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/pluginviewer.c: Deleted unused command line parameters
+	  and cleaned up usage output.
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/gai.h: Use HAVE_GETADDRINFO (instead of HAVE_GETNAMEINFO)
+	  to protect definition of getaddrinfo().
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h: Allocated some GSSAPI specific properties
+	  for Nico Williams (Sun)
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/common.c: Free default_plugin_path and
+	  default_conf_path variables in sasl_done.
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* sasldb/allockey.c: Cleaned up some warnings
+
+2006-04-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* win32/include/config.h: Deleted a misleading comment
+
+2006-04-06 Jeffrey Teaton <jeaton@cmu.edu>
+	* saslauthd/auth_rimap.c: patch from Dale Sedivec to prevent
+	  segfault when saslauth free()s returned string
+	* plugins/sql.c: patch from Matthew Hardin to do better
+	  error checking for mysql_real_query
+
+2006-04-03  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in, plugins/NTMakefile, plugins/sasldb.c,
+	  sasldb/db_berkeley.c, sasldb/sasldb.h:
+	  Patch to keep BerkleyDB handle open between operations
+	  (for performance reason). New behavior can be enabled
+	  with --enable-keep-db-open. Original patch by Curtis King.
+
+2006-03-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/server.c: Fixed bug # 2796: load_config now
+	  looks in all directories for the config file,
+	  not just in the first one.
+
+2006-03-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/saslplug.h, lib/auxprop.c, lib/client.c
+	  lib/server.c, utils/Makefile.am, utils/NTMakefile,
+	  utils/pluginviewer.c [new]:
+	  Added support for reporting information about
+	  loaded auxprop plugins. Changed the first parameter
+	  to sasl_server_plugin_info/sasl_client_plugin_info
+	  to be "const char *". Added new utility for
+	  reporting information about client and server side
+	  authentication plugins and auxprop plugins (e.g.
+	  supported features, methods, etc.).
+
+2006-03-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* saslauthd/Makefile.am, saslauthd/auth_httpform.c,
+	  saslauthd/auth_httpform.h, saslauthd/configure.in,
+	  saslauthd/mechanisms.c, saslauthd/mechanisms.h:
+	  Added support for HTTP POST password validation
+	  in saslauthd (patch by Joe Ammann <joe@pyx.ch>)
+
+2006-03-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* cmulocal/openldap.m4: Allow for compilation
+	  with OpenLDAP 2.3+.
+
+2006-03-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslutil.c, utils/testsuite.c: Various
+	  fixes to sasl_decode64: don't ignore partial
+	  base64 data, don't allow any data after the '='
+	  sign, etc.).
+
+2006-03-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/saslint.h: Increase canonicalization buffer
+	  size to 1024 bytes, as Luke Howard has reported
+	  that 256 is too small for some certificates.
+
+2006-03-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/NTMakefile: Include Cyrus version of
+	  getnameinfo() when compiling with Visual Studio 6,
+	  as Windows SDK emulation is not available.
+
+2006-02-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h, lib/common.c: Added sasl_set_path
+	  function (for a more convenient way of setting
+	  plugin and config paths. Changed the default
+	  sasl_getpath_t/sasl_getconfpath_t callbacks to
+	  calculate the value only once and cache it
+	  for later use.
+
+2006-02-13  Alexey Melnikov <alexey.melnikov@isode.com>
+	* configure.in, include/sasl.h, lib/common.c,
+	  lib/saslinit.h, lib/server.c, man/Makefile.am,
+	  man/sasl_callbacks.3, man/sasl_getconfpath_t.3,
+	  win32/include/config.h: Added a new sasl_getconf_t
+	  callback for specifying where SASL configuration files
+	  can be found. Based on patch from Artur Frysiak
+	  <wiget@pld.org.pl> for SASL v1, updated by Gentoo
+	  folks for SASL v2 and further modified by
+	  Andreas Hasenack <andreas@conectiva.com.br>.
+
+2006-01-31  Alexey Melnikov <alexey.melnikov@isode.com>
+	* INSTALL, INSTALL.TXT: Renamed INSTALL to INSTALL.TXT
+	  as the former conflicts with Windows "install" target
+	  (and Windows file names are case-insensitive).
+
+2005-08-11  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/sasldb.c: Return SASL_NOUSER only if all calls to
+	  _sasldb_putdata() return SASL_NOUSER. This prevents spurious
+	  SASL_NOUSER errors.
+
+2005-07-07  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/ntlm.c: Added <openssl/md5.h> include in order to fix
+	  building with OpenSSL 0.9.8.
+
+2005-05-19  Derrick Brashear <shadow@andrew.cmu.edu>    
+	* config/libtool.m4: do proper quoting, from Andreas Winkelmann
+	* configure.in: clean up enable switches, from Patrick Welche
+	* config/sasldb.m4: fix macro names, from Andreas Winkelmann
+	* lib/client.c: deal with gcc4 strictness, from Steven Simon
+	
+2005-05-16  Derrick Brashear <shadow@andrew.cmu.edu>   
+	* configure.in, include/sasl.h, lib/Makefile.am,
+	  plugins/Makefile.am, saslauthd/configure.in, sasldb/Makefile.am,
+	  win32/common.mak, win32/include/config.h: 2.1.21
+	* Makefile.am: fix dist-hook to run makeinit.sh in plugins/
+
+2005-05-15  Derrick Brashear <shadow@andrew.cmu.edu>  
+	* saslauthd/lak.c: leak fix from Igor Brezac
+	
+2005-05-15  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/NTMakefile: ldapdb on Windows might depend on OpenSSL.
+
+2005-05-06  Derrick Brashear <shadow@andrew.cmu.edu> 
+	* configure.in, saslauthd/auth_pam.c: detect pam header location also
+	  where MacOS provides it, and use it there
+	* utils/Makefile.am: change link order for MacOS
+	* configure.in: provide option to disable installing MacOS SASL2 
+	  framework
+	* configure.in, config/kerberos_v4.m4, config/plain.m4,
+	  config/sasldb.m4, lib/Makefile.am, sasldb/Makefile.am,
+	  (cmulocal/sasl2.m4): fix case where we are building 
+	  --enable-static --with-dblib=none causing automake's dependancy
+	  stuff to screw us when we try to build files with .. in their path
+	
+2005-04-11  Derrick Brashear <shadow@andrew.cmu.edu>
+	* configure.in, plugins/digestmd5.c: detect and include des.h if it 
+	  exists, otherwise assume we don't need it (Solaris 9)
+
+2005-04-11  Derrick Brashear <shadow@andrew.cmu.edu>
+	* sasldb/Makefile.am, config/sasldb.m4: work around HP-UX make's
+	  inability to have pipes in $(shell ...) by setting 
+	  LOCAL_SASL_DB_BACKEND_STATIC at the same time as
+	  SASL_DB_BACKEND_STATIC.
+	
+2005-03-15  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/dlopen.c: log the reason for opendir() failure
+	  when loading plugin.
+
+2005-03-08  Alexey Melnikov <alexey.melnikov@isode.com>
+	* man/sasl_auxprop.3, man/sasl_auxprop_getctx.3,
+	  man/sasl_auxprop_request.3, man/sasl_canon_user_t.3,
+	  man/sasl_client_init.3, man/sasl_client_new.3,
+	  man/sasl_client_start.3, man/sasl_client_step.3,
+	  man/sasl_decode.3, man/sasl_errdetail.3, man/sasl_errstring.3,
+	  man/sasl_getpath_t.3, man/sasl_getrealm_t.3,
+	  man/sasl_getsecret_t.3, man/sasl_server_init.3,
+	  man/sasl_server_new.3, man/sasl_server_start.3,
+	  man/sasl_server_step.3, man/sasl_setpass.3,
+	  man/sasl_user_exists.3, man/sasl_verifyfile_t.3: multiple
+	  spelling corrections from Steven Simon <steven_si@sbcglobal.net>.
+
+2005-03-07  Alexey Melnikov <alexey.melnikov@isode.com>
+	* utils/saslpasswd2.8, utils/sasldblistusers2.8: updated manpages.
+
+2005-03-01  Derrick Brashear <shadow@andrew.cmu.edu>  
+	* lib/common.c: honor log level setting
+	
+2005-02-28  Derrick Brashear <shadow@andrew.cmu.edu>   
+	* README.ldapdb: ldapdb license info
+	
+2005-02-25  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/sasl.h, lib/common.c: Added SASL_VERSION_FULL
+	  define
+
+2005-02-22  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/NTMakefile, win32/common.mak: Windows build of the ldapdb
+	  auxprop plugin
+
+2005-02-16  Derrick Brashear <shadow@andrew.cmu.edu> 
+	* configure.in, doc/install.html, doc/options.html, doc/readme.html,
+	  doc/sysadmin.html, lib/staticopen.h, plugins/Makefile.am,
+	  plugins/ldapdb.c, plugins/makeinit.sh: pull in ldapdb auxprop
+	  plugin, from Igor Brezac (Howard Chu's plugin)
+
+2005-02-14  Derrick Brashear <shadow@andrew.cmu.edu>
+	* saslauthd/krbtf.c: updated from CMUCS
+	* saslauthd/auth_krb5.c: log the krb5 error return if get_creds fails 
+	
+2005-02-01  Alexey Melnikov <alexey.melnikov@isode.com>
+	* win32/include/config.h: Updated to match gai.h changes.
+	* win32/include/config.h: added define for the OTP plugin.
+
+2005-01-27  Derrick Brashear <shadow@andrew.cmu.edu>
+	* configure.in, include/gai.h: move AI_NUMERICHOSTS definitions
+	  to config.h because gai.h is not always included.
+
+2005-01-10  Derrick Brashear <shadow@andrew.cmu.edu>
+	* saslauthd/auth_krb5.c, saslauthd/auth_krb4.c,
+	  saslauthd/krbtf.h (added), saslauthd/krbtf.c (added),
+	  saslauthd/cfile.h (added), saslauthd/cfile.c (added),
+	  saslauthd/Makefile.am: Kerberos V4/V5 alternate keytab
+	  in saslauthd, plus common code merging (from David Eckhardt
+	  via Dale Moore)
+
+2004-12-08  Alexey Melnikov <alexey.melnikov@isode.com>
+	* doc/windows.html: Updated as per recent build changes.
+	* plugins/ntlm.c: Fixed NTLM build on Windows,
+	  as compiler was complaining about array size not being
+	  a const.
+	* lib/NTMakefile, plugins/NTMakefile, win32/common.mak,
+	  win32/include/config.h: Use native IPv6 support on Windows,
+	  falling back to Microsoft emulation. Cleaner support
+	  for Visual Studio 6.
+
+2004-11-24  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: squashed unused parameter warnings
+
+2004-11-24  Ken Murchison <ken@oceana.com>
+	* plugins/passdss.c: added; PASSDSS-3DES-1 implementation
+	* configure.in, plugins/Makefile.am, plugins/makeinit.sh:
+	  added support for PASSDSS
+	* doc/draft-newman-sasl-passdss-xx.txt: added
+	* doc/index.html, doc/Makefile.am: added PASSDSS draft
+
+2004-11-19  Derrick Brashear <shadow@andrew.cmu.edu>
+	* saslauthd/auth_krb5.c: verify against the service we
+	  were passed. needs to be made configurable.
+
+2004-11-10  Alexey Melnikov <alexey.melnikov@isode.com>
+	* doc/draft-burdis-cat-srp-sasl-08.txt: deleted
+	* doc/draft-ietf-sasl-anon-02.txt: deleted
+	* doc/draft-ietf-sasl-crammd5-01.txt: deleted
+	* doc/draft-ietf-sasl-gssapi-00.txt: deleted
+	* doc/draft-ietf-sasl-plain-03.txt: deleted
+	* doc/draft-ietf-sasl-rfc2222bis-03.txt: deleted
+	* doc/draft-ietf-sasl-rfc2831bis-02.txt: deleted
+	* doc/draft-ietf-sasl-saslprep-04.txt: deleted
+	* doc/draft-newman-sasl-c-api-01.txt: deleted
+	* doc/draft-burdis-cat-srp-sasl-xx.txt: added
+	* doc/draft-ietf-sasl-anon-xx.txt: added
+	* doc/draft-ietf-sasl-crammd5-xx.txt: added
+	* doc/draft-ietf-sasl-gssapi-xx.txt: added
+	* doc/draft-ietf-sasl-plain-xx.txt: added
+	* doc/draft-ietf-sasl-rfc2222bis-xx.txt: added
+	* doc/draft-ietf-sasl-rfc2831bis-xx.txt: added
+	* doc/draft-ietf-sasl-saslprep-xx.txt: added
+	* doc/draft-newman-sasl-c-api-xx.txt: added
+	* doc/index.html, doc/Makefile.am: Renamed the files
+
+2004-11-02  Alexey Melnikov <alexey.melnikov@isode.com>
+	* include/saslplug.h, lib/common.c, lib/saslint.h,
+	  lib/client.c: Added sasl_client_plugin_info().
+
+2004-10-26  Alexey Melnikov <alexey.melnikov@isode.com>
+	* sample/sample-client.c, sample/sample-server.c: Fixed several
+	  64 bit portability warnings.
+	* utils/testsuite.c: Fixed several 64 bit portability warnings.
+	* utils/saslpasswd.c: Fixed typo in an auxprop name.
+	* include/saslplug.h, lib/common.c, lib/saslint.h,
+	  lib/server.c: Added sasl_server_plugin_info().
+
+2004-10-24  Derrick Brashear <shadow@andrew.cmu.edu> 
+	* lib/common.c: initialize path in case caller didn't.
+
+2004-10-24  Derrick Brashear <shadow@andrew.cmu.edu> 
+	* Prep for 2.1.20
+
+2004-10-19  Derrick Brashear <shadow@dementia.org>
+	* Makefile.am, saslauthd/Makefile.am: require automake 1.7;
+	  prior versions require AM_CONFIG_HEADER and dislike AM_LDFLAGS
+
+2004-10-14  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: portability fixes from Alexey, and squashed a
+	  signed/unsigned warning
+
+2004-10-14  Alexey Melnikov <alexey.melnikov@isode.com>
+	* lib/NTMakefile: Don't install intermediate file libsasl.res
+
+2004-09-22  Derrick Brashear <shadow@andrew.cmu.edu>
+	* lib/common.c: don't honor SASL_PATH in setuid environment. 
+	  from Gentoo
+	
+2004-09-08  Alexey Melnikov <alexey.melnikov@isode.com>
+	* plugins/cram.c, plugins/anonymous.c, plugins/login.c,
+	  plugins/plain.c, plugins/sasldb.c: Fixed several 64 bit
+	  portability warnings
+
+2004-09-02  Derrick Brashear <shadow@andrew.cmu.edu>
+	* plugins/kerberosv4.c: simple explanation in the code of one 
+	  possible error you might see in strange circumstances; 
+	  i should probably make openssl's des unable to be used if
+	  mit krb5 is being used.
+
+2004-08-06  Derrick Brashear <shadow@andrew.cmu.edu>
+	* plugins/cram.c: initialize authid to null so stack garbage 
+	  is not pushed into _sasl_canon_user
+	
+2004-07-29  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: Fix handling of client realm callback
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-07-21  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: Memory management cleanup
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-07-15  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* configure.in, plugins/gssapi.c: Wrap all GSS calls
+	  in mutexes when required by the implementation.
+	  (based on a patch by Simon Wilkinson <simon@sxw.org.uk>)
+
+2004-07-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: Fix potential buffer overflow, call
+	  add_to_challenge in 2 more places (Alexey Melnikov
+	  <Alexey.Melnikov@isode.com>)
+	* lib/server.c, lib/saslint.h, lib/common.c: don't directly
+	  store buffers in the params structure
+	* plugins/gssapi.c: Fix server side maxoutbuf calculation
+	  (Sam Hartman <hartmans@mit.edu>)
+	* plugins/gssapi.c: Use gss_wrap_size_limit on client side too
+	* Ready for 2.1.19
+
+2004-07-01  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Prep for 2.1.19
+
+2004-06-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/auth_rimap.c: Fix Tru64 compilation problem
+	* plugins/sql.c: Don't leak settings variable if init fails
+	* utils/testsuite.c: Update for current library
+	* plugins/digestmd5.c: Quoting fixes for client side
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-06-23  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: Minor bugfixes, support %R token
+	  (Igor Brezac <igor@ypass.net>)
+	* plugins/otp.c: Use plugin supplied authid for mech calculations
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* lib/auxprop.c: Use getopt callback from connection context when
+	  storing auxprops (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/otp.c, plugins/srp.c, plugins/plugin_common.c: Use correct
+	  form of userid (user@realm) when running setpass methods
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* saslauthd/configure.in: Handle LTLIBOBJS
+
+2004-06-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/NTMakefile: Remove only recognized (generated) .rc files,
+	  not just *.rc. This will allow for plugins with own resource files.
+	  Also corrected spelling mistake in OPENSSL (Alexey Melnikov
+	  <Alexey.Melnikov@isode.com>)
+	* lib/server.c, include/sasl.h: Support for SASL_SET_CURMECH_ONLY
+	  flag to sasl_setpass() (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-06-16  Ken Murchison <ken@oceana.com>
+	* lib/server.c: use more accurate errors codes for mech_permitted()
+
+2004-06-16  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: don't used the parsed authid for calculations
+	  (Alexey Melnikov <alexey.melnikov@isode.com>)
+
+2004-06-16  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Support for forwarding of GSSAPI credentials
+	  (Morten Olsen <mso@medical-insight.com & 
+	   Alexey Melnikov <alexey.melnikov@isode.com>)
+
+2004-06-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* win32/config.mak: Remove unneeded libraries
+	  (Alexey Melnikov <alexey.melnikov@isode.com>)
+
+2004-06-02  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Spelling Fixes (selsky@columbia.edu)
+
+2004-05-27  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* SQLite support (Norikatsu Shigemura <nork@ninth-nine.com>)
+	* SQLite support on windows (Alexey Melnikov
+	  <Alexey.Melnikov@isode.com>)
+
+2004-05-25  Ken Murchison <ken@oceana.com>
+	* plugins/digest-md5.c: use separate global contexts for client/server
+
+2004-05-21  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* configure.in, lib/Makefile.am: Better handling of -ldoor library
+	  addition (only add it to base library, don't add -lpthread)
+	* saslauthd/auth_krb5.c: zero out the krb5_data structure
+	  before use
+
+2004-05-20  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* include/sasl.h, lib/common.c, lib/saslint.h, lib/server.c:
+	  Add SASL_APPNAME to sasl_getprop/sasl_setprop for further
+	  compatibilty with SASL C API draft
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-05-18  Ken Murchison <ken@oceana.com>
+	* plugins/digest-md5.c: made the global context a struct
+	  containing the reauth_cache so we can NULL it after we free it
+
+2004-05-07  Ken Murchison <ken@oceana.com>
+	* contrib/stripplus_canonuser.patch: added
+
+2004-04-27  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/auth_shadow.c: Make thread-safe
+	  (Steve Barber <steveb@cme.nist.gov>)
+
+2004-04-26  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/auth_krb5.c: Alternate realm support for Kerberos 5
+
+2004-04-16  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: Mac OS X fix
+	  (Chris Ridd <chris.ridd@isode.com>)
+
+2004-04-14  Ken Murchison <ken@oceana.com>
+	* plugins/plain.c: don't include authzid in response unless
+	  specified by client
+
+2004-03-29  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* sample/server.c: Ensure that len has a value
+
+2004-03-25  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/saslauthd-main.c: add -r option to saslauthd for combining
+	  user and realm into user@realm (for the userid).  Based on a patch
+	  by Jeremy Rumpf <jrumpf@heavyload.net>.
+
+2004-03-17  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/checkpw.c: Include errno.h when HAVE_AUTHDAEMON is defined
+	* doc/windows.html: Updates (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-03-16  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* configure.in: Properly use CMU_ADD_LIBPATH_TO for pgsql and mysql
+
+2004-03-10  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/dlopen.c: HPUX 11 Fix (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* Add sasl_version_info() (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* Add a bunch of NTMakefile files to EXTRA_DIST in Makefile.am's
+	* Ready for 2.1.18
+
+2004-03-08  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* NI_WITHSCOPEID fixes (Hajimu UMEMOTO <ume@mahoroba.org>) - correct
+	  Solaris 9 IPLOCALPORT/IPREMOTEPORT issue
+
+2004-02-24  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* acinclude.m4: move to config/libtool.m4
+	* saslauthd/lak.[ch]: Added filter based group membership check
+	  (Paul Bender <pbender@qualcomm.com>, Igor Brezac <igor@ipass.net>)
+
+2004-02-23  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/NTMakefile: Enable DO_SRP_SETPASS on windows
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* doc/windows.html: Updates
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* win32/: Add version resource info to plugins
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/digestmd5.c: Comments and other cleanup
+
+2004-02-20  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/server.c, include/saslplug.h: Allow "temporary failure"
+	  return values from mech_avail
+	* lib/canonusr.c, lib/server.c: Comment Nits
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/NTMakefile, plugins/plugin_common.h, 
+	  plugins/plugin_common.c, plugins/otp.c: build OTP on Windows
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-02-19  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c, sample/server.c, sample/client.c:
+	  error checking of getnameinfo() (Paul Kranenburg <pk@cs.few.eur.nl>)
+	* plugins/ntlm.c: alignment and endian fixes in load_session_setup()
+	  (Paul Kranenburg <pk@cs.few.eur.nl>)
+
+2004-02-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/NTMakefile, NTMakefile: nmake install support
+	  for doc/ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/digestmd5.c: Check that digest-uri is only sent once
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* utils/Makefile.am: add LIB_PGSQL to static link line
+
+2004-02-17  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* win32/include/config.h: caddr_t might be already defined
+	  elsewhere (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+        * lib/NTMakefile, include/saslutil.h:  getopt might be already
+	  defined elsewhere. The change will produce libsasl.dll which exports
+	  getopt, buat a define can be used to prevent import of getopt from
+	  libsasl.dll. (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-02-16  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* configure.in: Remove deprecated AC_PROG_RANLIB, CMU_PROG_LIBTOOL
+	  (Patrick Welche <prlw1@newn.cam.ac.uk>)
+	* lib/dlopen.c: OpenBSD ELF patch (J.C. Roberts)
+
+2004-02-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/NTMakefile, utils/NTMakefile: fix "clean" target
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* General winsock.h -> winsock2.h conversion
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/plugin_common.h: add extern "C" wrapper
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-01-23  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Remove "experimental" designation from saslauthd/ldap
+	* Correct handling of sasl_setpass errors when no
+	  mechanisms implement the setpass interface
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-01-20  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* configure.in: minor sql nit (Edward Rudd <eddie@omegaware.com>)
+	* lib/staticopen.h: MYSQL should be SQL
+	  (Edward Rudd <eddie@omegaware.com>)
+
+2004-01-12  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* win32/include/config.h: fix VC++ 6.0 compiles
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* configure.in: Correct use of AC_LIBOBJ, quote macro names
+	  defined by AC_DEFUN, Use enable_shared to determine whether
+	  to enable the shared plugin.
+	  (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+	* plugins/srp.c: Fix typos
+	  (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+	* saslauthd/configure.in: Correct use of AC_LIBOBJ
+	  (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+
+2004-01-08  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: better error logging
+
+2004-01-07  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/checkpw.c & others: Support for Courier-IMAP authdaemond
+	  use during password verification (Leandro Santi
+	  <lesanti@uolsinectis.com.ar>)
+
+2003-12-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: Fix NULL pointer dereference
+	  (Simon Brady <simon.brady@otago.ac.nz>)
+	* saslauthd/lak.c, lak.h, LDAP_SASLAUTHD: Improved retry handler,
+	  Improved logging/debug messages, Fixed String checks, config
+	  option changes (Igor Brezac <igor@ipass.net>)
+
+2003-12-22  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: Fix memory leak
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-12-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/plugin_common.c: Fix handling of blob unwrapping
+	  in _plug_decode
+	* lib/checkpw.c: Fix some file descriptor leaks during failures
+	  in the saslauthd code.
+
+2003-12-15  Rob Siemborksi <rjs3@andrew.cmu.edu>
+	* utils/saslauthd.c: Fix Typo
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/plugin_common.c: Fix potential memory leak
+	* lib/external.c: Limit size of authzids in EXTERNAL
+	* plugins/gssapi.c: Pre-init some variables
+	* lib/cram.c: Detect possible buffer overrun
+	* lib/checkpw.c: Post-fence bug
+	  (Leandro Santi <lesanti@uolsinectis.com.ar>)
+
+2003-12-12  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: assign null to free
+	  variables (Juan Felipe Garcia <fgc@usal.es>)
+	* saslauthd/lak.c: Improve retry when ldap connection is reset
+	  (1st pass) (Igor Brezac <igor@ipass.net>)
+
+2003-12-11  Rolf Braun <rbraun@andrew.cmu.edu>
+	* Several MacOS X Fixes
+
+2003-12-06  Ken Murchison <ken@oceana.com>
+	* lib/checkpw.c, lib/server.c,
+	  plugins/cram.c, plugins/digestmd5.c, plugins/ntlm.c,
+	  plugins/otp.c, plugins/srp.c: erase the plaintext password
+	  property from the context when we're done with it
+
+2003-12-01  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-crammd5-01.txt: added
+	* doc/draft-ietf-sasl-gssapi-00.txt: added
+	* doc/draft-ietf-sasl-plain-03.txt: added
+	* doc/draft-ietf-sasl-rfc2222bis-03.txt: added
+	* doc/draft-ietf-sasl-saslprep-04.txt: added
+	* doc/draft-ietf-sasl-crammd5-00.txt: deleted
+	* doc/draft-ietf-cat-sasl-gssapi-05.txt: deleted
+	* doc/draft-ietf-sasl-plain-02.txt: deleted
+	* doc/draft-ietf-sasl-rfc2222bis-02.txt: deleted
+	* doc/draft-ietf-sasl-saslprep-03.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to latest version of
+	  SASL drafts
+
+2003-12-01  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Fix build nit in IRIX.
+	* Actual 2.1.17 release.
+
+2003-11-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.17
+
+2003-11-19  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* config/kerberos_v4.m4: Disable KERBEROS_V4 support by default
+
+2003-11-14  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/server.c: do authorization callback in sasl_checkpass()
+	  (Chris Newman <chris.newman@sun.com>)
+
+2003-11-11  Ken Murchison <ken@oceana.com>
+	* lib/client.c: allow serverFDQN to be NULL in sasl_client_new()
+	* plugins/digestmd5.c, gssapi.c: require that we have serverFQDN
+	  for the client side of the plugin
+
+2003-11-07  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* --with-gss_impl configure option
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-11-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* nmake install support for Win32
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-11-03  Ken Murchison <ken@oceana.com>
+	* include/saslplug.h, lib/server.c, plugins/cram.c,
+	  plugins/digestmd5.c, plugins/ntlm.c, plugins/otp.c,
+	  plugins/srp.c: return SASL_TRANS to the application where
+	  appropriate (auto_transition enabled with writable auxprop)
+
+2003-10-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: OpenLDAP 2.0 Compatability Fix
+	  (Igor Brezac <igor@ypass.net>)
+	* saslauthd/ipc_unix.c: Fix buglet of not using saved errno
+	  value (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-10-20  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Win64 warning squashing (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* GSSAPI cleanups and fixes (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-10-14  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.16-BETA
+
+2003-10-08  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Support for autoconf 2.57, automake 1.7
+	* Minor m4 quoting fixes (Patrick Welche <prlw1@cam.ac.uk>)
+
+2003-10-07  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: removed sql_delete - don't DELETE rows from the
+	  table, just set the properties to NULL;
+	  fix a stupid logic error in my PgSQL changes
+	* doc/options.html: removed sql_delete option; clarifications
+	* doc/install.html: note that we require PostgreSQL v7.2+
+
+2003-10-06  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: use the correct propctx in sql_auxprop_store()
+
+2003-10-06  Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+	* plugins/sql.c: tiny bugfix to begin pgsql transactions
+	
+2003-10-04  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: only do a txn when we have a property to fetch;
+	  _pgsql_open() cleanup/fixes; more intelligient sql_usessl parsing;
+	  require sql_select option
+	* doc/options.html: reorganized SQL option descriptions
+
+2003-10-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* sasldb/allockey.c, sasldb/sasldb.h, utils/sasldblistusers.c:
+	  Add enumeration capability to the sasldb API
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-10-02  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: changed abstraction layer for transactions
+
+2003-10-01  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/: Documentation Update
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/NTMakefile, plugins/srp.c: Win32 SRP Support
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: Clean up some warnings
+	* lib/canonusr.c, win32/include/config.h, win32/common.mak,
+	  include/saslplug.h: Minor Cleanup
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* utils/NTMakefile, utils/sasldblistusers.c, utils/saslpasswd.c:
+	  Add version options to command line utilities
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-29  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c, doc/options.html: added sql_update and sql_delete
+	  for a complete auxprop_store() implementation; logic cleanup
+
+2003-09-25  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* utils/saslpasswd.c: Win32 perror() related patch
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-25  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: renamed sql_statement to sql_select,
+	  cleanup and bugfixes
+
+2003-09-23  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/gssapi.html: Misc updates
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* lib/Makefile.am, plugins/Makefile.am, saslauthd/Makefile.am,
+	  sasldb/Makefile.am: Cleanup INCLUDES for different build
+	  directories. (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-23  Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+	* plugins/sql.c: put transaction handling around the entirety of 
+	  the queries, and not just per-property; return the result status
+	  of bad postgres tuples
+
+2003-09-22  Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+	* plugins/sql.c: added semicolon at the end of each sql statement
+	
+2003-09-19  Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+	* plugins/sql.c: moved transaction handling to a more useful place,
+	  minor bugfixes
+
+2003-09-18  Ken Murchison <ken@oceana.com>
+	* lib/server.c: log a message when no password change is attempted
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-17  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c: misc fixes from Patrick Welche <prlw1@newn.cam.ac.uk>
+	
+2003-09-16  Ken Murchison <ken@oceana.com>
+	* doc/mechanisms.html: updated to latest versions of LOGIN and
+	  SRP drafts
+
+2003-09-15  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-rfc2222bis-02.txt: added
+	* doc/draft-ietf-sasl-rfc2222bis-01.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to latest version of
+	  SASL draft
+
+2003-09-14  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c, plugins/plugin_common.[ch]: Win32 support
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-12  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/sql.c: Log errors on connect failures
+	  (based on patch from Bruce M Simpson <bms@spc.org>)
+	* plugins/NTMakefile: Add support for GSSAPI=CyberSafe
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-10  Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+	* plugins/sql.c: created generic sql store function, added 
+	  transaction handling to sql statements
+	* doc/options.html: put pretty new options in the documentation
+	
+2003-09-10  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c, win32/config.mak, sample/: Win32 Fixes
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-09  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/NTMakefile: Minor nit
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-09  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: use retry_read() instead of just read()
+	* lib/checkpw.c, plugins/ntlm.c, saslauthd/utils.c:
+	  squash signed/unsigned warning
+
+2003-09-08  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: fix byte-alignment and password handling problems
+
+2003-09-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/checkpw.c: Check return value of door_call
+	  (Gary Mills <mills@cc.umanitoba.ca>)
+	* saslauthd/ipc_doors.c: Implement thread limiting,
+	  minor cleanup and error checking
+	  (Gary Mills <mills@cc.umanitoba.ca>)
+	* plugins/digestmd5.c: Fix minor interop issues, limit maxbuf
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-02  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c, doc/options.html: added support for NTLMv2 responses;
+	  fixed potential buffer overflow
+
+2003-09-02  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/common.c, lib/server.c, lib/NTMakefile, include/md5.h:
+	  more windows compatibility
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* plugins/NTMakefile: Add ability to build NTLM plugin under
+	  Win32 (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* utils/NTMakefile: Add ability to build testsuite
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* saslauthd/lak.c: Minor error message fix
+	  (Igor Brezac <igor@ypass.net>)
+
+2003-08-29  Ken Murchison <ken@oceana.com>
+	* doc/draft-murchison-sasl-login-00.txt: added
+	* doc/draft-sasl-login.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to "official" LOGIN draft
+
+2003-08-29  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: properly compute GSSAPI MAXOUTBUF
+	  (Paul Turgyan <pturgyan@umich.edu>)
+	* Further Win32 cleanup + HIER_DELIMITER usage
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-08-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* include/md5.h, lib/md5.c: Misc cleanup
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* utils/sasldblistusers.c: UI Cleanup, Win32 support
+	  (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+	* acconfig.h: add HIER_DELIMITER
+
+2003-08-27  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c: handle OpenSSL 0.9.7+ w/o old DES support
+
+2003-08-26  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: only send one NT/LM response to server
+	  (NT preferred); don't use canonified authid when proxying
+
+2003-08-24  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c, doc/options.html: allow NTLM authentication to
+	  be optionally proxied to an NT server (ntlm_server option)
+
+2003-08-24  Ken Murchison <ken@oceana.com>
+	* lib/common.c: added support for unsigned int types in _sasl_log()
+
+2003-08-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Improvements in Win32 build system from Alexey Melnikov
+	  <Alexey.Melnikov@isode.com>
+
+2003-08-14  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/*: Massive documentation updates.
+
+2003-08-13  Ken Murchison <ken@oceana.com>
+	* doc/index.html: added reference to a CIFS (SMB/NTLM) document
+
+2003-08-12  Ken Murchison <ken@oceana.com>
+	* doc/index.html: added reference to a good NTLM document
+
+2003-07-29  Ken Murchison <ken@oceana.com>
+	* plugins/cram.c: don't truncate long secrets to 64 bytes on the
+	  client-side of CRAM-MD5 (jiang_xiong@yahoo.com)
+
+2003-07-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: another missed pointer init
+	  (Will Fiveash <william.fiveash@sun.com>)
+
+2003-07-26  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/server.c: Missed pointer initialization fix
+	  ("Dave Cridland [Home]" <dave@cridland.net>)
+
+2003-07-26  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c: merged privacy and integrity security layer
+	  code and removed use of tmp buffers for security layer
+
+2003-07-25  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: removed use of tmp buffer for security layer;
+	  don't make a big buffer out of iovecs when encoding
+	* lib/server.c, plugins/login.c, plugins/plain.c: better handling
+	  of auto_transition -- doesn't try to transition from auxprop to
+	  auxprop
+
+2003-07-25  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* configure.in: Fix up some mysql/pgsql detection
+	* plugins/gssapi.c: improved error reporting
+	  (William Fiveash <William.Fiveash@sun.com>)
+	* cmulocal/sasl2.m4, saslauthd/mechanisms.h: Improved
+	  GSSAPI detection (don't default to MIT, require HAVE_KRB5_H
+	  for the kerberos5 saslauthd module)
+	  (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+
+2003-07-24  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: updated security layer code to be closer to draft -08
+
+2003-07-23  Rob Siemborksi <rjs3@andrew.cmu.edu>
+	* saslauthd/utils.[ch], saslauthd/configure.in: Detect/replace
+	  strlcpy and strlcat (based on ideas from
+	  Igor Brezac <igor@ipass.net>)
+
+2003-07-22  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c, plugins/gssapi.c, plugins/kerberos4.c,
+	  plugins/plugin_common.[ch]: moved encoded packet buffering into
+	  _plug_decode()
+
+2003-07-21  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: updated auth code to draft -08 (layers still need
+	  to be updated)
+	* configure.in, plugins/srp.c: use auxprop_store() instead of
+	  direct sasldb access
+
+2003-07-21  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* configure.in: add runpath information for MySQL and Postgres;
+	  better behavior for the interaction of --enable-sql and
+	  --with-mysql / --with-pgsql
+	* saslauthd/lak.[ch]: %d to be derived from %u if it can be,
+	  otherwise use %r (to account for the recent change in the
+	  core library).  Add ldap_default_realm parameter
+	  (Igor Brezac <igor@ipass.net>)
+
+2003-07-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: Client side of digest md5 doesn't
+	  have quotes around its cypher= directive (Bug 2113).
+	* saslauthd/lak.[ch]: support for ldap sasl binds,
+	  support for tls (Igor Brezac <igor@ipass.net>)
+
+2003-07-17  Ken Murchison <ken@oceana.com>
+	* include/sasl.h, include/saslplug.h,
+	* lib/auxprop.c, lib/common.c, lib/server.c, plugins/sasldb.c:
+	  implemented writable auxprops
+	* configure.in, plugins/otp.c, utils/saslpasswd: use
+	  auxprop_store() instead of direct sasldb access
+	* doc/options.html, lib/server.c: implemented 'noplain' option for
+	  auto_transition
+
+2003-07-17  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/config.c: Remove sasl_config_getint and sasl_config_getswitch
+	  because they are unused and confusing
+	* lib/checkpw.c: Correctly split realm from username in
+	  saslauthd_verify_password
+
+2003-07-15  Ken Murchison <ken@oceana.com>
+	* plugins/sql.c, doc/options.html: added sql_usessl option
+
+2003-07-15  Ken Murchison <ken@oceana.com>
+	* plugins/mysql.c: deleted
+	* plugins/sql.c: added
+	* acconfig.h, configure.in,
+	  doc/components.html, doc/options.html, doc/sysadmin.html,
+	  plugins/Makefile.am, plugins/makeinit.sh: deprecated MySQL plugin
+	  in favor of a new generic SQL plugin (currently supports MySQL and
+	  PostgreSQL)
+
+2003-07-15  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.15
+
+2003-07-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/components.html: added in the hopes that this gives a better
+	  description of how all the components interact
+
+2003-07-02  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-anon-02.txt: added
+	* doc/draft-ietf-sasl-plain-02.txt: added
+	* doc/draft-ietf-sasl-saslprep-03.txt: added
+	* doc/draft-ietf-sasl-anon-01.txt: deleted
+	* doc/draft-ietf-sasl-plain-01.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to latest versions of
+	  PLAIN, ANONYMOUS, SASLprep drafts
+
+2003-07-02  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* acconfig.h, cmulocal/sasl2.m4, plugins/gssapi.c:
+	  Properly detect HAVE_GSS_C_NT_USER_NAME
+	  (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+
+2003-07-01  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/kerberos4.c: Fix some maxoutbuf handling issues
+
+2003-07-01  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/mysql.c: Check return value of mysql_init
+	  (Ivan Kelly <ivan@ivankelly.net>)
+
+2003-07-01  Ken Murchison <ken@oceana.com>
+	* doc/draft-burdis-cat-srp-sasl-08.txt: added
+	* doc/draft-ietf-sasl-rfc2222bis-01.txt: added
+	* doc/draft-ietf-sasl-rfc2831bis-02.txt: added
+	* doc/draft-burdis-cat-srp-sasl-06.txt: deleted
+	* doc/draft-ietf-sasl-rfc2222bis-00.txt: deleted
+	* doc/draft-ietf-sasl-rfc2831bis-01.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to latest versions of
+	  SASL, SRP, DIGEST-MD5 drafts
+
+2003-06-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/mysql.c: Call mysql_init() too
+	  (Hajimu UMEMOTO <ume@mahoroba.org>)
+
+2003-06-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/sysadmin.html: Add more text about how to use realms.
+
+2003-06-27  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.14
+
+2003-06-11  Rolf Braun <rbraun@andrew.cmu.edu>
+	* config/kerberos_v4.m4:
+	  fix fallback to -lkrb4 when --enable-krb4 is specified
+	* config/ltconfig:
+	* config/ltmain.sh:
+	  make the darwin libtool work on OS X v10.2
+	  (bash/zsh shell syntax, and don't link bundles with extra args)
+	* dlcompat-20010505/dlopen.c: back out bogus delimiter change
+	* doc/macosx.html: update for 10.2 and add known problems section
+	* mac/osx_cfm_glue/cfmglue.c: fix sasl_done followed by client_init
+
+2003-06-11  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* man/sasl_client_new.3, man/sasl_server_new.3:
+	  Security flags don't belong here, connection flags do.
+
+2003-06-10  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-crammd5-00.txt: added
+	* doc/draft-nerenberg-sasl-crammd5-03.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to WG version of
+	  CRAM-MD5 draft
+
+2003-05-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: If we get an empty output token back
+	  from gss_accept_sec_context, return
+	  an empty string to transmit to the client.
+
+2003-05-30  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-rfc2831bis-01.txt: added
+	* doc/draft-ietf-sasl-rfc2831bis-00.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to latest version of
+	  DIGEST-MD5 draft
+
+2003-05-28  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-anon-01.txt: added
+	* doc/draft-ietf-sasl-plain-01.txt: added
+	* doc/draft-ietf-sasl-rfc2222bis-00.txt: added
+	* doc/draft-ietf-sasl-anon-00.txt: deleted
+	* doc/draft-ietf-sasl-plain-00.txt: deleted
+	* doc/draft-myers-saslrev-02.txt: deleted
+	* doc/index.html, doc/Makefile.am: updated to latest versions of
+	  SASL, PLAIN, ANONYMOUS drafts
+
+2003-05-21  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/ipc_unix.c: Accept File Descriptor Locking
+	  Fixes (found by Leena Heino <Leena.Heino@uta.fi>)
+	* saslauthd/cache.c: Similar fixes
+	  (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-05-15  Rob Siemborski <rjs3@andrew.cmu.edu>	
+	* configure.in: Actually listen to --disable-java
+	  (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+	* saslauthd/saslauthd-main.h: Increase listen backlog to
+	  match Cyrus master process (Igor Brezac <igor@ipass.net>)
+
+2003-05-14  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* config/kerberos_v4.m4: Minor nit
+	  (Carlos Velasco <carlosev@newipnet.com>)
+	* plugins/gssapi.c: Use GSS_C_NT_USER_NAME
+	  to work around Solaris 8/9 libgss bug.
+	  (gssapi_client_mech_step): Pass GSS_C_NO_BUFFER to first
+	  invocation of gss_init_sec_context to work around Solaris 8/9
+	  mech_krb5 bug. (Rainer Orth  <ro@TechFak.Uni-Bielefeld.DE>)
+	* cmulocal/sasl2.m4: Check for Sun SEAM GSS-API implementation
+	  (Rainer Orth  <ro@TechFak.Uni-Bielefeld.DE>)
+	* saslauthd/configure.in: Check for krb5.h.  Don't define if GSSAPI
+	  is present. (Rainer Orth  <ro@TechFak.Uni-Bielefeld.DE>)
+	* saslauthd/mechanisms.h: Test for HAVE_KRB5_H instead of HAVE_GSSAPI_H
+	  to activate AUTH_KRB5. (Rainer Orth  <ro@TechFak.Uni-Bielefeld.DE>)
+	* plugins/mysql.c: Use mysql_real_connect() instead of mysql_connect()
+	  (Petri Riihikallio <Petri.Riihikallio@Metis.fi>)
+	* saslauthd/: Misc ANSI C cleanups (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-05-13  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* config/sasldb.m4, utils/Makefile.am: fix installation of man
+	  pages that are homed in the utils/ directory
+	* include/*.h: Add extern "C" blocks for C++ compiles
+
+2003-05-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/saslauthd-main.c: misc spelling and UI cleanups
+
+2003-04-16  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/saslauthd-main.c: Don't set the auth mech until
+	  all options have been processed. (Peter Stamfest <peter@stamfest.at>)
+	* lib/client.c, lib/common.c, lib/saslint.h, lib/server.c: Do
+	  reference counting of the number of times sasl has been inited/doned.
+
+2003-04-15  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* config/ltmain.sh: fix some portability problems in the use of expr
+	  (Oliver Eikemeier <eikemeier@fillmore-labs.com>)
+
+2003-04-14  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.13
+
+2003-04-08  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/external.c, lib/server.c: use mech_avail to disable
+	EXTERNAL instead of special casing it (Chris Newman
+	<Chris.Newman@Sun.COM>)
+
+2003-03-31  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/ipc_unix.c, saslauthd/saslauthd-main.c,
+	  saslauthd/saslauthd-main.h: use the pidfile locking from
+	  the Cyrus IMAPd master process (implemented for saslauthd by
+	  Igor Brezac <igor@ipass.net>)
+	* configure.in, acconfig.h: Add configure option to set what
+	  we use for /dev/random
+
+2003-03-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/: Unify the source files so that the IPC methods
+	  are broken out into a separate API.  Cacheing of authentication
+	  credentials is also available as a command-line option.
+	  Other changes include: Remove Time of Day Flag, omit
+	  SO_REUSEADDR on AF_UNIX sockets, make using the accept-socket
+	  locking runtime configurable, and misc other cleanup.
+	  (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-03-26  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/plain.c: Defend against memory leak on canon_user
+	  failure (Chris Newman <chris.newman@sun.com>)
+
+2003-03-19  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/auxprop.c, lib/checkpw.c, lib/common.c, lib/saslutil.c,
+	  lib/server.c: Assorted minor fixes from Sun Microsystems
+	  (provided by Chris Newman <chris.newman@sun.com>)
+
+2003-03-13  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: Fix a memset length.  (Igor Brezac <igor@ipass.net>)
+
+2003-03-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: fix parity of digest-uri test
+	* lib/client.c, common.c, saslint.h, server.c: Pass global
+	  callbacks to global utils structure
+	  (Howard Chu <hyc@highlandsun.com>)
+	* saslauthd/auth_krb5.c: Fix memory/file descriptor leak
+	  in krb5 authentication (Jonathen Chen <jon@spock.org>)
+	* saslauthd/lak.c, lak.h, LDAP_SASLAUTHD: Remove ldap_cache
+	  code, and rename MAX() to LAK_MAX()
+
+2003-02-20  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-rfc2831bis-00.txt: added
+	* doc/draft-melnikov-rfc2831bis-02.txt: deleted
+	* doc/draft-newman-sasl-c-api-01.txt: added
+	* doc/draft-newman-sasl-c-api-00.txt: deleted
+	* doc/index.html: updated to WG version of DIGEST-MD5 draft,
+	  updated to latest C API draft
+	* doc/Makefile.am: updated to WG version of DIGEST-MD5 draft,
+	  updated to latest C API draft
+
+2003-02-12  Lawrence Greenfield  <leg+@andrew.cmu.edu>
+	* plugins/digestmd5.c: verify the service component of digest-uri
+
+2003-02-11  Ken Murchison <ken@oceana.com>
+	* doc/draft-ietf-sasl-anon-00.txt: added
+	* doc/draft-ietf-sasl-plain-00.txt: added
+	* doc/draft-zeilenga-sasl-anon-01.txt: deleted
+	* doc/draft-zeilenga-sasl-plain-01.txt: deleted
+	* doc/index.html: updated to WG versions of ANONYMOUS, PLAIN drafts
+
+2003-02-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* cmulocal/sasl2.m4: Don't use -ldes to check for Heimdal
+	* saslauthd/auth_krb4.c, saslauthd/auth_shadow.c,
+	  saslauthd/auth_getpwent.c, lib/kerberos4.c:
+	  Smarter checking of #includs for des.h
+	  (Mark Keasling <mark@air.co.jp>)
+	* saslauthd/testsaslauthd.c, saslauthd/saslauthd-doors.c:
+	  retry_read() should use a char * buffer not a void *
+	  buffer (Mark Keasling <mark@air.co.jp>)	
+	* cmulocal/berkdb.m4: Set CPPFLAGS around tests
+	  (based on patch from Leena Heino <Leena.Heino@uta.fi>)
+	* config/sasldb.m4: Actually use results of Berkeley DB tests
+	  (Leena Heino <Leena.Heino@uta.fi>)
+	* Ready for 2.1.12
+
+2003-01-31  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.11
+	* utils/Makefile.am: Ensure that dbconverter-2 can see the sasldb
+	  include directory.
+
+2003-01-29  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: Fix a situation where the realm wasn't
+	  being set for the client context, causing a segfault
+	* config/kerberos_v4.m4: first check des_* then check DES_*
+	  during OpenSSL tests (based on ideas from
+	  Leena Heino <Leena.Heino@uta.fi>)
+
+2003-01-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* config/sasldb.m4: Don't build sasldb plugin if compiling
+	  --with-dblib=none, since it will only fail to load anyway.
+
+2003-01-27  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/configure.in: use CMU_ADD_LIBPATH for LDAP support
+	  (Simon Brady <simon.brady@otago.ac.nz>)
+
+2003-01-23  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/acconfig.h: protect file from being included more than
+	  once (reported by Jeremy Rumpf <jrumpf@heavyload.net>)
+	* saslauthd/configure.in, configure.in: Move OpenSSL detection into
+	  cmulocal, detect openssl for use with lak.c
+
+2003-01-21  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: only _require_ one response (LM and/or NT), not both
+
+2003-01-09  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c, saslauthd/lak.h: Add the fastbind auth method
+	  (Simon Brady <simon.brady@otago.ac.nz>)
+
+2003-01-01  Ken Murchison <ken@oceana.com>
+	* saslauthd/configure.in, saslauthd/Makefile.am: don't make
+	  -lcrypt dependent upon --enable-plain
+
+2002-12-11  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: set SASL_FEAT_ALLOWS_PROXY on client side
+
+2002-12-10  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: explicitly #include <openssl/md5.h> to resolve
+	  OpenBSD/OpenSSL cruftiness
+
+2002-12-10  Rob Siemborksi <rjs3@andrew.cmu.edu>
+	* saslauthd/saslauthd-doors.c: Fix a potential memory leak when
+	  we call door_return()
+
+2002-12-09  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/auxprop.c: Correct leak in prop_clear, also update list_end
+	  in prop_request.
+	* doc/options.html: Update use of saslauthd_path to be correct
+
+2002-12-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.10
+
+2002-12-05  Larry Greenfield <leg@andrew.cmu.edu>
+	* plugins/digestmd5.c: DES key fixes. stupid DES libraries want
+          the key in the stupid DES parity format.
+        * plugins/digestmd5.c:  refactored some of the cipher code so that
+          there isn't RC4 state around when we're using DES and vice versa
+
+2002-12-05  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: Allocate a large enough buffer to account for
+	  a completely escaped username. (lak_escape and lak_filter)
+	* lib/common.c: Ensure there is enough space for the trailing \0
+	  in _sasl_log
+
+2002-12-04  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/canonusr.c: Check for potential buffer overflow
+
+2002-12-03  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c: major fast reauth rewrite, mech_step cleanup
+	* doc/options.html: server-side reauth is disabled by default
+
+2002-11-24  Ken Murchison <ken@oceana.com>
+	* plugins/login.c: allow authid to be passed in initial response
+	* doc/draft-sasl-login.txt, doc/mechanisms.html:
+	  documentation updates re: initial response
+
+2002-11-07  Ken Murchison <ken@oceana.com>
+	* doc/draft-nerenberg-sasl-crammd5-03.txt: added
+	* doc/draft-nerenberg-sasl-crammd5-02.txt: deleted
+	* doc/draft-zeilenga-sasl-anon-01.txt: added
+	* doc/draft-zeilenga-sasl-anon-00.txt: deleted
+	* doc/draft-zeilenga-sasl-plain-01.txt: added
+	* doc/draft-zeilenga-sasl-plain-00.txt: deleted
+	* doc/index.html: updated to latest CRAM-MD5, ANONYMOUS, PLAIN drafts
+
+2002-11-01  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/kerberos4.c: Make at most 1 canon_user call, not two.
+	  (Howard Chu <hyc@highlandsun.com>)
+
+2002-10-25  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: minor cleanups
+
+2002-10-24  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: fix problem where saslauthd stops LDAP
+	  authentications when ldap_auth_method is bind.
+	  (Igor Brezac <igor@ypass.net>)
+	* doc/sysadmin.html, doc/options.html, saslauthd/saslauthd.mdoc:
+	  documentation updates re: saslauthd mux path
+
+2002-10-23  Ken Murchison <ken@oceana.com>
+	* lib/external.c: added SASL_SEC_NOANONYMOUS to client side
+	  (Howard Chu, <hyc@highlandsun.com>)
+
+2002-10-21  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: NTLM probably doesn't offer perfect forward secrecy
+	* doc/mechanisms: added table of properties/features
+
+2002-10-20  Ken Murchison <ken@oceana.com>
+	* saslauthd/lak.ch: consolidated hashed password checking code
+
+2002-10-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.[ch], saslauthd/auth_ldap.c:
+	  Code cleanup, now support {SHA}, {SSHA}, {MD5}, and {SMD5} hashes,
+	  misc other cleanup. (Igor Brezac <igor@ypass.net> and
+	  Thomas Lussnig <thomas.lussnig@bewegungsmelder.de>)
+
+2002-10-17  Ken Murchison <ken@oceana.com>
+	* doc/draft-melnikov-rfc2831bis-02.txt: added
+	* doc/draft-melnikov-rfc2831bis-01.txt: deleted
+	* doc/index.html: updated to latest RFC 2831bis draft
+
+2002-10-11  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/Makefile.am: add missing staticopen.h to EXTRA_DIST,
+	  fix some dependencies
+	* Ready for 2.1.9
+
+2002-10-10  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.8
+
+2002-10-09  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/client.c: Allow plaintext mechanisms under an external security
+	  layer.
+
+2002-10-07  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* sample/server.c: Fix some IPV6 defines
+	  (Marshall Rose <mrose@dbc.mtview.ca.us>)
+
+2002-10-02  Ken Murchison <ken@oceana.com>
+	* lib/checkpw.c: return SASL_NOUSER when we can't find APOP secret
+	* lib/server.c: plug APOP memory leak and consolidate canonification
+	* configure.in: force the use of a cache file
+	  (Carlos Velasco <carlosev@newipnet.com>)
+
+2002-10-02  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/checkpw.c: Fix some misuses of sasl_seterror
+	  (Martin Exler <m.exler@gmx.at>)
+
+2002-09-24  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* config/sasl2.m4, saslauthd/Makefile.am: GSSAPI doesn't need
+	  to link ndbm.  Also cleanup some sasldb linking in saslauthd.
+
+2002-09-23  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* config/kerberos_v4.m4: Don't compile with kerberos unless we
+	  have both the libs and the headers (Carlos Velasco
+	  <carlosv@newipnet.com>)
+
+2002-09-19  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: endinaness corrections
+	* sasldb/db_berkeley.c, utils/dbconverter-2.c: Berkley DB 4.1
+	  support (Mika Iisakkila <mika.iisakkila@pingrid.fi>)
+
+2002-09-19  Ken Murchison <ken@oceana.com>
+	* plugins/plugin_common.[ch]: make SASL_CB_USER and result optional
+	* plugins/anonymous.c: use SASL_CB_USER for fetching trace info,
+	  don't require SASL_CB_AUTHNAME
+	* plugins/gssapi.c, plugins/kerberos.c: don't require SASL_CB_USER
+	* lib/external.c: define SASL_FEAT_ALLOWS_PROXY for this mechanism,
+	  don't require SASL_CB_USER
+
+2002-09-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/srp.c, plugins/kerberos4.c: correct maxoutbuf handling
+	* plugins/digestmd5.c: correct maxoutbuf handling, actually
+	  send maxbuf to the remote.
+	* lib/common.c: sanity check security properties
+	
+2002-09-17  Ken Murchison <ken@oceana.com>
+	* plugins/ntlm.c: home-grown client/server NTLM implementation
+	* configure.in: NTLM depends on OpenSSL libcrypto
+	* doc/sysadmin.html: added NTLM blurb
+
+2002-09-16  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/canonusr.c: don't index begin_u with -1
+	  (Randy Kunkee <randy@randallkunkee.com>)
+	* doc/sysadmin.html: cleanup
+	* utils/saslpasswd.c: don't exit with -SASL_FAIL
+	* saslauthd/saslauthd-unix.c: use a char* instead of a void* in
+	  retry_read
+
+2002-09-12  Ken Murchison <ken@oceana.com>
+	* lib/common.c: NULL outbuf if we get no output from sasl_decode()
+
+2002-09-11  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/mysql.c: Actually loop through the potential servers
+	  properly (Seow Kok Heng <kokheng@jhs.com.sg>)
+	* acinclude.m4: Added copy of the correct libtool macros as
+	  acinclude.m4
+	* configure.in: fix for gcc 3.x
+	  (Carlos Velasco <carlosev@newipnet.com>)
+
+2002-09-10  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/server.c: Better handling of add_plugin failures
+
+2002-09-10  Ken Murchison <ken@oceana.com>
+	* acconfig.h, configure.in: enable/disable NTLM
+	* lib/staticopen.h, plugins/Makefile.am, makeinit.sh, ntlm.c:
+	  added NTLM support (client-side only)
+
+2002-09-07  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/configure.in, saslauthd/Makefile.am: don't
+	  do configure substitutions for the saslauthd_SOURCES variable
+	  (Carlos Velasco <carlosev@newipnet.com>)
+
+2002-09-05  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/os390.html: added
+	* doc/index.html: referenced os390.html and macosx.html
+	* lib/Makefile.am: better handling of plugin_common
+
+2002-09-04  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* (throughout) Extensive cleanup of how we build static and
+	  shared versions of libsasl.  Also some more portability
+	  fixes (Howard Chu <hyc@highlandsun.com>)
+
+2002-09-04  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* acconfig.h, configure.in: Actually check for sysexits.h,
+	  varargs.h, and stdarg.h
+	* lib/checkpw.c: compatibility patch for retry_read
+	  (Howard Chu <hyc@highlandsun.com>)
+
+2002-09-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* (throughout) fix handling of sys/param.h
+	* (throughout) fix handling of time.h and sys/time.h
+	* include/exits.h: include a replacement for sysexits.h
+	* acconfig.h: define MAXHOSTNAMELEN if it isn't
+	* lib/getaddrinfo.c, config/ipv6.m4: minor fixes for partial
+	  getaddrinfo/getnameinfo implementations
+	* (Above changes are all from or based on ideas from
+	   Howard Chu <hyc@highlandsun.com>)
+
+2002-08-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/client.c, lib/saslint.h: Properly handle client-side
+	  serverFQDN and clientFQDN
+
+2002-08-19  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/dlopen.c: use correct paths when a .la file is not present
+	  (Justin Gibbs <gibbs@scsiguy.com>)
+
+2002-08-13  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/sysadmin.html: fix some /usr/lib/sasl references to
+	  /usr/lib/sasl2 (Andrew Jones <arjones@simultan.dyndns.org>)
+
+2002-08-09  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/Makefile.am: fix small parts of the saslauthd.8 build
+	  process.
+	* Ready for 2.1.7
+
+2002-08-06  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c: disable/remove server-side fast reauth
+
+2002-08-02  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* include/sasl.h, lib/common.c: Add SASL_AUTHUSER as a parameter
+	  to sasl_getprop
+
+2002-08-01  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: allow use of more than one %u or %r in the filter
+	  (Laurent Larquère <llarquere@aacom.fr>)
+
+2002-07-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/client.c, lib/server.c: Add checks for SASL_NEED_PROXY and
+	  SASL_FEAT_ALLOWS_PROXY
+	* include/sasl.h, include/saslplug.h: Add SASL_NEED_PROXY and
+	  SASL_FEAT_ALLOWS_PROXY
+	* plugins/digestmd5.c, plugins/gssapi.c, plugins/kerberos4.c,
+	  plugins/otp.c, plugins/plain.c, plugins/srp.c: define
+	  SASL_FEAT_ALLOWS_PROXY for these mechanisms
+
+2002-07-27  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/auth_sasldb.c: Include mechanisms.h in a reasonable place.
+
+2002-07-24  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/Makefile.am: Fix DEFS to still supply -I. and -I..
+	* configure.in: Make --with-ldap show up in top level configure script,
+	  make saslauthd compile by default
+	* lib/saslutil.c: use read() and not fread() on /dev/random to preserve
+	  entropy
+	* doc/sysadmin.html: Add note about using /dev/urandom
+
+2002-07-19  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* doc/sysadmin.html, doc/readme.html, doc/upgrading.html:
+	  Misc. documentation cleanup (Joe Rhett <jrhett@isite.net>)
+
+2002-07-17  Ken Murchison <ken@oceana.com>
+	* lib/canonusr.c: update length of user string to length of output
+	  from callback 
+
+2002-07-16  Rob Siemborski <rjs3+@andrew.cmu.edu>
+        * plugins/cram.c: Fix a security problem in the verification of
+          the digest string. (Andrew Jones <arjones@simultan.dyndns.org>)
+	* Ready for 2.1.6
+
+2002-07-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/mysql.c: Further memory management cleanup. (never
+	  strdup the options, and therefore don't free staticly allocated
+	  strings)
+	* man/sasl_getopt_t.3: Clarify semantics of memory management
+
+2002-07-05  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/lak.c: Better handling of downed ldap servers
+	  (Igor Brezac <igor@ipass.net>)
+	* sasldb/db_berkeley.c, utils/dbconverter-2.c: Use db_strerror()
+          rather than strerror() for Berkeley DB error values.
+	  (J.H.M. Dassen (Ray) <jdassen@debian.org>)
+	* saslauthd/Makefile.am, saslauthd/auth_ldap.c: don't
+	  hardwire the saslauthd conf file
+	  (J.H.M. Dassen (Ray) <jdassen@debian.org>)
+
+2002-07-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* man/sasl_user_exists.3: fix sasl_idle reference
+
+2002-07-02  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/auxprop.c: Can now select multiple auxprop plugins
+	* doc/options.html: updated for above
+	* lib/client.c: improve mechanism selection to include
+	  number of security flags
+
+2002-06-27  Ken Murchison <ken@oceana.com>
+	* doc/draft-zeilenga-sasl-plain-00.txt: added
+	* doc/index.html: added PLAIN draft
+
+2002-06-26  Ken Murchison <ken@oceana.com>
+	* doc/draft-zeilenga-sasl-anon-00.txt: added
+	* doc/index.html: added ANONYMOUS draft
+
+2002-06-20  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/auxprop.c: Make "cound not find auxprop plugin" warning
+	  log at LOG_DEBUG
+
+2002-06-19  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: create layer keys for integrity as
+	  well as privacy
+	* saslauthd/auth_ldap.[ch], saslauthd/lak.[ch]:
+	  Large rewrite (Igor Brezac <igor@ipass.net>)
+	* lib/client.c, lib/server.c, lib/common.c:
+	  Actually set most of the sparams and cparams structures
+
+2002-06-19  Ken Murchison <ken@oceana.com>
+	* doc/draft-melnikov-rfc2831bis-01.txt: added
+	* doc/draft-melnikov-rfc2831bis-00.txt: deleted
+	* doc/index.html: updated to latest RFC 2831bis draft
+
+2002-06-18  Ken Murchison <ken@oceana.com>
+	* doc/draft-nerenberg-sasl-crammd5-02.txt: added
+	* doc/draft-nerenberg-sasl-crammd5-01.txt: deleted
+	* doc/index.html: updated to latest CRAM-MD5 draft
+
+2002-06-17  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/login.c, plugins/plain.c: Canonicalize username before
+	  doing checkpass
+
+2002-06-14  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/client.c, lib/server.c, lib/saslint.h, lib/common.c.
+	  lib/seterror.c: continued size_t vs unsigned cleanups
+
+2002-06-13  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/ : remove LDAP support
+	* Ready for 2.1.5
+
+2002-06-12  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/digestmd5.c: rename get_realm to get_server_realm, and
+	  pay attention to its return value
+	* lib/external.c, lib/seterror.c: cleanup size_t/unsigned confusion
+
+2002-06-10  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* sasldb/Makefile.am: fix handling of allockey (only include it once)
+	* plugins/kerberos4.c: fix a reference count leak
+	* Ready for 2.1.4
+
+2002-05-28  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/LDAP_SASLAUTHD, saslauthd/saslauthd.mdoc:
+	  Update documentation for LDAP and Saslauthd as per
+	  Igor Brezac <igor@ipass.net>
+
+2002-05-22  Lawrence Greenfield  <leg+@andrew.cmu.edu>
+	* lib/checkpw.c: close door file descriptor in
+	  saslauthd_verify_password
+
+2002-05-21  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/auth_krb5.c: fix a leak due to not
+	  calling krb5_cc_destroy on failure
+
+2002-05-17  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/saslauthd-*.c: support a generic mechanism option -O
+	  instead of -H
+	* saslauthd/auth_ldap.c, lak.c, et. al: auth_ldap overhaul
+	  (Igor Brezac <igor@ipass.net>)
+	* lib/common.c, include/sasl.h: add sasl_version
+
+2002-05-13  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* lib/checkpw.c: use "*cmusaslsecretPLAIN" in auxprop_verify_password
+	  (Howard Chu, <hyc@highlandsun.com>), also only make a single
+	  canon_user call.
+
+2002-05-13  Ken Murchison <ken@oceana.com>
+	* plugins/plugin_common.c: set the return code to SASL_FAIL, and
+	  NULL the results of the _plug_get_*() functions before we get
+	  started
+	* plugins/digestmd5.c, otp.c, plain.c, srp.c: check for NULL or
+	  empty authzid from callback
+
+2002-05-09  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/configure.in: --with-ldap now takes a path
+
+2002-05-08  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/acconfig.h, auth_ldap.c, configure.in, lak.c, lak.h:
+	  Misc compile/portability fixes (mostly header-related)
+	* utils/testsuite.c: minor getopt() parameter fix
+	  (Claus Assmann <ca+sasl@sendmail.org>)
+	* lib/checkpw.c: fix some warnings
+
+2002-05-07  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* Ready for 2.1.3-BETA
+
+2002-05-06  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* include/saslplug.h: add name member for canon_user plugins
+	* lib/canonusr.c: use name member
+
+2002-05-06  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c: added client-side reauth
+
+2002-05-05  Ken Murchison <ken@oceana.com>
+	* lib/client.c: pass global_context to mech_new()
+	* lib/server.c: don't free global_context (the plugin should free it)
+	* utils/testsuite: swapped serverlast tests so that the
+	  descriptions are correct
+
+2002-05-03  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c: added server-side reauth
+	* doc/index.html: added Marshall Rose's SASL papers
+	* doc/options.html: added 'reauth_timeout'
+
+2002-05-03  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/kerberos4.c: fix compile errors
+	* config/kerberos_v4.m4, plugins/digestmd5.c: fix des_cbc_encrypt
+	  interoperability problem (OpenSSL)
+	* saslauthd/Makefile.am, acconfig.h, auth_ldap.c, auth_ldap.h,
+	  configure.in, lak.c, lak.h, mechanisms.c, mechanisms.h,
+	  saslauthd.conf: added experimental LDAP saslauthd module 
+	  (by Igor Brezac <igor@ipass.net>)
+	* include/saslplug.h: give auxprop plugins a name
+	* plugins/sasldb.c: give sasldb plugin a name
+	* lib/auxprop.c: allow auxprop selection
+	* doc/options.html: document auxprop_plugin option
+
+2002-05-01  Ken Murchison <ken@oceana.com>
+	* plugins/digestmd5.c, gssapi.c, kerberos4.c, srp.c:
+	  general plugin cleanup - standardizing structure
+
+2002-04-30  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: Minor cleanup of struct hack in context structure
+
+2002-04-30  Ken Murchison <ken@oceana.com>
+	* plugins/plugin_common.[ch], anonymous.c, cram.c, login.c, otp.c,
+	  plain.c, sasldb.c, srp.c,
+	  lib/client.c, external.c, saslint.h, server.c: general plugin
+	  cleanup - reusing more common code, standardizing structure
+
+2002-04-28  Ken Murchison <ken@oceana.com>
+	* plugins/plugin_common.[ch], anonymous.c, cram.c, digestmd5.c,
+	  gssapi.c, kerberosv4.c, login.c, otp.c, plain.c, srp.c,
+	  lib/external.c:finalize movement of callback/interaction stuff
+	  into plugin_common
+
+2002-04-27  Ken Murchison <ken@oceana.com>
+	* plugins/plugin_common.[ch], anonymous.c, cram.c, digestmd5.c,
+	  gssapi.c, kerberosv4.c, login.c, otp.c, plain.c, srp.c,
+	  lib/external.c: move make_prompts stuff into plugin_common
+	* utils/testsuite.c: allow for testing of EXTERNAL
+
+2002-04-26  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* sasldb/allockey.c: be sure to set userPassword and not *userPassword
+
+2002-04-26  Ken Murchison <ken@oceana.com>
+	* lib/client.c, server.c: check 'doneflag' just before mech_step()
+	* plugins/plugin_common.[ch], anonymous.c, cram.c, digestmd5.c,
+	  gssapi.c, kerberosv4.c, login.c, otp.c, plain.c, srp.c,
+	  lib/external.c, Makefile.am: move callback/interaction stuff
+	  into plugin_common
+	* plugins/plugin_common.[ch], digestmd5.c, gssapi.c,
+	  kerberosv4.c, srp.c: move decode/concatenation of multiple
+	  packets into plugin_common
+	* utils/testsuite.c: set SASL_AUTH_EXTERNAL so we can test EXTERNAL
+
+2002-04-25  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: don't free the secret when we get data from a
+	  callback (and don't copy it)
+	* plugins/gssapi.c, plain.c: make sure to set 'doneflag' when done
+	* lib/client.c, server.c: don't call mech_step() if 'doneflag' is set
+
+2002-04-24  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/cram.c, digestmd5.c, login.c, plain.c, srp.c: don't
+	  free the secret when we get data from a callback (and don't copy it)
+	
+2002-04-22  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* include/gai.h: Fix for compatibility with older glibc versions
+	  (Howard Chu, <hyc@highlandsun.com>)
+	* plugins/gssapi.c: Don't always send authzid on client side
+	  (Howard Chu, <hyc@highlandsun.com>)
+
+2002-04-18  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* saslauthd/auth_sasldb.c: Use "use_realm" instead of "realm"
+	  for lookup of secret. (Jonas Oberg <jonas@gnu.org>)
+	* plugins/gssapi.c: Correct handling of client-side authid and
+	  authzid (Howard Chu, <hyc@highlandsun.com>)
+	* lib/external.c: Better handling of user canonicalization
+	  (Howard Chu, <hyc@highlandsun.com>)
+	* plugins/cram.c, digestmd5.c, gssapi.c, kerberos4.c,
+	  login.c, otp.c, plain.c, srp.c:  zero out prompt_need structures
+	  before use
+
+2002-04-17  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/cram.c, digestmd5.c, srp.c: Adjust cmusaslsecretFOO to
+	  *cmusaslsecretFOO
+	* plugins/sasldb.c: correctly handle *(property)
+	* lib/canonusr.c, server.c: Lookup authzid and authid auxprops
+	  correctly (and in the same place).
+	* include/sasl.h, saslplug.h: Fix auxprop lookups
+	  (e.g. SASL_AUXPROP_AUTHZID)
+
+2002-04-15  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: Handle null authzid's correctly
+	* lib/server.c: fix a strcmp() that should be a memcmp()
+
+2002-04-15  Rob Siemborski <rjs3@andrew.cmu.edu>
+	* plugins/gssapi.c: fix how name_token and name_without_realm are
+	  freed.
+
+2002-04-12  Ken Murchison <ken@oceana.com>
+	* doc/draft-melnikov-rfc2831bis-00.txt: added
+	* doc/draft-myers-saslrev-02.txt: moved TOC
+	* doc/draft-myers-saslrev-02.txt: added
+	* doc/draft-myers-saslrev-01.txt: deleted
+	* doc/index.html: changed link to updated saslrev draft,
+	  added KERBEROS_V4 notation,
+	  added link to rfc2831bis draft
+
+2002-04-08  Ken Murchison <ken@oceana.com>
+	* lib/server.c, doc/options.html: allow multiple pwcheck_methods
+
+2002-04-03  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/configure.in: properly define AUTH_KRB5
+	* saslauthd/auth_krb5.c: changes for MIT KRB5
+
+2002-03-27  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Removed check for db3/db.h (people can just use --with-bdb-incdir)
+
+2002-03-26  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Ready for 2.1.2
+
+2002-03-11  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/kerberos4.c: Fix a race condition during mutex allocation
+
+2002-03-04  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/checkpw.c: Stop logging "authentication failed" message
+	* plugins/gssapi.c: Reduce log level of "gss_accept_context" message
+
+2002-02-27  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/saslauthd.mdoc: Clarify that sasldb with saslauthd
+	  is not what you want to be doing.
+	* doc/sysadmin.html: Update "sasldb" verifier to "auxprop"
+
+2002-02-22  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/checkpw.c: made retry_read static
+
+2002-02-21  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/checkpw.c (auxprop_verify_password) report SASL_NOUSER instead
+	  of SASL_FAIL.
+	* lib/client.c, lib/server.c: More Complete returning of SASL_NOTINIT
+	* utils/testsuite.c: Better checking for SASL_NOTINIT
+
+2002-02-11  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: removed OpenSSL 0.9.6 dependencies, small bugfix
+	* configure.in: cleaned up OpenSSL (libcrypto) check
+
+2002-02-05  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* contrib/tclsasl: Add Marshall Rose's <mrose@dbc.mtview.ca.us>
+	  tclsasl patch.
+	* plugins/anonymous.c: No longer append extra NUL to client response
+
+2002-02-04  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/saslpasswd.c: Added -n option (Ken Murchison)
+	* lib/dlopen.c: Removed confusing entry point message.
+	* Ready for 2.1.1
+
+2002-02-01  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: fixed srp_setpass()
+
+2002-01-31  Ken Murchison <ken@oceana.com>
+	* include/sasl.h, lib/server.c,
+	  plugins/digestmd5.c, gssapi.c, kerberos4.c, srp.c:
+	  added SASL_SEC_MUTUAL_AUTH
+	* plugins/srp.c: cleanup error messages and return codes
+	
+2002-01-30  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c, plugins/otp.h: added non-OPIE client/server
+	  implementation (requires OpenSSL)
+	* configure.in: OTP now requires OpenSSL, OPIE is optional
+	* doc/options.html, doc/readme.html, doc/sysadmin.html, doc/TODO:
+	  updated for new OTP implementation
+
+2002-01-25  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/Makefile.am: Correct multiple EXTRA_DIST bug
+	* saslauthd/Makefile.am: small typo fixed (Leena Heino <liinu@uta.fi>)
+
+2002-01-23  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/dbconverter-2.c (main): More intelligent default paths
+	* acconfig.h: #ifndef's for _GNU_SOURCE (Assar <assar@permabit.com>)
+
+2002-01-22  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/common.c: Complete definition of sasl_global_listmech
+	  (from Love <lha@stacken.kth.se>)
+	* lib/client.c: added checks for _sasl_client_active to
+	  sasl_client_new and sasl_client_start
+
+2002-01-21  Ken Murchison <ken@oceana.com>
+	* doc/draft-myers-saslrev-01.txt: moved TOC
+	* doc/draft-ietf-cat-sasl-gssapi-05.txt: moved TOC
+	* doc/draft-nerenberg-sasl-crammd5-01.txt: added
+	* doc/draft-nerenberg-sasl-crammd5-00.txt: deleted
+	* doc/index.html: changed link to updated draft
+	* plugins/login.c (login_client_mech_step): fix client-first
+	  handling
+
+2002-01-21  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/server.c (sasl_server_start): null out *serverout and
+	  *serveroutlen, just in case.
+	* lib/external.c: Added correct required_prompts
+	* saslauthd/testsaslauthd.c: Added simple saslauthd client
+	* saslauthd/Makefile.am: rules for testsaslauthd
+	* doc/sysadmin.html: updated to reference testsaslauthd
+	* saslauthd/saslauthd.c: allow -n 0 (for fork-per-connection)
+	* saslauthd/saslauthd.mdoc: documentation of -n 0
+	* plugins/cram.c (crammd5_client_mech_step): fix client-first
+	  handling
+	* sasldb/db_gdbm.c: improved error reporting
+	  (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>
+	* config/sasldb.m4: improved gdbm configure handling
+	  (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>
+	* config/kerberos_v4.m4: Detect OpenSSL libdes first.
+	  (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>
+	* plugins/cram.c, digestmd5.c, kervberos4.c, login.c,
+	  lib/client.c, server.c, include/saslplug.h:
+	  Cleaner client-first ABI.
+
+2002-01-19  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: set serverout to NULL where we have nothing to
+	  send instead of the empty string
+	* plugins/srp.c: let glue code handle client-last/server-last
+	  situation by setting serverout appropriately
+
+2002-01-19  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/plain.c, plugins/login.c, plugins/digestmd5.c:
+          set serverout to NULL where we have nothing to send instead of
+	  the empty string
+	* include/saslplug.h, lib/client.c, lib/server.c: eliminated
+	  SASL_FEAT_WANT_SERVER_LAST in favor of clever setting of serverout
+	* plugins/digestmd5.c: removed SASL_FEAT_WANT_SERVER_LAST
+
+2002-01-18  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: updated to draft-burdis-cat-srp-sasl-06
+	* plugins/srp.c: server uses external SSF
+	* plugins/srp.c: server sends mandatory options based on min SSF
+	* doc/draft-burdis-cat-srp-sasl-06.txt: added
+	* doc/draft-burdis-cat-srp-sasl-05.txt: deleted
+	* doc/index.html: changed link to updated draft
+
+2002-01-17  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/kerberos4.c: Actually allocate a mutex on the client side
+
+2002-01-16  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/server.c (mech_permitted): fixed incorrect return value of
+	  SASL_NOMECH that should have been 0.
+	* lib/common.c (sasl_errdetail): fixed core if passed in conn is NULL
+	* plugins/digestmd5.c (encode_tmp_buf): removed unneeded buffer
+
+2002-01-16  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: fixed layer decoding to handle multiple packets
+	* plugins/srp.c: plugged memory leaks (now passes testsuite)
+	* plugins/srp.c: more logging
+	* plugins/srp.c: lots of other nits, bug fixes
+	* utils/testsuite.c: added SSF=0/56 test
+
+2002-01-14  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/auth_krb4.c (auth_krb4): fix tf_name memory leak,
+	  and other efficency fixes
+
+2002-01-11  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* include/saslplug.h: Add flags member to params structures
+	* lib/client.c, lib/server.c: flags parameter to sasl_*_new
+	  now gets to the plugins
+
+2002-01-10  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* include/sasl.h: Update for sasl_global_listmech API
+	* lib/common.c, lib/client.c, lib/server.c: sasl_global_listmech()
+	* lib/dlopen.c (_parse_la): fix parseing of dlname= line
+	* Ready for 2.1.0
+
+2002-01-09  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: fixed security_flags
+	* plugins/srp.c: corrected integrity layer encoding
+	* plugins/srp.c: finished maxbuffersize handling
+	* plugins/srp.c: fixed security_flags
+	* doc/index.html: added reference to SRP paper
+
+2002-01-09  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/common.c (sasl_decode): Removed maxoutbuf check
+	* man/sasl_setprop.3: Minor clarifications
+	* plugins/digestmd5.c, plugins/gssapi.c, plugins/kerberos4.c:
+	  Assorted security layer fixes (maxoutbuf setting, mech_ssf setting)
+	* lib/common.c, lib/client.c, lib/server.c, lib/saslint.h:
+	  Allowed client-side sasl_listmech calls.
+	* include/sasl.h: Minor cosmetic fix to comments
+	* doc/programming.html: Interaction memory management clarifications
+	* lib/common.c: Fix several crash problems in getprop
+	  (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>)
+
+2002-01-05  Lawrence Greenfield  <leg+@andrew.cmu.edu>
+	* saslauthd/saslauthd.c: F_SETLK doesn't block; F_SETLKW does
+	* saslauthd/saslauthd.c: detect errors somewhat better
+
+2002-01-04  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/common.c: Allow sasl_setprop for SASL_DEFUSERREALM
+
+2002-01-04  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: don't send M2 if using a confidentiality layer
+	* plugins/srp.c: more constraint checks
+	* plugins/otp.c: improve standard hex/word response detection
+	* doc/install.html, doc/sysadmin.html, contrib/opie-2.4-fixes:
+	  add patch for OPIE 2.4 to enable extended responses
+
+2002-01-03  Ken Murchison <ken@oceana.com>
+	* configure.in: removed check fpr gmp
+	* plugins/srp.c: migrated to OpenSSL's BN (removed GNU MP dependency)
+
+2001-12-20  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* sasldb/db_ndbm.c: Fixed small memory leak
+	  (Courtesy  Howard Chu <hyc@highlandsun.com>)
+
+2001-12-18  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: more constraint checks
+
+2001-12-17  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/saslauthd.c: Prefork a number of processes to handle
+	  connections.
+	* saslauthd/auth_krb4.c: Handle concurrent accesses better.
+
+2001-12-15  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: added confidentiality layers
+
+2001-12-14  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: improved client/server layer option handling
+	* plugins/srp.c: added client-side support for mandatory options
+	* plugins/srp.c: added framework for confidentiality layers
+	* plugins/srp.c: added some data sanity checking (thanks to
+	  Tom Holroyd <tomh@po.crl.go.jp> for feedback)
+
+2001-12-13  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/server.c, lib/common.c: Fix handling of
+	  global callbacks so that plugin_list works again
+
+2001-12-12  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* pwcheck/Makefile.am: Added include of ../lib
+	  (from Hajimu UMEMOTO <ume@mahoroba.org>)
+
+2001-12-11  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* sasldb/db_ndbm.c: fix call to dbm_nextkey, from
+	  Scot W. Hetzel <scot@genroco.com>
+
+2001-12-10  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* doc/plugprog.html: Update for new user canonicalization usage.
+	* man/sasl_canon_user.3: Update for new user canonicalization usage.
+	* configure.in: Actually set STATIC_GSSAPIV2 when necessary
+
+2001-12-08  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: make sure we have the HMAC before trying to use it
+	* plugins/srp.c: don't advertise server integrity w/o HMAC-SHA-1
+	* plugins/srp.c: move EVP_cleanup() to mech_free so mech can be reused
+
+2001-12-07  Ken Murchison <ken@oceana.com>
+	* configure.in: SRP now requires OpenSSL
+	* plugins/srp.c: migrated to OpenSSL's MDA/cipher abstraction API 
+	* plugins/srp.c: added RIPEMD-160 support
+	* plugins/srp.c: using "standard ACSII names" for MDA-names as
+	  documented by [SCAN] (until determined otherwise)
+	* plugins/srp.c: using updated canon_user API to allow separate
+	  canonicalization of authid and authzid.
+
+2001-12-06  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/canonusr.c: Better logging when desired plugin is not found.
+	* lib/checkpw.c: spelling error fixed.
+	* lib/canonusr.c, lib/checkpw.c, lib/client.c, lib/external.c,
+	  lib/saslint.h, lib/server.c, include/sasl.h, include/saslplug.h,
+	  plugins/*.c: Updated canon_user API to allow separate
+	  canonicalization of authid and authzid.
+
+2001-12-05  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/Makefile.am, saslauthd/acconfig.h, saslauthd/configure.in:
+	  Solaris 7 and FreeBSD (FreeBSD is courtesy of Claus Assmann
+	  <ca+sasl@sendmail.org>)
+	* sasldb/Makefile.am: link order fix (Courtesy Claus Assmann
+	  <ca+sasl@sendmail.org>)
+
+2001-12-05  Ken Murchison <ken@oceana.com>
+	* configure.in:
+	* plugins/Makefile.am: only build SRP with sasldb libs when
+	  srp_setpass() is enabled
+	* plugins/srp.c: added HMAC-SHA-160 integrity layer
+	* plugins/srp.c: don't offer integrity layers unless HMAC-SHA-160
+	  is available (mandatory)
+	* plugins/srp.c: fixed multiple integrity/confidentiality layer
+	  client-side bug
+	* plugins/srp.c: fixed delete SRP secret bug
+	* plugins/srp.c: removed VL() stuff
+
+2001-12-04  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/Makefile.am, config/sasldb.m4: Build sasldblistusers2
+	  and saslpasswd2.  Default database now /etc/sasldb2
+	* INSTALL, README, doc/index.html, doc/upgrading.html: Update
+	  with upgrading instructions in preparation for release.
+	* doc/, /: Documentation reorganization, convert README and INSTALL to
+	  HTML format.
+	* Bumped appropriate version numbers, Ready for 2.0.5-BETA
+
+2001-12-04  Ken Murchison <ken@oceana.com>
+	* acconfig.h, configure.in: dependency checking for SRP
+	* acconfig.h, configure.in:
+	* plugins/srp.c: made srp_setpass() a compile-time option (default=off)
+	* plugins/srp.c: use auxprop to fetch cmusaslsecretSRP/userPassword
+	* plugins/srp.c: code cleanup
+	* acconfig.h, configure.in:
+	* doc/sysadmin.html:
+	* plugins/otp.c: made otp_setpass() a compile-time option (default=off)
+
+2001-12-02  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: fixed SHA1 support
+	* plugins/srp.c: changed calculation of 'x' to coincide with draft -05
+	* plugins/srp.c: code cleanup
+
+2001-12-01  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: abstracted MDA interface
+	* plugins/srp.c: added SHA1 support (not working)
+
+2001-11-30  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: renumbered steps to start at 1
+	* plugins/srp.c: check plugin API version instead of SRP_VERSION
+	* plugins/srp.c: changed data exchanges to conform to draft -05
+
+2001-11-29  Ken Murchison <ken@oceana.com>
+	* plugins/srp.c: code now compiles and runs
+	* plugins/Makefile.am: added sasldb libs to SRP build
+
+2001-11-24  Ken Murchison <ken@oceana.com>
+	* lib/external.c: made EXTERNAL a client-send-first mechanism
+	* doc/index.html: added CRAM-MD5 draft
+
+2001-11-22  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: fixed otp_setpass() bug
+	* doc/sysadmin.html: OTP additions/changes
+
+2001-11-19  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/saslpasswd.c: Corrected disable handling
+
+2001-11-17  Ken Murchison <ken@oceana.com>
+	* doc/index.html, rfc2945.txt, rfc3174.txt: specification additions
+	* doc/Makefile.am: Updated included RFCs and IDs
+	
+2001-11-14  Ken Murchison <ken@oceana.com>
+	* lib/server.c, doc/options.html: added 'mech_list' option
+
+2001-11-14  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* sasldb/allockey.c: removed an assert() call
+	* sasldb/db_ndmb.c, sasldb/db_gdbm.c: Fixed cntxt's to be conn's 
+
+2001-11-13  Ken Murchison <ken@oceana.com>
+	* acconfig.h, configure.in:
+	* plugins/otp.c: support client-side OTP without OPIE
+
+2001-11-08  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: allow entry of one-time password via
+	  SASL_CB_ECHOPROMPT callback
+	* plugins/otp.c: code cleanup
+	* doc/index.html, draft*.txt: specification updates/additions
+
+2001-11-08  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/cram.c, digestmd5.c, sasldb.c: Removed all assert()
+	  calls from supported plugins.
+
+2001-11-07  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/testsuite.c: added proxy policy checks
+	* lib/checkpw.c (_sasl_auxprop_verify_apop): correct handling
+	  of seterror calls
+
+2001-11-06  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/canonusr.c (_canonuser_internal): added necessary seterror calls
+	* doc/Makefile.am: Updated included RFCs and IDs
+	* lib/canonusr.c, lib/server.c: Corrected authzid/authid handling
+	* plugins/digestmd5.c: Unconfused authzid/authid in server call to
+	  canon_user
+
+2001-11-01  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/gssapi.c, plugins/kerberos4.c: Get rid of unnecessary
+	  buffer copy in security layer encodes.
+
+2001-10-24  Ken Murchison <ken@oceana.com>
+	* plugins/otp.c: added otp_setpass() so that saslpasswd can
+	  be used instead of opiepasswd on closed systems
+	* doc/sysadmin.html: OTP additions/changes
+
+2001-10-22  Ken Murchison <ken@oceana.com>
+	* acconfig.h, configure.in: detect OPIE, enable/disable OTP
+	* plugins/Makefile.am, makeinit.sh, otp.c: added OTP support
+	  (still need work on RFC2444 compliance - depends on OPIE changes)
+	* doc/index.html, options.html, sysadmin.html, rfc*.txt:
+	  OTP additions/changes
+
+2001-10-18  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/testsuite.c: Test DES harder for DIGEST-MD5
+	* plugins/digestmd5.c (enc_des): Get rid of one buffer copy.
+	* plugins/digestmd5.c (dec_des, dec_3des): correct handling of
+	  padding length check.
+
+2001-10-17  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* config/sasldb.m4: detect berkeley db 4
+	* plugins/gssapi.c, cram.c, kerberos4.c, digestmd5.c: have dispose
+	  calls deal with the possibility of a null context
+
+2001-10-16  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/Makefile.am: Link LIB_PAM  as well, if needed
+	* plugins/digestmd5.c: Don't send a trailing nul on challenge and
+	  responses.
+	* lib/server.c (sasl_server_start, sasl_server_step): Deal with
+	  authentication failures better. (Reported by Larry Rosenbaum
+	  <lmr@ornl.gov>)
+
+2001-10-02  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/Makefile.am, saslauthd/auth_sasldb.c,
+	  saslauthd/configure.in: Changes to allow extraction of saslauthd
+	  as needed.
+
+2001-09-19  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/getaddrinfo.c (getaddrinfo): Correct fix for
+	  AI_PASSIVE bug from Hajimu UMEMOTO <ume@mahoroba.org>
+	* plugins/plugin_common.c, lib/common.c (_*_ipfromstring):
+	  revert to previous versions.
+
+	* plugins/Makefile.am: Include necessry compatibility objects
+	  as needed.
+	* lib/Makefile.am: compatibility code for static libsasl
+	* configure.in: small changes to make compatibility objects easy
+	  to use.
+
+2001-09-18  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/plugin_common.c, lib/common.c (_*_ipfromstring):
+	  no longer use AI_PASSIVE hint for getaddrinfo
+
+2001-09-13  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/auth_sasldb.c, saslauthd/auth_sasldb.h:
+	  Added experimental sasldb saslauthd module
+	* saslauthd/configure.in: sasldb related config changes,
+	  do not config if disabled
+
+2001-09-12  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/*, lib/checkpw.c (saslauthd_verify_password):
+	  merged new saslauthd protocol from Ken Murchison <ken@oceana.com>
+
+2001-08-30  Rob Siemborski <rjs3+@andrew.cmu.edu>
+
+	* configure.in, saslauthd/configure.in: check for inet_aton
+	  in libresolv.so, so as to link it if necessary
+
+	* config/sasldb.m4 (BERKELEY_DB_CHK_LIB): set runpath of library
+	  if necessary
+
+2001-08-29  Rob Siemborski <rjs3+@andrew.cmu.edu>
+
+	* utils/testsuite.c: Minor testsuite fix (include paths)
+
+	* Ready for 2.0.4-BETA
+
+2001-08-24  Rolf Braun <rbraun+@andrew.cmu.edu>
+
+	* Mac OS 9 and X support, including Carbon
+	  Mac OS 9 Classic support based on the SASL v1 code
+	  by Aaron Wohl <n3liw+@andrew.cmu.edu>
+
+	* updated ltconfig and ltmain.sh
+	* acconfig.h:
+	* configure.in:
+	* lib/saslutil.c: use random() when jrand48() isn't available
+
+	* dlcompat-20010505:
+	  dlcompat included for OS X support, compiles separately
+	* lib/dlopen.c: prefix symbols with underscore on OS X, as on OpenBSD
+	  note that this is also detected automatically by configure,
+	  this only helps when cross-compiling (for OS X?)
+
+	* acconfig.h:
+	* configure.in:
+	* config/kerberos_v4.m4
+	  look for libdes524 when libdes doesn't exist.
+	  look for libkrb4 when libkrb doesn't exist.
+
+	* lib/saslint.h:
+	* lib/common.c:
+	* lib/seterror.c:
+	* lib/Makefile.am:
+	  split sasl_seterror() into a new file.
+	  add_string -> _sasl_add_string and made this non-static
+	  so seterror can use it.
+	  added _sasl_get_errorbuf to go into the conn_t struct
+	  so we don't have to know the format of that struct when
+	  seterror.c is linked from glue code (i.e., the Mac OS X CFM glue)
+
+	* acconfig.h:
+	  fix the order of the fake iovec struct for systems that
+	  don't have it (like Mac OS 9) so it's the same order as
+	  most Unixes that do (like Mac OS X) -- the CFM glue needs this
+
+	* acconfig.h:
+	  include <sys/types.h> before we include <sys/uio.h>
+
+	* plugins/kerberos4.c:
+	* lib/checkpw.c:
+	* acconfig.h:
+	* configure.in:
+	  check for krb_get_err_txt in the kerberos 4 library,
+	  and use it instead of the krb_err_txt[] array if available
+
+	* plugins/kerberos4.c:
+	  define KEYFILE to "/etc/srvtab" if not already defined
+	  by the kerberos 4 headers (needed for MIT KfM 4.0)
+
+	* doc/macosx.html: added this
+	* README: point Mac OS X users to doc/macosx.html
+	* doc/Makefile.am: add doc/macosx.html to distfiles
+
+	* Makefile.am:
+	* lib/Makefile.am:
+	* include/Makefile.am:
+	* config/Info.plist:
+	* configure.in:
+	  when building on Mac OS X, install a framework
+	  in /Library/Frameworks
+
+	* mac/*:
+	  projects and support files for Mac OS 9, classic and Carbon
+	* mac/osx_cfm_glue:
+	  the glue to allow CFM Carbon applications under Mac OS X
+	  call the Unix-layer SASL library
+
+	* lib/common.c:
+	* lib/canonusr.c:
+	  don't do the auxprop stuff on Mac OS 9
+
+	* lib/getaddrinfo.c:
+	  don't look up hostnames on Mac OS 9 (we only officially
+	  support passing IP address strings anyway)
+
+	* lib/getaddrinfo.c:
+	* plugins/plugin_common.c:
+	* plugins/plugin_common.h:
+	  don't include headers on Mac OS 9 that we don't have.
+
+	* sample/sample-client.c:
+	  add a cast for Mac OS 9 (different type handling of char)
+
+	* plugins/makeinit.sh:
+	  include the stub header to export the right symbols on Mac OS 9
+
+2001-08-20  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/gssapi.c (gssapi_server_mech_step): fixed accidental
+	  back link into glue code
+
+	* config/kerberos4.m4: Actually link in -lkrb
+
+2001-08-15  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/common.c (_sasl_iptostring): #if 0'd out.
+
+	* lib/server.c (sasl_user_exists): only check the verifier we
+	  are using
+
+	* config/kerberos_v4.m4 (SASL_DES_CHK): added
+	* config/kerberos_v4.m4 (SASL_KERBEROS_V4_CHK): included
+	  entire check from configure.in
+	* configure.in: moved kerberos 4 code completely out.
+	* saslauthd/acconfig.h (WITH_DES, WITH_SSL_DES): Added
+	  DES-related symbols	
+
+2001-08-14  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* configure.in: Check for sys/uio.h
+	* saslauthd/configure.in: Check for sys/uio.h
+	* config.h: Do the Right Thing for struct iovec (and
+	  no longer include sys/uio.h elsewhere)
+	* saslauthd/config.h: Do the Right Thing for struct iovec (and
+	  no longer include sys/uio.h elsewhere)
+
+2001-08-13  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/digestmd5.c (init_des, init_3des, enc_des, dec_des,
+	  enc_3des, dec_3des): fixed interoperability problems,
+	  3des was not decrypting with correct key and des was not
+	  setting up the initial vector.
+
+	* lib/checkpw.c (always_true): log users who log in via this verifier
+
+2001-08-13  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/testsuite.c (giveokpath): fix memory leak
+
+	* lib/common.c (sasl_ipfromstring): add call to freeaddrinfo()
+	* plugins/plugin_common.c (_plug_ipfromstring): add call to
+	  freeaddrinfo()
+
+	* lib/saslutil.c (sasl_randseed): actually initialize the randpool
+
+	* saslauthd/auth_getpwent.c (auth_getpwent): clear a warning
+	* saslauthd/auth_shadow.c (auth_shadow): clear a similar warning
+
+	* utils/Makefile.am (EXTRA_DIST): Actually include the needed files
+
+	* saslauthd/configure.in: Handle shadow passwords correctly
+	* saslauthd/acconfig.h: Handle shadow passwords correctly
+
+	* lib/checkpw.c (always_true): added
+	* configure.in: added check for alwaystrue verifier
+	* acconfig.h: added HAVE_ALWAYSTRUE
+	* doc/options.html: alwaystrue verifier documented
+
+2001-08-11  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/: Now configures separately from SASL, so as
+	  to localize tests for that package within that package
+
+	* utils/dbconverter-2.c (listusers_cb): fix handling of APOP 
+
+2001-08-10  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/Makefile.am (install-data-local):
+	  correct handling of $(DESTDIR) (and create the directory if it
+	  isn't there) [Amos Gouaux <amos@utdallas.edu>]
+
+	* lib/server.c (sasl_server_init): Added plugname to add_plugin
+	  call for EXTERNAL
+
+	* doc/index.html: updated
+	* doc/appconvert.html: cleaned up
+
+2001-08-09  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/digestmd5.c (digestmd5_client_mech_step): handle
+	  missing authorization name
+	* plugins/plain.c (plain_client_mech_step): handle
+	  missing authorization name
+
+	* include/sasl.h: better documentation of SASL_CB_CANON_USER
+
+2001-08-08  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* saslauthd/saslauthd.mdoc: updated re: pam
+	* saslauthd/saslauthd.8: regenerated
+	* saslauthd/Makefile.am: Link against PLAIN_LIBS also
+	  (from Ken Murchison <ken@oceana.com>)
+
+2001-08-07  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/client.c (sasl_server_step): corrected maxoutbuf handleing
+	* lib/server.c (sasl_server_step): corrected maxoutbuf handleing
+	* lib/saslint.h (DEFAULT_MAXOUTBUF): removed
+
+	* lib/common.c (sasl_encodev, sasl_decode): maxbufsize checking
+
+	* utils/testsuite.c (testseclayer,doauth): more security layer
+	  checking.  Added parameter to doauth to disable fatal() calls,
+	  updated all callers.
+
+	* utils/smtptest.c (main): added ability to support LMTP
+
+	* plugins/gssapi.c: conform with draft-ietf-cat-sasl-gssapi-05.txt
+
+	* doc/draft-ietf-cat-sasl-gssapi-05.txt: added
+	* doc/Makefile.am (EXTRA_DIST): added above to EXTRA_DIST
+
+2001-08-06  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/dbconverter-2.c (listusers_cb): handle PLAIN-APOP
+
+	* lib/client.c (sasl_client_add_plugin, client_done):
+	  save plugin name
+	* lib/server.c (sasl_server_add_plugin, server_done):
+	  save plugin name
+	* lib/dlopen.c (_sasl_plugin_load): correctly pass pluginname
+	* lib/common.c (sasl_getprop): implement SASL_AUTHSOURCE properly
+	* lib/saslint.h (cmechanism_t, mechanism_t): added plugname field
+	* lib/canonusr.c (internal_canonuser_init): no longer limit
+	  based on plugname
+	* plugins/sasldb.c (sasldb_auxprop_plug_init): no longer limit
+	  based on plugname
+
+2001-08-01  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* utils/smtptest.c (iptostring): better behaved w.r.t endianness
+
+	* plugins/cram.c (crammd5_server_mech_step): support for old-style
+	  secrets
+	* plugins/digestmd5.c (digestmd5_server_mech_step): support for
+	  old-style secrets
+	* lib/checkpw.c (auxprop_verify_password,_sasl_make_plain_secret):
+	  support for old-style secrets
+	* utils/dbconverter-2.c: added
+	* utils/sasldblistusers.c (listusers): Print out property names
+	  as well as username@realm format.
+	* utils/saslpasswd.c (_sasl_sasldb_set_pass): Correctly handle updates
+	  that concern old-style secrets
+
+	* sasldb/allockey.c: Added a missing null to propName in key parser
+	
+2001-07-31  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/kerberos4.c (mech_avail): made static
+
+	* plugins/kerberos4.c (mech_avail): fixed ipv4 check
+	  (patch from Hajimu UMEMOTO <ume@mahoroba.org>)
+
+	* doc/appconvert.html: vague guide documenting our experience
+	  porting Cyrus IMAPd to use SASLv2
+	* doc/Makefile.am: added appconvert.html
+
+	* lib/client.c (sasl_client_new): fixed ip address setting to hit
+		relevant params structures as well
+	* lib/server.c (sasl_server_new): fixed ip address setting to hit
+		relevant params structures as well
+	* lib/common.c (sasl_setprop): fixed ip address setting to hit
+		relevant params structures as well
+
+	* lib/common.c (sasl_seterror): fixed spelling error
+
+2001-07-30  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* sasldb/db_berkeley.c: utils->seterror() calls
+	* sasldb/db_gdbm.c: utils->seterror() calls
+	* sasldb/db_ndbm.c: utils->seterror() calls
+	* sasldb/allockey.c: utils->seterror() calls
+
+	* lib/common.c (sasl_seterror): still call logging callback with a
+	  null sasl_conn_t
+
+	* plugins/sasldb.c (sasldb_auxprop_lookup): support for multiple
+	  properties
+
+	* plugins/Makefile.am: added -module to LDFLAGS
+
+	* config/sasldb.m4: Allow specification of exact berkeley db
+	  lib and include paths
+	* sasldb/Makefile.am: Add proper include directory
+
+	* sasldb/sasldb.m4 (SASL_DB_BACKEND_STATIC): include allockey.o
+	
+	* Ready for 2.0.3-BETA	
+
+	* plugins/kerberos4.c (kerberos4_server_plug_init): reset
+	  srvtab when we do not load correctly.
+
+	* lib/staticopen.c (_sasl_load_plugins): do not fail
+	  if a single plugin load fails
+
+	* include/sasl.h (SASL_CLIENT_FALLBACK): removed
+
+2001-07-27  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* configure.in: extracted SASLDB-related checking
+	* config/sasldb.m4: added
+
+	* configure.in: now cache the JNI include directory path
+
+	* utils/testsuite.c: switch some sasl_errstrings to sasl_errdetail
+	* plugins/gssapi.c: Fix error reporting
+
+	* plugins/gssapi.c: Required SASL_CB_USER instead of SASL_CB_AUTHNAME
+
+	* plugins/anonymous.c: Function name standardization
+	* plugins/cram.c: Function name standardization
+	* plugins/digestmd5.c: Function name standardization
+	* plugins/gssapi.c: Function name standardization
+	* plugins/kerberos.c: Function name standardization
+	* plugins/login.c: Function name standardization
+	* plugins/plain.c: Function name standardization	
+
+	* sasldb/allockey.c: Generalized SASLdb API
+	* sasldb/db_berkeley.c: Generalized SASLdb API
+	* sasldb/db_gdbm.c: Generalized SASLdb API
+	* sasldb/db_ndbm.c: Generalized SASLdb API
+	* sasldb/db_none.c: Generalized SASLdb API
+	* sasldb/db_testw32.c: Added #error to block compile so the API will
+		be fixed when we do the Win 32 port
+	* plugins/sasldb.c: Use new SASLdb API
+	* utils/saslpasswd.c: Use new SASLdb API
+	
+2001-07-26  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/common.c (_sasl_getcallback): fixed reference to
+	  	possibly NULL conn
+
+	* configure.in: only build saslpasswd and sasldblistusers
+		if we have a meaningfull libsasldb (e.g. not db_none),
+	* utils/Makefile.am: only build saslpasswd and sasldblistusers
+		if we have a meaningfull libsasldb (e.g. not db_none),
+
+	* configure.in: conditionally build smtptest
+	* utils/Makefile.am: conditionally build smtptest
+	
+	* sasldb/allockey.c (_sasldb_parse_key): added
+
+	* sasldb/sasldb.h: New key list access API, added  parameter to
+		sasl_check_db (all callers updated, all callees updated)
+	* sasldb/db_berkeley.c: Implement key list access API
+	* sasldb/db_gdbm.c: Implement key list access API
+	* sasldb/db_ndbm.c: Implement key list access API
+	* sasldb/db_none.c: Implement key list access API
+
+	* utils/sasldblistuser.c: Use libsasldb instead of internal
+	  	functions.
+	
+	* utils/saslpasswd.c: No longer have separate global_utils,
+		call sasl_dispose and sasl_done
+
+	* acconfig.h: check for inttypes.h
+	* configure.in: check for inttypes.h
+	* plugins/plugin_common.c: include, if necessary, inttypes.h,
+		reference uint32_t instead of u_int32_t
+
+2001-07-25  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* lib/saslint.h: changed "sasldb" verifier to "auxprop"
+	* lib/server.c: changed "sasldb" verifier to "auxprop"
+	* lib/checkpw.c: changed "sasldb" verifier to "auxprop"
+	* utils/testsuite.c: changed "sasldb" verifier to "auxprop"
+	* doc/options.html: changed "sasldb" verifier to "auxprop"
+
+	* README: updated upgrade information
+
+	* utils/Makefile.am (CLEANFILES): added
+
+	* sasldb/allockey.c (alloc_key): single place for alloc_key()
+	  Removed alloc_key from other source files.
+	* sasldb/sasldb.h: added declaration of alloc_key()	
+
+	* configure.in: added checks for db-3.3 and db3.3
+
+	* plugins/digestmd5.c (get_realm): now error on empty user_realm
+
+	* plugins/cram.c (client_required_prompts): removed redundant
+	  required_prompts
+
+	* plugins/plain.c (client_continue_step): server-send-last error
+
+	* utils/testsuite.c (main): detailed client-send-first,
+		server-send-last checking
+	
+2001-07-24  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* plugins/sasldb.c: Cleaned up calls into the glue code
+
+	* java/Test/*: Cleaned up java test utilities
+	
+	* configure.in: Minor GSSAPI configure changes
+
+	* utils/saslpasswd.c: Clarfied -d option for saslpasswd
+	* utils/saslpasswd.8: Clarfied -d option for saslpasswd
+	
+	* doc/plugprog.html: Added plugin programmer's guide
+	* doc/index.html: linked to plugin programmer's guide
+	
+        * configure.in: corrected configure checking of Berkeley DB
+          (from Scot W. Hetzel <scot@genroco.com>)
+
+	* configure.in: corrected checking for libcom_err
+	  (from Scot W. Hetzel <scot@genroco.com>)
+
+2001-07-23  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* configure.in: Added check for db3/db.h
+
+	* plugins/kerberos4.c Added mech_avail (checks for IP info)
+	
+	* lib/common.c: Fixed setting of serverFQDN in _sasl_conn_init
+	
+	* lib/server.c: Fully Implemented mech_avail calls in glue code
+	
+	* lib/server.c: Fixed allocation/destruction of sasl_conn_t's
+	* lib/client.c: Fixed allocation/destruction of sasl_conn_t's
+	* lib/common.c: Rely on earlier initialization in server.c and client.c
+
+	* doc/options.html: added
+
+	* ChangeLog: back to standard format
+	
+2001-07-20  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Can now deal with variable client-first mechs such as
+	  DIGEST-MD5, though this interface is subject to change
+	* Modified parseuser to deal better with default realms
+	* Simplified realm handling in DIGEST-MD5 (getrealm callback
+	  is no longer required).
+	* Cleaned up some memory management issues in DIGEST-MD5
+
+2001-07-19  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Fixed prototype of sasl_getpath_t to be in conformance with
+	  memory allocation rules
+	* Fixed up samples directory
+	* Try to dlopen using information in .la file if available
+	  (based on patch from
+	   Stoned Elipot <Stoned.Elipot@script.jussieu.fr>)
+	* Resolution of most of the server-send-first and client-send-last
+	  issues (using mechanism feature flags)
+
+2001-07-18  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Updated config.guess and config.sub
+	* Better underscore checking for dlsym
+	* Resolved possible global_utils namespace collision
+	* Updated sasldb library to be expandable to multiple properties
+	  if the need arises in the future.
+	* IPv6 support from Hajimu UMEMOTO <ume@mahoroba.org>
+
+2001-07-17  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Extricated sasldb support to an auxprop plugin only.
+	  sasldb modifications can now only be done through the saslpasswd
+	  interface.
+
+2001-07-13  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Fixed buffer overrun problem in sasldb auxprop plugin
+	* Removed severe memory leak from testsuite
+	* Version 2.0.2-ALPHA Released
+
+2001-07-11  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* error reporting in KERBEROS_V4 plugin
+	* vague handling of SASL_AUTHSOURCE for getprop
+	* random misc error reporting bugs
+	* basic error messages for GSSAPI plugin
+
+2001-07-10  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* added client-send-first logic in glue code
+	* removed some client-send-first logic in mechanisms
+	* removed IPv4 specifics from sasl_conn_t
+	* Much gluecode error revamping (store the error code
+	  in sasl_conn_t)
+
+2001-07-09  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Removed dependency on "name" in canonuser plugin structure
+	* Update configure.in from a new configure.scan
+	* Update copyright info in man pages, finished all API man pages
+	* Added auxprop tests to testsuite
+	* Added userdb callback support
+
+2001-07-09  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* First attempt at making the java code work again
+	* Minor memory and byte order bugfixes
+	* Added testing support for dmalloc (--with-dmalloc)
+
+2001-07-06  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Loading of auxprop and canonuser plugins from DSOs
+	  (This still sucks performance wise, and will be fixed soon)
+	* Fixed some lack of indirection in the plugins
+	* Reverted to the v1 entry points for the plugins
+	* Cleaned up a good deal of the library loading code so it
+	  now only gets called from the sasl_*_init functions, and
+	  all the cleanup happens in the common sasl_done function
+	* Added SASL_IPREMOTEPORT and SASL_IPLOCALPORT to setprop,
+	  and now _sasl_conn_init calls it to do the same work.
+
+2001-07-05  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Working libsfsasl and smtptest program (--with-sfio)
+	* Fixed sasldblistusers (atleast for Berkeley DB)
+	* seterror() calls in ANONYMOUS, CRAM, PLAIN and LOGIN
+	* Some new manpages
+
+2001-07-03  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Static library compilation now optional (--with-staticsasl)
+	  Note that this is different from --enable-static, which causes
+	  libtool to build static versions of everything is is almost
+	  certainly NOT what you want.
+	* Removed all references to the ancient NANA code.
+	* Updated some documentation.
+
+2001-07-02  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Improved allocation efficiency of KERBEROS_V4, DIGEST-MD5,
+	  and GSSAPI security layers.
+	* Fixed a decode bug in DIGEST-MD5 (and testsuite improvements to
+	  help find similar ones)
+	* Fixed a number of solaris compiler warnings
+	* Static Library Build Support
+
+2001-06-30  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Cleanup of some man pages (added sasl_errors.3)
+
+2001-06-29  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Cleanup of APOP Code + new man page (Ken Murchison <ken@oceana.com>)
+	* Cleanup of comments in some files (Ken Murchison <ken@oceana.com>)
+	* Fixed some compiler errors on Solaris using /opt/SUNWspro/bin/cc
+	  (Reported by Mei-Hui Su <mei@ISI.EDU>
+
+2001-06-28  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Improved memory allocation in default sasl_decode handler
+	* Added ability to disable sasl_checkapop (--disable-checkapop)
+	* Re-initialized kerberos mutex to NULL after it was freed
+
+2001-06-28  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Fixed a severe bug in DIGEST-MD5 Plugin
+	* KERBEROS_V4 plugin now thread safe
+	* Version 2.0.1-ALPHA Released (due to DIGEST-MD5 problem)
+
+2001-06-27  Rob Siemborski <rjs3+@andrew.cmu.edu>
+	* Version 2.0.0-ALPHA Released

+ 302 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/INSTALL

@@ -0,0 +1,302 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  6. Often, you can also type `make uninstall' to remove the installed
+     files again.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *Note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+

+ 1 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/INSTALL.TXT

@@ -0,0 +1 @@
+For installation instructions, see doc/install.html.

+ 503 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/NEWS

@@ -0,0 +1,503 @@
+New in 2.1.26
+-------------
+
+* Modernize SASL malloc/realloc callback prototypes
+* Added sasl_config_done() to plug a memory leak when using an application
+  specific config file
+* Fixed PLAIN/LOGIN authentication failure when using saslauthd
+  with no auxprop plugins (bug # 3590).
+* unlock the mutex in sasl_dispose if the context was freed by another thread
+* MINGW32 compatibility patches
+* Fixed broken logic in get_fqhostname() when abort_if_no_fqdn is 0
+* Fixed some memory leaks in libsasl
+* GSSAPI plugin:
+ - Fixed a segfault in gssapi.c introduced in 2.1.25.
+ - Code refactoring
+ - Added support for GSS-SPNEGO SASL mechanism (Unix only), which is also
+   HTTP capable
+* GS2 plugin:
+ - Updated GS2 plugin not to lose minor GSS-API status codes on errors
+* DIGEST-MD5 plugin:
+ - Correctly send "stale" directive to prevent clients from (re)promtping
+   for password
+ - Better handling of HTTP reauthentication cases
+ - fixed some memory leaks
+* SASLDB plugin:
+ - Added support for BerkleyDB 5.X or later
+* OTP plugin:
+ - Removed calling of EVP_cleanup() on plugin shutdown in order to prevent
+   TLS from failing in calling applications
+* SRP plugin:
+ - Removed calling of EVP_cleanup() on plugin shutdown in order to prevent
+   TLS from failing in calling applications
+* saslauthd:
+ - auth_rimap.c: qstring incorrectly appending the closing double quote,
+   which might be causing crashes
+ - auth_rimap.c: read the whole IMAP greeting
+ - better error reporting from some drivers
+ - fixed some memory leaks
+
+New in 2.1.25
+-------------
+
+* Make sure that a failed authorization doesn't preclude
+  further server-side SASL authentication attempts from working.
+* Fixed a crash caused by aborted SASL authentication
+  and initiation of another one using the same SASL context.
+* (Windows) Fixed the random number generator to actually produce random
+  output on each run.
+* Be protective against calling sasl_server_step once authentication
+  has failed (multiple SASL plugins)
+* Fixed several bugs in the mech_avail callback handling
+  in the server side code.
+* Added support for channel bindings
+* Added support for ordering SASL mechanisms by strength (on the client side),
+  or using the "client_mech_list" option.
+* server_idle needs to obey server's SASL mechanism list from the server
+  context.
+* Better server plugin API mismatch reporting
+* Build:
+ - Updated config to the latest GNU snapshot
+ - Fixed SASL's libtool MacOS/X 64-bit file magic
+* New SASL plugin: SCRAM
+* New SASL plugin: GS2
+* DIGEST-MD5 plugin:
+ -  Allow DIGEST-MD5 plugin to be used for client-side and
+    server-side HTTP Digest, including running over non-persistent
+    connections (RFC 2617)
+ - Use the same username for reauthentication cache lookup and update
+ - Minimize the number of auxprop lookups in the server side DIGEST-MD5
+   plugin for the most common case when authentication and authorization
+   identities are the same.
+ - Updated digestmd5_server_mech_step2() to be more defensive against
+   empty client input.
+ - Fixed some memory leaks on failed plugin initialization.
+   Prevent potential race condition when freeding plugin state.
+   Set the freed reauthentication cache mutex to NULL, to make errors
+   due to mutex access after free more obvious.
+ - Test against broken UTF-8 based hashes if calculation using special
+   ISO-8859-1 code fails.
+ - Fixed an interop problem with some LDAP clients ignoring server
+   advertised realm and providing their own.
+* GSSAPI plugin:
+ - Fix to build GSSAPI with Heimdal
+ - Properly set serveroutlen to 0 in one place.
+   Don't send empty challenge once server context establishment is done,
+   as this is in violation of the RFC 2222 and its successor.
+ - Don't send maxbuf, if no security layer can be established.
+   Added additional checks for buffer lengths.
+* LDAPDB plugin:
+ - build fixes
+
+New in 2.1.24
+-------------
+
+* Order advertised server-side SASL mechanisms per the specified 'mech_list'
+  option or by relative "strength"
+* Make sure that sasl_set_alloc() has no effect once sasl_client_init()
+  or sasl_server_init() is called
+* Fixed sasl_set_mutex() to disallow changing mutex management functions
+  once sasl_server_init()/sasl_client_init() is called (bug # 3083)
+* Removed unused mutexes in lib/client.c and lib/server.c (bug # 3141)
+* Added direct support for hashed password to auxprop API
+* Don't treat a constraint violation as an error to store an auxprop property
+* Extended libsasl (auxprop) to support user deletion
+* Extended SASL auxprop_lookup to return error code
+* Updated sasl_user_exists() so that it can handle passwordless accounts (e.g. disabled)
+* (Windows) Free handles of shared libraries on Windows that were loaded
+  but are not SASL plugins (bug # 2089)
+* Prevent freeing of common state on a subsequent call to _sasl_common_init.
+  Make sure that the last global callback always wins.
+* Implemented sasl_client_done()/sasl_server_done()
+* Added automatic hostname canonicalization inside libsasl
+* Made sasl_config_init() public
+* Strip trailing spaces from server config file option values (bug # 3139, bug # 3041)
+* Fixed potential buffer overflow in saslautd_verify_password().
+* Fixed segfault in dlclose() on HPUX
+* Various bugfixes for 64bit platforms
+* Fixed bug # 2895 (passing LF to sasl_decode64) in sample/sample-client.c,
+  sample/sample-server.c, utils/smtptest.c
+* pluginviewer: Code cleanup, improved human readable messages
+* Build:
+ - (Windows) Updated makefiles to build with VC 8.0 (VC++ 2005)
+ - (Windows) Added Windows64 build
+ - Updated to use .plugin extension on MacOS
+ - Changed 64bit HP-UX build to use .so for shared libraries
+* saslauthd:
+ - Fixed bug counting double-quotes in username/password in
+   auth_rimap.c. Also fixed bug zeroing password.
+ - auth_krb.c: improved diagnostic in the k5support_verify_tgt() function.
+ - auth_sasldb.c: pid_file_lock is created with a mask of 644 instead of 0644
+ - auth_shadow.c: Define _XOPEN_SOURCE before including unistd.h,
+   so that crypt is correctly defined
+ - auth_getpwent.c: Fixed Solaris build
+* SASLDB plugin:
+ - Fixed spurious 'user not found' errors caused by an attempt
+   to delete a non-existent property
+ - Added direct support for hashed password to auxprop API
+ - Sleepycat driver:  Return SASL_NOUSER instead of SASL_FAIL when the database
+   file doesn't exist
+ - Ignore properties starting with '*' in the auxprop store function
+* SQL plugin:
+ - Added support for SQLITE3
+ - Uninitialized variables can cause crash when the searched user is not found
+ - Added direct support for hashed password
+ - Ignore properties starting with '*' in the auxprop store function
+* LDAPDB plugin:
+ - Added code to extend LDAPDB into a canon_user plugin in addition
+   to its existing auxprop plugin functionality
+* PLAIN plugin:
+ - Advertise SASL_SEC_PASS_CREDENTIALS feature
+* LOGIN plugin:
+ - Advertise SASL_SEC_PASS_CREDENTIALS feature
+* DIGEST-MD5 plugin:
+ - Fixed a memory leak in the DIGEST-MD5 security layer
+ - Fixed memory leaks in client-side reauth and other places
+ - More detailed error reporting.
+ - Fixed parsing of challenges/responses with extra commas.
+ - Allow for multiple qop options from the server and require
+   a single qop option from the client.
+* GSSAPI plugin:
+ - Check that params->serverFQDN is not NULL before using strlen on it
+ - Make auxprop lookup calls optional
+* EXTERNAL plugin:
+ - Make auxprop lookup calls optional
+* NTLM plugin:
+ - allow a comma separated list of servernames in 'ntlm_server' option
+ - Fixed crash in calculating NTv2 reponse
+* OTP plugin:
+ - Don't use a stack variable for an OTP prompt (bug # 2822)
+ - Downgrade the failure to store OTP secret to debug level
+* KERBEROS_V4 plugin:
+ - Make auxprop lookup calls optional
+
+New in 2.1.23
+-------------
+
+* Fixed CERT VU#238019 (make sure sasl_encode64() always NUL
+  terminates output or returns SASL_BUFOVER)
+
+New in 2.1.22
+-------------
+
+* Added support for spliting big data blocks (bigger than maxbuf)
+  into multiple SASL packets in sasl_encodev
+* Various sasl_decode64() fixes
+* Increase canonicalization buffer size to 1024 bytes
+* Call do_authorization() after successful APOP authentication
+* Allow for configuration file location to be configurable independently
+  of plugin location (bug # 2795)
+* Added sasl_set_path function, which provides a more convenient way
+  of setting plugin and config paths. Changed the default
+  sasl_getpath_t/sasl_getconfpath_t callbacks to calculate
+  the value only once and cache it for later use.
+* Fixed load_config to search for the config file in all directories
+  (bug # 2796). Changed the default search path to be
+  /usr/lib/sasl2:/etc/sasl2
+* Don't ignore log_level configuration option in default UNIX syslog
+  logging callback
+* (Windows) Minor IPv6 related changes in Makefiles for Visual Studio 6
+* (Windows) Fixed bug of not setting the CODEGEN (code generation option)
+  nmake option if STATIC nmake option is set.
+* Several fixed to DIGEST-MD5 plugin:
+  - Enable RC4 cipher in Windows build of DIGEST-MD5
+  - Server side: handle missing realm option as if realm="" was sent
+  - Fix DIGEST-MD5 to properly advertise maxssf when both DES and RC4
+    are disabled
+  - Check that DIGEST-MD5 SASL packet are no shorter than 16 bytes
+* Several changes/fixed to SASLDB plugin:
+  - Prevent spurious SASL_NOUSER errors
+  - Added ability to keep BerkleyDB handle open between operations
+    (for performance reason). New behavior can be enabled
+    with --enable-keep-db-open.
+* Better error checking in SQL (MySQL) auxprop plugin code
+* Added support for HTTP POST password validation in saslauthd
+* Added new application ("pluginviewer") that helps report information
+  about installed plugins
+* Allow for building with OpenSSL 0.9.8
+* Allow for building with OpenLDAP 2.3+
+* Several quoting fixes to configure script
+* A large number of other minor bugfixes and cleanups
+
+New in 2.1.21
+-------------
+* Fixes DIGEST-MD5 server side segfault caused by the client not sending
+  any realms
+* Minor Other bugfixes
+
+New in 2.1.20
+-------------
+* Fixes to cram plugin to avoid attempting to canonify uninitialized data.
+* NTLM portability fixes.
+* Avoid potential attack using SASL_PATH when sasl is used in a setuid 
+  environment.
+* A trivial number of small bugfixes.
+
+New in 2.1.19
+-------------
+* Fixes to saslauthd to allow better integration with realms (-r flag to
+  saslauthd, %R token in LDAP module)
+* Support for forwarding of GSSAPI credentials
+* SQLite support for the SQL plugin
+* A nontrivial number of small bugfixes.
+
+New in 2.1.18
+-------------
+* saslauthd/LDAP no longer tagged "experimental"
+* Add group membership check to saslauthd/LDAP
+* Fix Solaris 9 "NI_WITHSCOPEID" issue
+* Fix missing "getaddrinfo.c" and other distribution problems
+* Significant Windows enhancements
+* A large number of other minor bugfixes and cleanups
+
+New in 2.1.17
+-------------
+* Allow selection of GSSAPI implementation explicitly (--with-gss_impl)
+* Other GSSAPI detection improvements
+* Now correctly do authorizaton callback in sasl_checkpass()
+* Disable KERBEROS_V4 by default
+* Continued Win32/Win64 Improvements
+* Minor Other bugfixes
+
+New in 2.1.16-BETA
+------------------
+* Significantly improved Win32 support
+* Writable auxprop support
+* Expanded SQL support (including postgres)
+* Significantly improved documentation
+* Improved realm/username handling with saslauthd
+* Support for modern automake and autoconf
+
+New in 2.1.15
+-------------
+* Fix a number of build issues
+* Add a doc/components.html that hopefully describes how things
+  interact better.
+
+New in 2.1.14
+-------------
+* OS X 10.2 support
+* Support for the Sun SEAM GSSAPI implementation
+* Support for MySQL 4
+* A number of build fixes
+* Other minor bugfixes
+
+New in 2.1.13
+-------------
+* Add a configure option to allow specification of what /dev/random to use.
+* Addition of a saslauthd credential cache feature (-c option).
+* Unification of the saslauthd ipc method code.
+* Fix a number of autoconf issues.
+* A significant number of fixes throughout the library from Sun Microsystems.
+* Other minor bugfixes.
+
+New in 2.1.12
+-------------
+* Distribute in Solaris tar (not GNU tar format)
+* Fix a number of build/configure related issues.
+
+New in 2.1.11
+-------------
+* Add the fastbind auth method to the saslauthd LDAP module.
+* Fix a potential memory leak in the doors version of saslauthd.
+* NTLM now only requires one of LM or NT, not both.
+* Fix a variety of Berkeley DB, LDAP, OpenSSL, and other build issues.
+* Win32 support compiles, but no documentation as of yet.
+
+New in 2.1.10
+-------------
+* Further DIGEST-MD5 DES interoperability fixes.  Now works against Active
+  Directory.
+* Fix some potential buffer overflows.
+* Misc. cleanups in the saslauthd LDAP module
+* Fix security properties of NTLM and EXTERNAL
+
+New in 2.1.9
+------------
+* Include missing lib/staticopen.h file.
+
+New in 2.1.8
+------------
+* Support for the NTLM mechanism (Ken Murchison <ken@oceana.com>)
+* Support libtool --enable-shared and --enable-static
+  (Howard Chu <hyc@highlandsun.com>)
+* OS/390 Support (Howard Chu <hyc@highlandsun.com>)
+* Berkeley DB 4.1 Support (Mika Iisakkila <mika.iisakkila@pingrid.fi>)
+* Documentation fixes
+* The usual round of assorted other minor bugfixes.
+
+New in 2.1.7
+------------
+* Add SASL_AUTHUSER as a parameter to sasl_getprop
+* Allow applications to require proxy-capable mechanisms (SASL_NEED_PROXY)
+* Performance improvements in our treatment of /dev/random
+* Removal of buggy DIGEST-MD5 reauth support.
+* Documentation fixes
+* Assorted other minor bugfixes.
+
+New in 2.1.6
+------------
+* Security fix for the CRAM-MD5 plugin to check the full length of the
+  digest string.
+* Return of the Experimental LDAP saslauthd module.
+* Addition of Experimental MySQL auxprop plugin.
+* Can now select multiple auxprop plugins (and a priority ordering)
+* Mechanism selection now includes number of security flags
+* Mac OS X 10.1 Fixes
+* Misc other minor bugfixes.
+
+New in 2.1.5
+------------
+* Remove LDAP support due to copyright concerns.
+* Minor bugfixes.
+
+New in 2.1.4
+------------
+* Enhancements and cleanup to the experimental LDAP saslauthd module
+  (Igor Brezac <igor@ipass.net>)
+* Addition of a new sasl_version() API
+* Misc. Bugfixes
+
+New in 2.1.3-BETA
+-----------------
+* Significant amount of plugin cleanup / standardization.  A good deal of code
+  is now shared between them. (mostly due to Ken Murchison <ken@oceana.com>)
+* DIGEST-MD5 now supports reauthentication.  Also has a fix for DES
+  interoperability.
+* saslauthd now supports the Solaris "doors" IPC method
+  (--with-ipctype=doors)
+* Significant GSSAPI fixes (mostly due to Howard Chu <hyc@highlandsun.com>)
+* Auxprop interface now correctly deals with the * prefix indicating 
+  authid vs. authzid.  (May break some incompatible auxprop plugins).
+* We now allow multiple pwcheck_method(s).  Also you can restrict auxprop
+  plugins to the use of a single plugin.
+* Added an experimental saslauthd LDAP module (Igor Brezac <igor@ipass.net>)
+* Removed check for db3/db.h
+* Misc. documentation updates.  (Marshall Rose, and others)
+* Other misc. bugfixes.
+
+New in 2.1.2
+------------
+* Mostly a minor-bugfix release
+* Improved documentation / cleanup of old references to obsolete
+  pwcheck_methods
+* Better error reporting for auxprop password verifiers
+
+New in 2.1.1
+------------
+* Many minor bugfixes throughout.
+* Improvements to OTP and SRP mechanisms (now compliant with
+  draft-burdis-cat-srp-sasl-06.txt)
+* API additions including sasl_global_listmech, and a cleaner handling of
+  client-first and server-last semantics (no application level changes)
+* Minor documentation improvements
+
+New in 2.1.0
+------------
+* The Cyrus SASL library is now considered stable.  It is still not backwards
+  compatible with applications that require SASLv1.
+* Minor API changes occured, namely the canon_user callback interface.
+* saslauthd now preforks a number of processes to handle connections
+* Many bugfixes through the entire library.
+
+New in 2.0.5-BETA
+-----------------
+* THIS IS A BETA-QUALITY RELEASE THAT IS NOT INTENDED FOR PRODUCTION USE.
+  IT *WILL BREAK* ANY APPLICATION EXPECTING THE SASLv1 API.
+* Improved performance of security layers in KERBEROS_V4, GSSAPI, and DIGEST.
+* This release includes an OTP plugin that requires libopie.
+* SRP plugin now in alpha stage.
+* Includes many significant bugfixes throughout the library.
+
+New in 2.0.4-BETA
+-----------------
+* THIS IS A BETA-QUALITY RELEASE THAT IS ONLY INTENDED FOR USE BY
+  DEVELOPERS WHOSE APPLICATIONS MAKE USE OF THE CYRUS SASL LIBRARY.
+  IT *WILL BREAK* ANY APPLICATION EXPECTING THE SASLv1 API.
+* This release now includes Mac OS 9 and Mac OS X support.
+* Significant new features include 
+  * DES and 3DES Encryption should now be working for DIGEST-MD5
+  * Improved configuration system
+  * Improved documentation (now includes plugin writers guide)
+  * Many other bugfixes (see ChangeLog)
+
+New in 2.0.3-BETA
+-----------------
+* THIS IS A BETA-QUALITY RELEASE THAT IS ONLY INTENDED FOR USE BY
+  DEVELOPERS WHOSE APPLICATIONS MAKE USE OF THE CYRUS SASL LIBRARY.
+  IT *WILL BREAK* ANY APPLICATION EXPECTING THE SASLv1 API.
+* This library should be fairly close to the core features that will be
+  released in a final version of Cyrus SASLv2.  It very likely has bugs.
+* Major new features included in this release:
+  - The glue code now correctly handles client-send-first and server-send-last
+    situations based on what the protocol and mechanism each support.
+  - The sasldb code has been extracted from the main library and now resides
+    in a separate libsasldb.la that is available at build time.
+  - SASLdb now supports multiple auxiliary properties, though as distributed
+    only userPassword is implemented and used.
+  - Much improved configure checking for various items, including
+    Berkeley DB, Kerberos, and GSSAPI.
+  - Better (more standard) handling of realms in DIGEST-MD5.
+  - A new Plugin Programmer's guide.
+  - IPv6 support.
+  - Error reporting now works in the GSSAPI plugin.
+* See the ChangeLog for a more detailed list of changes.
+
+New in 2.0.2-ALPHA
+------------------
+* THIS IS AN ALPHA-QUALITY RELEASE THAT IS ONLY INTENDED FOR DEVELOPERS
+  WHOSE APPLICATIONS MAKE USE OF THE CYRUS SASL LIBRARY.  
+* This release is intended to show developers that use Cyrus SASL what
+  direction we are planning on taking the library so that they can make
+  plans to migrate their applications accordingly
+* Major new features included in this release:
+  - Ability to compile a static library including all mechanisms.  This
+    means lower memory usage and faster mechanism loading time, but
+    is not for everyone (or even many people). See doc/advanced.html,
+    as well as the '--with-staticsasl' configure flag.
+  - Man pages should now all be present and are close to being correct.
+  - Can now build libsfsasl and the smtptest program (using the --with-sfio
+    configure flag)
+  - Reverted to the v1 entry points for mechanisms, to allow v1 mechanisms
+    to fail loading cleanly.
+  - Auxprop and canon_user plugins can now load from DSOs
+  - Java code now compiles (but is not well tested, or up to date with the
+    current Java API draft)
+  - Error handling and use of sasl_errdetail has been fleshed out and
+    should now work in most cases.
+* Still Coming:
+  - Cleanup of the client-send-first and server-send-last situation
+  - Error reporting in GSSAPI plugin
+  - Move the sasldb code out of the main library and into plugins and
+    utilities only.
+
+New in 2.0.0-ALPHA
+------------------
+* THIS IS AN ALPHA-QUALITY RELEASE THAT IS ONLY INTENDED FOR DEVELOPERS
+  WHOSE APPLICATIONS MAKE USE OF THE CYRUS SASL LIBRARY.  
+* This release is intended to show developers that use Cyrus SASL what
+  direction we are planning on taking the library so that they can make
+  plans to migrate their applications accordingly
+* This release implements the SASLv2 API.
+  Some of the major improvements in the API include:
+  - Memory management is now sane (whoever allocates the memory is responsible
+    for freeing it)
+  - Auxiliary Property plugin support (ability to interface with directory
+    services as part of authentication)
+  - Username canonification plugin support
+  - Improved error reporting (not fully implemented in this release)
+  - Database support has been simplified.  We now maintain only a single
+    store of plaintext passwords that is shared by all supplied plugins
+    (using the auxiliary property interface).
+  The new API is more fully documented in the header files sasl.h, saslplug.h
+  saslutil.h, and prop.h.  The man pages, programmers guide, and system
+  administrators guide have also been rewritten to deal with the new API.
+* There is still a good amount of work to be done, and as this code is alpha
+  quality, it has bugs, known and unknown.  Please either use our bugzilla at
+  http://bugzilla.andrew.cmu.edu, or email cyrus-bugs@andrew.cmu.edu with
+  questions, comments, or bug reports.
+  - Most notably, the Java bindings have not been converted to work with
+    the new API, and thus will not compile successfully.
+  - The current development branch with this source is in our
+    cvs repository as the "sasl-v2-rjs3" branch of the "sasl" collection.
+    (see http://asg.web.cmu.edu/cyrus/download/anoncvs.html for more info)

+ 21 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/README

@@ -0,0 +1,21 @@
+This is the Cyrus SASL API implentation. It can be used on the client
+or server side to provide authentication and authorization services.
+See RFC 4422 for more information.
+
+The latest version is available at:
+ftp://ftp.andrew.cmu.edu/pub/cyrus-mail
+
+There's a mailing list for Cyrus SASL.  Subscribe by sending a message
+to majordomo@lists.andrew.cmu.edu with the body "subscribe
+cyrus-sasl". The mailing list is available via anonymous IMAP at
+imap://cyrus.andrew.cmu.edu/archive.cyrus-sasl or via the web at
+http://asg.web.cmu.edu/archive/mailbox.php3?mailbox=archive.cyrus-sasl.
+
+If you are looking to port SASLv1 applications to SASLv2, please see
+doc/appconvert.html
+
+Bugs can be searched/reported at: http://bugzilla.cyrussasl.org
+
+DOCUMENTATION
+--------------
+Please see doc/index.html for the remainder of the documentation.

+ 65 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/Makefile.am

@@ -0,0 +1,65 @@
+# Makefile.am for SASL includes
+# Rob Earhart
+#
+################################################################
+# Copyright (c) 2000 Carnegie Mellon University.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer. 
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# 3. The name "Carnegie Mellon University" must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission. For permission or any other legal
+#    details, please contact  
+#      Office of Technology Transfer
+#      Carnegie Mellon University
+#      5000 Forbes Avenue
+#      Pittsburgh, PA  15213-3890
+#      (412) 268-4387, fax: (412) 268-7395
+#      tech-transfer@andrew.cmu.edu
+#
+# 4. Redistributions of any form whatsoever must retain the following
+#    acknowledgment:
+#    "This product includes software developed by Computing Services
+#     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+#
+# CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+################################################################
+
+noinst_HEADERS = gai.h exits.h
+
+saslincludedir = $(includedir)/sasl
+saslinclude_HEADERS = hmac-md5.h md5.h md5global.h sasl.h saslplug.h saslutil.h prop.h
+
+noinst_PROGRAMS = makemd5
+
+makemd5_SOURCES = makemd5.c
+
+md5global.h: makemd5
+	-rm -f md5global.h
+	./makemd5 md5global.h
+
+EXTRA_DIST = NTMakefile
+DISTCLEANFILES = md5global.h
+
+if MACOSX
+framedir = /Library/Frameworks/SASL2.framework
+frameheaderdir = $(framedir)/Versions/A/Headers
+frameheader_DATA = $(saslinclude_HEADERS)
+endif

+ 65 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/NTMakefile

@@ -0,0 +1,65 @@
+# NTMakefile for SASL, include directory
+# Alexey Melnikov
+#
+################################################################
+# Copyright (c) 2003 Carnegie Mellon University.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer. 
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# 3. The name "Carnegie Mellon University" must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission. For permission or any other legal
+#    details, please contact  
+#      Office of Technology Transfer
+#      Carnegie Mellon University
+#      5000 Forbes Avenue
+#      Pittsburgh, PA  15213-3890
+#      (412) 268-4387, fax: (412) 268-7395
+#      tech-transfer@andrew.cmu.edu
+#
+# 4. Redistributions of any form whatsoever must retain the following
+#    acknowledgment:
+#    "This product includes software developed by Computing Services
+#     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+#
+# CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+################################################################
+
+#Suppress verbose output from defaulting values
+VERBOSE=0
+
+!INCLUDE ..\win32\common.mak
+
+includedir = $(prefix)\include
+
+saslincludedir = $(includedir)\sasl\
+
+saslinclude_HEADERS = hmac-md5.h md5.h sasl.h saslplug.h saslutil.h prop.h
+
+# The first target get executed by default. We don't want this to be "install"
+all:
+	@echo Nothing to be done for $@
+
+#
+# /I flag to xcopy tells to treat the last parameter as directory and create all missing levels
+#
+install: $(saslinclude_HEADERS)
+	!xcopy sasl*.h $(saslincludedir) /I /F /Y
+	!xcopy $? $(saslincludedir) /I /F /Y

+ 607 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/config.h

@@ -0,0 +1,607 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+
+/* acconfig.h - autoheader configuration input */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+/* Runtime config file location */
+#define CONFIGDIR "/usr/lib/sasl2:/etc/sasl2"
+
+/* Do we need a leading _ for dlsym? */
+/* #undef DLSYM_NEEDS_UNDERSCORE */
+
+/* Should we build a shared plugin (via dlopen) library? */
+/* #undef DO_DLOPEN */
+
+/* should we support sasl_checkapop? */
+#define DO_SASL_CHECKAPOP /**/
+
+/* should we support setpass() for SRP? */
+/* #undef DO_SRP_SETPASS */
+
+/* should we mutex-wrap calls into the GSS library? */
+#define GSS_USE_MUTEXES /**/
+
+/* Enable 'alwaystrue' password verifier? */
+/* #undef HAVE_ALWAYSTRUE */
+
+/* Include support for Courier's authdaemond? */
+#define HAVE_AUTHDAEMON /**/
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dns_lookup' function. */
+/* #undef HAVE_DNS_LOOKUP */
+
+/* Define to 1 if you have the `dn_expand' function. */
+#define HAVE_DN_EXPAND 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Do we have a getaddrinfo? */
+#define HAVE_GETADDRINFO /**/
+
+/* Define to 1 if you have the `getdomainname' function. */
+#define HAVE_GETDOMAINNAME 1
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Do we have a getnameinfo() function? */
+#define HAVE_GETNAMEINFO /**/
+
+/* Define to 1 if you have the `getpassphrase' function. */
+/* #undef HAVE_GETPASSPHRASE */
+
+/* Define to 1 if you have the `getpwnam' function. */
+#define HAVE_GETPWNAM 1
+
+/* Define to 1 if you have the `getspnam' function. */
+/* #undef HAVE_GETSPNAM */
+
+/* do we have getsubopt()? */
+#define HAVE_GETSUBOPT /**/
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <gssapi/gssapi_ext.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_EXT_H */
+
+/* Define if you have the gssapi.h header file */
+#define HAVE_GSSAPI_H /**/
+
+/* Define to 1 if you have the `gsskrb5_register_acceptor_identity' function.
+   */
+/* #undef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY */
+
+/* Define if your GSSAPI implementation defines GSS_C_NT_HOSTBASED_SERVICE */
+#define HAVE_GSS_C_NT_HOSTBASED_SERVICE /**/
+
+/* Define if your GSSAPI implementation defines GSS_C_NT_USER_NAME */
+#define HAVE_GSS_C_NT_USER_NAME /**/
+
+/* Define to 1 if you have the `gss_decapsulate_token' function. */
+/* #undef HAVE_GSS_DECAPSULATE_TOKEN */
+
+/* Define to 1 if you have the `gss_encapsulate_token' function. */
+/* #undef HAVE_GSS_ENCAPSULATE_TOKEN */
+
+/* Define to 1 if you have the `gss_get_name_attribute' function. */
+/* #undef HAVE_GSS_GET_NAME_ATTRIBUTE */
+
+/* Define to 1 if you have the `gss_oid_equal' function. */
+/* #undef HAVE_GSS_OID_EQUAL */
+
+/* Define to 1 if you have the `inet_aton' function. */
+#define HAVE_INET_ATON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `jrand48' function. */
+#define HAVE_JRAND48 1
+
+/* Do we have Kerberos 4 Support? */
+/* #undef HAVE_KRB */
+
+/* Define to 1 if you have the `krb_get_err_text' function. */
+/* #undef HAVE_KRB_GET_ERR_TEXT */
+
+/* Define to 1 if you have the <lber.h> header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the <ldap.h> header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <malloc.h> header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkdir' function. */
+#define HAVE_MKDIR 1
+
+/* Do we have mysql support? */
+/* #undef HAVE_MYSQL */
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Do we have OpenSSL? */
+#define HAVE_OPENSSL /**/
+
+/* Use OPIE for server-side OTP? */
+/* #undef HAVE_OPIE */
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+/* #undef HAVE_PAM_PAM_APPL_H */
+
+/* Define to 1 if you have the <paths.h> header file. */
+#define HAVE_PATHS_H 1
+
+/* Do we have Postgres support? */
+/* #undef HAVE_PGSQL */
+
+/* Include Support for pwcheck daemon? */
+/* #undef HAVE_PWCHECK */
+
+/* Include support for saslauthd? */
+#define HAVE_SASLAUTHD /**/
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#define HAVE_SECURITY_PAM_APPL_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Does the system have snprintf()? */
+#define HAVE_SNPRINTF /**/
+
+/* Does sockaddr have an sa_len? */
+/* #undef HAVE_SOCKADDR_SA_LEN */
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Do we have a socklen_t? */
+#define HAVE_SOCKLEN_T /**/
+
+/* Do we have SQLite support? */
+/* #undef HAVE_SQLITE */
+
+/* Do we have SQLite3 support? */
+/* #undef HAVE_SQLITE3 */
+
+/* Is there an ss_family in sockaddr_storage? */
+#define HAVE_SS_FAMILY /**/
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strspn' function. */
+#define HAVE_STRSPN 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Do we have struct sockaddr_stroage? */
+#define HAVE_STRUCT_SOCKADDR_STORAGE /**/
+
+/* Define to 1 if you have the <sysexits.h> header file. */
+#define HAVE_SYSEXITS_H 1
+
+/* Define to 1 if you have the `syslog' function. */
+#define HAVE_SYSLOG 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <varargs.h> header file. */
+/* #undef HAVE_VARARGS_H */
+
+/* Does the system have vsnprintf()? */
+#define HAVE_VSNPRINTF /**/
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__ 1
+
+/* Should we keep handle to Berkeley DB open in SASLDB plugin? */
+/* #undef KEEP_DB_OPEN */
+
+/* Ignore IP Address in Kerberos 4 tickets? */
+/* #undef KRB4_IGNORE_IP_ADDRESS */
+
+/* Name of package */
+#define PACKAGE "cyrus-sasl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Where do we look for Courier authdaemond's socket? */
+#define PATH_AUTHDAEMON_SOCKET "/dev/null"
+
+/* Where do we look for saslauthd's socket? */
+#define PATH_SASLAUTHD_RUNDIR "/var/state/saslauthd"
+
+/* Runtime plugin location */
+#define PLUGINDIR "/usr/lib/sasl2"
+
+/* Force a preferred mechanism */
+/* #undef PREFER_MECH */
+
+/* Location of pwcheck socket */
+/* #undef PWCHECKDIR */
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Use BerkeleyDB for SASLdb */
+/* #undef SASL_BERKELEYDB */
+
+/* Path to default SASLdb database */
+#define SASL_DB_PATH "/etc/sasldb2"
+
+/* File to use for source of randomness */
+#define SASL_DEV_RANDOM "/dev/random"
+
+/* Use GDBM for SASLdb */
+/* #undef SASL_GDBM */
+
+/* Use NDBM for SASLdb */
+#define SASL_NDBM /**/
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* Link ANONYMOUS Staticly */
+#define STATIC_ANONYMOUS /**/
+
+/* Link CRAM-MD5 Staticly */
+#define STATIC_CRAMMD5 /**/
+
+/* Link DIGEST-MD5 Staticly */
+#define STATIC_DIGESTMD5 /**/
+
+/* Link GSSAPI Staticly */
+/* #undef STATIC_GSSAPIV2 */
+
+/* User KERBEROS_V4 Staticly */
+/* #undef STATIC_KERBEROS4 */
+
+/* Link ldapdb plugin Staticly */
+/* #undef STATIC_LDAPDB */
+
+/* Link LOGIN Staticly */
+#define STATIC_LOGIN
+
+/* Link NTLM Staticly */
+/* #undef STATIC_NTLM */
+
+/* Link OTP Staticly */
+#define STATIC_OTP /**/
+
+/* Link PASSDSS Staticly */
+/* #undef STATIC_PASSDSS */
+
+/* Link PLAIN Staticly */
+#define STATIC_PLAIN /**/
+
+/* Link SASLdb Staticly */
+/* #undef STATIC_SASLDB */
+
+/* Link SCRAM Staticly */
+#define STATIC_SCRAM /**/
+
+/* Link SQL plugin staticly */
+/* #undef STATIC_SQL */
+
+/* Link SRP Staticly */
+/* #undef STATIC_SRP */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Should we try to dlopen() plugins while staticly compiled? */
+/* #undef TRY_DLOPEN_WHEN_STATIC */
+
+/* use the doors IPC API for saslauthd? */
+/* #undef USE_DOORS */
+
+/* Version number of package */
+#define VERSION "2.1.25"
+
+/* Use DES */
+#define WITH_DES /**/
+
+/* Linking against dmalloc? */
+/* #undef WITH_DMALLOC */
+
+/* Use internal RC4 implementation? */
+#define WITH_RC4 /**/
+
+/* Use OpenSSL DES Implementation */
+#define WITH_SSL_DES /**/
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef mode_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+
+
+
+/* Create a struct iovec if we need one */
+#if !defined(_WIN32) && !defined(HAVE_SYS_UIO_H)
+/* (win32 is handled in sasl.h) */
+struct iovec {
+    char *iov_base;
+    long iov_len;
+};
+#else
+#include <sys/types.h>
+#include <sys/uio.h>
+#endif
+
+/* location of the random number generator */
+#ifdef DEV_RANDOM
+/* #undef DEV_RANDOM */
+#endif
+#define DEV_RANDOM SASL_DEV_RANDOM
+
+/* if we've got krb_get_err_txt, we might as well use it;
+   especially since krb_err_txt isn't in some newer distributions
+   (MIT Kerb for Mac 4 being a notable example). If we don't have
+   it, we fall back to the krb_err_txt array */
+#ifdef HAVE_KRB_GET_ERR_TEXT
+#define get_krb_err_txt krb_get_err_text
+#else
+#define get_krb_err_txt(X) (krb_err_txt[(X)])
+#endif
+
+/* Make Solaris happy... */
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+
+/* Make Linux happy... */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef HAVE___ATTRIBUTE__
+/* Can't use attributes... */
+#define __attribute__(foo)
+#endif
+
+#define SASL_PATH_ENV_VAR "SASL_PATH"
+#define SASL_CONF_PATH_ENV_VAR "SASL_CONF_PATH"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifndef WIN32
+# include <netdb.h>
+# ifdef HAVE_SYS_PARAM_H
+#  include <sys/param.h>
+# endif
+#else /* WIN32 */
+# include <winsock2.h>
+#endif /* WIN32 */
+#include <string.h>
+
+#include <netinet/in.h>
+
+#ifndef HAVE_SOCKLEN_T
+typedef unsigned int socklen_t;
+#endif /* HAVE_SOCKLEN_T */
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+#define	_SS_MAXSIZE	128	/* Implementation specific max size */
+#define	_SS_PADSIZE	(_SS_MAXSIZE - sizeof (struct sockaddr))
+
+struct sockaddr_storage {
+	struct	sockaddr ss_sa;
+	char		__ss_pad2[_SS_PADSIZE];
+};
+# define ss_family ss_sa.sa_family
+#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
+
+#ifndef AF_INET6
+/* Define it to something that should never appear */
+#define	AF_INET6	AF_MAX
+#endif
+
+#ifndef HAVE_GETADDRINFO
+#define	getaddrinfo	sasl_getaddrinfo
+#define	freeaddrinfo	sasl_freeaddrinfo
+#define	gai_strerror	sasl_gai_strerror
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+#define	getnameinfo	sasl_getnameinfo
+#endif
+
+#if !defined(HAVE_GETNAMEINFO) || !defined(HAVE_GETADDRINFO)
+#include "gai.h"
+#endif
+
+#ifndef AI_NUMERICHOST   /* support glibc 2.0.x */
+#define AI_NUMERICHOST  4
+#define NI_NUMERICHOST  2
+#define NI_NAMEREQD     4
+#define NI_NUMERICSERV  8
+#endif
+
+/* Defined in RFC 1035. max strlen is only 253 due to length bytes. */
+#ifndef MAXHOSTNAMELEN
+#define        MAXHOSTNAMELEN  255
+#endif
+
+// #ifndef HAVE_SYSEXITS_H
+// #include "exits.h"
+// #else
+// #include "sysexits.h"
+// #endif
+
+/* Get the correct time.h */
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#ifndef HIER_DELIMITER
+#define HIER_DELIMITER '/'
+#endif
+
+#endif /* CONFIG_H */
+

+ 118 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/exits.h

@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)sysexits.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef	_SYSEXITS_H_
+#define	_SYSEXITS_H_
+
+/*
+ *  SYSEXITS.H -- Exit status codes for system programs.
+ *
+ *	This include file attempts to categorize possible error
+ *	exit statuses for system programs, notably delivermail
+ *	and the Berkeley network.
+ *
+ *	Error numbers begin at EX__BASE to reduce the possibility of
+ *	clashing with other exit statuses that random programs may
+ *	already return.  The meaning of the codes is approximately
+ *	as follows:
+ *
+ *	EX_USAGE -- The command was used incorrectly, e.g., with
+ *		the wrong number of arguments, a bad flag, a bad
+ *		syntax in a parameter, or whatever.
+ *	EX_DATAERR -- The input data was incorrect in some way.
+ *		This should only be used for user's data & not
+ *		system files.
+ *	EX_NOINPUT -- An input file (not a system file) did not
+ *		exist or was not readable.  This could also include
+ *		errors like "No message" to a mailer (if it cared
+ *		to catch it).
+ *	EX_NOUSER -- The user specified did not exist.  This might
+ *		be used for mail addresses or remote logins.
+ *	EX_NOHOST -- The host specified did not exist.  This is used
+ *		in mail addresses or network requests.
+ *	EX_UNAVAILABLE -- A service is unavailable.  This can occur
+ *		if a support program or file does not exist.  This
+ *		can also be used as a catchall message when something
+ *		you wanted to do doesn't work, but you don't know
+ *		why.
+ *	EX_SOFTWARE -- An internal software error has been detected.
+ *		This should be limited to non-operating system related
+ *		errors as possible.
+ *	EX_OSERR -- An operating system error has been detected.
+ *		This is intended to be used for such things as "cannot
+ *		fork", "cannot create pipe", or the like.  It includes
+ *		things like getuid returning a user that does not
+ *		exist in the passwd file.
+ *	EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+ *		etc.) does not exist, cannot be opened, or has some
+ *		sort of error (e.g., syntax error).
+ *	EX_CANTCREAT -- A (user specified) output file cannot be
+ *		created.
+ *	EX_IOERR -- An error occurred while doing I/O on some file.
+ *	EX_TEMPFAIL -- temporary failure, indicating something that
+ *		is not really an error.  In sendmail, this means
+ *		that a mailer (e.g.) could not create a connection,
+ *		and the request should be reattempted later.
+ *	EX_PROTOCOL -- the remote system returned something that
+ *		was "not possible" during a protocol exchange.
+ *	EX_NOPERM -- You did not have sufficient permission to
+ *		perform the operation.  This is not intended for
+ *		file system problems, which should use NOINPUT or
+ *		CANTCREAT, but rather for higher level permissions.
+ */
+
+#define EX_OK		0	/* successful termination */
+
+#define EX__BASE	64	/* base value for error messages */
+
+#define EX_USAGE	64	/* command line usage error */
+#define EX_DATAERR	65	/* data format error */
+#define EX_NOINPUT	66	/* cannot open input */
+#define EX_NOUSER	67	/* addressee unknown */
+#define EX_NOHOST	68	/* host name unknown */
+#define EX_UNAVAILABLE	69	/* service unavailable */
+#define EX_SOFTWARE	70	/* internal software error */
+#define EX_OSERR	71	/* system error (e.g., can't fork) */
+#define EX_OSFILE	72	/* critical OS file missing */
+#define EX_CANTCREAT	73	/* can't create (user) output file */
+#define EX_IOERR	74	/* input/output error */
+#define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
+#define EX_PROTOCOL	76	/* remote error in protocol */
+#define EX_NOPERM	77	/* permission denied */
+#define EX_CONFIG	78	/* configuration error */
+
+#define EX__MAX	78	/* maximum listed value */
+
+#endif /* !_SYSEXITS_H_ */

+ 108 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/gai.h

@@ -0,0 +1,108 @@
+/*
+ * Mar  8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
+ * $Id: gai.h,v 1.8 2006/04/10 13:36:20 mel Exp $
+ *
+ * This module is besed on ssh-1.2.27-IPv6-1.5 written by
+ * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * fake library for ssh
+ *
+ * This file is included in getaddrinfo.c and getnameinfo.c.
+ * See getaddrinfo.c and getnameinfo.c.
+ */
+
+#ifndef _GAI_H_
+#define _GAI_H_
+
+#ifndef NI_MAXHOST
+#define	NI_MAXHOST	1025
+#endif
+#ifndef NI_MAXSERV
+#define	NI_MAXSERV	32
+#endif
+
+/* for old netdb.h */
+#ifndef EAI_NODATA
+#define EAI_NODATA	1
+#define EAI_MEMORY	2
+#define EAI_FAMILY	5	/* ai_family not supported */
+#define EAI_SERVICE	9	/* servname not supported for ai_socktype */
+#endif
+
+/* dummy value for old netdb.h */
+#ifndef AI_PASSIVE
+#define AI_PASSIVE	1
+#define AI_CANONNAME	2
+struct addrinfo {
+	int	ai_flags;	/* AI_PASSIVE, AI_CANONNAME */
+	int	ai_family;	/* PF_xxx */
+	int	ai_socktype;	/* SOCK_xxx */
+	int	ai_protocol;	/* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+	size_t	ai_addrlen;	/* length of ai_addr */
+	char	*ai_canonname;	/* canonical name for hostname */
+	struct sockaddr *ai_addr;	/* binary address */
+	struct addrinfo *ai_next;	/* next structure in linked list */
+};
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+int	getnameinfo(const struct sockaddr *, socklen_t, char *,
+		    size_t, char *, size_t, int);
+#endif
+
+#ifndef HAVE_GETADDRINFO
+int	getaddrinfo(const char *, const char *,
+		    const struct addrinfo *, struct addrinfo **);
+void	freeaddrinfo(struct addrinfo *);
+char	*gai_strerror(int);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 59 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/hmac-md5.h

@@ -0,0 +1,59 @@
+/* hmac-md5.h -- HMAC_MD5 functions
+ */
+
+#ifndef HMAC_MD5_H
+#define HMAC_MD5_H 1
+
+#define HMAC_MD5_SIZE 16
+
+/* intermediate MD5 context */
+typedef struct HMAC_MD5_CTX_s {
+    MD5_CTX ictx, octx;
+} HMAC_MD5_CTX;
+
+/* intermediate HMAC state
+ *  values stored in network byte order (Big Endian)
+ */
+typedef struct HMAC_MD5_STATE_s {
+    UINT4 istate[4];
+    UINT4 ostate[4];
+} HMAC_MD5_STATE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* One step hmac computation
+ *
+ * digest may be same as text or key
+ */
+void _sasl_hmac_md5(const unsigned char *text, int text_len,
+		    const unsigned char *key, int key_len,
+		    unsigned char digest[HMAC_MD5_SIZE]);
+
+/* create context from key
+ */
+void _sasl_hmac_md5_init(HMAC_MD5_CTX *hmac,
+			 const unsigned char *key, int key_len);
+
+/* precalculate intermediate state from key
+ */
+void _sasl_hmac_md5_precalc(HMAC_MD5_STATE *hmac,
+			    const unsigned char *key, int key_len);
+
+/* initialize context from intermediate state
+ */
+void _sasl_hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state);
+
+#define _sasl_hmac_md5_update(hmac, text, text_len) _sasl_MD5Update(&(hmac)->ictx, (text), (text_len))
+
+/* finish hmac from intermediate result.  Intermediate result is zeroed.
+ */
+void _sasl_hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
+			  HMAC_MD5_CTX *hmac);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HMAC_MD5_H */

+ 246 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/makemd5.c

@@ -0,0 +1,246 @@
+/* creates the md5global.h file. 
+ *  Derived from KTH kerberos library bits.c program
+ * Tim Martin 
+ * $Id: makemd5.c,v 1.4 2003/02/13 19:55:52 rjs3 Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden). 
+ * All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the distribution. 
+ *
+ * 3. All advertising materials mentioning features or use of this software 
+ *    must display the following acknowledgement: 
+ *      This product includes software developed by Kungliga Tekniska 
+ *      Högskolan and its contributors. 
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE. 
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+
+static void
+my_strupr(char *s)
+{
+    char *p = s;
+    while(*p){
+	if(islower((int) *p))
+	    *p = toupper((int) *p);
+	p++;
+    }	
+}
+
+
+#define BITSIZE(TYPE)						\
+{								\
+    int b = 0; TYPE x = 1, zero = 0; char *pre = "U";		\
+    char tmp[128], tmp2[128];					\
+    while(x){ x <<= 1; b++; if(x < zero) pre=""; }		\
+    if(b >= len){						\
+        int tabs;						\
+	sprintf(tmp, "%sINT%d" , pre, len/8);			\
+	sprintf(tmp2, "typedef %s %s;", #TYPE, tmp);		\
+	my_strupr(tmp);						\
+	tabs = 5 - strlen(tmp2) / 8;				\
+        fprintf(f, "%s", tmp2);					\
+	while(tabs-- > 0) fprintf(f, "\t");			\
+	fprintf(f, "/* %2d bits */\n", b);			\
+        return;                                                 \
+    }								\
+}
+
+static void
+try_signed(FILE *f, int len)
+{
+    BITSIZE(signed char);
+    BITSIZE(short);
+    BITSIZE(int);
+    BITSIZE(long);
+#ifdef HAVE_LONG_LONG
+    BITSIZE(long long);
+#endif
+    fprintf(f, "/* There is no %d bit type */\n", len);
+}
+
+static void
+try_unsigned(FILE *f, int len)
+{
+    BITSIZE(unsigned char);
+    BITSIZE(unsigned short);
+    BITSIZE(unsigned int);
+    BITSIZE(unsigned long);
+#ifdef HAVE_LONG_LONG
+    BITSIZE(unsigned long long);
+#endif
+    fprintf(f, "/* There is no %d bit type */\n", len);
+}
+
+static int print_pre(FILE *f)
+{
+  fprintf(f,
+	  "/* GLOBAL.H - RSAREF types and constants\n"
+	  " */\n"
+          "#ifndef MD5GLOBAL_H\n"
+          "#define MD5GLOBAL_H\n"
+	  "\n"
+	  "/* PROTOTYPES should be set to one if and only if the compiler supports\n"
+	  "  function argument prototyping.\n"
+	  "The following makes PROTOTYPES default to 0 if it has not already\n"
+	  "  been defined with C compiler flags.\n"
+	  " */\n"
+	  "#ifndef PROTOTYPES\n"
+	  "#define PROTOTYPES 0\n"
+	  "#endif\n"
+	  "\n"
+	  "/* POINTER defines a generic pointer type */\n"
+	  "typedef unsigned char *POINTER;\n"
+	  "\n"
+	  );
+  return 1;
+}
+
+static int print_post(FILE *f)
+{
+  fprintf(f, "\n"
+	  "/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.\n"
+	  "If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it\n"
+	  "returns an empty list.\n"
+	  "*/\n"
+	  "#if PROTOTYPES\n"
+	  "#define PROTO_LIST(list) list\n"
+	  "#else\n"
+	  "#define PROTO_LIST(list) ()\n"
+	  "#endif\n"
+	  "\n"
+	  "#endif /* MD5GLOBAL_H */\n\n"
+	  );
+
+  return 1;
+}
+
+
+int main(int argc, char **argv)
+{
+  FILE *f;
+  char *fn, *hb;
+    
+  if(argc < 2){
+    fn = "bits.h";
+    hb = "__BITS_H__";
+    f = stdout;
+  } else {
+    char *p;
+    fn = argv[1];
+    hb = malloc(strlen(fn) + 5);
+    sprintf(hb, "__%s__", fn);
+    for(p = hb; *p; p++){
+      if(!isalnum((int) *p))
+	*p = '_';
+    }
+    f = fopen(argv[1], "w");
+  }
+
+  print_pre(f);
+
+#ifndef HAVE_INT8_T
+    try_signed (f, 8);
+#endif /* HAVE_INT8_T */
+#ifndef HAVE_INT16_T
+    try_signed (f, 16);
+#endif /* HAVE_INT16_T */
+#ifndef HAVE_INT32_T
+    try_signed (f, 32);
+#endif /* HAVE_INT32_T */
+#ifndef HAVE_INT64_T
+    try_signed (f, 64);
+#endif /* HAVE_INT64_T */
+
+#ifndef HAVE_U_INT8_T
+    try_unsigned (f, 8);
+#endif /* HAVE_INT8_T */
+#ifndef HAVE_U_INT16_T
+    try_unsigned (f, 16);
+#endif /* HAVE_U_INT16_T */
+#ifndef HAVE_U_INT32_T
+    try_unsigned (f, 32);
+#endif /* HAVE_U_INT32_T */
+#ifndef HAVE_U_INT64_T
+    try_unsigned (f, 64);
+#endif /* HAVE_U_INT64_T */
+
+    print_post(f);
+  
+    fclose(f);
+
+    return 0;  
+}

+ 42 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/md5.h

@@ -0,0 +1,42 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _sasl_MD5Init (MD5_CTX *);
+void _sasl_MD5Update (MD5_CTX *, const unsigned char *, unsigned int);
+void _sasl_MD5Final (unsigned char [16], MD5_CTX *);
+
+#ifdef __cplusplus
+}
+#endif

+ 38 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/md5global.h

@@ -0,0 +1,38 @@
+/* GLOBAL.H - RSAREF types and constants
+ */
+#ifndef MD5GLOBAL_H
+#define MD5GLOBAL_H
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+  function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+  been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+typedef signed char INT1;		/*  8 bits */
+typedef short INT2;			/* 16 bits */
+typedef int INT4;			/* 32 bits */
+/* There is no 64 bit type */
+typedef unsigned char UINT1;		/*  8 bits */
+typedef unsigned short UINT2;		/* 16 bits */
+typedef unsigned int UINT4;		/* 32 bits */
+/* There is no 64 bit type */
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+returns an empty list.
+*/
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif /* MD5GLOBAL_H */
+

+ 186 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/prop.h

@@ -0,0 +1,186 @@
+/* prop.h -- property request/response management routines
+ *
+ * Author: Chris Newman
+ * Removal of implementation-specific details by: Rob Siemborski
+ *
+ * This is intended to be used to create a list of properties to request,
+ * and _then_ request values for all properties.  Any change to the request
+ * list will discard any existing values.  This assumption allows a very
+ * efficient and simple memory model.  This was designed for SASL API auxiliary
+ * property support, but would be fine for other contexts where this property
+ * model is appropriate.
+ *
+ * The "struct propctx" is allocated by prop_new and is a fixed size structure.
+ * If a prop_init() call were added, it would be reasonable to embed a "struct
+ * propctx" in another structure.  prop_new also allocates a pool of memory
+ * (in the vbase field) which will be used for an array of "struct propval"
+ * to list all the requested properties.
+ *
+ * Properties may be multi-valued.
+ */
+
+#ifndef PROP_H
+#define PROP_H 1
+
+/* The following ifdef block is the standard way of creating macros
+ * which make exporting from a DLL simpler. All files within this DLL
+ * are compiled with the LIBSASL_EXPORTS symbol defined on the command
+ * line. this symbol should not be defined on any project that uses
+ * this DLL. This way any other project whose source files include
+ * this file see LIBSASL_API functions as being imported from a DLL,
+ * wheras this DLL sees symbols defined with this macro as being
+ * exported.  */
+/* Under Unix, life is simpler: we just need to mark library functions
+ * as extern.  (Technically, we don't even have to do that.) */
+#ifdef WIN32
+# ifdef LIBSASL_EXPORTS
+#  define LIBSASL_API  extern __declspec(dllexport)
+# else /* LIBSASL_EXPORTS */
+#  define LIBSASL_API  extern __declspec(dllimport)
+# endif /* LIBSASL_EXPORTS */
+#else /* WIN32 */
+# define LIBSASL_API extern
+#endif /* WIN32 */
+
+/* Same as above, but used during a variable declaration. */
+#ifdef WIN32
+# ifdef LIBSASL_EXPORTS
+#  define LIBSASL_VAR  extern __declspec(dllexport)
+# else /* LIBSASL_EXPORTS */
+#  define LIBSASL_VAR  extern __declspec(dllimport)
+# endif /* LIBSASL_EXPORTS */
+#else /* WIN32 */
+# define LIBSASL_VAR extern
+#endif /* WIN32 */
+
+/* the resulting structure for property values
+ */
+struct propval {
+    const char *name;	 /* name of property; NULL = end of list */
+                         /* same pointer used in request will be used here */
+    const char **values; /* list of strings, values == NULL if property not
+			  * found, *values == NULL if property found with
+			  * no values */
+    unsigned nvalues;    /* total number of value strings */
+    unsigned valsize;	 /* total size in characters of all value strings */
+};
+
+/*
+ * private internal structure
+ */
+#define PROP_DEFAULT 4		/* default number of propvals to assume */
+struct propctx;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* create a property context
+ *  estimate -- an estimate of the storage needed for requests & responses
+ *              0 will use module default
+ * returns a new property context on success and NULL on any error
+ */
+LIBSASL_API struct propctx *prop_new(unsigned estimate);
+
+/* create new propctx which duplicates the contents of an existing propctx
+ * returns SASL_OK on success
+ * possible other return values include: SASL_NOMEM, SASL_BADPARAM
+ */
+LIBSASL_API int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx);
+
+/* Add property names to request
+ *  ctx       -- context from prop_new()
+ *  names     -- list of property names; must persist until context freed
+ *               or requests cleared (This extends to other contexts that
+ *               are dup'ed from this one, and their children, etc)
+ *
+ * NOTE: may clear values from context as side-effect
+ * returns SASL_OK on success
+ * possible other return values include: SASL_NOMEM, SASL_BADPARAM
+ */
+LIBSASL_API int prop_request(struct propctx *ctx, const char **names);
+
+/* return array of struct propval from the context
+ *  return value persists until next call to
+ *   prop_request, prop_clear or prop_dispose on context
+ *
+ *  returns NULL on error
+ */
+LIBSASL_API const struct propval *prop_get(struct propctx *ctx);
+
+/* Fill in an array of struct propval based on a list of property names
+ *  return value persists until next call to
+ *   prop_request, prop_clear or prop_dispose on context
+ *  returns number of matching properties which were found (values != NULL)
+ *  if a name requested here was never requested by a prop_request, then
+ *  the name field of the associated vals entry will be set to NULL
+ *
+ * The vals array MUST be atleast as long as the names array.
+ *
+ * returns # of matching properties on success
+ * possible other return values include: SASL_BADPARAM
+ */
+LIBSASL_API int prop_getnames(struct propctx *ctx, const char **names,
+		  struct propval *vals);
+
+/* clear values and optionally requests from property context
+ *  ctx      -- property context
+ *  requests -- 0 = don't clear requests, 1 = clear requests
+ */
+LIBSASL_API void prop_clear(struct propctx *ctx, int requests);
+
+/* erase the value of a property
+ */
+LIBSASL_API void prop_erase(struct propctx *ctx, const char *name);
+
+/* dispose of property context
+ *  ctx      -- is disposed and set to NULL; noop if ctx or *ctx is NULL
+ */
+LIBSASL_API void prop_dispose(struct propctx **ctx);
+
+
+/****fetcher interfaces****/
+
+/* format the requested property names into a string
+ *  ctx    -- context from prop_new()/prop_request()
+ *  sep    -- separator between property names (unused if none requested)
+ *  seplen -- length of separator, if < 0 then strlen(sep) will be used
+ *  outbuf -- output buffer
+ *  outmax -- maximum length of output buffer including NUL terminator
+ *  outlen -- set to length of output string excluding NUL terminator
+ * returns SASL_OK on success
+ * returns SASL_BADPARAM or amount of additional space needed on failure
+ */
+LIBSASL_API int prop_format(struct propctx *ctx, const char *sep, int seplen,
+		char *outbuf, unsigned outmax, unsigned *outlen);
+
+/* add a property value to the context
+ *  ctx    -- context from prop_new()/prop_request()
+ *  name   -- name of property to which value will be added
+ *            if NULL, add to the same name as previous prop_set/setvals call
+ *  value  -- a value for the property; will be copied into context
+ *            if NULL, remove existing values
+ *  vallen -- length of value, if <= 0 then strlen(value) will be used
+ * returns SASL_OK on success
+ * possible error return values include: SASL_BADPARAM, SASL_NOMEM
+ */
+LIBSASL_API int prop_set(struct propctx *ctx, const char *name,
+	     const char *value, int vallen);
+
+/* set the values for a property
+ *  ctx    -- context from prop_new()/prop_request()
+ *  name   -- name of property to which value will be added
+ *            if NULL, add to the same name as previous prop_set/setvals call
+ *  values -- array of values, ending in NULL.  Each value is a NUL terminated
+ *            string
+ * returns SASL_OK on success
+ * possible error return values include: SASL_BADPARAM, SASL_NOMEM
+ */
+LIBSASL_API int prop_setvals(struct propctx *ctx, const char *name,
+		 const char **values);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PROP_H */

+ 1321 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/sasl.h

@@ -0,0 +1,1321 @@
+/* This is a proposed C API for support of SASL
+ *
+ *********************************IMPORTANT*******************************
+ * send email to chris.newman@innosoft.com and cyrus-bugs@andrew.cmu.edu *
+ * if you need to add new error codes, callback types, property values,  *
+ * etc.   It is important to keep the multiple implementations of this   *
+ * API from diverging.                                                   *
+ *********************************IMPORTANT*******************************
+ *
+ * Basic Type Summary:
+ *  sasl_conn_t       Context for a SASL connection negotiation
+ *  sasl_ssf_t        Security layer Strength Factor
+ *  sasl_callback_t   A typed client/server callback function and context
+ *  sasl_interact_t   A client interaction descriptor
+ *  sasl_secret_t     A client password
+ *  sasl_rand_t       Random data context structure
+ *  sasl_security_properties_t  An application's required security level
+ *
+ * Callbacks:
+ *  sasl_getopt_t     client/server: Get an option value
+ *  sasl_logmsg_t     client/server: Log message handler
+ *  sasl_getsimple_t  client: Get user/language list
+ *  sasl_getsecret_t  client: Get authentication secret
+ *  sasl_chalprompt_t client: Display challenge and prompt for response
+ *
+ * Server only Callbacks:
+ *  sasl_authorize_t             user authorization policy callback
+ *  sasl_getconfpath_t           get path to search for config file
+ *  sasl_server_userdb_checkpass check password and auxprops in userdb
+ *  sasl_server_userdb_setpass   set password in userdb
+ *  sasl_server_canon_user       canonicalize username routine
+ *
+ * Client/Server Function Summary:
+ *  sasl_done         Release all SASL global state
+ *  sasl_dispose      Connection done: Dispose of sasl_conn_t
+ *  sasl_getprop      Get property (e.g., user name, security layer info)
+ *  sasl_setprop      Set property (e.g., external ssf)
+ *  sasl_errdetail    Generate string from last error on connection
+ *  sasl_errstring    Translate sasl error code to a string
+ *  sasl_encode       Encode data to send using security layer
+ *  sasl_decode       Decode data received using security layer
+ *  
+ * Utility functions:
+ *  sasl_encode64     Encode data to send using MIME base64 encoding
+ *  sasl_decode64     Decode data received using MIME base64 encoding
+ *  sasl_erasebuffer  Erase a buffer
+ *
+ * Client Function Summary:
+ *  sasl_client_init  Load and initialize client plug-ins (call once)
+ *  sasl_client_new   Initialize client connection context: sasl_conn_t
+ *  sasl_client_start Select mechanism for connection
+ *  sasl_client_step  Perform one authentication step
+ *
+ * Server Function Summary
+ *  sasl_server_init  Load and initialize server plug-ins (call once)
+ *  sasl_server_new   Initialize server connection context: sasl_conn_t
+ *  sasl_listmech     Create list of available mechanisms
+ *  sasl_server_start Begin an authentication exchange
+ *  sasl_server_step  Perform one authentication exchange step
+ *  sasl_checkpass    Check a plaintext passphrase
+ *  sasl_checkapop    Check an APOP challenge/response (uses pseudo "APOP"
+ *                    mechanism similar to CRAM-MD5 mechanism; optional)
+ *  sasl_user_exists  Check if user exists
+ *  sasl_setpass      Change a password or add a user entry
+ *  sasl_auxprop_request  Request auxiliary properties
+ *  sasl_auxprop_getctx   Get auxiliary property context for connection
+ *  sasl_auxprop_store    Store a set of auxiliary properties
+ *
+ * Basic client model:
+ *  1. client calls sasl_client_init() at startup to load plug-ins
+ *  2. when connection formed, call sasl_client_new()
+ *  3. once list of supported mechanisms received from server, client
+ *     calls sasl_client_start().  goto 4a
+ *  4. client calls sasl_client_step()
+ * [4a. If SASL_INTERACT, fill in prompts and goto 4
+ *      -- doesn't happen if callbacks provided]
+ *  4b. If SASL error, goto 7 or 3
+ *  4c. If SASL_OK, continue or goto 6 if last server response was success
+ *  5. send message to server, wait for response
+ *  5a. On data or success with server response, goto 4
+ *  5b. On failure goto 7 or 3
+ *  5c. On success with no server response continue
+ *  6. continue with application protocol until connection closes
+ *     call sasl_getprop/sasl_encode/sasl_decode() if using security layer
+ *  7. call sasl_dispose(), may return to step 2
+ *  8. call sasl_done() when program terminates
+ *
+ * Basic Server model:
+ *  1. call sasl_server_init() at startup to load plug-ins
+ *  2. On connection, call sasl_server_new()
+ *  3. call sasl_listmech() and send list to client]
+ *  4. after client AUTH command, call sasl_server_start(), goto 5a
+ *  5. call sasl_server_step()
+ *  5a. If SASL_CONTINUE, output to client, wait response, repeat 5
+ *  5b. If SASL error, then goto 7
+ *  5c. If SASL_OK, move on
+ *  6. continue with application protocol until connection closes
+ *     call sasl_getprop to get username
+ *     call sasl_getprop/sasl_encode/sasl_decode() if using security layer
+ *  7. call sasl_dispose(), may return to step 2
+ *  8. call sasl_done() when program terminates
+ *
+ *************************************************
+ * IMPORTANT NOTE: server realms / username syntax
+ *
+ * If a user name contains a "@", then the rightmost "@" in the user name
+ * separates the account name from the realm in which this account is
+ * located.  A single server may support multiple realms.  If the
+ * server knows the realm at connection creation time (e.g., a server
+ * with multiple IP addresses tightly binds one address to a specific
+ * realm) then that realm must be passed in the user_realm field of
+ * the sasl_server_new call.  If user_realm is non-empty and an
+ * unqualified user name is supplied, then the canon_user facility is
+ * expected to append "@" and user_realm to the user name.  The canon_user
+ * facility may treat other characters such as "%" as equivalent to "@".
+ *
+ * If the server forbids the use of "@" in user names for other
+ * purposes, this simplifies security validation.
+ */
+
+#ifndef SASL_H
+#define SASL_H 1
+
+/* Keep in sync with win32/common.mak */
+#define SASL_VERSION_MAJOR 2
+#define SASL_VERSION_MINOR 1
+#define SASL_VERSION_STEP 26
+
+/* A convenience macro: same as was defined in the OpenLDAP LDAPDB */
+#define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\
+      (SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
+
+#include "prop.h"
+
+/*************
+ * Basic API *
+ *************/
+
+/* SASL result codes: */
+#define SASL_CONTINUE    1   /* another step is needed in authentication */
+#define SASL_OK          0   /* successful result */
+#define SASL_FAIL       -1   /* generic failure */
+#define SASL_NOMEM      -2   /* memory shortage failure */
+#define SASL_BUFOVER    -3   /* overflowed buffer */
+#define SASL_NOMECH     -4   /* mechanism not supported */
+#define SASL_BADPROT    -5   /* bad protocol / cancel */
+#define SASL_NOTDONE    -6   /* can't request info until later in exchange */
+#define SASL_BADPARAM   -7   /* invalid parameter supplied */
+#define SASL_TRYAGAIN   -8   /* transient failure (e.g., weak key) */
+#define SASL_BADMAC	-9   /* integrity check failed */
+#define SASL_NOTINIT    -12  /* SASL library not initialized */
+                             /* -- client only codes -- */
+#define SASL_INTERACT    2   /* needs user interaction */
+#define SASL_BADSERV    -10  /* server failed mutual authentication step */
+#define SASL_WRONGMECH  -11  /* mechanism doesn't support requested feature */
+                             /* -- server only codes -- */
+#define SASL_BADAUTH    -13  /* authentication failure */
+#define SASL_NOAUTHZ    -14  /* authorization failure */
+#define SASL_TOOWEAK    -15  /* mechanism too weak for this user */
+#define SASL_ENCRYPT    -16  /* encryption needed to use mechanism */
+#define SASL_TRANS      -17  /* One time use of a plaintext password will
+				enable requested mechanism for user */
+#define SASL_EXPIRED    -18  /* passphrase expired, has to be reset */
+#define SASL_DISABLED   -19  /* account disabled */
+#define SASL_NOUSER     -20  /* user not found */
+#define SASL_BADVERS    -23  /* version mismatch with plug-in */
+#define SASL_UNAVAIL    -24  /* remote authentication server unavailable */
+#define SASL_NOVERIFY   -26  /* user exists, but no verifier for user */
+			     /* -- codes for password setting -- */
+#define SASL_PWLOCK     -21  /* passphrase locked */
+#define SASL_NOCHANGE   -22  /* requested change was not needed */
+#define SASL_WEAKPASS   -27  /* passphrase is too weak for security policy */
+#define SASL_NOUSERPASS -28  /* user supplied passwords not permitted */
+#define SASL_NEED_OLD_PASSWD -29 /* sasl_setpass needs old password in order
+				    to perform password change */
+#define SASL_CONSTRAINT_VIOLAT	-30 /* a property can't be stored,
+				       because of some constrains/policy violation */
+
+#define SASL_BADBINDING -32  /* channel binding failure */
+
+/* max size of a sasl mechanism name */
+#define SASL_MECHNAMEMAX 20
+
+#ifdef _WIN32
+/* Define to have the same layout as a WSABUF */
+#ifndef STRUCT_IOVEC_DEFINED
+#define STRUCT_IOVEC_DEFINED 1
+struct iovec {
+    long iov_len;
+    char *iov_base;
+};
+#endif
+#else
+struct iovec;				     /* Defined in OS headers */
+#endif
+
+
+/* per-connection SASL negotiation state for client or server
+ */
+typedef struct sasl_conn sasl_conn_t;
+
+/* Plain text password structure.
+ *  len is the length of the password, data is the text.
+ */
+typedef struct sasl_secret {
+    unsigned long len;
+    unsigned char data[1];		/* variable sized */
+} sasl_secret_t;
+
+/* random data context structure
+ */
+typedef struct sasl_rand_s sasl_rand_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************
+ * Configure Basic Services *
+ ****************************/
+
+/* the following functions are used to adjust how allocation and mutexes work
+ * they must be called before all other SASL functions:
+ */
+
+/* memory allocation functions which may optionally be replaced:
+ */
+typedef void *sasl_malloc_t(size_t);
+typedef void *sasl_calloc_t(size_t, size_t);
+typedef void *sasl_realloc_t(void *, size_t);
+typedef void sasl_free_t(void *);
+
+LIBSASL_API void sasl_set_alloc(sasl_malloc_t *,
+				sasl_calloc_t *,
+				sasl_realloc_t *,
+				sasl_free_t *);
+
+/* mutex functions which may optionally be replaced:
+ *  sasl_mutex_alloc allocates a mutex structure
+ *  sasl_mutex_lock blocks until mutex locked
+ *   returns -1 on deadlock or parameter error
+ *   returns 0 on success
+ *  sasl_mutex_unlock unlocks mutex if it's locked
+ *   returns -1 if not locked or parameter error
+ *   returns 0 on success
+ *  sasl_mutex_free frees a mutex structure
+ */
+typedef void *sasl_mutex_alloc_t(void);
+typedef int sasl_mutex_lock_t(void *mutex);
+typedef int sasl_mutex_unlock_t(void *mutex);
+typedef void sasl_mutex_free_t(void *mutex);
+LIBSASL_API void sasl_set_mutex(sasl_mutex_alloc_t *, sasl_mutex_lock_t *,
+				sasl_mutex_unlock_t *, sasl_mutex_free_t *);
+
+/*****************************
+ * Security preference types *
+ *****************************/
+
+/* security layer strength factor -- an unsigned integer usable by the caller
+ *  to specify approximate security layer strength desired.  Roughly
+ *  correlated to effective key length for encryption.
+ * 0   = no protection
+ * 1   = integrity protection only
+ * 40  = 40-bit DES or 40-bit RC2/RC4
+ * 56  = DES
+ * 112 = triple-DES
+ * 128 = 128-bit RC2/RC4/BLOWFISH
+ * 256 = baseline AES
+ */
+typedef unsigned sasl_ssf_t;
+
+/* usage flags provided to sasl_server_new and sasl_client_new:
+ */
+#define SASL_SUCCESS_DATA    0x0004 /* server supports data on success */
+#define SASL_NEED_PROXY      0x0008 /* require a mech that allows proxying */
+#define SASL_NEED_HTTP       0x0010 /* require a mech that can do HTTP auth */
+
+/***************************
+ * Security Property Types *
+ ***************************/
+
+/* Structure specifying the client or server's security policy
+ * and optional additional properties.
+ */
+
+/* These are the various security flags apps can specify. */
+/* NOPLAINTEXT          -- don't permit mechanisms susceptible to simple
+ *                         passive attack (e.g., PLAIN, LOGIN)
+ * NOACTIVE             -- protection from active (non-dictionary) attacks
+ *                         during authentication exchange.
+ *                         Authenticates server.
+ * NODICTIONARY         -- don't permit mechanisms susceptible to passive
+ *                         dictionary attack
+ * FORWARD_SECRECY      -- require forward secrecy between sessions
+ *                         (breaking one won't help break next)
+ * NOANONYMOUS          -- don't permit mechanisms that allow anonymous login
+ * PASS_CREDENTIALS     -- require mechanisms which pass client
+ *			   credentials, and allow mechanisms which can pass
+ *			   credentials to do so
+ * MUTUAL_AUTH          -- require mechanisms which provide mutual
+ *			   authentication
+ */
+#define SASL_SEC_NOPLAINTEXT      0x0001
+#define SASL_SEC_NOACTIVE         0x0002
+#define SASL_SEC_NODICTIONARY     0x0004
+#define SASL_SEC_FORWARD_SECRECY  0x0008
+#define SASL_SEC_NOANONYMOUS      0x0010
+#define SASL_SEC_PASS_CREDENTIALS 0x0020
+#define SASL_SEC_MUTUAL_AUTH      0x0040
+#define SASL_SEC_MAXIMUM          0x00FF
+
+typedef struct sasl_security_properties 
+{ 
+    /* security strength factor
+     *  min_ssf      = minimum acceptable final level
+     *  max_ssf      = maximum acceptable final level
+     */ 
+    sasl_ssf_t min_ssf;
+    sasl_ssf_t max_ssf;
+
+    /* Maximum security layer receive buffer size.
+     *  0=security layer not supported
+     */
+    unsigned maxbufsize; 
+    
+    /* bitfield for attacks to protect against */
+    unsigned security_flags;
+
+    /* NULL terminated array of additional property names, values */ 
+    const char **property_names;
+    const char **property_values;
+} sasl_security_properties_t; 
+
+/******************
+ * Callback types *
+ ******************/
+
+/*
+ * Extensible type for a client/server callbacks
+ *  id      -- identifies callback type
+ *  proc    -- procedure call arguments vary based on id
+ *  context -- context passed to procedure
+ */
+/* Note that any memory that is allocated by the callback needs to be
+ * freed by the application, be it via function call or interaction.
+ *
+ * It may be freed after sasl_*_step returns SASL_OK.  if the mechanism
+ * requires this information to persist (for a security layer, for example)
+ * it must maintain a private copy.
+ */
+typedef struct sasl_callback {
+    /* Identifies the type of the callback function.
+     * Mechanisms must ignore callbacks with id's they don't recognize.
+     */
+    unsigned long id;
+    int (*proc)(void);   /* Callback function.  Types of arguments vary by 'id' */
+    void *context;
+} sasl_callback_t;
+
+/* callback ids & functions:
+ */
+#define SASL_CB_LIST_END   0  /* end of list */
+
+/* option reading callback -- this allows a SASL configuration to be
+ *  encapsulated in the caller's configuration system.  Some implementations
+ *  may use default config file(s) if this is omitted.  Configuration items
+ *  may be plugin-specific and are arbitrary strings.
+ *
+ * inputs:
+ *  context     -- option context from callback record
+ *  plugin_name -- name of plugin (NULL = general SASL option)
+ *  option      -- name of option
+ * output:
+ *  result      -- set to result which persists until next getopt in
+ *                 same thread, unchanged if option not found
+ *  len         -- length of result (may be NULL)
+ * returns:
+ *  SASL_OK     -- no error
+ *  SASL_FAIL   -- error
+ */
+typedef int sasl_getopt_t(void *context, const char *plugin_name,
+			  const char *option,
+			  const char **result, unsigned *len);
+#define SASL_CB_GETOPT       1
+
+/* Logging levels for use with the logging callback function. */
+#define SASL_LOG_NONE  0	/* don't log anything */
+#define SASL_LOG_ERR   1	/* log unusual errors (default) */
+#define SASL_LOG_FAIL  2	/* log all authentication failures */
+#define SASL_LOG_WARN  3	/* log non-fatal warnings */
+#define SASL_LOG_NOTE  4	/* more verbose than LOG_WARN */
+#define SASL_LOG_DEBUG 5	/* more verbose than LOG_NOTE */
+#define SASL_LOG_TRACE 6	/* traces of internal protocols */
+#define SASL_LOG_PASS  7	/* traces of internal protocols, including
+				 * passwords */
+
+/* logging callback -- this allows plugins and the middleware to
+ *  log operations they perform.
+ * inputs:
+ *  context     -- logging context from the callback record
+ *  level       -- logging level; see above
+ *  message     -- message to log
+ * returns:
+ *  SASL_OK     -- no error
+ *  SASL_FAIL   -- error
+ */
+typedef int sasl_log_t(void *context,
+		       int level,
+		       const char *message);
+#define SASL_CB_LOG	    2
+
+/* getpath callback -- this allows applications to specify the
+ * colon-separated path to search for plugins (by default,
+ * taken from an implementation-specific location).
+ * inputs:
+ *  context     -- getpath context from the callback record
+ * outputs:
+ *  path	-- colon seperated path
+ * returns:
+ *  SASL_OK     -- no error
+ *  SASL_FAIL   -- error
+ */
+typedef int sasl_getpath_t(void *context,
+			   const char **path);
+
+#define SASL_CB_GETPATH	    3
+
+/* verify file callback -- this allows applications to check if they
+ * want SASL to use files, file by file.  This is intended to allow
+ * applications to sanity check the environment to make sure plugins
+ * or the configuration file can't be written to, etc.
+ * inputs: 
+ *  context     -- verifypath context from the callback record
+ *  file        -- full path to file to verify
+ *  type        -- type of file to verify (see below)
+
+ * returns:
+ *  SASL_OK        -- no error (file can safely be used)
+ *  SASL_CONTINUE  -- continue WITHOUT using this file
+ *  SASL_FAIL      -- error 
+ */
+
+/* these are the types of files libsasl will ask about */
+typedef enum {
+    SASL_VRFY_PLUGIN=0,		/* a DLL/shared library plug-in */
+    SASL_VRFY_CONF=1,		/* a configuration file */
+    SASL_VRFY_PASSWD=2,		/* a password storage file/db */
+    SASL_VRFY_OTHER=3		/* some other file */
+} sasl_verify_type_t;
+
+typedef int sasl_verifyfile_t(void *context,
+                              const char *file, sasl_verify_type_t type);
+#define SASL_CB_VERIFYFILE  4
+
+/* getconfpath callback -- this allows applications to specify the
+ * colon-separated path to search for config files (by default,
+ * taken from the SASL_CONF_PATH environment variable).
+ * inputs:
+ *  context     -- getconfpath context from the callback record
+ * outputs:
+ *  path        -- colon seperated path (allocated on the heap; the
+ *                 library will free it using the sasl_free_t *
+ *                 passed to sasl_set_callback, or the standard free()
+ *                 library call).
+ * returns:
+ *  SASL_OK     -- no error
+ *  SASL_FAIL   -- error
+ */
+typedef int sasl_getconfpath_t(void *context,
+                               char **path);
+
+#define SASL_CB_GETCONFPATH  5
+
+/* client/user interaction callbacks:
+ */
+/* Simple prompt -- result must persist until next call to getsimple on
+ *  same connection or until connection context is disposed
+ * inputs:
+ *  context       -- context from callback structure
+ *  id            -- callback id
+ * outputs:
+ *  result        -- set to NUL terminated string
+ *                   NULL = user cancel
+ *  len           -- length of result
+ * returns SASL_OK
+ */
+typedef int sasl_getsimple_t(void *context, int id,
+			     const char **result, unsigned *len);
+#define SASL_CB_USER         0x4001  /* client user identity to login as */
+#define SASL_CB_AUTHNAME     0x4002  /* client authentication name */
+#define SASL_CB_LANGUAGE     0x4003  /* comma separated list of RFC 1766
+			              * language codes in order of preference
+				      * to be used to localize client prompts
+				      * or server error codes */
+#define SASL_CB_CNONCE       0x4007  /* caller supplies client-nonce
+				      * primarily for testing purposes */
+
+/* get a sasl_secret_t (plaintext password with length)
+ * inputs:
+ *  conn          -- connection context
+ *  context       -- context from callback structure
+ *  id            -- callback id
+ * outputs:
+ *  psecret       -- set to NULL to cancel
+ *                   set to password structure which must persist until
+ *                   next call to getsecret in same connection, but middleware
+ *                   will erase password data when it's done with it.
+ * returns SASL_OK
+ */
+typedef int sasl_getsecret_t(sasl_conn_t *conn, void *context, int id,
+			     sasl_secret_t **psecret);
+#define SASL_CB_PASS         0x4004  /* client passphrase-based secret */
+
+
+/* prompt for input in response to a challenge.
+ * input:
+ *  context   -- context from callback structure
+ *  id        -- callback id
+ *  challenge -- server challenge
+ * output:
+ *  result    -- NUL terminated result, NULL = user cancel
+ *  len       -- length of result
+ * returns SASL_OK
+ */
+typedef int sasl_chalprompt_t(void *context, int id,
+			      const char *challenge,
+			      const char *prompt, const char *defresult,
+			      const char **result, unsigned *len);
+#define SASL_CB_ECHOPROMPT   0x4005 /* challenge and client enterred result */
+#define SASL_CB_NOECHOPROMPT 0x4006 /* challenge and client enterred result */
+
+/* prompt (or autoselect) the realm to do authentication in.
+ *  may get a list of valid realms.
+ * input:
+ *  context     -- context from callback structure
+ *  id          -- callback id
+ *  availrealms -- available realms; string list; NULL terminated
+ *                 list may be empty.
+ * output:
+ *  result      -- NUL terminated realm; NULL is equivalent to ""
+ * returns SASL_OK
+ * result must persist until the next callback
+ */
+typedef int sasl_getrealm_t(void *context, int id,
+			    const char **availrealms,
+			    const char **result);
+#define SASL_CB_GETREALM (0x4008) /* realm to attempt authentication in */
+
+/* server callbacks:
+ */
+
+/* improved callback to verify authorization;
+ *     canonicalization now handled elsewhere
+ *  conn           -- connection context
+ *  requested_user -- the identity/username to authorize (NUL terminated)
+ *  rlen           -- length of requested_user
+ *  auth_identity  -- the identity associated with the secret (NUL terminated)
+ *  alen           -- length of auth_identity
+ *  default_realm  -- default user realm, as passed to sasl_server_new if
+ *  urlen          -- length of default realm
+ *  propctx        -- auxiliary properties
+ * returns SASL_OK on success,
+ *         SASL_NOAUTHZ or other SASL response on failure
+ */
+typedef int sasl_authorize_t(sasl_conn_t *conn,
+			     void *context,
+			     const char *requested_user, unsigned rlen,
+			     const char *auth_identity, unsigned alen,
+			     const char *def_realm, unsigned urlen,
+			     struct propctx *propctx);
+#define SASL_CB_PROXY_POLICY 0x8001
+
+/* functions for "userdb" based plugins to call to get/set passwords.
+ * the location for the passwords is determined by the caller or middleware.
+ * plug-ins may get passwords from other locations.
+ */
+
+/* callback to verify a plaintext password against the caller-supplied
+ * user database.  This is necessary to allow additional <method>s for
+ * encoding of the userPassword property.
+ *  user          -- NUL terminated user name with user@realm syntax
+ *  pass          -- password to check (may not be NUL terminated)
+ *  passlen       -- length of password to check
+ *  propctx       -- auxiliary properties for user
+ */
+typedef int sasl_server_userdb_checkpass_t(sasl_conn_t *conn,
+					   void *context,
+					   const char *user,
+					   const char *pass,
+					   unsigned passlen,
+					   struct propctx *propctx);
+#define SASL_CB_SERVER_USERDB_CHECKPASS (0x8005)
+
+/* callback to store/change a plaintext password in the user database
+ *  user          -- NUL terminated user name with user@realm syntax
+ *  pass          -- password to store (may not be NUL terminated)
+ *  passlen       -- length of password to store
+ *  propctx       -- auxiliary properties (not stored)
+ *  flags         -- see SASL_SET_* flags below (SASL_SET_CREATE optional)
+ */
+typedef int sasl_server_userdb_setpass_t(sasl_conn_t *conn,
+					 void *context,
+					 const char *user,
+					 const char *pass,
+					 unsigned passlen,
+					 struct propctx *propctx,
+					 unsigned flags);
+#define SASL_CB_SERVER_USERDB_SETPASS (0x8006)
+
+/* callback for a server-supplied user canonicalization function.
+ *
+ * This function is called directly after the mechanism has the
+ * authentication and authorization IDs.  It is called before any
+ * User Canonicalization plugin is called.  It has the responsibility
+ * of copying its output into the provided output buffers.
+ * 
+ *  in, inlen     -- user name to canonicalize, may not be NUL terminated
+ *                   may be same buffer as out
+ *  flags         -- not currently used, supplied by auth mechanism
+ *  user_realm    -- the user realm (may be NULL in case of client)
+ *  out           -- buffer to copy user name
+ *  out_max       -- max length of user name
+ *  out_len       -- set to length of user name
+ *
+ * returns
+ *  SASL_OK         on success
+ *  SASL_BADPROT    username contains invalid character
+ */
+
+/* User Canonicalization Function Flags */
+
+#define SASL_CU_NONE    0x00 /* Not a valid flag to pass */
+/* One of the following two is required */
+#define SASL_CU_AUTHID  0x01
+#define SASL_CU_AUTHZID 0x02
+
+/* Combine the following with SASL_CU_AUTHID, if you don't want
+   to fail if auxprop returned SASL_NOUSER/SASL_NOMECH.
+   This flag has no effect on SASL_CU_AUTHZID. */
+#define SASL_CU_EXTERNALLY_VERIFIED 0x04
+
+#define SASL_CU_OVERRIDE	    0x08    /* mapped to SASL_AUXPROP_OVERRIDE */
+
+/* The following CU flags are passed "as is" down to auxprop lookup */
+#define SASL_CU_ASIS_MASK	    0xFFF0
+/* NOTE: Keep in sync with SASL_AUXPROP_<XXX> flags */
+#define SASL_CU_VERIFY_AGAINST_HASH 0x10
+
+
+typedef int sasl_canon_user_t(sasl_conn_t *conn,
+			      void *context,
+			      const char *in, unsigned inlen,
+			      unsigned flags,
+			      const char *user_realm,
+			      char *out,
+			      unsigned out_max, unsigned *out_len);
+
+#define SASL_CB_CANON_USER (0x8007)
+
+/**********************************
+ * Common Client/server functions *
+ **********************************/
+
+/* Types of paths to set (see sasl_set_path below). */
+#define SASL_PATH_TYPE_PLUGIN	0
+#define SASL_PATH_TYPE_CONFIG	1
+
+/* a simpler way to set plugin path or configuration file path
+ * without the need to set sasl_getpath_t callback.
+ *
+ * This function can be called before sasl_server_init/sasl_client_init.
+ */  
+LIBSASL_API int sasl_set_path (int path_type, char * path);
+
+/* get sasl library version information
+ * implementation is a vendor-defined string
+ * version is a vender-defined representation of the version #.
+ *
+ * This function is being deprecated in favor of sasl_version_info. */
+LIBSASL_API void sasl_version(const char **implementation,
+			      int *version);
+
+/* Extended version of sasl_version().
+ *
+ * This function is to be used
+ *  for library version display and logging
+ *  for bug workarounds in old library versions
+ *
+ * The sasl_version_info is not to be used for API feature detection.
+ *
+ * All parameters are optional. If NULL is specified, the value is not returned.
+ */
+LIBSASL_API void sasl_version_info (const char **implementation,
+				const char **version_string,
+				int *version_major,
+				int *version_minor,
+				int *version_step,
+				int *version_patch);
+
+/* dispose of all SASL plugins.  Connection
+ * states have to be disposed of before calling this.
+ *
+ * This function is DEPRECATED in favour of sasl_server_done/
+ * sasl_client_done.
+ */
+LIBSASL_API void sasl_done(void);
+
+/* dispose of all SASL plugins.  Connection
+ * states have to be disposed of before calling this.
+ * This function should be called instead of sasl_done(),
+   whenever possible.
+ */
+LIBSASL_API int sasl_server_done(void);
+
+/* dispose of all SASL plugins.  Connection
+ * states have to be disposed of before calling this.
+ * This function should be called instead of sasl_done(),
+   whenever possible.
+ */
+LIBSASL_API int sasl_client_done(void);
+
+/* dispose connection state, sets it to NULL
+ *  checks for pointer to NULL
+ */
+LIBSASL_API void sasl_dispose(sasl_conn_t **pconn);
+
+/* translate an error number into a string
+ * input:
+ *  saslerr  -- the error number
+ *  langlist -- comma separated list of RFC 1766 languages (may be NULL)
+ * results:
+ *  outlang  -- the language actually used (may be NULL if don't care)
+ * returns:
+ *  the error message in UTF-8 (only the US-ASCII subset if langlist is NULL)
+ */
+LIBSASL_API const char *sasl_errstring(int saslerr,
+				       const char *langlist,
+				       const char **outlang);
+
+/* get detail about the last error that occurred on a connection
+ * text is sanitized so it's suitable to send over the wire
+ * (e.g., no distinction between SASL_BADAUTH and SASL_NOUSER)
+ * input:
+ *  conn          -- mandatory connection context
+ * returns:
+ *  the error message in UTF-8 (only the US-ASCII subset permitted if no
+ *  SASL_CB_LANGUAGE callback is present)
+ */
+LIBSASL_API const char *sasl_errdetail(sasl_conn_t *conn);
+
+/* set the error string which will be returned by sasl_errdetail() using
+ *  syslog()-style formatting (e.g. printf-style with %m as most recent
+ *  errno error)
+ *
+ *  primarily for use by server callbacks such as the sasl_authorize_t
+ *  callback and internally to plug-ins
+ *
+ * This will also trigger a call to the SASL logging callback (if any)
+ * with a level of SASL_LOG_FAIL unless the SASL_NOLOG flag is set.
+ *
+ * Messages should be sensitive to the current language setting.  If there
+ * is no SASL_CB_LANGUAGE callback messages MUST be US-ASCII otherwise UTF-8
+ * is used and use of RFC 2482 for mixed-language text is encouraged.
+ *
+ * if conn is NULL, function does nothing
+ */
+LIBSASL_API void sasl_seterror(sasl_conn_t *conn, unsigned flags,
+			       const char *fmt, ...);
+#define SASL_NOLOG       0x01
+			   
+/* get property from SASL connection state
+ *  propnum       -- property number
+ *  pvalue        -- pointer to value
+ * returns:
+ *  SASL_OK       -- no error
+ *  SASL_NOTDONE  -- property not available yet
+ *  SASL_BADPARAM -- bad property number
+ */
+LIBSASL_API int sasl_getprop(sasl_conn_t *conn, int propnum,
+			     const void **pvalue);
+#define SASL_USERNAME     0	/* pointer to NUL terminated user name */
+#define SASL_SSF          1	/* security layer security strength factor,
+                                 * if 0, call to sasl_encode, sasl_decode
+                                 * unnecessary */
+#define SASL_MAXOUTBUF    2     /* security layer max output buf unsigned */  
+#define SASL_DEFUSERREALM 3	/* default realm passed to server_new */
+				/* or set with setprop */
+#define SASL_GETOPTCTX    4	/* context for getopt callback */
+#define SASL_CALLBACK     7	/* current callback function list */
+#define SASL_IPLOCALPORT  8	/* iplocalport string passed to server_new */
+#define SASL_IPREMOTEPORT 9	/* ipremoteport string passed to server_new */
+
+/* This returns a string which is either empty or has an error message
+ * from sasl_seterror (e.g., from a plug-in or callback).  It differs
+ * from the result of sasl_errdetail() which also takes into account the
+ * last return status code.
+ */
+#define SASL_PLUGERR     10
+
+/* a handle to any delegated credentials or NULL if none is present 
+ * is returned by the mechanism. The user will probably need to know
+ * which mechanism was used to actually known how to make use of them
+ * currently only implemented for the gssapi mechanism */
+#define SASL_DELEGATEDCREDS 11
+
+#define SASL_SERVICE      12	/* service passed to sasl_*_new */
+#define SASL_SERVERFQDN   13	/* serverFQDN passed to sasl_*_new */
+#define SASL_AUTHSOURCE   14	/* name of auth source last used, useful
+				 * for failed authentication tracking */
+#define SASL_MECHNAME     15    /* active mechanism name, if any */
+#define SASL_AUTHUSER     16    /* authentication/admin user */
+#define SASL_APPNAME	  17	/* application name (used for logging/
+				   configuration), same as appname parameter
+				   to sasl_server_init */
+
+/* GSS-API credential handle for sasl_client_step() or sasl_server_step().
+ * The application is responsible for releasing this credential handle. */
+#define	SASL_GSS_CREDS	  18
+
+/* GSS name (gss_name_t) of the peer, as output by gss_inquire_context()
+ * or gss_accept_sec_context().
+ * On server end this is similar to SASL_USERNAME, but the gss_name_t
+ * structure can contain additional attributes associated with the peer.
+ */
+#define	SASL_GSS_PEER_NAME	19
+
+/* Local GSS name (gss_name_t) as output by gss_inquire_context(). This
+ * is particularly useful for servers that respond to multiple names. */
+#define	SASL_GSS_LOCAL_NAME	20
+
+/* Channel binding information. Memory is managed by the caller. */
+typedef struct sasl_channel_binding {
+    const char *name;
+    int critical;
+    unsigned long len;
+    const unsigned char *data;
+} sasl_channel_binding_t;
+
+#define SASL_CHANNEL_BINDING    21
+
+/* HTTP Request (RFC 2616) - ONLY used for HTTP Digest Auth (RFC 2617) */
+typedef struct sasl_http_request {
+    const char *method;			/* HTTP Method */
+    const char *uri;			/* request-URI */
+    const unsigned char *entity;	/* entity-body */
+    unsigned long elen;			/* entity-body length */
+    unsigned non_persist;		/* Is it a non-persistent connection? */
+} sasl_http_request_t;
+
+#define SASL_HTTP_REQUEST	22
+
+/* set property in SASL connection state
+ * returns:
+ *  SASL_OK       -- value set
+ *  SASL_BADPARAM -- invalid property or value
+ */
+LIBSASL_API int sasl_setprop(sasl_conn_t *conn,
+			     int propnum,
+			     const void *value);
+#define SASL_SSF_EXTERNAL  100	/* external SSF active (sasl_ssf_t *) */
+#define SASL_SEC_PROPS     101	/* sasl_security_properties_t */
+#define SASL_AUTH_EXTERNAL 102	/* external authentication ID (const char *) */
+
+/* If the SASL_AUTH_EXTERNAL value is non-NULL, then a special version of the
+ * EXTERNAL mechanism is enabled (one for server-embedded EXTERNAL mechanisms).
+ * Otherwise, the EXTERNAL mechanism will be absent unless a plug-in
+ * including EXTERNAL is present.
+ */
+
+/* do precalculations during an idle period or network round trip
+ *  may pass NULL to precompute for some mechanisms prior to connect
+ *  returns 1 if action taken, 0 if no action taken
+ */
+LIBSASL_API int sasl_idle(sasl_conn_t *conn);
+
+/**************
+ * Client API *
+ **************/
+
+/* list of client interactions with user for caller to fill in
+ */
+typedef struct sasl_interact {
+    unsigned long id;		/* same as client/user callback ID */
+    const char *challenge;	/* presented to user (e.g. OTP challenge) */
+    const char *prompt;		/* presented to user (e.g. "Username: ") */
+    const char *defresult;	/* default result string */
+    const void *result;		/* set to point to result */
+    unsigned len;		/* set to length of result */
+} sasl_interact_t;
+
+/* initialize the SASL client drivers
+ *  callbacks      -- base callbacks for all client connections;
+ *                    must include getopt callback
+ * returns:
+ *  SASL_OK        -- Success
+ *  SASL_NOMEM     -- Not enough memory
+ *  SASL_BADVERS   -- Mechanism version mismatch
+ *  SASL_BADPARAM  -- missing getopt callback or error in config file
+ *  SASL_NOMECH    -- No mechanisms available
+ *  ...
+ */
+LIBSASL_API int sasl_client_init(const sasl_callback_t *callbacks);
+
+/* initialize a client exchange based on the specified mechanism
+ *  service       -- registered name of the service using SASL (e.g. "imap")
+ *  serverFQDN    -- the fully qualified domain name of the server
+ *  iplocalport   -- client IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  ipremoteport  -- server IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  prompt_supp   -- list of client interactions supported
+ *                   may also include sasl_getopt_t context & call
+ *                   NULL prompt_supp = user/pass via SASL_INTERACT only
+ *                   NULL proc = interaction supported via SASL_INTERACT
+ *  flags         -- server usage flags (see above)
+ * in/out:
+ *  pconn         -- connection negotiation structure
+ *                   pointer to NULL => allocate new
+ *
+ * Returns:
+ *  SASL_OK       -- success
+ *  SASL_NOMECH   -- no mechanism meets requested properties
+ *  SASL_NOMEM    -- not enough memory
+ */
+LIBSASL_API int sasl_client_new(const char *service,
+				const char *serverFQDN,
+				const char *iplocalport,
+				const char *ipremoteport,
+				const sasl_callback_t *prompt_supp,
+				unsigned flags,
+				sasl_conn_t **pconn);
+
+/* select a mechanism for a connection
+ *  mechlist      -- mechanisms server has available (punctuation ignored)
+ *                   if NULL, then discard cached info and retry last mech
+ * output:
+ *  prompt_need   -- on SASL_INTERACT, list of prompts needed to continue
+ *                   may be NULL if callbacks provided
+ *  clientout     -- the initial client response to send to the server
+ *                   will be valid until next call to client_start/client_step
+ *                   NULL if mech doesn't include initial client challenge
+ *  mech          -- set to mechansm name of selected mechanism (may be NULL)
+ *
+ * Returns:
+ *  SASL_OK       -- success
+ *  SASL_NOMEM    -- not enough memory
+ *  SASL_NOMECH   -- no mechanism meets requested properties
+ *  SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ */
+LIBSASL_API int sasl_client_start(sasl_conn_t *conn,
+				  const char *mechlist,
+				  sasl_interact_t **prompt_need,
+				  const char **clientout,
+				  unsigned *clientoutlen,
+				  const char **mech);
+
+/* do a single authentication step.
+ *  serverin    -- the server message received by the client, MUST have a NUL
+ *                 sentinel, not counted by serverinlen
+ * output:
+ *  prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ *  clientout   -- the client response to send to the server
+ *                 will be valid until next call to client_start/client_step
+ *
+ * returns:
+ *  SASL_OK        -- success
+ *  SASL_INTERACT  -- user interaction needed to fill in prompt_need list
+ *  SASL_BADPROT   -- server protocol incorrect/cancelled
+ *  SASL_BADSERV   -- server failed mutual auth
+ */
+LIBSASL_API int sasl_client_step(sasl_conn_t *conn,
+				 const char *serverin,
+				 unsigned serverinlen,
+				 sasl_interact_t **prompt_need,
+				 const char **clientout,
+				 unsigned *clientoutlen);
+
+/**************
+ * Server API *
+ **************/
+
+/* initialize server drivers, done once per process
+ *  callbacks      -- callbacks for all server connections; must include
+ *                    getopt callback
+ *  appname        -- name of calling application (for lower level logging)
+ * results:
+ *  state          -- server state
+ * returns:
+ *  SASL_OK        -- success
+ *  SASL_BADPARAM  -- error in config file
+ *  SASL_NOMEM     -- memory failure
+ *  SASL_BADVERS   -- Mechanism version mismatch
+ */
+LIBSASL_API int sasl_server_init(const sasl_callback_t *callbacks,
+				 const char *appname);
+
+/* IP/port syntax:
+ *  a.b.c.d;p              where a-d are 0-255 and p is 0-65535 port number.
+ *  e:f:g:h:i:j:k:l;p      where e-l are 0000-ffff lower-case hexidecimal
+ *  e:f:g:h:i:j:a.b.c.d;p  alternate syntax for previous
+ *
+ *  Note that one or more "0" fields in f-k can be replaced with "::"
+ *  Thus:                 e:f:0000:0000:0000:j:k:l;p
+ *  can be abbreviated:   e:f::j:k:l;p
+ *
+ * A buffer of size 52 is adequate for the longest format with NUL terminator.
+ */
+
+/* create context for a single SASL connection
+ *  service        -- registered name of the service using SASL (e.g. "imap")
+ *  serverFQDN     -- Fully qualified domain name of server.  NULL means use
+ *                    gethostname() or equivalent.
+ *                    Useful for multi-homed servers.
+ *  user_realm     -- permits multiple user realms on server, NULL = default
+ *  iplocalport    -- server IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  ipremoteport   -- client IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  callbacks      -- callbacks (e.g., authorization, lang, new getopt context)
+ *  flags          -- usage flags (see above)
+ * returns:
+ *  pconn          -- new connection context
+ *
+ * returns:
+ *  SASL_OK        -- success
+ *  SASL_NOMEM     -- not enough memory
+ */
+LIBSASL_API int sasl_server_new(const char *service,
+				const char *serverFQDN,
+				const char *user_realm,
+				const char *iplocalport,
+				const char *ipremoteport,
+				const sasl_callback_t *callbacks,
+				unsigned flags,
+				sasl_conn_t **pconn);
+
+/* Return an array of NUL-terminated strings, terminated by a NULL pointer,
+ * which lists all possible mechanisms that the library can supply
+ *
+ * Returns NULL on failure. */
+LIBSASL_API const char ** sasl_global_listmech(void);
+
+/* This returns a list of mechanisms in a NUL-terminated string
+ *  conn          -- the connection to list mechanisms for (either client
+ *                   or server)
+ *  user          -- restricts mechanisms to those available to that user
+ *                   (may be NULL, not used for client case)
+ *  prefix        -- appended to beginning of result
+ *  sep           -- appended between mechanisms
+ *  suffix        -- appended to end of result
+ * results:
+ *  result        -- NUL terminated result which persists until next
+ *                   call to sasl_listmech for this sasl_conn_t
+ *  plen          -- gets length of result (excluding NUL), may be NULL
+ *  pcount        -- gets number of mechanisms, may be NULL
+ *
+ * returns:
+ *  SASL_OK        -- success
+ *  SASL_NOMEM     -- not enough memory
+ *  SASL_NOMECH    -- no enabled mechanisms
+ */
+LIBSASL_API int sasl_listmech(sasl_conn_t *conn,
+			      const char *user,
+			      const char *prefix,
+			      const char *sep,
+			      const char *suffix,
+			      const char **result,
+			      unsigned *plen,
+			      int *pcount);
+
+/* start a mechanism exchange within a connection context
+ *  mech           -- the mechanism name client requested
+ *  clientin       -- client initial response (NUL terminated), NULL if empty
+ *  clientinlen    -- length of initial response
+ *  serverout      -- initial server challenge, NULL if done 
+ *                    (library handles freeing this string)
+ *  serveroutlen   -- length of initial server challenge
+ * output:
+ *  pconn          -- the connection negotiation state on success
+ *
+ * Same returns as sasl_server_step() or
+ * SASL_NOMECH if mechanism not available.
+ */
+LIBSASL_API int sasl_server_start(sasl_conn_t *conn,
+				  const char *mech,
+				  const char *clientin,
+				  unsigned clientinlen,
+				  const char **serverout,
+				  unsigned *serveroutlen);
+
+/* perform one step of the SASL exchange
+ *  inputlen & input -- client data
+ *                      NULL on first step if no optional client step
+ *  outputlen & output -- set to the server data to transmit
+ *                        to the client in the next step
+ *                        (library handles freeing this)
+ *
+ * returns:
+ *  SASL_OK        -- exchange is complete.
+ *  SASL_CONTINUE  -- indicates another step is necessary.
+ *  SASL_TRANS     -- entry for user exists, but not for mechanism
+ *                    and transition is possible
+ *  SASL_BADPARAM  -- service name needed
+ *  SASL_BADPROT   -- invalid input from client
+ *  ...
+ */
+LIBSASL_API int sasl_server_step(sasl_conn_t *conn,
+				 const char *clientin,
+				 unsigned clientinlen,
+				 const char **serverout,
+				 unsigned *serveroutlen);
+
+/* check if an apop exchange is valid
+ *  (note this is an optional part of the SASL API)
+ *  if challenge is NULL, just check if APOP is enabled
+ * inputs:
+ *  challenge     -- challenge which was sent to client
+ *  challen       -- length of challenge, 0 = strlen(challenge)
+ *  response      -- client response, "<user> <digest>" (RFC 1939)
+ *  resplen       -- length of response, 0 = strlen(response)
+ * returns 
+ *  SASL_OK       -- success
+ *  SASL_BADAUTH  -- authentication failed
+ *  SASL_BADPARAM -- missing challenge
+ *  SASL_BADPROT  -- protocol error (e.g., response in wrong format)
+ *  SASL_NOVERIFY -- user found, but no verifier
+ *  SASL_NOMECH   -- mechanism not supported
+ *  SASL_NOUSER   -- user not found
+ */
+LIBSASL_API int sasl_checkapop(sasl_conn_t *conn,
+			       const char *challenge, unsigned challen,
+			       const char *response, unsigned resplen);
+
+/* check if a plaintext password is valid
+ *   if user is NULL, check if plaintext passwords are enabled
+ * inputs:
+ *  user          -- user to query in current user_domain
+ *  userlen       -- length of username, 0 = strlen(user)
+ *  pass          -- plaintext password to check
+ *  passlen       -- length of password, 0 = strlen(pass)
+ * returns 
+ *  SASL_OK       -- success
+ *  SASL_NOMECH   -- mechanism not supported
+ *  SASL_NOVERIFY -- user found, but no verifier
+ *  SASL_NOUSER   -- user not found
+ */
+LIBSASL_API int sasl_checkpass(sasl_conn_t *conn,
+			       const char *user, unsigned userlen,
+			       const char *pass, unsigned passlen);
+
+/* check if a user exists on server
+ *  conn          -- connection context
+ *  service       -- registered name of the service using SASL (e.g. "imap")
+ *  user_realm    -- permits multiple user realms on server, NULL = default
+ *  user          -- NUL terminated user name
+ *
+ * returns:
+ *  SASL_OK       -- success
+ *  SASL_DISABLED -- account disabled
+ *  SASL_NOUSER   -- user not found
+ *  SASL_NOVERIFY -- user found, but no usable mechanism
+ *  SASL_NOMECH   -- no mechanisms enabled
+ *  SASL_UNAVAIL  -- remote authentication server unavailable, try again later
+ */
+LIBSASL_API int sasl_user_exists(sasl_conn_t *conn,
+				 const char *service,
+				 const char *user_realm,
+				 const char *user);
+
+/* set the password for a user
+ *  conn        -- SASL connection
+ *  user        -- user name
+ *  pass        -- plaintext password, may be NULL to remove user
+ *  passlen     -- length of password, 0 = strlen(pass)
+ *  oldpass     -- NULL will sometimes work
+ *  oldpasslen  -- length of password, 0 = strlen(oldpass)
+ *  flags       -- see flags below
+ * 
+ * returns:
+ *  SASL_NOCHANGE  -- proper entry already exists
+ *  SASL_NOMECH    -- no authdb supports password setting as configured
+ *  SASL_NOVERIFY  -- user exists, but no settable password present
+ *  SASL_DISABLED  -- account disabled
+ *  SASL_PWLOCK    -- password locked
+ *  SASL_WEAKPASS  -- password too weak for security policy
+ *  SASL_NOUSERPASS -- user-supplied passwords not permitted
+ *  SASL_FAIL      -- OS error
+ *  SASL_BADPARAM  -- password too long
+ *  SASL_OK        -- successful
+ */
+LIBSASL_API int sasl_setpass(sasl_conn_t *conn,
+			     const char *user,
+			     const char *pass, unsigned passlen,
+			     const char *oldpass, unsigned oldpasslen,
+			     unsigned flags);
+#define SASL_SET_CREATE  0x01   /* create a new entry for user */
+#define SASL_SET_DISABLE 0x02	/* disable user account */
+#define SASL_SET_NOPLAIN 0x04	/* do not store secret in plain text */
+#define SASL_SET_CURMECH_ONLY 0x08	/* set the mechanism specific password only.
+					   fail if no current mechanism */
+
+/*********************************************************
+ * Auxiliary Property Support -- added by cjn 1999-09-29 *
+ *********************************************************/
+
+#define SASL_AUX_END      NULL	/* last auxiliary property */
+
+#define SASL_AUX_ALL "*" /* A special flag to signal user deletion */
+
+/* traditional Posix items (should be implemented on Posix systems) */
+#define SASL_AUX_PASSWORD_PROP "userPassword" /* User Password */
+#define SASL_AUX_PASSWORD "*" SASL_AUX_PASSWORD_PROP /* User Password (of authid) */
+#define SASL_AUX_UIDNUM   "uidNumber"	/* UID number for the user */
+#define SASL_AUX_GIDNUM   "gidNumber"	/* GID for the user */
+#define SASL_AUX_FULLNAME "gecos"	/* full name of the user, unix-style */
+#define SASL_AUX_HOMEDIR  "homeDirectory" /* home directory for user */
+#define SASL_AUX_SHELL    "loginShell"	/* login shell for the user */
+
+/* optional additional items (not necessarily implemented) */
+/* single preferred mail address for user canonically-quoted
+ * RFC821/822 syntax */
+#define SASL_AUX_MAILADDR "mail"
+/* path to unix-style mailbox for user */
+#define SASL_AUX_UNIXMBX  "mailMessageStore"
+/* SMTP mail channel name to use if user authenticates successfully */
+#define SASL_AUX_MAILCHAN "mailSMTPSubmitChannel"
+
+/* Request a set of auxiliary properties
+ *  conn         connection context
+ *  propnames    list of auxiliary property names to request ending with
+ *               NULL.  
+ *
+ * Subsequent calls will add items to the request list.  Call with NULL
+ * to clear the request list.
+ *
+ * errors
+ *  SASL_OK       -- success
+ *  SASL_BADPARAM -- bad count/conn parameter
+ *  SASL_NOMEM    -- out of memory
+ */
+LIBSASL_API int sasl_auxprop_request(sasl_conn_t *conn,
+				     const char **propnames);
+
+/* Returns current auxiliary property context.
+ * Use functions in prop.h to access content
+ *
+ *  if authentication hasn't completed, property values may be empty/NULL
+ *
+ *  properties not recognized by active plug-ins will be left empty/NULL
+ *
+ *  returns NULL if conn is invalid.
+ */
+LIBSASL_API struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn);
+
+/* Store the set of auxiliary properties for the given user.
+ * Use functions in prop.h to set the content.
+ *
+ *  conn         connection context
+ *  ctx          property context from prop_new()/prop_request()/prop_set()
+ *  user         NUL terminated user
+ *
+ * Call with NULL 'ctx' to see if the backend allows storing properties.
+ *
+ * errors
+ *  SASL_OK       -- success
+ *  SASL_NOMECH   -- can not store some/all properties
+ *  SASL_BADPARAM -- bad conn/ctx/user parameter
+ *  SASL_NOMEM    -- out of memory
+ *  SASL_FAIL     -- failed to store
+ */
+LIBSASL_API int sasl_auxprop_store(sasl_conn_t *conn,
+				   struct propctx *ctx, const char *user);
+
+/**********************
+ * security layer API *
+ **********************/
+
+/* encode a block of data for transmission using security layer,
+ *  returning the input buffer if there is no security layer.
+ *  output is only valid until next call to sasl_encode or sasl_encodev
+ * returns:
+ *  SASL_OK      -- success (returns input if no layer negotiated)
+ *  SASL_NOTDONE -- security layer negotiation not finished
+ *  SASL_BADPARAM -- inputlen is greater than the SASL_MAXOUTBUF
+ */
+LIBSASL_API int sasl_encode(sasl_conn_t *conn,
+			    const char *input, unsigned inputlen,
+			    const char **output, unsigned *outputlen);
+
+/* encode a block of data for transmission using security layer
+ *  output is only valid until next call to sasl_encode or sasl_encodev
+ * returns:
+ *  SASL_OK      -- success (returns input if no layer negotiated)
+ *  SASL_NOTDONE -- security layer negotiation not finished
+ *  SASL_BADPARAM -- input length is greater than the SASL_MAXOUTBUF
+ *		     or no security layer
+ */
+LIBSASL_API int sasl_encodev(sasl_conn_t *conn,
+			     const struct iovec *invec, unsigned numiov,
+			     const char **output, unsigned *outputlen);
+
+/* decode a block of data received using security layer
+ *  returning the input buffer if there is no security layer.
+ *  output is only valid until next call to sasl_decode
+ *
+ *  if outputlen is 0 on return, than the value of output is undefined.
+ *  
+ * returns:
+ *  SASL_OK      -- success (returns input if no layer negotiated)
+ *  SASL_NOTDONE -- security layer negotiation not finished
+ *  SASL_BADMAC  -- bad message integrity check
+ */
+LIBSASL_API int sasl_decode(sasl_conn_t *conn,
+			    const char *input, unsigned inputlen,
+			    const char **output, unsigned *outputlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SASL_H */

+ 986 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/saslplug.h

@@ -0,0 +1,986 @@
+/* saslplug.h --  API for SASL plug-ins
+ */
+
+#ifndef SASLPLUG_H
+#define SASLPLUG_H 1
+
+#ifndef MD5GLOBAL_H
+#include "md5global.h"
+#endif
+#ifndef MD5_H
+#include "md5.h"
+#endif
+#ifndef HMAC_MD5_H
+#include "hmac-md5.h"
+#endif
+#ifndef PROP_H
+#include "prop.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* callback to lookup a sasl_callback_t for a connection
+ * input:
+ *  conn        -- the connection to lookup a callback for
+ *  callbacknum -- the number of the callback
+ * output:
+ *  pproc       -- pointer to the callback function (set to NULL on failure)
+ *  pcontext    -- pointer to the callback context (set to NULL on failure)
+ * returns:
+ *  SASL_OK -- no error
+ *  SASL_FAIL -- unable to find a callback of the requested type
+ *  SASL_INTERACT -- caller must use interaction to get data
+ */
+typedef int (*sasl_callback_ft)(void);
+typedef int sasl_getcallback_t(sasl_conn_t *conn,
+			       unsigned long callbackid,
+			       sasl_callback_ft * pproc,
+			       void **pcontext);
+
+/* The sasl_utils structure will remain backwards compatible unless
+ * the SASL_*_PLUG_VERSION is changed incompatibly
+ * higher SASL_UTILS_VERSION numbers indicate more functions are available
+ */
+#define SASL_UTILS_VERSION 4
+
+/* utility function set for plug-ins
+ */
+typedef struct sasl_utils {
+    int version;
+
+    /* contexts */
+    sasl_conn_t *conn;
+    sasl_rand_t *rpool;
+    void *getopt_context;
+
+    /* option function */
+    sasl_getopt_t *getopt;
+    
+    /* allocation functions: */
+    sasl_malloc_t *malloc;
+    sasl_calloc_t *calloc;
+    sasl_realloc_t *realloc;
+    sasl_free_t *free;
+
+    /* mutex functions: */
+    sasl_mutex_alloc_t *mutex_alloc;
+    sasl_mutex_lock_t *mutex_lock;
+    sasl_mutex_unlock_t *mutex_unlock;
+    sasl_mutex_free_t *mutex_free;
+
+    /* MD5 hash and HMAC functions */
+    void (*MD5Init)(MD5_CTX *);
+    void (*MD5Update)(MD5_CTX *, const unsigned char *text, unsigned int len);
+    void (*MD5Final)(unsigned char [16], MD5_CTX *);
+    void (*hmac_md5)(const unsigned char *text, int text_len,
+		     const unsigned char *key, int key_len,
+		     unsigned char [16]);
+    void (*hmac_md5_init)(HMAC_MD5_CTX *, const unsigned char *key, int len);
+    /* hmac_md5_update() is just a call to MD5Update on inner context */
+    void (*hmac_md5_final)(unsigned char [16], HMAC_MD5_CTX *);
+    void (*hmac_md5_precalc)(HMAC_MD5_STATE *,
+			     const unsigned char *key, int len);
+    void (*hmac_md5_import)(HMAC_MD5_CTX *, HMAC_MD5_STATE *);
+
+    /* mechanism utility functions (same as above): */
+    int (*mkchal)(sasl_conn_t *conn, char *buf, unsigned maxlen,
+		  unsigned hostflag);
+    int (*utf8verify)(const char *str, unsigned len);
+    void (*rand)(sasl_rand_t *rpool, char *buf, unsigned len);
+    void (*churn)(sasl_rand_t *rpool, const char *data, unsigned len);
+
+    /* This allows recursive calls to the sasl_checkpass() routine from
+     * within a SASL plug-in.  This MUST NOT be used in the PLAIN mechanism
+     * as sasl_checkpass MAY be a front-end for the PLAIN mechanism.
+     * This is intended for use by the non-standard LOGIN mechanism and
+     * potentially by a future mechanism which uses public-key technology to
+     * set up a lightweight encryption layer just for sending a password.
+     */
+    int (*checkpass)(sasl_conn_t *conn,
+		     const char *user, unsigned userlen,
+		     const char *pass, unsigned passlen);
+    
+    /* Access to base64 encode/decode routines */
+    int (*decode64)(const char *in, unsigned inlen,
+		    char *out, unsigned outmax, unsigned *outlen);
+    int (*encode64)(const char *in, unsigned inlen,
+		    char *out, unsigned outmax, unsigned *outlen);
+
+    /* erase a buffer */
+    void (*erasebuffer)(char *buf, unsigned len);
+
+    /* callback to sasl_getprop() and sasl_setprop() */
+    int (*getprop)(sasl_conn_t *conn, int propnum, const void **pvalue);
+    int (*setprop)(sasl_conn_t *conn, int propnum, const void *value);
+
+    /* callback function */
+    sasl_getcallback_t *getcallback;
+
+    /* format a message and then pass it to the SASL_CB_LOG callback
+     *
+     * use syslog()-style formatting (printf with %m as a human readable text
+     * (strerror()) for the error specified as the parameter).
+     * The implementation may use a fixed size buffer not smaller
+     * than 512 octets if it securely truncates the message.
+     *
+     * level is a SASL_LOG_* level (see sasl.h)
+     */
+    void (*log)(sasl_conn_t *conn, int level, const char *fmt, ...);
+
+    /* callback to sasl_seterror() */
+    void (*seterror)(sasl_conn_t *conn, unsigned flags, const char *fmt, ...);
+
+    /* spare function pointer */
+    int *(*spare_fptr)(void);
+
+    /* auxiliary property utilities */
+    struct propctx *(*prop_new)(unsigned estimate);
+    int (*prop_dup)(struct propctx *src_ctx, struct propctx **dst_ctx);
+    int (*prop_request)(struct propctx *ctx, const char **names);
+    const struct propval *(*prop_get)(struct propctx *ctx);
+    int (*prop_getnames)(struct propctx *ctx, const char **names,
+			 struct propval *vals);
+    void (*prop_clear)(struct propctx *ctx, int requests);
+    void (*prop_dispose)(struct propctx **ctx);
+    int (*prop_format)(struct propctx *ctx, const char *sep, int seplen,
+		       char *outbuf, unsigned outmax, unsigned *outlen);
+    int (*prop_set)(struct propctx *ctx, const char *name,
+		    const char *value, int vallen);
+    int (*prop_setvals)(struct propctx *ctx, const char *name,
+			const char **values);
+    void (*prop_erase)(struct propctx *ctx, const char *name);
+    int (*auxprop_store)(sasl_conn_t *conn,
+			 struct propctx *ctx, const char *user);
+
+    /* for additions which don't require a version upgrade; set to 0 */
+    int (*spare_fptr1)(void);
+    int (*spare_fptr2)(void);
+} sasl_utils_t;
+
+/*
+ * output parameters from SASL API
+ *
+ * created / destroyed by the glue code, though probably filled in
+ * by a combination of the plugin, the glue code, and the canon_user callback.
+ *
+ */
+typedef struct sasl_out_params {
+    unsigned doneflag;		/* exchange complete */
+
+    const char *user;		/* canonicalized user name */
+    const char *authid;		/* canonicalized authentication id */
+
+    unsigned ulen;		/* length of canonicalized user name */
+    unsigned alen;		/* length of canonicalized authid */
+
+    /* security layer information */
+    unsigned maxoutbuf;         /* Maximum buffer size, which will
+                                   produce buffer no bigger than the
+                                   negotiated SASL maximum buffer size */
+    sasl_ssf_t mech_ssf;   /* Should be set non-zero if negotiation of a
+	 		    * security layer was *attempted*, even if
+			    * the negotiation failed */
+    void *encode_context;
+    int (*encode)(void *context, const struct iovec *invec, unsigned numiov,
+		  const char **output, unsigned *outputlen);
+    void *decode_context;
+    int (*decode)(void *context, const char *input, unsigned inputlen,
+		  const char **output, unsigned *outputlen);
+    
+    /* Pointer to delegated (client's) credentials, if supported by
+       the SASL mechanism */
+    void *client_creds;
+
+    /* for additions which don't require a version upgrade; set to 0 */
+    const void *gss_peer_name;
+    const void *gss_local_name;
+    const char *cbindingname;   /* channel binding name from packet */
+    int (*spare_fptr1)(void);
+    int (*spare_fptr2)(void);
+    unsigned int cbindingdisp;  /* channel binding disposition from client */
+    int spare_int2;
+    int spare_int3;
+    int spare_int4;
+
+    /* set to 0 initially, this allows a plugin with extended parameters
+     * to work with an older framework by updating version as parameters
+     * are added.
+     */
+    int param_version;
+} sasl_out_params_t;
+
+
+
+/* Used by both client and server side plugins */
+typedef enum  {
+    SASL_INFO_LIST_START = 0,
+    SASL_INFO_LIST_MECH,
+    SASL_INFO_LIST_END
+} sasl_info_callback_stage_t;
+
+/******************************
+ * Channel binding macros     **
+ ******************************/
+
+typedef enum {
+    SASL_CB_DISP_NONE = 0,          /* client did not support CB */
+    SASL_CB_DISP_WANT,              /* client supports CB, thinks server does not */
+    SASL_CB_DISP_USED               /* client supports and used CB */
+} sasl_cbinding_disp_t;
+
+/* TRUE if channel binding is non-NULL */
+#define SASL_CB_PRESENT(params)     ((params)->cbinding != NULL)
+/* TRUE if channel binding is marked critical */
+#define SASL_CB_CRITICAL(params)    (SASL_CB_PRESENT(params) && \
+				     (params)->cbinding->critical)
+
+/******************************
+ * Client Mechanism Functions *
+ ******************************/
+
+/*
+ * input parameters to client SASL plugin
+ *
+ * created / destroyed by the glue code
+ *
+ */
+typedef struct sasl_client_params {
+    const char *service;	/* service name */
+    const char *serverFQDN;	/* server fully qualified domain name */
+    const char *clientFQDN;	/* client's fully qualified domain name */
+    const sasl_utils_t *utils;	/* SASL API utility routines --
+				 * for a particular sasl_conn_t,
+				 * MUST remain valid until mech_free is
+				 * called */
+    const sasl_callback_t *prompt_supp; /* client callback list */
+    const char *iplocalport;	/* server IP domain literal & port */
+    const char *ipremoteport;	/* client IP domain literal & port */
+
+    unsigned servicelen;	/* length of service */
+    unsigned slen;		/* length of serverFQDN */
+    unsigned clen;		/* length of clientFQDN */
+    unsigned iploclen;		/* length of iplocalport */
+    unsigned ipremlen;		/* length of ipremoteport */
+
+    /* application's security requirements & info */
+    sasl_security_properties_t props;
+    sasl_ssf_t external_ssf;	/* external SSF active */
+
+    /* for additions which don't require a version upgrade; set to 0 */
+    const void *gss_creds;                  /* GSS credential handle */
+    const sasl_channel_binding_t *cbinding; /* client channel binding */
+    const sasl_http_request_t *http_request;/* HTTP Digest request method */
+    void *spare_ptr4;
+
+    /* Canonicalize a user name from on-wire to internal format
+     *  added rjs3 2001-05-23
+     *  Must be called once user name aquired if canon_user is non-NULL.
+     *  conn        connection context
+     *  in          user name from wire protocol (need not be NUL terminated)
+     *  len         length of user name from wire protocol (0 = strlen(user))
+     *  flags       for SASL_CU_* flags
+     *  oparams     the user, authid, ulen, alen, fields are
+     *              set appropriately after canonicalization/copying and
+     *              authorization of arguments
+     *
+     *  responsible for setting user, ulen, authid, and alen in the oparams
+     *  structure
+     *
+     *  default behavior is to strip leading and trailing whitespace, as
+     *  well as allocating space for and copying the parameters.
+     *
+     * results:
+     *  SASL_OK       -- success
+     *  SASL_NOMEM    -- out of memory
+     *  SASL_BADPARAM -- invalid conn
+     *  SASL_BADPROT  -- invalid user/authid
+     */
+    int (*canon_user)(sasl_conn_t *conn,
+                    const char *in, unsigned len,
+                    unsigned flags,
+                    sasl_out_params_t *oparams);
+
+    int (*spare_fptr1)(void);
+
+    unsigned int cbindingdisp;
+    int spare_int2;
+    int spare_int3;
+
+    /* flags field as passed to sasl_client_new */
+    unsigned flags;
+
+    /* set to 0 initially, this allows a plugin with extended parameters
+     * to work with an older framework by updating version as parameters
+     * are added.
+     */
+    int param_version;
+} sasl_client_params_t;
+
+/* features shared between client and server */
+/* These allow the glue code to handle client-first and server-last issues */
+
+/* This indicates that the mechanism prefers to do client-send-first
+ * if the protocol allows it. */
+#define SASL_FEAT_WANT_CLIENT_FIRST	0x0002
+
+/* This feature is deprecated.  Instead, plugins should set *serverout to
+ * non-NULL and return SASL_OK intelligently to allow flexible use of
+ * server-last semantics
+#define SASL_FEAT_WANT_SERVER_LAST	0x0004
+*/
+
+/* This feature is deprecated.  Instead, plugins should correctly set
+ * SASL_FEAT_SERVER_FIRST as needed
+#define SASL_FEAT_INTERNAL_CLIENT_FIRST	0x0008
+*/
+
+/* This indicates that the plugin is server-first only. 
+ * Not defining either of SASL_FEAT_SERVER_FIRST or 
+ * SASL_FEAT_WANT_CLIENT_FIRST indicates that the mechanism
+ * will handle the client-first situation internally.
+ */
+#define SASL_FEAT_SERVER_FIRST		0x0010
+
+/* This plugin allows proxying */
+#define SASL_FEAT_ALLOWS_PROXY		0x0020
+
+/* server plugin don't use cleartext userPassword attribute */
+#define SASL_FEAT_DONTUSE_USERPASSWD 	0x0080
+
+/* Underlying mechanism uses GSS framing */
+#define SASL_FEAT_GSS_FRAMING	 	0x0100
+
+/* Underlying mechanism supports channel binding */
+#define SASL_FEAT_CHANNEL_BINDING	0x0800
+
+/* This plugin can be used for HTTP authentication */
+#define SASL_FEAT_SUPPORTS_HTTP	    	0x1000
+
+/* client plug-in features */
+#define SASL_FEAT_NEEDSERVERFQDN	0x0001
+
+/* a C object for a client mechanism
+ */
+typedef struct sasl_client_plug {
+    /* mechanism name */
+    const char *mech_name;
+
+    /* best mech additional security layer strength factor */
+    sasl_ssf_t max_ssf;
+
+    /* best security flags, as defined in sasl_security_properties_t */
+    unsigned security_flags;
+
+    /* features of plugin */
+    unsigned features;
+
+    /* required prompt ids, NULL = user/pass only */
+    const unsigned long *required_prompts;
+    
+    /* global state for mechanism */
+    void *glob_context;
+    
+    /* create context for mechanism, using params supplied
+     *  glob_context   -- from above
+     *  params         -- params from sasl_client_new
+     *  conn_context   -- context for one connection
+     * returns:
+     *  SASL_OK        -- success
+     *  SASL_NOMEM     -- not enough memory
+     *  SASL_WRONGMECH -- mech doesn't support security params
+     */
+    int (*mech_new)(void *glob_context,
+		    sasl_client_params_t *cparams,
+		    void **conn_context);
+    
+    /* perform one step of exchange.  NULL is passed for serverin on
+     * first step.
+     * returns:
+     *  SASL_OK        -- success
+     *  SASL_INTERACT  -- user interaction needed to fill in prompts
+     *  SASL_BADPROT   -- server protocol incorrect/cancelled
+     *  SASL_BADSERV   -- server failed mutual auth
+     */
+    int (*mech_step)(void *conn_context,
+		     sasl_client_params_t *cparams,
+		     const char *serverin,
+		     unsigned serverinlen,
+		     sasl_interact_t **prompt_need,
+		     const char **clientout,
+		     unsigned *clientoutlen,
+		     sasl_out_params_t *oparams);
+    
+    /* dispose of connection context from mech_new
+     */
+    void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
+    
+    /* free all global space used by mechanism
+     *  mech_dispose must be called on all mechanisms first
+     */
+    void (*mech_free)(void *glob_context, const sasl_utils_t *utils);
+     
+    /* perform precalculations during a network round-trip
+     *  or idle period.  conn_context may be NULL
+     *  returns 1 if action taken, 0 if no action taken
+     */
+    int (*idle)(void *glob_context,
+		void *conn_context,
+		sasl_client_params_t *cparams);
+
+    /* for additions which don't require a version upgrade; set to 0 */
+    int (*spare_fptr1)(void);
+    int (*spare_fptr2)(void);
+} sasl_client_plug_t;
+
+#define SASL_CLIENT_PLUG_VERSION         4
+
+/* plug-in entry point:
+ *  utils       -- utility callback functions
+ *  max_version -- highest client plug version supported
+ * returns:
+ *  out_version -- client plug version of result
+ *  pluglist    -- list of mechanism plug-ins
+ *  plugcount   -- number of mechanism plug-ins
+ * results:
+ *  SASL_OK       -- success
+ *  SASL_NOMEM    -- failure
+ *  SASL_BADVERS  -- max_version too small
+ *  SASL_BADPARAM -- bad config string
+ *  ...
+ */
+typedef int sasl_client_plug_init_t(const sasl_utils_t *utils,
+				    int max_version,
+				    int *out_version,
+				    sasl_client_plug_t **pluglist,
+				    int *plugcount);
+
+
+/* add a client plug-in
+ */
+LIBSASL_API int sasl_client_add_plugin(const char *plugname,
+				       sasl_client_plug_init_t *cplugfunc);
+
+typedef struct client_sasl_mechanism
+{
+    int version;
+
+    char *plugname;
+    const sasl_client_plug_t *plug;
+} client_sasl_mechanism_t;
+
+typedef void sasl_client_info_callback_t (client_sasl_mechanism_t *m,
+					  sasl_info_callback_stage_t stage,
+					  void *rock);
+
+/* Dump information about available client plugins */
+LIBSASL_API int sasl_client_plugin_info (const char *mech_list,
+	sasl_client_info_callback_t *info_cb,
+	void *info_cb_rock);
+
+
+/********************
+ * Server Functions *
+ ********************/
+
+/* log message formatting routine */
+typedef void sasl_logmsg_p(sasl_conn_t *conn, const char *fmt, ...);
+
+/*
+ * input parameters to server SASL plugin
+ *
+ * created / destroyed by the glue code
+ *
+ */
+typedef struct sasl_server_params {
+    const char *service;	/* NULL = default service for user_exists
+				   and setpass */
+    const char *appname;	/* name of calling application */
+    const char *serverFQDN;	/* server default fully qualified domain name
+				 * (e.g., gethostname) */
+    const char *user_realm;	/* realm for user (NULL = client supplied) */
+    const char *iplocalport;	/* server IP domain literal & port */
+    const char *ipremoteport;	/* client IP domain literal & port */
+
+    unsigned servicelen;	/* length of service */
+    unsigned applen;		/* length of appname */
+    unsigned slen;		/* length of serverFQDN */
+    unsigned urlen;		/* length of user_realm */
+    unsigned iploclen;		/* length of iplocalport */
+    unsigned ipremlen;		/* length of ipremoteport */
+
+    /* This indicates the level of logging desired.  See SASL_LOG_*
+     * in sasl.h
+     *
+     * Plug-ins can ignore this and just pass their desired level to
+     * the log callback.  This is primarily used to eliminate logging which
+     * might be a performance problem (e.g., full protocol trace) and
+     * to select between SASL_LOG_TRACE and SASL_LOG_PASS alternatives
+     */
+    int log_level;
+
+    const sasl_utils_t *utils;	/* SASL API utility routines --
+				 * for a particular sasl_conn_t,
+				 * MUST remain valid until mech_free is
+				 * called */
+    const sasl_callback_t *callbacks;	/* Callbacks from application */
+
+    /* application's security requirements */
+    sasl_security_properties_t props;
+    sasl_ssf_t external_ssf;	/* external SSF active */
+
+    /* Pointer to the function which takes the plaintext passphrase and
+     *  transitions a user to non-plaintext mechanisms via setpass calls.
+     *  (NULL = auto transition not enabled/supported)
+     *
+     *  If passlen is 0, it defaults to strlen(pass).
+     *  returns 0 if no entry added, 1 if entry added
+     */
+    int (*transition)(sasl_conn_t *conn, const char *pass, unsigned passlen);
+
+    /* Canonicalize a user name from on-wire to internal format
+     *  added cjn 1999-09-21
+     *  Must be called once user name acquired if canon_user is non-NULL.
+     *  conn        connection context
+     *  user        user name from wire protocol (need not be NUL terminated)
+     *  ulen        length of user name from wire protocol (0 = strlen(user))
+     *  flags       for SASL_CU_* flags
+     *  oparams     the user, authid, ulen, alen, fields are
+     *              set appropriately after canonicalization/copying and
+     *              authorization of arguments
+     *
+     *  responsible for setting user, ulen, authid, and alen in the oparams
+     *  structure
+     *
+     *  default behavior is to strip leading and trailing whitespace, as
+     *  well as allocating space for and copying the parameters.
+     *
+     * results:
+     *  SASL_OK       -- success
+     *  SASL_NOMEM    -- out of memory
+     *  SASL_BADPARAM -- invalid conn
+     *  SASL_BADPROT  -- invalid user/authid
+     */
+    int (*canon_user)(sasl_conn_t *conn,
+		      const char *user, unsigned ulen,
+		      unsigned flags,
+		      sasl_out_params_t *oparams);
+    
+    /* auxiliary property context (see definitions in prop.h)
+     *  added cjn 2000-01-30
+     *
+     * NOTE: these properties are the ones associated with the
+     * canonicalized "user" (user to login as / authorization id), not
+     * the "authid" (user whose credentials are used / authentication id)
+     * Prefix the property name with a "*" if a property associated with
+     * the "authid" is interesting.
+     */
+    struct propctx *propctx;
+
+    /* for additions which don't require a version upgrade; set to 0 */
+    const void *gss_creds;                  /* GSS credential handle */
+    const sasl_channel_binding_t *cbinding; /* server channel binding */
+    const sasl_http_request_t *http_request;/* HTTP Digest request method */
+    void *spare_ptr4;
+    int (*spare_fptr1)(void);
+    int (*spare_fptr2)(void);
+    int spare_int1;
+    int spare_int2;
+    int spare_int3;
+
+    /* flags field as passed to sasl_server_new */
+    unsigned flags;
+
+    /* set to 0 initially, this allows a plugin with extended parameters
+     * to work with an older framework by updating version as parameters
+     * are added.
+     */
+    int param_version;
+} sasl_server_params_t;
+
+/* logging levels (more levels may be added later, if necessary):
+ */
+#define SASL_LOG_NONE  0	/* don't log anything */
+#define SASL_LOG_ERR   1	/* log unusual errors (default) */
+#define SASL_LOG_FAIL  2	/* log all authentication failures */
+#define SASL_LOG_WARN  3	/* log non-fatal warnings */
+#define SASL_LOG_NOTE  4	/* more verbose than LOG_WARN */
+#define SASL_LOG_DEBUG 5	/* more verbose than LOG_NOTE */
+#define SASL_LOG_TRACE 6	/* traces of internal protocols */
+#define SASL_LOG_PASS  7	/* traces of internal protocols, including
+				 * passwords */
+
+/* additional flags for setpass() function below:
+ */
+/*      SASL_SET_CREATE                     create user if pass non-NULL */
+/*      SASL_SET_DISABLE                    disable user */
+#define SASL_SET_REMOVE  SASL_SET_CREATE /* remove user if pass is NULL */
+
+/* features for server plug-in
+ */
+#define SASL_FEAT_SERVICE    0x0200 /* service-specific passwords supported */
+#define SASL_FEAT_GETSECRET  0x0400 /* sasl_server_{get,put}secret_t callbacks
+				     * required by plug-in */
+
+/* a C object for a server mechanism
+ */
+typedef struct sasl_server_plug {
+    /* mechanism name */
+    const char *mech_name;
+
+    /* best mech additional security layer strength factor */
+    sasl_ssf_t max_ssf;
+
+    /* best security flags, as defined in sasl_security_properties_t */
+    unsigned security_flags;
+
+    /* features of plugin */
+    unsigned features;
+    
+    /* global state for mechanism */
+    void *glob_context;
+
+    /* create a new mechanism handler
+     *  glob_context  -- global context
+     *  sparams       -- server config params
+     *  challenge     -- server challenge from previous instance or NULL
+     *  challen       -- length of challenge from previous instance or 0
+     * out:
+     *  conn_context  -- connection context
+     *  errinfo       -- error information
+     *
+     * returns:
+     *  SASL_OK       -- successfully created mech instance
+     *  SASL_*        -- any other server error code
+     */
+    int (*mech_new)(void *glob_context,
+		    sasl_server_params_t *sparams,
+		    const char *challenge,
+		    unsigned challen,
+		    void **conn_context);
+    
+    /* perform one step in exchange
+     *
+     * returns:
+     *  SASL_OK       -- success, all done
+     *  SASL_CONTINUE -- success, one more round trip
+     *  SASL_*        -- any other server error code
+     */
+    int (*mech_step)(void *conn_context,
+		     sasl_server_params_t *sparams,
+		     const char *clientin,
+		     unsigned clientinlen,
+		     const char **serverout,
+		     unsigned *serveroutlen,
+		     sasl_out_params_t *oparams);
+    
+    /* dispose of a connection state
+     */
+    void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
+    
+    /* free global state for mechanism
+     *  mech_dispose must be called on all mechanisms first
+     */
+    void (*mech_free)(void *glob_context, const sasl_utils_t *utils);
+    
+    /* set a password (optional)
+     *  glob_context  -- global context
+     *  sparams       -- service, middleware utilities, etc. props ignored
+     *  user          -- user name
+     *  pass          -- password/passphrase (NULL = disable/remove/delete)
+     *  passlen       -- length of password/passphrase
+     *  oldpass       -- old password/passphrase (NULL = transition)
+     *  oldpasslen    -- length of password/passphrase
+     *  flags         -- see above
+     *
+     * returns:
+     *  SASL_NOCHANGE -- no change was needed
+     *  SASL_NOUSER   -- no entry for user
+     *  SASL_NOVERIFY -- no mechanism compatible entry for user
+     *  SASL_PWLOCK   -- password locked
+     *  SASL_DIABLED  -- account disabled
+     *  etc.
+     */
+    int (*setpass)(void *glob_context,
+		   sasl_server_params_t *sparams,
+		   const char *user,
+		   const char *pass, unsigned passlen,
+		   const char *oldpass, unsigned oldpasslen,
+		   unsigned flags);
+
+    /* query which mechanisms are available for user
+     *  glob_context  -- context
+     *  sparams       -- service, middleware utilities, etc. props ignored
+     *  user          -- NUL terminated user name
+     *  maxmech       -- max number of strings in mechlist (0 = no output)
+     * output:
+     *  mechlist      -- an array of C string pointers, filled in with
+     *                   mechanism names available to the user
+     *
+     * returns:
+     *  SASL_OK       -- success
+     *  SASL_NOMEM    -- not enough memory
+     *  SASL_FAIL     -- lower level failure
+     *  SASL_DISABLED -- account disabled
+     *  SASL_NOUSER   -- user not found
+     *  SASL_BUFOVER  -- maxmech is too small
+     *  SASL_NOVERIFY -- user found, but no mechanisms available
+     */
+    int (*user_query)(void *glob_context,
+		      sasl_server_params_t *sparams,
+		      const char *user,
+		      int maxmech,
+		      const char **mechlist);
+     
+    /* perform precalculations during a network round-trip
+     *  or idle period.  conn_context may be NULL (optional)
+     *  returns 1 if action taken, 0 if no action taken
+     */
+    int (*idle)(void *glob_context,
+		void *conn_context,
+		sasl_server_params_t *sparams);
+
+    /* check if mechanism is available
+     *  optional--if NULL, mechanism is available based on ENABLE= in config
+     *
+     *  If this routine sets conn_context to a non-NULL value, then the call
+     *  to mech_new will be skipped.  This should not be done unless
+     *  there's a significant performance benefit, since it can cause
+     *  additional memory allocation in SASL core code to keep track of
+     *  contexts potentially for multiple mechanisms.
+     *
+     *  This is called by the first call to sasl_listmech() for a
+     *  given connection context, thus for a given protocol it may
+     *  never be called.  Note that if mech_avail returns SASL_NOMECH,
+     *  then that mechanism is considered disabled for the remainder
+     *  of the session.  If mech_avail returns SASL_NOTDONE, then a
+     *  future call to mech_avail may still return either SASL_OK
+     *  or SASL_NOMECH.
+     *
+     *  returns SASL_OK on success,
+     *          SASL_NOTDONE if mech is not available now, but may be later
+     *                       (e.g. EXTERNAL w/o auth_id)
+     *          SASL_NOMECH if mech disabled
+     */
+    int (*mech_avail)(void *glob_context,
+		      sasl_server_params_t *sparams,
+		      void **conn_context);
+
+    /* for additions which don't require a version upgrade; set to 0 */
+    int (*spare_fptr2)(void);
+} sasl_server_plug_t;
+
+#define SASL_SERVER_PLUG_VERSION 4
+
+/* plug-in entry point:
+ *  utils         -- utility callback functions
+ *  plugname      -- name of plug-in (may be NULL)
+ *  max_version   -- highest server plug version supported
+ * returns:
+ *  out_version   -- server plug-in version of result
+ *  pluglist      -- list of mechanism plug-ins
+ *  plugcount     -- number of mechanism plug-ins
+ * results:
+ *  SASL_OK       -- success
+ *  SASL_NOMEM    -- failure
+ *  SASL_BADVERS  -- max_version too small
+ *  SASL_BADPARAM -- bad config string
+ *  ...
+ */
+typedef int sasl_server_plug_init_t(const sasl_utils_t *utils,
+				    int max_version,
+				    int *out_version,
+				    sasl_server_plug_t **pluglist,
+				    int *plugcount);
+
+/* 
+ * add a server plug-in
+ */
+LIBSASL_API int sasl_server_add_plugin(const char *plugname,
+				       sasl_server_plug_init_t *splugfunc);
+
+
+typedef struct server_sasl_mechanism
+{
+    int version;
+    int condition; /* set to SASL_NOUSER if no available users;
+		      set to SASL_CONTINUE if delayed plugin loading */
+    char *plugname; /* for AUTHSOURCE tracking */
+    const sasl_server_plug_t *plug;
+    char *f;       /* where should i load the mechanism from? */
+} server_sasl_mechanism_t;
+
+typedef void sasl_server_info_callback_t (server_sasl_mechanism_t *m,
+					  sasl_info_callback_stage_t stage,
+					  void *rock);
+
+
+/* Dump information about available server plugins (separate functions are
+   used for canon and auxprop plugins) */
+LIBSASL_API int sasl_server_plugin_info (const char *mech_list,
+	sasl_server_info_callback_t *info_cb,
+	void *info_cb_rock);
+
+
+/*********************************************************
+ * user canonicalization plug-in -- added cjn 1999-09-29 *
+ *********************************************************/
+
+typedef struct sasl_canonuser {
+    /* optional features of plugin (set to 0) */
+    int features;
+
+    /* spare integer (set to 0) */
+    int spare_int1;
+
+    /* global state for plugin */
+    void *glob_context;
+
+    /* name of plugin */
+    char *name;
+
+    /* free global state for plugin */
+    void (*canon_user_free)(void *glob_context, const sasl_utils_t *utils);
+
+    /* canonicalize a username
+     *  glob_context     -- global context from this structure
+     *  sparams          -- server params, note user_realm&propctx elements
+     *  user             -- user to login as (may not be NUL terminated)
+     *  len              -- length of user name (0 = strlen(user))
+     *  flags            -- for SASL_CU_* flags
+     *  out              -- buffer to copy user name
+     *  out_max          -- max length of user name
+     *  out_len          -- set to length of user name
+     *
+     *  note that the output buffers MAY be the same as the input buffers.
+     *
+     * returns
+     *  SASL_OK         on success
+     *  SASL_BADPROT    username contains invalid character
+     */
+    int (*canon_user_server)(void *glob_context,
+			     sasl_server_params_t *sparams,
+			     const char *user, unsigned len,
+			     unsigned flags,
+			     char *out,
+			     unsigned out_umax, unsigned *out_ulen);
+
+    int (*canon_user_client)(void *glob_context,
+			     sasl_client_params_t *cparams,
+			     const char *user, unsigned len,
+			     unsigned flags,
+			     char *out,
+			     unsigned out_max, unsigned *out_len);
+
+    /* for additions which don't require a version upgrade; set to 0 */
+    int (*spare_fptr1)(void);
+    int (*spare_fptr2)(void);
+    int (*spare_fptr3)(void);
+} sasl_canonuser_plug_t;
+
+#define SASL_CANONUSER_PLUG_VERSION 5
+
+/* default name for canonuser plug-in entry point is "sasl_canonuser_init"
+ *  similar to sasl_server_plug_init model, except only returns one
+ *  sasl_canonuser_plug_t structure;
+ */
+typedef int sasl_canonuser_init_t(const sasl_utils_t *utils,
+				  int max_version,
+				  int *out_version,
+				  sasl_canonuser_plug_t **plug,
+				  const char *plugname);
+
+/* add a canonuser plugin
+ */
+LIBSASL_API int sasl_canonuser_add_plugin(const char *plugname,
+				  sasl_canonuser_init_t *canonuserfunc);
+
+/******************************************************
+ * auxiliary property plug-in -- added cjn 1999-09-29 *
+ ******************************************************/
+
+typedef struct sasl_auxprop_plug {
+    /* optional features of plugin (none defined yet, set to 0) */
+    int features;
+
+    /* spare integer, must be set to 0 */
+    int spare_int1;
+
+    /* global state for plugin */
+    void *glob_context;
+
+    /* free global state for plugin (OPTIONAL) */
+    void (*auxprop_free)(void *glob_context, const sasl_utils_t *utils);
+
+    /* fill in fields of an auxiliary property context
+     *  last element in array has id of SASL_AUX_END
+     *  elements with non-0 len should be ignored.
+     */
+    int (*auxprop_lookup)(void *glob_context,
+			   sasl_server_params_t *sparams,
+			   unsigned flags,
+			   const char *user, unsigned ulen);
+
+    /* name of the auxprop plugin */
+    char *name;
+
+    /* store the fields/values of an auxiliary property context (OPTIONAL)
+     *
+     * if ctx is NULL, just check if storing properties is enabled
+     *
+     * returns
+     *  SASL_OK         on success
+     *  SASL_FAIL       on failure
+     */
+    int (*auxprop_store)(void *glob_context,
+			 sasl_server_params_t *sparams,
+			 struct propctx *ctx,
+			 const char *user, unsigned ulen);
+} sasl_auxprop_plug_t;
+
+/* auxprop lookup flags */
+#define SASL_AUXPROP_OVERRIDE 0x01 /* if clear, ignore auxiliary properties
+				    * with non-zero len field.  If set,
+				    * override value of those properties */
+#define SASL_AUXPROP_AUTHZID  0x02 /* if clear, we are looking up the
+				    * authid flags (prefixed with *), otherwise
+				    * we are looking up the authzid flags
+				    * (no prefix) */
+
+/* NOTE: Keep in sync with SASL_CU_<XXX> flags */
+#define SASL_AUXPROP_VERIFY_AGAINST_HASH 0x10
+
+
+#define SASL_AUXPROP_PLUG_VERSION 8
+
+/* default name for auxprop plug-in entry point is "sasl_auxprop_init"
+ *  similar to sasl_server_plug_init model, except only returns one
+ *  sasl_auxprop_plug_t structure;
+ */
+typedef int sasl_auxprop_init_t(const sasl_utils_t *utils,
+				int max_version,
+				int *out_version,
+				sasl_auxprop_plug_t **plug,
+				const char *plugname);
+
+/* add an auxiliary property plug-in
+ */
+LIBSASL_API int sasl_auxprop_add_plugin(const char *plugname,
+					sasl_auxprop_init_t *auxpropfunc);
+
+typedef void auxprop_info_callback_t (sasl_auxprop_plug_t *m,
+			              sasl_info_callback_stage_t stage,
+				      void *rock);
+
+/* Dump information about available auxprop plugins (separate functions are
+   used for canon and server authentication plugins) */
+LIBSASL_API int auxprop_plugin_info (const char *mech_list,
+	auxprop_info_callback_t *info_cb,
+	void *info_cb_rock);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SASLPLUG_H */

+ 99 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/include/sasl/saslutil.h

@@ -0,0 +1,99 @@
+/* saslutil.h -- various utility functions in SASL library
+ */
+
+#ifndef SASLUTIL_H
+#define SASLUTIL_H 1
+
+#ifndef SASL_H
+#include "sasl.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* base64 decode
+ *  in     -- input data
+ *  inlen  -- length of input data
+ *  out    -- output data (may be same as in, must have enough space)
+ *  outmax  -- max size of output buffer
+ * result:
+ *  outlen -- actual output length
+ *
+ * returns SASL_BADPROT on bad base64,
+ *  SASL_BUFOVER if result won't fit
+ *  SASL_OK on success
+ */
+LIBSASL_API int sasl_decode64(const char *in, unsigned inlen,
+			      char *out, unsigned outmax, unsigned *outlen);
+
+/* base64 encode
+ *  in      -- input data
+ *  inlen   -- input data length
+ *  out     -- output buffer (will be NUL terminated)
+ *  outmax  -- max size of output buffer
+ * result:
+ *  outlen  -- gets actual length of output buffer (optional)
+ * 
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+LIBSASL_API int sasl_encode64(const char *in, unsigned inlen,
+			      char *out, unsigned outmax, unsigned *outlen);
+
+/* make a challenge string (NUL terminated)
+ *  buf      -- buffer for result
+ *  maxlen   -- max length of result
+ *  hostflag -- 0 = don't include hostname, 1 = include hostname
+ * returns final length or 0 if not enough space
+ */
+LIBSASL_API int sasl_mkchal(sasl_conn_t *conn, char *buf, 
+			    unsigned maxlen, unsigned hostflag);
+
+/* verify a string is valid UTF-8
+ * if len == 0, strlen(str) will be used.
+ * returns SASL_BADPROT on error, SASL_OK on success
+ */
+LIBSASL_API int sasl_utf8verify(const char *str, unsigned len);
+
+/* create random pool seeded with OS-based params */
+LIBSASL_API int sasl_randcreate(sasl_rand_t **rpool);
+
+/* free random pool from randcreate */
+LIBSASL_API void sasl_randfree(sasl_rand_t **rpool);
+
+/* seed random number generator */
+LIBSASL_API void sasl_randseed(sasl_rand_t *rpool, const char *seed,
+			       unsigned len);
+
+/* generate random octets */
+LIBSASL_API void sasl_rand(sasl_rand_t *rpool, char *buf, unsigned len);
+
+/* churn data into random number generator */
+LIBSASL_API void sasl_churn(sasl_rand_t *rpool, const char *data,
+			    unsigned len);
+
+/* erase a security sensitive buffer or password.
+ *   Implementation may use recovery-resistant erase logic.  
+ */
+LIBSASL_API void sasl_erasebuffer(char *pass, unsigned len);
+
+/* Lowercase string in place */
+LIBSASL_API char *sasl_strlower (char *val);
+
+LIBSASL_API int sasl_config_init(const char *filename);
+
+LIBSASL_API void sasl_config_done(void);
+
+#ifdef WIN32
+/* Just in case a different DLL defines this as well */
+#if defined(NEED_GETOPT)
+LIBSASL_API int getopt(int argc, char **argv, char *optstring);
+#endif
+LIBSASL_API char * getpass(const char *prompt);
+#endif /* WIN32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SASLUTIL_H */

+ 104 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/Makefile.am

@@ -0,0 +1,104 @@
+# Makefile.am for the SASL library
+# Rob Earhart
+# $Id: Makefile.am,v 1.88 2011/09/05 14:18:10 murch Exp $
+# Copyright (c) 2000 Carnegie Mellon University.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer. 
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# 3. The name "Carnegie Mellon University" must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission. For permission or any other legal
+#    details, please contact  
+#      Office of Technology Transfer
+#      Carnegie Mellon University
+#      5000 Forbes Avenue
+#      Pittsburgh, PA  15213-3890
+#      (412) 268-4387, fax: (412) 268-7395
+#      tech-transfer@andrew.cmu.edu
+#
+# 4. Redistributions of any form whatsoever must retain the following
+#    acknowledgment:
+#    "This product includes software developed by Computing Services
+#     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+#
+# CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+# Library version info - here at the top, for sanity
+# See <http://www.gnu.org/software/libtool/manual/libtool.html#Versioning>
+# CURRENT:REVISION:AGE
+sasl_version = 3:0:0
+
+INCLUDES=-DLIBSASL_EXPORTS=1 -I$(top_srcdir)/include -I$(top_srcdir)/plugins -I$(top_builddir)/include -I$(top_srcdir)/sasldb
+
+EXTRA_DIST = windlopen.c staticopen.h NTMakefile
+EXTRA_LIBRARIES = libsasl2.a
+noinst_LIBRARIES = @SASL_STATIC_LIBS@
+libsasl2_a_SOURCES=
+
+BUILT_SOURCES = $(SASL_STATIC_SRCS)
+
+common_headers = saslint.h
+common_sources = auxprop.c canonusr.c checkpw.c client.c common.c config.c external.c md5.c saslutil.c server.c seterror.c dlopen.c ../plugins/plugin_common.c
+
+LTLIBOBJS = @LTLIBOBJS@
+LIBOBJS = @LIBOBJS@
+LIB_DOOR= @LIB_DOOR@
+
+lib_LTLIBRARIES = libsasl2.la
+
+libsasl2_la_SOURCES = $(common_sources) $(common_headers)
+libsasl2_la_LDFLAGS = -version-info $(sasl_version)
+libsasl2_la_DEPENDENCIES = $(LTLIBOBJS)
+libsasl2_la_LIBADD = $(LTLIBOBJS) $(SASL_DL_LIB) $(LIB_SOCKET) $(LIB_DOOR)
+
+if MACOSX
+framedir = /Library/Frameworks/SASL2.framework
+install-exec-hook:
+	$(mkinstalldirs) $(framedir)/Versions/A
+	ln -fs $(libdir)/libsasl2.dylib $(framedir)/Versions/A/SASL2
+	cd $(framedir) ; ln -fs Versions/A/SASL2 .
+else
+install-exec-hook:
+endif
+
+libsasl2.a: libsasl2.la $(SASL_STATIC_OBJS)
+	@echo adding static plugins and dependencies
+	$(AR) cru .libs/$@ $(SASL_STATIC_OBJS)
+	@for i in ./libsasl2.la ../sasldb/libsasldb.la ../plugins/lib*.la; do \
+	if test ! -f $$i; then continue; fi; . $$i; \
+	for j in $$dependency_libs foo; do \
+	case $$j in foo) ;; \
+	-L*) for k in $$depdirs foo; do \
+	    if test $$k = $$j; then break; fi; done; \
+	  if test $$k = foo; then depdirs="$$depdirs $$j"; fi ;; \
+	-l*) for k in $$deplibs foo; do \
+	    if test $$k = $$j; then break; fi; done; \
+	  if test $$k = foo; then deplibs="$$deplibs $$j"; fi ;; \
+	esac; done; dependency_libs=""; done; \
+	sed -e "/^dependency_libs=/s%=.*%='$${depdirs}$${deplibs}'%" \
+	libsasl2.la >TMP.$$ && mv TMP.$$ libsasl2.la
+	rm -f $@
+	ln -s .libs/$@ $@
+
+$(SASL_STATIC_SRCS): linksrcs
+
+linksrcs:
+	-ln -s $(SASL_STATIC_SRCS) .
+

+ 128 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/NTMakefile

@@ -0,0 +1,128 @@
+!INCLUDE ..\win32\common.mak
+
+# WS2tcpip.h included in Visual Studio 7 provides getaddrinfo, ...
+# emulation on Windows, so there is no need to build getaddrinfo.c
+
+!IF "$(VCVER)" == "6"
+compat_sources = getaddrinfo.c getnameinfo.c
+compat_objs = getaddrinfo.obj getnameinfo.obj
+!ENDIF
+
+
+libsasl_sources = auxprop.c canonusr.c checkpw.c client.c common.c config.c external.c md5.c saslutil.c server.c seterror.c windlopen.c getsubopt.c plugin_common.c plugin_common.h $(compat_sources)
+libsasl_objs = auxprop.obj canonusr.obj checkpw.obj client.obj common.obj config.obj external.obj md5.obj saslutil.obj server.obj seterror.obj windlopen.obj getsubopt.obj plugin_common.obj $(compat_objs)
+libsasl_res = libsasl.res
+libsasl_out = libsasl.dll libsasl.exp libsasl.lib $(libsasl_res)
+
+CPPFLAGS = /wd4996 /Wp64 /D NEED_GETOPT /I "..\win32\include" /I "." /I "..\include" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBSASL_EXPORTS"
+
+!IF $(TARGET_WIN_SYSTEM) >= 51
+CPPFLAGS = /D TARGET_WIN_SYSTEM=$(TARGET_WIN_SYSTEM) $(CPPFLAGS)
+!ENDIF 
+
+all_objs = $(libsasl_objs)
+all_out = $(libsasl_out)
+
+libdir = $(prefix)\lib
+bindir = $(prefix)\bin
+exclude_list = binexclude.lst
+
+all: all-recursive
+
+#
+# /I flag to xcopy tells to treat the last parameter as directory and create all missing levels
+#
+# In order to force xcopy not to confirm if the second parameter is file or directory,
+# the first parameter has to contain a wildcard character. For example, we use libsasl.l*,
+# instead of libsasl.lib. Ugly, but works!
+#
+install: libsasl.dll
+	@echo libsasl.exp > $(exclude_list)
+	@echo libsasl.res >> $(exclude_list)
+	@echo libsasl.dll.manifest >> $(exclude_list)
+# .lib is excluded only because it is copied separately below
+	@echo libsasl.lib >> $(exclude_list)
+	@xcopy libsasl.* $(bindir) /I /F /Y /EXCLUDE:$(exclude_list)
+	@xcopy libsasl.l* $(libdir) /I /F /Y
+
+all-recursive: libsasl.dll
+
+libsasl.dll: $(libsasl_objs) $(libsasl_res)
+	$(LINK32DLL) @<< $(LINK32DLL_FLAGS) /out:"libsasl.dll" /implib:"libsasl.lib" /pdb:"libsasl.pdb" $(libsasl_objs) $(libsasl_res)
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+plugin_common.c: ..\plugins\plugin_common.c plugin_common.h
+	xcopy /D /Y ..\plugins\plugin_common.c .
+
+plugin_common.h: ..\plugins\plugin_common.h
+	xcopy /D /Y ..\plugins\plugin_common.h .
+
+auxprop.obj checkpw.obj client.obj common.obj external.obj plugin_common.obj server.obj seterror.obj: ..\include\saslplug.h
+
+auxprop.obj canonusr.obj checkpw.obj client.obj common.obj config.obj external.obj getsubopt.obj md5.obj plugin_common.obj server.obj seterror.obj windlopen.obj: ..\include\sasl.h ..\include\prop.h
+
+auxprop.obj canonusr.obj checkpw.obj client.obj common.obj config.obj dlopen.obj external.obj saslutil.obj server.obj seterror.obj windlopen.obj: saslint.h
+
+CLEAN :
+	-@erase $(all_objs)
+	-@erase "*.idb"
+	-@erase "*.pdb"
+	-@erase "*.manifest"
+	-@erase $(all_out)
+	-@erase plugin_common.h
+	-@erase plugin_common.c
+	-@erase $(exclude_list)
+
+$(libsasl_res): NTMakefile
+	rc /fo"$(libsasl_res)" <<
+#include "windows.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION $(SASL_VERSION_MAJOR),$(SASL_VERSION_MINOR),$(SASL_VERSION_STEP),0
+ PRODUCTVERSION $(SASL_VERSION_MAJOR),$(SASL_VERSION_MINOR),$(SASL_VERSION_STEP),0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Carnegie Mellon University\0"
+            VALUE "FileDescription", "CMU SASL API v2\0"
+            VALUE "FileVersion", "$(SASL_VERSION_MAJOR).$(SASL_VERSION_MINOR).$(SASL_VERSION_STEP).0\0"
+            VALUE "InternalName", "libsasl\0"
+            VALUE "LegalCopyright", "Copyright (c) Carnegie Mellon University 2002-2012\0"
+            VALUE "OriginalFilename", "libsasl.dll\0"
+            VALUE "ProductName", "Carnegie Mellon University SASL\0"
+            VALUE "ProductVersion", "$(SASL_VERSION_MAJOR).$(SASL_VERSION_MINOR).$(SASL_VERSION_STEP)-0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+<<
+
+.c.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<

+ 1198 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/auxprop.c

@@ -0,0 +1,1198 @@
+/* auxprop.c - auxilliary property support
+ * Rob Siemborski
+ * $Id: auxprop.c,v 1.21 2011/09/01 14:12:53 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <sasl.h>
+#include <prop.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "saslint.h"
+
+struct proppool 
+{
+    struct proppool *next;
+
+    size_t size;          /* Size of Block */
+    size_t unused;        /* Space unused in this pool between end
+			   * of char** area and beginning of char* area */
+
+    char data[1];         /* Variable Sized */
+};
+
+struct propctx  {
+    struct propval *values;
+    struct propval *prev_val; /* Previous value used by set/setvalues */
+
+    unsigned used_values, allocated_values;
+
+    char *data_end; /* Bottom of string area in current pool */
+    char **list_end; /* Top of list area in current pool */
+
+    struct proppool *mem_base;
+    struct proppool *mem_cur;
+};
+
+typedef struct auxprop_plug_list 
+{
+    struct auxprop_plug_list *next;
+    const sasl_auxprop_plug_t *plug;
+} auxprop_plug_list_t;
+
+static auxprop_plug_list_t *auxprop_head = NULL;
+
+static struct proppool *alloc_proppool(size_t size) 
+{
+    struct proppool *ret;
+    /* minus 1 for the one that is already a part of the array
+     * in the struct */
+    size_t total_size = sizeof(struct proppool) + size - 1;
+    ret = sasl_ALLOC(total_size);
+    if(!ret) return NULL;
+
+    memset(ret, 0, total_size);
+
+    ret->size = ret->unused = size;
+
+    return ret;
+}
+
+/* Resize a proppool.  Invalidates the unused value for this pool */
+static struct proppool *resize_proppool(struct proppool *pool, size_t size)
+{
+    struct proppool *ret;
+    
+    if(pool->size >= size) return pool;
+    ret = sasl_REALLOC(pool, sizeof(struct proppool) + size);
+    if(!ret) return NULL;
+
+    ret->size = size;
+
+    return ret;
+}
+
+static int prop_init(struct propctx *ctx, unsigned estimate) 
+{
+    const unsigned VALUES_SIZE = PROP_DEFAULT * sizeof(struct propval);
+
+    ctx->mem_base = alloc_proppool(VALUES_SIZE + estimate);
+    if(!ctx->mem_base) return SASL_NOMEM;
+
+    ctx->mem_cur = ctx->mem_base;
+
+    ctx->values = (struct propval *)ctx->mem_base->data;
+    ctx->mem_base->unused = ctx->mem_base->size - VALUES_SIZE;
+    ctx->allocated_values = PROP_DEFAULT;
+    ctx->used_values = 0;
+
+    ctx->data_end = ctx->mem_base->data + ctx->mem_base->size;
+    ctx->list_end = (char **)(ctx->mem_base->data + VALUES_SIZE);
+
+    ctx->prev_val = NULL;
+
+    return SASL_OK;
+}
+
+/* create a property context
+ *  estimate -- an estimate of the storage needed for requests & responses
+ *              0 will use module default
+ * returns NULL on error
+ */
+struct propctx *prop_new(unsigned estimate) 
+{
+    struct propctx *new_ctx;
+
+    if(!estimate) estimate = PROP_DEFAULT * 255;
+
+    new_ctx = sasl_ALLOC(sizeof(struct propctx));
+    if(!new_ctx) return NULL;
+
+    if(prop_init(new_ctx, estimate) != SASL_OK) {
+	prop_dispose(&new_ctx);
+    }
+
+    return new_ctx;
+}
+
+/* create new propctx which duplicates the contents of an existing propctx
+ * returns -1 on error
+ */
+int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx) 
+{
+    struct proppool *pool;
+    struct propctx *retval = NULL;
+    unsigned i;
+    int result;
+    unsigned total_size = 0;
+    size_t values_size;
+    
+    if(!src_ctx || !dst_ctx) return SASL_BADPARAM;
+
+    /* What is the total allocated size of src_ctx? */
+    pool = src_ctx->mem_base;
+    while(pool) {
+	total_size += (unsigned) pool->size;
+	pool = pool->next;
+    }
+
+    /* allocate the new context */
+    retval = prop_new(total_size);
+    if(!retval) return SASL_NOMEM;
+
+    retval->used_values = src_ctx->used_values;
+    retval->allocated_values = src_ctx->used_values + 1;
+
+    values_size = (retval->allocated_values * sizeof(struct propval));
+
+    retval->mem_base->unused = retval->mem_base->size - values_size;
+
+    retval->list_end = (char **)(retval->mem_base->data + values_size);
+    /* data_end should still be OK */
+
+    /* Now dup the values */
+    for(i=0; i<src_ctx->used_values; i++) {
+	retval->values[i].name = src_ctx->values[i].name;
+	result = prop_setvals(retval, retval->values[i].name,
+			      src_ctx->values[i].values);
+	if(result != SASL_OK)
+	    goto fail;
+    }
+
+    retval->prev_val = src_ctx->prev_val;
+
+    *dst_ctx = retval;
+    return SASL_OK;
+
+    fail:
+    if(retval) prop_dispose(&retval);
+    return result;
+}
+
+/*
+ * dispose of property context
+ *  ctx      -- is disposed and set to NULL; noop if ctx or *ctx is NULL
+ */
+void prop_dispose(struct propctx **ctx)
+{
+    struct proppool *tmp;
+    
+    if(!ctx || !*ctx) return;
+
+    while((*ctx)->mem_base) {
+	tmp = (*ctx)->mem_base;
+	(*ctx)->mem_base = tmp->next;
+	sasl_FREE(tmp);
+    }
+    
+    sasl_FREE(*ctx);
+    *ctx = NULL;
+
+    return;
+}
+
+/* Add property names to request
+ *  ctx       -- context from prop_new()
+ *  names     -- list of property names; must persist until context freed
+ *               or requests cleared
+ *
+ * NOTE: may clear values from context as side-effect
+ * returns -1 on error
+ */
+int prop_request(struct propctx *ctx, const char **names) 
+{
+    unsigned i, new_values, total_values;
+
+    if(!ctx || !names) return SASL_BADPARAM;
+
+    /* Count how many we need to add */
+    for(new_values=0; names[new_values]; new_values++);
+
+    /* Do we need to add ANY? */
+    if(!new_values) return SASL_OK;
+
+    /* We always want at least one extra to mark the end of the array */
+    total_values = new_values + ctx->used_values + 1;
+
+    /* Do we need to increase the size of our propval table? */
+    if(total_values > ctx->allocated_values) {
+	unsigned max_in_pool;
+
+	/* Do we need a larger base pool? */
+	max_in_pool = (unsigned) (ctx->mem_base->size / sizeof(struct propval));
+	
+	if(total_values <= max_in_pool) {
+	    /* Don't increase the size of the base pool, just use what
+	       we need */
+	    ctx->allocated_values = total_values;
+	    ctx->mem_base->unused =
+		ctx->mem_base->size - (sizeof(struct propval)
+				       * ctx->allocated_values);
+      	} else {
+	    /* We need to allocate more! */
+	    unsigned new_alloc_length;
+	    size_t new_size;
+
+	    new_alloc_length = 2 * ctx->allocated_values;
+	    while(total_values > new_alloc_length) {
+		new_alloc_length *= 2;
+	    }
+
+	    new_size = new_alloc_length * sizeof(struct propval);
+	    ctx->mem_base = resize_proppool(ctx->mem_base, new_size);
+
+	    if(!ctx->mem_base) {
+		ctx->values = NULL;
+		ctx->allocated_values = ctx->used_values = 0;
+		return SASL_NOMEM;
+	    }
+
+	    /* It worked! Update the structure! */
+	    ctx->values = (struct propval *)ctx->mem_base->data;
+	    ctx->allocated_values = new_alloc_length;
+	    ctx->mem_base->unused = ctx->mem_base->size
+		- sizeof(struct propval) * ctx->allocated_values;
+	}
+
+	/* Clear out new propvals */
+	memset(&(ctx->values[ctx->used_values]), 0,
+	       sizeof(struct propval) * (ctx->allocated_values - ctx->used_values));
+
+        /* Finish updating the context -- we've extended the list! */
+	/* ctx->list_end = (char **)(ctx->values + ctx->allocated_values); */
+	/* xxx test here */
+	ctx->list_end = (char **)(ctx->values + total_values);
+    }
+
+    /* Now do the copy, or referencing rather */
+    for(i=0;i<new_values;i++) {
+	unsigned j, flag;
+
+	flag = 0;
+
+	/* Check for dups */
+	for(j=0;j<ctx->used_values;j++) {
+	    if(!strcmp(ctx->values[j].name, names[i])) {
+		flag = 1;
+		break;
+	    }
+	}
+
+	/* We already have it... skip! */
+	if(flag) continue;
+
+	ctx->values[ctx->used_values++].name = names[i];
+    }
+
+    prop_clear(ctx, 0);
+
+    return SASL_OK;
+}
+
+/* return array of struct propval from the context
+ *  return value persists until next call to
+ *   prop_request, prop_clear or prop_dispose on context
+ */
+const struct propval *prop_get(struct propctx *ctx) 
+{
+    if(!ctx) return NULL;
+    
+    return ctx->values;
+}
+
+/* Fill in an array of struct propval based on a list of property names
+ *  return value persists until next call to
+ *   prop_request, prop_clear or prop_dispose on context
+ *  returns -1 on error (no properties ever requested, ctx NULL, etc)
+ *  returns number of matching properties which were found (values != NULL)
+ *  if a name requested here was never requested by a prop_request, then
+ *  the name field of the associated vals entry will be set to NULL
+ */
+int prop_getnames(struct propctx *ctx, const char **names,
+		  struct propval *vals) 
+{
+    int found_names = 0;
+    
+    struct propval *cur = vals;
+    const char **curname;
+
+    if(!ctx || !names || !vals) return SASL_BADPARAM;
+    
+    for(curname = names; *curname; curname++) {
+	struct propval *val;
+	for(val = ctx->values; val->name; val++) {
+	    if(!strcmp(*curname,val->name)) { 
+		found_names++;
+		memcpy(cur, val, sizeof(struct propval));
+		goto next;
+	    }
+	}
+
+	/* If we are here, we didn't find it */
+	memset(cur, 0, sizeof(struct propval));
+	
+	next:
+	cur++;
+    }
+
+    return found_names;
+}
+
+
+/* clear values and optionally requests from property context
+ *  ctx      -- property context
+ *  requests -- 0 = don't clear requests, 1 = clear requests
+ */
+void prop_clear(struct propctx *ctx, int requests) 
+{
+    struct proppool *new_pool, *tmp;
+    unsigned i;
+
+    /* We're going to need a new proppool once we reset things */
+    new_pool = alloc_proppool(ctx->mem_base->size +
+			      (ctx->used_values+1) * sizeof(struct propval));
+
+    if(requests) {
+	/* We're wiping the whole shebang */
+	ctx->used_values = 0;
+    } else {
+	/* Need to keep around old requets */
+	struct propval *new_values = (struct propval *)new_pool->data;
+	for(i=0; i<ctx->used_values; i++) {
+	    new_values[i].name = ctx->values[i].name;
+	}
+    }
+
+    while(ctx->mem_base) {
+	tmp = ctx->mem_base;
+	ctx->mem_base = tmp->next;
+	sasl_FREE(tmp);
+    }
+    
+    /* Update allocation-related metadata */
+    ctx->allocated_values = ctx->used_values+1;
+    new_pool->unused =
+	new_pool->size - (ctx->allocated_values * sizeof(struct propval));
+
+    /* Setup pointers for the values array */
+    ctx->values = (struct propval *)new_pool->data;
+    ctx->prev_val = NULL;
+
+    /* Setup the pools */
+    ctx->mem_base = ctx->mem_cur = new_pool;
+
+    /* Reset list_end and data_end for the new memory pool */
+    ctx->list_end =
+	(char **)((char *)ctx->mem_base->data + ctx->allocated_values * sizeof(struct propval));
+    ctx->data_end = (char *)ctx->mem_base->data + ctx->mem_base->size;
+
+    return;
+}
+
+/*
+ * erase the value of a property
+ */
+void prop_erase(struct propctx *ctx, const char *name)
+{
+    struct propval *val;
+    int i;
+
+    if(!ctx || !name) return;
+
+    for(val = ctx->values; val->name; val++) {
+	if(!strcmp(name,val->name)) {
+	    if(!val->values) break;
+
+	    /*
+	     * Yes, this is casting away the const, but
+	     * we should be okay because the only place this
+	     * memory should be is in the proppool's
+	     */
+	    for(i=0;val->values[i];i++) {
+		memset((void *)(val->values[i]),0,strlen(val->values[i]));
+		val->values[i] = NULL;
+	    }
+
+	    val->values = NULL;
+	    val->nvalues = 0;
+	    val->valsize = 0;
+	    break;
+	}
+    }
+    
+    return;
+}
+
+/****fetcher interfaces****/
+
+/* format the requested property names into a string
+ *  ctx    -- context from prop_new()/prop_request()
+ *  sep    -- separator between property names (unused if none requested)
+ *  seplen -- length of separator, if < 0 then strlen(sep) will be used
+ *  outbuf -- output buffer
+ *  outmax -- maximum length of output buffer including NUL terminator
+ *  outlen -- set to length of output string excluding NUL terminator
+ * returns 0 on success and amount of additional space needed on failure
+ */
+int prop_format(struct propctx *ctx, const char *sep, int seplen,
+		char *outbuf, unsigned outmax, unsigned *outlen) 
+{
+    unsigned needed, flag = 0;
+    struct propval *val;
+    
+    if (!ctx || !outbuf) return SASL_BADPARAM;
+
+    if (!sep) seplen = 0;    
+    if (seplen < 0) seplen = (int) strlen(sep);
+/* If seplen is negative now we have overflow.
+   But if you have a string longer than 2Gb, you are an idiot anyway */
+    if (seplen < 0) return SASL_BADPARAM;
+
+    needed = seplen * (ctx->used_values - 1);
+    for(val = ctx->values; val->name; val++) {
+	needed += (unsigned) strlen(val->name);
+    }
+    
+    if(!outmax) return (needed + 1); /* Because of unsigned funkiness */
+    if(needed > (outmax - 1)) return (needed - (outmax - 1));
+
+    *outbuf = '\0';
+    if(outlen) *outlen = needed;
+
+    if(needed == 0) return SASL_OK;
+
+    for(val = ctx->values; val->name; val++) {
+	if(seplen && flag) {
+	    strncat(outbuf, sep, seplen);
+	} else {
+	    flag = 1;
+	}
+	strcat(outbuf, val->name);
+    }
+    
+    return SASL_OK;
+}
+
+/* add a property value to the context
+ *  ctx    -- context from prop_new()/prop_request()
+ *  name   -- name of property to which value will be added
+ *            if NULL, add to the same name as previous prop_set/setvals call
+ *  value  -- a value for the property; will be copied into context
+ *            if NULL, remove existing values
+ *  vallen -- length of value, if <= 0 then strlen(value) will be used
+ */
+int prop_set(struct propctx *ctx, const char *name,
+	     const char *value, int vallen)
+{
+    struct propval *cur;
+
+    if(!ctx) return SASL_BADPARAM;
+    if(!name && !ctx->prev_val) return SASL_BADPARAM; 
+
+    if(name) {
+	struct propval *val;
+
+	ctx->prev_val = NULL;
+	
+	for(val = ctx->values; val->name; val++) {
+	    if(!strcmp(name,val->name)){
+		ctx->prev_val = val;
+		break;
+	    }
+	}
+
+	/* Couldn't find it! */
+	if(!ctx->prev_val) return SASL_BADPARAM;
+    }
+
+    cur = ctx->prev_val;
+
+    if(name) /* New Entry */ {
+	unsigned nvalues = 1; /* 1 for NULL entry */
+	const char **old_values = NULL;
+	char **tmp, **tmp2;
+	size_t size;
+	
+	if(cur->values) {
+
+	    if(!value) {
+		/* If we would be adding a null value, then we are done */
+		return SASL_OK;
+	    }
+
+	    old_values = cur->values;
+	    tmp = (char **)cur->values;
+	    while(*tmp) {
+		nvalues++;
+		tmp++;
+	    }
+
+	}
+
+	if(value) {
+	    nvalues++; /* for the new value */
+	}
+
+	size = nvalues * sizeof(char*);
+
+	if(size > ctx->mem_cur->unused) {
+	    size_t needed;
+
+	    for(needed = ctx->mem_cur->size * 2; needed < size; needed *= 2);
+
+	    /* Allocate a new proppool */
+	    ctx->mem_cur->next = alloc_proppool(needed);
+	    if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+	    ctx->mem_cur = ctx->mem_cur->next;
+
+	    ctx->list_end = (char **)ctx->mem_cur->data;
+	    ctx->data_end = ctx->mem_cur->data + needed;
+	}
+
+	/* Grab the memory */
+	ctx->mem_cur->unused -= size;
+	cur->values = (const char **)ctx->list_end;
+	cur->values[nvalues - 1] = NULL;
+
+	/* Finish updating the context */
+	ctx->list_end = (char **)(cur->values + nvalues);
+
+	/* If we don't have an actual value to fill in, we are done */
+	if(!value)
+	    return SASL_OK;
+
+	tmp2 = (char **)cur->values;
+	if(old_values) {
+	    tmp = (char **)old_values;
+	    
+	    while(*tmp) {
+		*tmp2 = *tmp;
+		tmp++; tmp2++;
+	    }
+	}
+	    
+	/* Now allocate the last entry */
+	if(vallen <= 0)
+	    size = (size_t)(strlen(value) + 1);
+	else
+	    size = (size_t)(vallen + 1);
+
+	if(size > ctx->mem_cur->unused) {
+	    size_t needed;
+	    
+	    needed = ctx->mem_cur->size * 2;
+	    
+	    while(needed < size) {
+		needed *= 2;
+	    }
+
+	    /* Allocate a new proppool */
+	    ctx->mem_cur->next = alloc_proppool(needed);
+	    if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+	    ctx->mem_cur = ctx->mem_cur->next;
+	    ctx->list_end = (char **)ctx->mem_cur->data;
+	    ctx->data_end = ctx->mem_cur->data + needed;
+	}
+
+	/* Update the data_end pointer */
+	ctx->data_end -= size;
+	ctx->mem_cur->unused -= size;
+
+	/* Copy and setup the new value! */
+	memcpy(ctx->data_end, value, size-1);
+	ctx->data_end[size - 1] = '\0';
+	cur->values[nvalues - 2] = ctx->data_end;
+
+	cur->nvalues++;
+	cur->valsize += ((unsigned) size - 1);
+    } else /* Appending an entry */ {
+	char **tmp;
+	size_t size;
+
+	/* If we are setting it to be NULL, we are done */
+	if(!value) return SASL_OK;
+
+	size = sizeof(char*);
+
+	/* Is it in the current pool, and will it fit in the unused space? */
+	if(size > ctx->mem_cur->unused &&
+	    (void *)cur->values > (void *)(ctx->mem_cur->data) &&
+	    (void *)cur->values < (void *)(ctx->mem_cur->data + ctx->mem_cur->size)) {
+	    /* recursively call the not-fast way */
+	    return prop_set(ctx, cur->name, value, vallen);
+	}
+
+	/* Note the invariant: the previous value list must be
+	   at the top of the CURRENT pool at this point */
+
+	/* Grab the memory */
+	ctx->mem_cur->unused -= size;
+	ctx->list_end++;
+
+	*(ctx->list_end - 1) = NULL;
+	tmp = (ctx->list_end - 2);
+
+	/* Now allocate the last entry */
+	if(vallen <= 0)
+	    size = strlen(value) + 1;
+	else
+	    size = vallen + 1;
+
+	if(size > ctx->mem_cur->unused) {
+	    size_t needed;
+	    
+	    needed = ctx->mem_cur->size * 2;
+	    
+	    while(needed < size) {
+		needed *= 2;
+	    }
+
+	    /* Allocate a new proppool */
+	    ctx->mem_cur->next = alloc_proppool(needed);
+	    if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+	    ctx->mem_cur = ctx->mem_cur->next;
+	    ctx->list_end = (char **)ctx->mem_cur->data;
+	    ctx->data_end = ctx->mem_cur->data + needed;
+	}
+
+	/* Update the data_end pointer */
+	ctx->data_end -= size;
+	ctx->mem_cur->unused -= size;
+
+	/* Copy and setup the new value! */
+	memcpy(ctx->data_end, value, size-1);
+	ctx->data_end[size - 1] = '\0';
+	*tmp = ctx->data_end;
+
+	cur->nvalues++;
+	cur->valsize += ((unsigned) size - 1);
+    }
+    
+    return SASL_OK;
+}
+
+
+/* set the values for a property
+ *  ctx    -- context from prop_new()/prop_request()
+ *  name   -- name of property to which value will be added
+ *            if NULL, add to the same name as previous prop_set/setvals call
+ *  values -- array of values, ending in NULL.  Each value is a NUL terminated
+ *            string
+ */
+int prop_setvals(struct propctx *ctx, const char *name,
+		 const char **values)
+{
+    const char **val = values;
+    int result = SASL_OK;
+
+    if(!ctx) return SASL_BADPARAM;
+
+    /* If they want us to add no values, we can do that */
+    if(!values) return SASL_OK;
+    
+    /* Basically, use prop_set to do all our dirty work for us */
+    if(name) {
+	result = prop_set(ctx, name, *val, 0);
+	val++;
+    }
+
+    for(;*val;val++) {
+	if(result != SASL_OK) return result;
+	result = prop_set(ctx, NULL, *val,0);
+    }
+
+    return result;
+}
+
+/* Request a set of auxiliary properties
+ *  conn         connection context
+ *  propnames    list of auxiliary property names to request ending with
+ *               NULL.  
+ *
+ * Subsequent calls will add items to the request list.  Call with NULL
+ * to clear the request list.
+ *
+ * errors
+ *  SASL_OK       -- success
+ *  SASL_BADPARAM -- bad count/conn parameter
+ *  SASL_NOMEM    -- out of memory
+ */
+int sasl_auxprop_request(sasl_conn_t *conn, const char **propnames) 
+{
+    int result;
+    sasl_server_conn_t *sconn;
+
+    if(!conn) return SASL_BADPARAM;
+    if(conn->type != SASL_CONN_SERVER)
+	PARAMERROR(conn);
+    
+    sconn = (sasl_server_conn_t *)conn;
+
+    if(!propnames) {
+	prop_clear(sconn->sparams->propctx,1);
+	return SASL_OK;
+    }
+    
+    result = prop_request(sconn->sparams->propctx, propnames);
+    RETURN(conn, result);
+}
+
+
+/* Returns current auxiliary property context.
+ * Use functions in prop.h to access content
+ *
+ *  if authentication hasn't completed, property values may be empty/NULL
+ *
+ *  properties not recognized by active plug-ins will be left empty/NULL
+ *
+ *  returns NULL if conn is invalid.
+ */
+struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn) 
+{
+    sasl_server_conn_t *sconn;
+    
+    if(!conn || conn->type != SASL_CONN_SERVER) return NULL;
+
+    sconn = (sasl_server_conn_t *)conn;
+
+    return sconn->sparams->propctx;
+}
+
+/* add an auxiliary property plugin */
+int sasl_auxprop_add_plugin(const char *plugname,
+			    sasl_auxprop_init_t *auxpropfunc)
+{
+    int result, out_version;
+    auxprop_plug_list_t *new_item;
+    sasl_auxprop_plug_t *plug;
+    
+    result = auxpropfunc(sasl_global_utils, SASL_AUXPROP_PLUG_VERSION,
+			 &out_version, &plug, plugname);
+
+    /* Check if out_version is too old.
+       We only support the current at the moment */
+    if (result == SASL_OK && out_version < SASL_AUXPROP_PLUG_VERSION) {
+        result = SASL_BADVERS;
+    }
+
+    if(result != SASL_OK) {
+	_sasl_log(NULL, SASL_LOG_ERR, "auxpropfunc error %s\n",
+		  sasl_errstring(result, NULL, NULL));
+	return result;
+    }
+
+    /* We require that this function is implemented */
+    if(!plug->auxprop_lookup) return SASL_BADPROT;
+
+    new_item = sasl_ALLOC(sizeof(auxprop_plug_list_t));
+    if(!new_item) return SASL_NOMEM;    
+
+    /* These will load from least-important to most important */
+    new_item->plug = plug;
+    new_item->next = auxprop_head;
+    auxprop_head = new_item;
+
+    return SASL_OK;
+}
+
+void _sasl_auxprop_free() 
+{
+    auxprop_plug_list_t *ptr, *ptr_next;
+    
+    for(ptr = auxprop_head; ptr; ptr = ptr_next) {
+	ptr_next = ptr->next;
+	if(ptr->plug->auxprop_free)
+	    ptr->plug->auxprop_free(ptr->plug->glob_context,
+				    sasl_global_utils);
+	sasl_FREE(ptr);
+    }
+
+    auxprop_head = NULL;
+}
+
+/* Return the updated account status based on the current ("so far") and
+   the specific status returned by the latest auxprop call */
+static int
+_sasl_account_status (int current_status,
+                      int specific_status)
+{
+    switch (specific_status) {
+	case SASL_NOVERIFY:
+	    specific_status = SASL_OK;
+	    /* fall through */
+	case SASL_OK:
+	    if (current_status == SASL_NOMECH ||
+		current_status == SASL_NOUSER) {
+		current_status = specific_status;
+	    }
+	    break;
+
+	case SASL_NOUSER:
+	    if (current_status == SASL_NOMECH) {
+		current_status = specific_status;
+	    }
+	    break;
+
+	/* NOTE: The disabled flag sticks, unless we hit an error */
+	case SASL_DISABLED:
+	    if (current_status == SASL_NOMECH ||
+		current_status == SASL_NOUSER ||
+		current_status == SASL_OK) {
+		current_status = specific_status;
+	    }
+	    break;
+
+	case SASL_NOMECH:
+	    /* ignore */
+	    break;
+
+	/* SASL_UNAVAIL overrides everything */
+	case SASL_UNAVAIL:
+	    current_status = specific_status;
+	    break;
+
+	default:
+	    current_status = specific_status;
+	    break;
+    }
+    return (current_status);
+}
+
+/* Do the callbacks for auxprop lookups */
+int _sasl_auxprop_lookup(sasl_server_params_t *sparams,
+			  unsigned flags,
+			  const char *user, unsigned ulen) 
+{
+    sasl_getopt_t *getopt;
+    int ret, found = 0;
+    void *context;
+    const char *plist = NULL;
+    auxprop_plug_list_t *ptr;
+    int result = SASL_NOMECH;
+
+    if(_sasl_getcallback(sparams->utils->conn,
+			 SASL_CB_GETOPT,
+			 (sasl_callback_ft *)&getopt,
+			 &context) == SASL_OK) {
+	ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
+	if(ret != SASL_OK) plist = NULL;
+    }
+
+    if(!plist) {
+	/* Do lookup in all plugins */
+
+	/* TODO: Ideally, each auxprop plugin should be marked if its failure
+	   should be ignored or treated as a fatal error of the whole lookup. */
+	for(ptr = auxprop_head; ptr; ptr = ptr->next) {
+	    found=1;
+	    ret = ptr->plug->auxprop_lookup(ptr->plug->glob_context,
+				      sparams, flags, user, ulen);
+	    result = _sasl_account_status (result, ret);
+	}
+    } else {
+	char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
+
+	if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_NOMEM;
+	thisplugin = freeptr = pluginlist;
+	
+	/* Do lookup in all *specified* plugins, in order */
+	while(*thisplugin) {
+	    char *p;
+	    int last=0;
+	    
+	    while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
+	    if(!(*thisplugin)) break;
+	    
+	    for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
+	    if(*p == '\0') last = 1;
+	    else *p='\0';
+	    
+	    for(ptr = auxprop_head; ptr; ptr = ptr->next) {
+		/* Skip non-matching plugins */
+		if(!ptr->plug->name
+		   || strcasecmp(ptr->plug->name, thisplugin))
+		    continue;
+	    
+		found=1;
+		ret = ptr->plug->auxprop_lookup(ptr->plug->glob_context,
+					  sparams, flags, user, ulen);
+		result = _sasl_account_status (result, ret);
+	    }
+
+	    if(last) break;
+
+	    thisplugin = p+1;
+	}
+
+	sasl_FREE(freeptr);
+    }
+
+    if(!found) {
+	_sasl_log(sparams->utils->conn, SASL_LOG_DEBUG,
+		  "could not find auxprop plugin, was searching for '%s'",
+		  plist ? plist : "[all]");
+    }
+
+    return result;
+}
+
+/* Do the callbacks for auxprop stores */
+int sasl_auxprop_store(sasl_conn_t *conn,
+		       struct propctx *ctx, const char *user)
+{
+    sasl_getopt_t *getopt;
+    int ret;
+    void *context;
+    const char *plist = NULL;
+    auxprop_plug_list_t *ptr;
+    sasl_server_params_t *sparams = NULL;
+    unsigned userlen = 0;
+    int num_constraint_violations = 0;
+    int total_plugins = 0;
+
+    if (ctx) {
+	if (!conn || !user)
+	    return SASL_BADPARAM;
+
+	sparams = ((sasl_server_conn_t *) conn)->sparams;
+	userlen = (unsigned) strlen(user);
+    }
+    
+    /* Pickup getopt callback from the connection, if conn is not NULL */
+    if(_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+	ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
+	if(ret != SASL_OK) plist = NULL;
+    }
+
+    ret = SASL_OK;
+    if(!plist) {
+	/* Do store in all plugins */
+	for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
+	    total_plugins++;
+	    if (ptr->plug->auxprop_store) {
+		ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
+					       sparams, ctx, user, userlen);
+		if (ret == SASL_CONSTRAINT_VIOLAT) {
+		    ret = SASL_OK;
+		    num_constraint_violations++;
+		}
+	    }
+	}
+    } else {
+	char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
+
+	if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_FAIL;
+	thisplugin = freeptr = pluginlist;
+	
+	/* Do store in all *specified* plugins, in order */
+	while(*thisplugin) {
+	    char *p;
+	    int last=0;
+	    
+	    while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
+	    if(!(*thisplugin)) break;
+	    
+	    for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
+	    if(*p == '\0') last = 1;
+	    else *p='\0';
+	    
+	    for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
+		/* Skip non-matching plugins */
+		if((!ptr->plug->name
+		    || strcasecmp(ptr->plug->name, thisplugin)))
+		    continue;
+
+		total_plugins++;
+		if (ptr->plug->auxprop_store) {
+		    ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
+						   sparams, ctx, user, userlen);
+		    if (ret == SASL_CONSTRAINT_VIOLAT) {
+			ret = SASL_OK;
+			num_constraint_violations++;
+		    }
+		}
+	    }
+
+	    if(last) break;
+
+	    thisplugin = p+1;
+	}
+
+	sasl_FREE(freeptr);
+    }
+
+    if(total_plugins == 0) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "could not find auxprop plugin, was searching for %s",
+		  plist ? plist : "[all]");
+	return SASL_FAIL;
+    } else if (total_plugins == num_constraint_violations) {
+	ret = SASL_CONSTRAINT_VIOLAT;
+    }
+
+    return ret;
+}
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (sasl_auxprop_plug_t *m,
+		       sasl_info_callback_stage_t stage,
+		       void *rock __attribute__((unused))
+)
+{
+    if (stage == SASL_INFO_LIST_START) {
+	printf ("List of auxprop plugins follows\n");
+	return;
+    } else if (stage == SASL_INFO_LIST_END) {
+	return;
+    }
+
+    /* Process the mechanism */
+    printf ("Plugin \"%s\" ", m->name);
+
+#ifdef NOT_YET
+    switch (m->condition) {
+	case SASL_OK:
+	    printf ("[loaded]");
+	    break;
+
+	case SASL_CONTINUE:
+	    printf ("[delayed]");
+	    break;
+
+	case SASL_NOUSER:
+	    printf ("[no users]");
+	    break;
+
+	default:
+	    printf ("[unknown]");
+	    break;
+    }
+#endif
+
+    printf (", \tAPI version: %d\n", /* m->version */ SASL_AUXPROP_PLUG_VERSION);
+
+    /* TODO - Update for auxprop_export, etc. */
+    printf ("\tsupports store: %s\n",
+	    (m->auxprop_store != NULL) ? "yes" : "no"
+	    );
+
+    /* No features defined yet */
+#ifdef NOT_YET
+    printf ("\n\tfeatures:");
+#endif
+
+    printf ("\n");
+}
+
+/* Dump information about available auxprop plugins (separate functions are
+   used for canon and server authentication plugins) */
+int auxprop_plugin_info (
+  const char *c_mech_list,		/* space separated mechanism list or NULL for ALL */
+  auxprop_info_callback_t *info_cb,
+  void *info_cb_rock
+)
+{
+    auxprop_plug_list_t *m;
+    sasl_auxprop_plug_t plug_data;
+    char * cur_mech;
+    char *mech_list = NULL;
+    char * p;
+
+    if (info_cb == NULL) {
+	info_cb = _sasl_print_mechanism;
+    }
+
+    if (auxprop_head != NULL) {
+	info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+	if (c_mech_list == NULL) {
+	    m = auxprop_head; /* m point to beginning of the list */
+
+	    while (m != NULL) {
+                /* TODO: Need to be careful when dealing with auxprop_export, etc. */
+		memcpy (&plug_data, m->plug, sizeof(plug_data));
+
+		info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+	    
+		m = m->next;
+	    }
+	} else {
+            mech_list = strdup(c_mech_list);
+
+	    cur_mech = mech_list;
+
+	    while (cur_mech != NULL) {
+		p = strchr (cur_mech, ' ');
+		if (p != NULL) {
+		    *p = '\0';
+		    p++;
+		}
+
+		m = auxprop_head; /* m point to beginning of the list */
+
+		while (m != NULL) {
+		    if (strcasecmp (cur_mech, m->plug->name) == 0) {
+			memcpy (&plug_data, m->plug, sizeof(plug_data));
+
+			info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+		    }
+	    
+		    m = m->next;
+		}
+
+		cur_mech = p;
+	    }
+
+            free (mech_list);
+	}
+
+	info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
+
+	return (SASL_OK);
+    }
+
+    return (SASL_NOTINIT);
+}

+ 462 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/canonusr.c

@@ -0,0 +1,462 @@
+/* canonusr.c - user canonicalization support
+ * Rob Siemborski
+ * $Id: canonusr.c,v 1.22 2011/09/01 16:33:42 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <sasl.h>
+#include <string.h>
+#include <ctype.h>
+#include <prop.h>
+#include <stdio.h>
+
+#include "saslint.h"
+
+typedef struct canonuser_plug_list 
+{
+    struct canonuser_plug_list *next;
+    char name[PATH_MAX];
+    const sasl_canonuser_plug_t *plug;
+} canonuser_plug_list_t;
+
+static canonuser_plug_list_t *canonuser_head = NULL;
+
+/* default behavior:
+ *                   eliminate leading & trailing whitespace,
+ *                   null-terminate, and get into the outparams
+ *                   (handled by INTERNAL plugin) */
+/* a zero ulen or alen indicates that it is strlen(value) */
+int _sasl_canon_user(sasl_conn_t *conn,
+                     const char *user, unsigned ulen,
+                     unsigned flags,
+                     sasl_out_params_t *oparams)
+{
+    canonuser_plug_list_t *ptr;
+    sasl_server_conn_t *sconn = NULL;
+    sasl_client_conn_t *cconn = NULL;
+    sasl_canon_user_t *cuser_cb;
+    sasl_getopt_t *getopt;
+    void *context;
+    int result;
+    const char *plugin_name = NULL;
+    char *user_buf;
+    unsigned *lenp;
+
+    if(!conn) return SASL_BADPARAM;    
+    if(!user || !oparams) return SASL_BADPARAM;
+
+    if(flags & SASL_CU_AUTHID) {
+	user_buf = conn->authid_buf;
+	lenp = &(oparams->alen);
+    } else if (flags & SASL_CU_AUTHZID) {
+	user_buf = conn->user_buf;
+	lenp = &(oparams->ulen);
+    } else {
+	return SASL_BADPARAM;
+    }
+    
+    if(conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
+    else if(conn->type == SASL_CONN_CLIENT) cconn = (sasl_client_conn_t *)conn;
+    else return SASL_FAIL;
+    
+    if(!ulen) ulen = (unsigned int)strlen(user);
+    
+    /* check to see if we have a callback to make*/
+    result = _sasl_getcallback(conn,
+			       SASL_CB_CANON_USER,
+			       (sasl_callback_ft *)&cuser_cb,
+			       &context);
+    if(result == SASL_OK && cuser_cb) {
+	result = cuser_cb(conn,
+			  context,
+			  user,
+			  ulen,
+			  flags,
+			  (conn->type == SASL_CONN_SERVER ?
+				sconn->user_realm :
+				NULL),
+			  user_buf,
+			  CANON_BUF_SIZE,
+			  lenp);
+	
+
+	if (result != SASL_OK) return result;
+
+	/* Point the input copy at the stored buffer */
+	user = user_buf;
+	ulen = *lenp;
+    }
+
+    /* which plugin are we supposed to use? */
+    result = _sasl_getcallback(conn,
+			       SASL_CB_GETOPT,
+			       (sasl_callback_ft *)&getopt,
+			       &context);
+    if (result == SASL_OK && getopt) {
+	getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
+    }
+
+    if (!plugin_name) {
+	/* Use Default */
+	plugin_name = "INTERNAL";
+    }
+    
+    for (ptr = canonuser_head; ptr; ptr = ptr->next) {
+	/* A match is if we match the internal name of the plugin, or if
+	 * we match the filename (old-style) */
+	if ((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
+	   || !strcmp(plugin_name, ptr->name)) break;
+    }
+
+    /* We clearly don't have this one! */
+    if (!ptr) {
+	sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
+		      plugin_name);
+	return SASL_NOMECH;
+    }
+    
+    if (sconn) {
+	/* we're a server */
+	result = ptr->plug->canon_user_server(ptr->plug->glob_context,
+					      sconn->sparams,
+					      user, ulen,
+					      flags,
+					      user_buf,
+					      CANON_BUF_SIZE, lenp);
+    } else {
+	/* we're a client */
+	result = ptr->plug->canon_user_client(ptr->plug->glob_context,
+					      cconn->cparams,
+					      user, ulen,
+					      flags,
+					      user_buf,
+					      CANON_BUF_SIZE, lenp);
+    }
+
+    if (result != SASL_OK) return result;
+
+    if ((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
+	/* We did both, so we need to copy the result into
+	 * the buffer for the authzid from the buffer for the authid */
+	memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
+	oparams->ulen = oparams->alen;
+    }
+	
+    /* Set the appropriate oparams (lengths have already been set by lenp) */
+    if (flags & SASL_CU_AUTHID) {
+	oparams->authid = conn->authid_buf;
+    }
+
+    if (flags & SASL_CU_AUTHZID) {
+	oparams->user = conn->user_buf;
+    }
+
+    RETURN(conn, result);
+}
+
+/* Lookup all properties for authentication and/or authorization identity. */
+static int _sasl_auxprop_lookup_user_props (sasl_conn_t *conn,
+					    unsigned flags,
+					    sasl_out_params_t *oparams)
+{
+    sasl_server_conn_t *sconn = NULL;
+    int result = SASL_OK;
+
+    if (!conn) return SASL_BADPARAM;    
+    if (!oparams) return SASL_BADPARAM;
+
+#ifndef macintosh
+    if (conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
+
+    /* do auxprop lookups (server only) */
+    if (sconn) {
+	int authz_result;
+	unsigned auxprop_lookup_flags = flags & SASL_CU_ASIS_MASK;
+
+	if (flags & SASL_CU_OVERRIDE) {
+	    auxprop_lookup_flags |= SASL_AUXPROP_OVERRIDE;
+	}
+
+	if (flags & SASL_CU_AUTHID) {
+	    result = _sasl_auxprop_lookup(sconn->sparams,
+					  auxprop_lookup_flags,
+					  oparams->authid,
+					  oparams->alen);
+	} else {
+	    result = SASL_CONTINUE;
+	}
+	if (flags & SASL_CU_AUTHZID) {
+	    authz_result = _sasl_auxprop_lookup(sconn->sparams,
+						auxprop_lookup_flags | SASL_AUXPROP_AUTHZID,
+						oparams->user,
+						oparams->ulen);
+
+	    if (result == SASL_CONTINUE) {
+		/* Only SASL_CU_AUTHZID was requested.
+		   The authz_result value is authoritative. */
+		result = authz_result;
+	    } else if (result == SASL_OK && authz_result != SASL_NOUSER) {
+		/* Use the authz_result value, unless "result"
+		   already contains an error */
+		result = authz_result;
+	    }
+	}
+
+	if ((flags & SASL_CU_EXTERNALLY_VERIFIED) && (result == SASL_NOUSER || result == SASL_NOMECH)) {
+	    /* The called has explicitly told us that the authentication identity
+	       was already verified or will be verified independently.
+	       So a failure to retrieve any associated properties
+	       is not an error. For example the caller is using Kerberos to verify user,
+	       but the LDAPDB/SASLDB auxprop plugin doesn't contain any auxprops for
+	       the user.
+	       Another case is PLAIN/LOGIN not using auxprop to verify user passwords. */
+	    result = SASL_OK;
+	}	
+    }
+#endif
+
+    RETURN(conn, result);
+}
+
+/* default behavior:
+ *                   Eliminate leading & trailing whitespace,
+ *                   null-terminate, and get into the outparams
+ *                   (handled by INTERNAL plugin).
+ *
+ *                   Server only: Also does auxprop lookups once username
+ *                   is canonicalized. */
+int _sasl_canon_user_lookup (sasl_conn_t *conn,
+			     const char *user,
+			     unsigned ulen,
+			     unsigned flags,
+			     sasl_out_params_t *oparams)
+{
+    int result;
+
+    result = _sasl_canon_user (conn,
+			       user,
+			       ulen,
+			       flags,
+			       oparams);
+    if (result == SASL_OK) {
+	result = _sasl_auxprop_lookup_user_props (conn,
+						  flags,
+						  oparams);
+    }
+
+    RETURN(conn, result);
+}
+
+void _sasl_canonuser_free() 
+{
+    canonuser_plug_list_t *ptr, *ptr_next;
+    
+    for(ptr = canonuser_head; ptr; ptr = ptr_next) {
+	ptr_next = ptr->next;
+	if(ptr->plug->canon_user_free)
+	    ptr->plug->canon_user_free(ptr->plug->glob_context,
+				       sasl_global_utils);
+	sasl_FREE(ptr);
+    }
+
+    canonuser_head = NULL;
+}
+
+int sasl_canonuser_add_plugin(const char *plugname,
+			      sasl_canonuser_init_t *canonuserfunc) 
+{
+    int result, out_version;
+    canonuser_plug_list_t *new_item;
+    sasl_canonuser_plug_t *plug;
+
+    if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
+	sasl_seterror(NULL, 0,
+		      "bad plugname passed to sasl_canonuser_add_plugin\n");
+	return SASL_BADPARAM;
+    }
+    
+    result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
+			   &out_version, &plug, plugname);
+
+    if(result != SASL_OK) {
+	_sasl_log(NULL, SASL_LOG_ERR, "%s_canonuser_plug_init() failed in sasl_canonuser_add_plugin(): %z\n",
+		  plugname, result);
+	return result;
+    }
+
+    if(!plug->canon_user_server && !plug->canon_user_client) {
+	/* We need at least one of these implemented */
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "canonuser plugin '%s' without either client or server side", plugname);
+	return SASL_BADPROT;
+    }
+    
+    new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
+    if(!new_item) return SASL_NOMEM;
+
+    strncpy(new_item->name, plugname, PATH_MAX);
+
+    new_item->plug = plug;
+    new_item->next = canonuser_head;
+    canonuser_head = new_item;
+
+    return SASL_OK;
+}
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) (((a) < (b))? (a):(b))
+
+static int _canonuser_internal(const sasl_utils_t *utils,
+			       const char *user, unsigned ulen,
+			       unsigned flags __attribute__((unused)),
+			       char *out_user,
+			       unsigned out_umax, unsigned *out_ulen) 
+{
+    unsigned i;
+    char *in_buf, *userin;
+    const char *begin_u;
+    unsigned u_apprealm = 0;
+    sasl_server_conn_t *sconn = NULL;
+
+    if(!utils || !user) return SASL_BADPARAM;
+
+    in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
+    if(!in_buf) return SASL_NOMEM;
+
+    userin = in_buf;
+
+    memcpy(userin, user, ulen);
+    userin[ulen] = '\0';
+    
+    /* Strip User ID */
+    for(i=0;isspace((int)userin[i]) && i<ulen;i++);
+    begin_u = &(userin[i]);
+    if(i>0) ulen -= i;
+
+    for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
+    if(begin_u == &(userin[ulen])) {
+	sasl_FREE(in_buf);
+	utils->seterror(utils->conn, 0, "All-whitespace username.");
+	return SASL_FAIL;
+    }
+
+    if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
+	sconn = (sasl_server_conn_t *)utils->conn;
+
+    /* Need to append realm if necessary (see sasl.h) */
+    if(sconn && sconn->user_realm && !strchr(user, '@')) {
+	u_apprealm = (unsigned) strlen(sconn->user_realm) + 1;
+    }
+    
+    /* Now Copy */
+    memcpy(out_user, begin_u, MIN(ulen, out_umax));
+    if(sconn && u_apprealm) {
+	if(ulen >= out_umax) return SASL_BUFOVER;
+	out_user[ulen] = '@';
+	memcpy(&(out_user[ulen+1]), sconn->user_realm,
+	       MIN(u_apprealm-1, out_umax-ulen-1));
+    }
+    out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
+
+    if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
+
+    if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
+    
+    sasl_FREE(in_buf);
+    return SASL_OK;
+}
+
+static int _cu_internal_server(void *glob_context __attribute__((unused)),
+			       sasl_server_params_t *sparams,
+			       const char *user, unsigned ulen,
+			       unsigned flags,
+			       char *out_user,
+			       unsigned out_umax, unsigned *out_ulen) 
+{
+    return _canonuser_internal(sparams->utils,
+			       user, ulen,
+			       flags, out_user, out_umax, out_ulen);
+}
+
+static int _cu_internal_client(void *glob_context __attribute__((unused)),
+			       sasl_client_params_t *cparams,
+			       const char *user, unsigned ulen,
+			       unsigned flags,
+			       char *out_user,
+			       unsigned out_umax, unsigned *out_ulen) 
+{
+    return _canonuser_internal(cparams->utils,
+			       user, ulen,
+			       flags, out_user, out_umax, out_ulen);
+}
+
+static sasl_canonuser_plug_t canonuser_internal_plugin = {
+        0, /* features */
+	0, /* spare */
+	NULL, /* glob_context */
+	"INTERNAL", /* name */
+	NULL, /* canon_user_free */
+	_cu_internal_server,
+	_cu_internal_client,
+	NULL,
+	NULL,
+	NULL
+};
+
+int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
+                            int max_version,
+                            int *out_version,
+                            sasl_canonuser_plug_t **plug,
+                            const char *plugname __attribute__((unused))) 
+{
+    if(!out_version || !plug) return SASL_BADPARAM;
+
+    if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
+    
+    *out_version = SASL_CANONUSER_PLUG_VERSION;
+
+    *plug = &canonuser_internal_plugin;
+
+    return SASL_OK;
+}

+ 1097 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/checkpw.c

@@ -0,0 +1,1097 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: checkpw.c,v 1.79 2009/05/08 00:43:44 murch Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+/* checkpw stuff */
+
+#include <stdio.h>
+#include "sasl.h"
+#include "saslutil.h"
+#include "saslplug.h"
+#include "saslint.h"
+
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#ifdef USE_DOORS
+#include <sys/mman.h>
+#include <door.h>
+#endif
+
+#include <stdlib.h>
+
+#ifndef WIN32
+#include <strings.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#else
+#include <string.h>
+#endif
+
+#include <limits.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif /* HAVE_SHADOW_H */
+
+#if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+# include <errno.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+#endif
+
+
+/* we store the following secret to check plaintext passwords:
+ *
+ * <salt> \0 <secret>
+ *
+ * where <secret> = MD5(<salt>, "sasldb", <pass>)
+ */
+static int _sasl_make_plain_secret(const char *salt, 
+				   const char *passwd, size_t passlen,
+				   sasl_secret_t **secret)
+{
+    MD5_CTX ctx;
+    unsigned sec_len = 16 + 1 + 16; /* salt + "\0" + hash */
+
+    *secret = (sasl_secret_t *) sasl_ALLOC(sizeof(sasl_secret_t) +
+					   sec_len * sizeof(char));
+    if (*secret == NULL) {
+	return SASL_NOMEM;
+    }
+
+    _sasl_MD5Init(&ctx);
+    _sasl_MD5Update(&ctx, salt, 16);
+    _sasl_MD5Update(&ctx, "sasldb", 6);
+    _sasl_MD5Update(&ctx, passwd, (unsigned int) passlen);
+    memcpy((*secret)->data, salt, 16);
+    (*secret)->data[16] = '\0';
+    _sasl_MD5Final((*secret)->data + 17, &ctx);
+    (*secret)->len = sec_len;
+    
+    return SASL_OK;
+}
+
+/* verify user password using auxprop plugins
+ */
+static int auxprop_verify_password(sasl_conn_t *conn,
+				   const char *userstr,
+				   const char *passwd,
+				   const char *service __attribute__((unused)),
+				   const char *user_realm __attribute__((unused)))
+{
+    int ret = SASL_FAIL;
+    int result = SASL_OK;
+    sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+    const char *password_request[] = { SASL_AUX_PASSWORD,
+				       "*cmusaslsecretPLAIN",
+				       NULL };
+    struct propval auxprop_values[3];
+    
+    if (!conn || !userstr)
+	return SASL_BADPARAM;
+
+    /* We need to clear any previous results and re-canonify to 
+     * ensure correctness */
+
+    prop_clear (sconn->sparams->propctx, 0);
+	
+    /* ensure its requested */
+    result = prop_request(sconn->sparams->propctx, password_request);
+
+    if(result != SASL_OK) return result;
+
+    result = _sasl_canon_user_lookup (conn,
+				      userstr,
+				      0,
+				      SASL_CU_AUTHID | SASL_CU_AUTHZID,
+				      &(conn->oparams));
+    if(result != SASL_OK) return result;
+    
+    result = prop_getnames(sconn->sparams->propctx, password_request,
+			   auxprop_values);
+    if (result < 0) {
+	return result;
+    }
+
+    /* Verify that the returned <name>s are correct.
+       But we defer checking for NULL values till after we verify
+       that a passwd is specified. */
+    if (!auxprop_values[0].name && !auxprop_values[1].name) {
+	return SASL_NOUSER;
+    }
+        
+    /* It is possible for us to get useful information out of just
+     * the lookup, so we won't check that we have a password until now */
+    if(!passwd) {
+	ret = SASL_BADPARAM;
+	goto done;
+    }
+
+    if ((!auxprop_values[0].values || !auxprop_values[0].values[0])
+	&& (!auxprop_values[1].values || !auxprop_values[1].values[0])) {
+	return SASL_NOUSER;
+    }
+        
+    /* At the point this has been called, the username has been canonified
+     * and we've done the auxprop lookup.  This should be easy. */
+    if(auxprop_values[0].name
+       && auxprop_values[0].values
+       && auxprop_values[0].values[0]
+       && !strcmp(auxprop_values[0].values[0], passwd)) {
+	/* We have a plaintext version and it matched! */
+	return SASL_OK;
+    } else if(auxprop_values[1].name
+	      && auxprop_values[1].values
+	      && auxprop_values[1].values[0]) {
+	const char *db_secret = auxprop_values[1].values[0];
+	sasl_secret_t *construct;
+	
+	ret = _sasl_make_plain_secret(db_secret, passwd,
+				      strlen(passwd),
+				      &construct);
+	if (ret != SASL_OK) {
+	    goto done;
+	}
+
+	if (!memcmp(db_secret, construct->data, construct->len)) {
+	    /* password verified! */
+	    ret = SASL_OK;
+	} else {
+	    /* passwords do not match */
+	    ret = SASL_BADAUTH;
+	}
+
+	sasl_FREE(construct);
+    } else {
+	/* passwords do not match */
+	ret = SASL_BADAUTH;
+    }
+
+    /* erase the plaintext password */
+    sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
+				      password_request[0]);
+
+ done:
+    /* We're not going to erase the property here because other people
+     * may want it */
+    return ret;
+}
+
+/* Verify user password using auxprop plugins. Allow verification against a hashed password,
+ * or non-retrievable password. Don't use cmusaslsecretPLAIN attribute.
+ *
+ * This function is similar to auxprop_verify_password().
+ */
+static int auxprop_verify_password_hashed(sasl_conn_t *conn,
+					  const char *userstr,
+					  const char *passwd,
+					  const char *service __attribute__((unused)),
+					  const char *user_realm __attribute__((unused)))
+{
+    int ret = SASL_FAIL;
+    int result = SASL_OK;
+    sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+    const char *password_request[] = { SASL_AUX_PASSWORD,
+				       NULL };
+    struct propval auxprop_values[2];
+    unsigned extra_cu_flags = 0;
+
+    if (!conn || !userstr)
+	return SASL_BADPARAM;
+
+    /* We need to clear any previous results and re-canonify to 
+     * ensure correctness */
+
+    prop_clear(sconn->sparams->propctx, 0);
+	
+    /* ensure its requested */
+    result = prop_request(sconn->sparams->propctx, password_request);
+
+    if (result != SASL_OK) return result;
+
+    /* We need to pass "password" down to the auxprop_lookup */
+    /* NB: We don't support binary passwords */
+    if (passwd != NULL) {
+	prop_set (sconn->sparams->propctx,
+		  SASL_AUX_PASSWORD,
+		  passwd,
+		  -1);
+	extra_cu_flags = SASL_CU_VERIFY_AGAINST_HASH;
+    }
+
+    result = _sasl_canon_user_lookup (conn,
+				      userstr,
+				      0,
+				      SASL_CU_AUTHID | SASL_CU_AUTHZID | extra_cu_flags,
+				      &(conn->oparams));
+
+    if (result != SASL_OK) return result;
+    
+    result = prop_getnames(sconn->sparams->propctx, password_request,
+			   auxprop_values);
+    if (result < 0) {
+	return result;
+    }
+
+    /* Verify that the returned <name>s are correct.
+       But we defer checking for NULL values till after we verify
+       that a passwd is specified. */
+    if (!auxprop_values[0].name && !auxprop_values[1].name) {
+	return SASL_NOUSER;
+    }
+        
+    /* It is possible for us to get useful information out of just
+     * the lookup, so we won't check that we have a password until now */
+    if (!passwd) {
+	ret = SASL_BADPARAM;
+	goto done;
+    }
+
+    if ((!auxprop_values[0].values || !auxprop_values[0].values[0])) {
+	return SASL_NOUSER;
+    }
+
+    /* At the point this has been called, the username has been canonified
+     * and we've done the auxprop lookup.  This should be easy. */
+
+    /* NB: Note that if auxprop_lookup failed to verify the password,
+       then the userPassword property value would be NULL */
+    if (auxprop_values[0].name
+        && auxprop_values[0].values
+        && auxprop_values[0].values[0]
+        && !strcmp(auxprop_values[0].values[0], passwd)) {
+	/* We have a plaintext version and it matched! */
+	return SASL_OK;
+    } else {
+	/* passwords do not match */
+	ret = SASL_BADAUTH;
+    }
+
+ done:
+    /* We're not going to erase the property here because other people
+     * may want it */
+    return ret;
+}
+
+#ifdef DO_SASL_CHECKAPOP
+int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
+			      const char *userstr,
+			      const char *challenge,
+			      const char *response,
+			      const char *user_realm __attribute__((unused)))
+{
+    int ret = SASL_BADAUTH;
+    char *userid = NULL;
+    char *realm = NULL;
+    unsigned char digest[16];
+    char digeststr[33];
+    const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
+    struct propval auxprop_values[2];
+    sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+    MD5_CTX ctx;
+    int i;
+
+    if (!conn || !userstr || !challenge || !response)
+       PARAMERROR(conn)
+
+    /* We've done the auxprop lookup already (in our caller) */
+    /* sadly, APOP has no provision for storing secrets */
+    ret = prop_getnames(sconn->sparams->propctx, password_request,
+			auxprop_values);
+    if(ret < 0) {
+	sasl_seterror(conn, 0, "could not perform password lookup");
+	goto done;
+    }
+    
+    if(!auxprop_values[0].name ||
+       !auxprop_values[0].values ||
+       !auxprop_values[0].values[0]) {
+	sasl_seterror(conn, 0, "could not find password");
+	ret = SASL_NOUSER;
+	goto done;
+    }
+    
+    _sasl_MD5Init(&ctx);
+    _sasl_MD5Update(&ctx, challenge, strlen(challenge));
+    _sasl_MD5Update(&ctx, auxprop_values[0].values[0],
+		    strlen(auxprop_values[0].values[0]));
+    _sasl_MD5Final(digest, &ctx);
+
+    /* erase the plaintext password */
+    sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
+				      password_request[0]);
+
+    /* convert digest from binary to ASCII hex */
+    for (i = 0; i < 16; i++)
+      sprintf(digeststr + (i*2), "%02x", digest[i]);
+
+    if (!strncasecmp(digeststr, response, 32)) {
+      /* password verified! */
+      ret = SASL_OK;
+    } else {
+      /* passwords do not match */
+      ret = SASL_BADAUTH;
+    }
+
+ done:
+    if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
+					   "login incorrect");
+    if (userid) sasl_FREE(userid);
+    if (realm)  sasl_FREE(realm);
+
+    return ret;
+}
+#endif /* DO_SASL_CHECKAPOP */
+
+#if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+/*
+ * Wait for file descriptor to be writable. Return with error if timeout.
+ */
+static int write_wait(int fd, unsigned delta)
+{
+    fd_set wfds;
+    fd_set efds;
+    struct timeval tv;
+
+    /* 
+     * Wait for file descriptor fd to be writable. Retry on
+     * interruptions. Return with error upon timeout.
+     */
+    while (1) {
+	FD_ZERO(&wfds);
+	FD_ZERO(&efds);
+	FD_SET(fd, &wfds);
+	FD_SET(fd, &efds);
+	tv.tv_sec = (long) delta;
+	tv.tv_usec = 0;
+	switch(select(fd + 1, 0, &wfds, &efds, &tv)) {
+	case 0:
+	    /* Timeout. */
+	    errno = ETIMEDOUT;
+	    return -1;
+	case +1:
+	    if (FD_ISSET(fd, &wfds)) {
+		/* Success, file descriptor is writable. */
+		return 0;
+	    }
+	    return -1;
+	case -1:
+	    if (errno == EINTR || errno == EAGAIN)
+		continue;
+	default:
+	    /* Error catch-all. */
+	    return -1;
+	}
+    }
+    /* Not reached. */
+    return -1;
+}
+
+/*
+ * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
+ * until all the data is written out or an error/timeout occurs.
+ */
+static int retry_writev(int fd, struct iovec *iov, int iovcnt, unsigned delta)
+{
+    int n;
+    int i;
+    int written = 0;
+    static int iov_max =
+#ifdef MAXIOV
+	MAXIOV
+#else
+#ifdef IOV_MAX
+	IOV_MAX
+#else
+	8192
+#endif
+#endif
+	;
+    
+    for (;;) {
+	while (iovcnt && iov[0].iov_len == 0) {
+	    iov++;
+	    iovcnt--;
+	}
+
+	if (!iovcnt) return written;
+
+	if (delta > 0) {
+	    if (write_wait(fd, delta))
+		return -1;
+	}
+	n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
+	if (n == -1) {
+	    if (errno == EINVAL && iov_max > 10) {
+		iov_max /= 2;
+		continue;
+	    }
+	    if (errno == EINTR) continue;
+	    return -1;
+	}
+
+	written += n;
+
+	for (i = 0; i < iovcnt; i++) {
+	    if ((int) iov[i].iov_len > n) {
+		iov[i].iov_base = (char *)iov[i].iov_base + n;
+		iov[i].iov_len -= n;
+		break;
+	    }
+	    n -= iov[i].iov_len;
+	    iov[i].iov_len = 0;
+	}
+
+	if (i == iovcnt) return written;
+    }
+}
+
+#endif
+
+#ifdef HAVE_PWCHECK
+/* pwcheck daemon-authenticated login */
+static int pwcheck_verify_password(sasl_conn_t *conn,
+				   const char *userid, 
+				   const char *passwd,
+				   const char *service __attribute__((unused)),
+				   const char *user_realm 
+				               __attribute__((unused)))
+{
+    int s;
+    struct sockaddr_un srvaddr;
+    int r;
+    struct iovec iov[10];
+    static char response[1024];
+    unsigned start, n;
+    char pwpath[1024];
+
+    if (strlen(PWCHECKDIR)+8+1 > sizeof(pwpath)) return SASL_FAIL;
+
+    strcpy(pwpath, PWCHECKDIR);
+    strcat(pwpath, "/pwcheck");
+
+    s = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) return errno;
+
+    memset((char *)&srvaddr, 0, sizeof(srvaddr));
+    srvaddr.sun_family = AF_UNIX;
+    strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
+    r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
+    if (r == -1) {
+	sasl_seterror(conn,0,"cannot connect to pwcheck server");
+	return SASL_FAIL;
+    }
+
+    iov[0].iov_base = (char *)userid;
+    iov[0].iov_len = strlen(userid)+1;
+    iov[1].iov_base = (char *)passwd;
+    iov[1].iov_len = strlen(passwd)+1;
+
+    retry_writev(s, iov, 2, 0);
+
+    start = 0;
+    while (start < sizeof(response) - 1) {
+	n = read(s, response+start, sizeof(response) - 1 - start);
+	if (n < 1) break;
+	start += n;
+    }
+
+    close(s);
+
+    if (start > 1 && !strncmp(response, "OK", 2)) {
+	return SASL_OK;
+    }
+
+    response[start] = '\0';
+    sasl_seterror(conn,0,response);
+    return SASL_BADAUTH;
+}
+
+#endif
+
+#if defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+static int read_wait(int fd, unsigned delta)
+{
+    fd_set rfds;
+    fd_set efds;
+    struct timeval tv;
+    /* 
+     * Wait for file descriptor fd to be readable. Retry on 
+     * interruptions. Return with error upon timeout.
+     */
+    while (1) {
+	FD_ZERO(&rfds);
+	FD_ZERO(&efds);
+	FD_SET(fd, &rfds);
+	FD_SET(fd, &efds);
+	tv.tv_sec = (long) delta;
+	tv.tv_usec = 0;
+	switch(select(fd + 1, &rfds, 0, &efds, &tv)) {
+	case 0:
+	    /* Timeout. */
+	    errno = ETIMEDOUT;
+	    return -1;
+	case +1:
+	    if (FD_ISSET(fd, &rfds)) {
+		/* Success, file descriptor is readable. */
+		return 0;
+	    }
+	    return -1;
+	case -1:
+	    if (errno == EINTR || errno == EAGAIN)
+		continue;
+	default:
+	    /* Error catch-all. */
+	    return -1;
+	}
+    }
+    /* Not reached. */
+    return -1;
+}
+
+/*
+ * Keep calling the read() system call until all the data is read in, 
+ * timeout, EOF, or an error occurs. This function returns the number 
+ * of useful bytes, or -1 if timeout/error.
+ */
+static int retry_read(int fd, void *buf0, unsigned nbyte, unsigned delta)
+{
+    int nr;
+    unsigned nleft = nbyte;
+    char *buf = (char*) buf0;
+    
+    while (nleft >= 1) {
+	if (delta > 0) {
+	    if (read_wait(fd, delta))
+		return -1;
+	}
+	nr = read(fd, buf, nleft);
+	if (nr < 0) {
+	    if (errno == EINTR || errno == EAGAIN)
+		continue;
+	    return -1;
+	} else if (nr == 0) {
+	    break;
+	}
+      buf += nr;
+      nleft -= nr;
+    }
+    return nbyte - nleft;
+}
+#endif
+
+#ifdef HAVE_SASLAUTHD
+/* saslauthd-authenticated login */
+static int saslauthd_verify_password(sasl_conn_t *conn,
+				     const char *userid, 
+				     const char *passwd,
+				     const char *service,
+				     const char *user_realm)
+{
+    char response[1024];
+    char query[8192];
+    char *query_end = query;
+    int s;
+    struct sockaddr_un srvaddr;
+    sasl_getopt_t *getopt;
+    void *context;
+    char pwpath[sizeof(srvaddr.sun_path)];
+    const char *p = NULL;
+    char *freeme = NULL;
+#ifdef USE_DOORS
+    door_arg_t arg;
+#endif
+
+    /* check to see if the user configured a rundir */
+    if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
+	getopt(context, NULL, "saslauthd_path", &p, NULL);
+    }
+    if (p) {
+	strncpy(pwpath, p, sizeof(pwpath));
+    } else {
+	if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
+	    return SASL_FAIL;
+
+	strcpy(pwpath, PATH_SASLAUTHD_RUNDIR);
+	strcat(pwpath, "/mux");
+    }
+
+    /* Split out username/realm if necessary */
+    if(strrchr(userid,'@') != NULL) {
+	char *rtmp;
+	
+	if(_sasl_strdup(userid, &freeme, NULL) != SASL_OK)
+	    goto fail;
+
+	userid = freeme;
+	rtmp = strrchr(userid,'@');
+	*rtmp = '\0';
+	user_realm = rtmp + 1;
+    }
+
+    /*
+     * build request of the form:
+     *
+     * count authid count password count service count realm
+     */
+    {
+ 	unsigned short max_len, req_len, u_len, p_len, s_len, r_len;
+ 
+	max_len = (unsigned short) sizeof(query);
+
+	/* prevent buffer overflow */
+	if ((strlen(userid) > USHRT_MAX) ||
+	    (strlen(passwd) > USHRT_MAX) ||
+	    (strlen(service) > USHRT_MAX) ||
+	    (user_realm && (strlen(user_realm) > USHRT_MAX))) {
+	    goto toobig;
+	}
+
+ 	u_len = (strlen(userid));
+ 	p_len = (strlen(passwd));
+	s_len = (strlen(service));
+	r_len = ((user_realm ? strlen(user_realm) : 0));
+
+	/* prevent buffer overflow */
+	req_len = 30;
+	if (max_len - req_len < u_len) goto toobig;
+	req_len += u_len;
+	if (max_len - req_len < p_len) goto toobig;
+	req_len += p_len;
+	if (max_len - req_len < s_len) goto toobig;
+	req_len += s_len;
+	if (max_len - req_len < r_len) goto toobig;
+
+	u_len = htons(u_len);
+	p_len = htons(p_len);
+	s_len = htons(s_len);
+	r_len = htons(r_len);
+
+	memcpy(query_end, &u_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	while (*userid) *query_end++ = *userid++;
+
+	memcpy(query_end, &p_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	while (*passwd) *query_end++ = *passwd++;
+
+	memcpy(query_end, &s_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	while (*service) *query_end++ = *service++;
+
+	memcpy(query_end, &r_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
+    }
+
+#ifdef USE_DOORS
+    s = open(pwpath, O_RDONLY);
+    if (s < 0) {
+	sasl_seterror(conn, 0, "cannot open door to saslauthd server: %m", errno);
+	goto fail;
+    }
+
+    arg.data_ptr = query;
+    arg.data_size = query_end - query;
+    arg.desc_ptr = NULL;
+    arg.desc_num = 0;
+    arg.rbuf = response;
+    arg.rsize = sizeof(response);
+
+    if (door_call(s, &arg) < 0) {
+      /* Parameters are undefined */
+      close(s);
+      sasl_seterror(conn, 0, "door call to saslauthd server failed: %m", errno);
+      goto fail;
+    }
+
+    if (arg.data_ptr != response || arg.data_size >= sizeof(response)) {
+	/* oh damn, we got back a really long response */
+	munmap(arg.rbuf, arg.rsize);
+	close(s);
+	sasl_seterror(conn, 0, "saslauthd sent an overly long response");
+	goto fail;
+    }
+    response[arg.data_size] = '\0';
+
+    close(s);
+#else
+    /* unix sockets */
+
+    s = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+	sasl_seterror(conn, 0, "cannot create socket for saslauthd: %m", errno);
+	goto fail;
+    }
+
+    memset((char *)&srvaddr, 0, sizeof(srvaddr));
+    srvaddr.sun_family = AF_UNIX;
+    strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
+
+    {
+	int r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
+	if (r == -1) {
+	    close(s);
+	    sasl_seterror(conn, 0, "cannot connect to saslauthd server: %m", errno);
+	    goto fail;
+	}
+    }
+
+    {
+ 	struct iovec iov[8];
+ 
+	iov[0].iov_len = query_end - query;
+	iov[0].iov_base = query;
+
+	if (retry_writev(s, iov, 1, 0) == -1) {
+	    close(s);
+            sasl_seterror(conn, 0, "write failed");
+	    goto fail;
+  	}
+    }
+
+    {
+	unsigned short count = 0;
+
+	/*
+	 * read response of the form:
+	 *
+	 * count result
+	 */
+	if (retry_read(s, &count, sizeof(count), 0) < (int) sizeof(count)) {
+	    sasl_seterror(conn, 0, "size read failed");
+	    goto fail;
+	}
+	
+	count = ntohs(count);
+	if (count < 2) { /* MUST have at least "OK" or "NO" */
+	    close(s);
+	    sasl_seterror(conn, 0, "bad response from saslauthd");
+	    goto fail;
+	}
+	
+	count = (int)sizeof(response) <= count ? sizeof(response) - 1 : count;
+	if (retry_read(s, response, count, 0) < count) {
+	    close(s);
+	    sasl_seterror(conn, 0, "read failed");
+	    goto fail;
+	}
+	response[count] = '\0';
+    }
+
+    close(s);
+#endif /* USE_DOORS */
+  
+    if(freeme) free(freeme);
+
+    if (!strncmp(response, "OK", 2)) {
+	return SASL_OK;
+    }
+  
+    sasl_seterror(conn, SASL_NOLOG, "authentication failed");
+    return SASL_BADAUTH;
+
+ toobig:
+    /* request just too damn big */
+    sasl_seterror(conn, 0, "saslauthd request too large");
+
+ fail:
+    if (freeme) free(freeme);
+    return SASL_FAIL;
+}
+
+#endif
+
+#ifdef HAVE_AUTHDAEMON
+/* 
+ * Preliminary support for Courier's authdaemond.
+ */
+#define AUTHDAEMON_IO_TIMEOUT 30
+
+static int authdaemon_blocking(int fd, int block)
+{
+    int f, r;
+
+    /* Get the fd's blocking bit. */
+    f = fcntl(fd, F_GETFL, 0);
+    if (f == -1)
+	return -1;
+
+    /* Adjust the bitmap accordingly. */
+#ifndef O_NONBLOCK
+#define NB_BITMASK FNDELAY
+#else
+#define NB_BITMASK O_NONBLOCK
+#endif
+    if (block)
+	f &= ~NB_BITMASK;
+    else
+	f |=  NB_BITMASK;
+#undef NB_BITMASK
+
+    /* Adjust the fd's blocking bit. */
+    r = fcntl(fd, F_SETFL, f);
+    if (r)
+	return -1;
+
+    /* Success. */
+    return 0;
+}
+
+static int authdaemon_connect(sasl_conn_t *conn, const char *path)
+{
+    int r, s = -1;
+    struct sockaddr_un srvaddr;
+
+    if (strlen(path) >= sizeof(srvaddr.sun_path)) {
+	sasl_seterror(conn, 0, "unix socket path too large", errno);
+	goto fail;
+    }
+
+    s = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+	sasl_seterror(conn, 0, "cannot create socket for connection to Courier authdaemond: %m", errno);
+	goto fail;
+    }
+
+    memset((char *)&srvaddr, 0, sizeof(srvaddr));
+    srvaddr.sun_family = AF_UNIX;
+    strncpy(srvaddr.sun_path, path, sizeof(srvaddr.sun_path) - 1);
+
+    /* Use nonblocking unix socket connect(2). */
+    if (authdaemon_blocking(s, 0)) {
+	sasl_seterror(conn, 0, "cannot set nonblocking bit: %m", errno);
+	goto fail;
+    }
+
+    r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
+    if (r == -1) {
+	sasl_seterror(conn, 0, "cannot connect to Courier authdaemond: %m", errno);
+	goto fail;
+    }
+
+    if (authdaemon_blocking(s, 1)) {
+	sasl_seterror(conn, 0, "cannot clear nonblocking bit: %m", errno);
+	goto fail;
+    }
+
+    return s;
+fail:
+    if (s >= 0)
+	close(s);
+    return -1;
+}
+
+static char *authdaemon_build_query(const char *service,
+				    const char *authtype,
+				    const char *user,
+				    const char *passwd)
+{
+    int sz;
+    int l = strlen(service) 
+            + 1
+            + strlen(authtype) 
+            + 1
+            + strlen(user)
+            + 1
+            + strlen(passwd) 
+            + 1;
+    char *buf, n[5];
+    if (snprintf(n, sizeof(n), "%d", l) >= (int)sizeof(n))
+	return NULL;
+    sz = strlen(n) + l + 20;
+    if (!(buf = sasl_ALLOC(sz)))
+	return NULL;
+    snprintf(buf, 
+             sz, 
+             "AUTH %s\n%s\n%s\n%s\n%s\n\n",
+             n,
+             service,
+             authtype,
+             user,
+             passwd);
+    return buf;
+}
+
+static int authdaemon_read(int fd, void *buf0, unsigned sz)
+{
+    int nr;
+    char *buf = (char*) buf0;
+    if (sz <= 1)
+	return -1;
+    if ((nr = retry_read(fd, buf0, sz - 1, AUTHDAEMON_IO_TIMEOUT)) < 0)
+	return -1;
+    /* We need a null-terminated buffer. */
+    buf[nr] = 0;
+    /* Check for overflow condition. */
+    return nr + 1 < (int)sz ? 0 : -1;
+}
+
+static int authdaemon_write(int fd, void *buf0, unsigned sz)
+{
+    int nw;
+    struct iovec io;
+    io.iov_len = sz;
+    io.iov_base = buf0;
+    nw = retry_writev(fd, &io, 1, AUTHDAEMON_IO_TIMEOUT);
+    return nw == (int)sz ? 0 : -1;
+}
+
+static int authdaemon_talk(sasl_conn_t *conn, int sock, char *authreq)
+{
+    char *str;
+    char buf[8192];
+
+    if (authdaemon_write(sock, authreq, strlen(authreq)))
+	goto _err_out;
+    if (authdaemon_read(sock, buf, sizeof(buf)))
+	goto _err_out;
+    for (str = buf; *str; ) {
+	char *sub;
+
+	for (sub = str; *str; ++str) {
+	    if (*str == '\n') {
+		*str++ = 0;
+		break;
+	    }
+	}
+	if (strcmp(sub, ".") == 0) {
+	    /* success */
+	    return SASL_OK;
+	}
+	if (strcmp(sub, "FAIL") == 0) {
+	    /* passwords do not match */
+	    sasl_seterror(conn, SASL_NOLOG, "authentication failed");
+	    return SASL_BADAUTH;
+	}
+    }
+_err_out:
+    /* catchall: authentication error */
+    sasl_seterror(conn, 0, "could not verify password");
+    return SASL_FAIL;
+}
+
+static int authdaemon_verify_password(sasl_conn_t *conn,
+				      const char *userid, 
+				      const char *passwd,
+				      const char *service,
+				      const char *user_realm __attribute__((unused)))
+{
+    const char *p = NULL;
+    sasl_getopt_t *getopt;
+    void *context;
+    int result = SASL_FAIL;
+    char *query = NULL;
+    int sock = -1;
+
+    /* check to see if the user configured a rundir */
+    if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
+	getopt(context, NULL, "authdaemond_path", &p, NULL);
+    }
+    if (!p) {
+	/*
+	 * XXX should we peek at Courier's build-time config ?
+	 */
+	p = PATH_AUTHDAEMON_SOCKET;
+    }
+
+    if ((sock = authdaemon_connect(conn, p)) < 0)
+	goto out;
+    if (!(query = authdaemon_build_query(service, "login", userid, passwd)))
+	goto out;
+    result = authdaemon_talk(conn, sock, query);
+out:
+    if (sock >= 0)
+	close(sock), sock = -1;
+    if (query)
+	sasl_FREE(query), query = 0;
+    return result;
+}
+#endif
+
+#ifdef HAVE_ALWAYSTRUE
+static int always_true(sasl_conn_t *conn,
+		       const char *userstr,
+		       const char *passwd __attribute__((unused)),
+		       const char *service __attribute__((unused)),
+		       const char *user_realm __attribute__((unused))) 
+{
+    _sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s",
+	      userstr);
+    return SASL_OK;
+}
+#endif
+
+struct sasl_verify_password_s _sasl_verify_password[] = {
+    { "auxprop", &auxprop_verify_password },
+    { "auxprop-hashed", &auxprop_verify_password_hashed },
+#ifdef HAVE_PWCHECK
+    { "pwcheck", &pwcheck_verify_password },
+#endif
+#ifdef HAVE_SASLAUTHD
+    { "saslauthd", &saslauthd_verify_password },
+#endif
+#ifdef HAVE_AUTHDAEMON
+    { "authdaemond", &authdaemon_verify_password },
+#endif
+#ifdef HAVE_ALWAYSTRUE
+    { "alwaystrue", &always_true },
+#endif
+    { NULL, NULL }
+};

+ 1349 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/client.c

@@ -0,0 +1,1349 @@
+/* SASL client API implementation
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: client.c,v 1.86 2011/09/01 14:12:53 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* SASL Headers */
+#include "sasl.h"
+#include "saslplug.h"
+#include "saslutil.h"
+#include "saslint.h"
+
+static cmech_list_t *cmechlist; /* global var which holds the list */
+static sasl_global_callbacks_t global_callbacks_client;
+static int _sasl_client_active = 0;
+
+static int init_mechlist()
+{
+  cmechlist->utils=_sasl_alloc_utils(NULL, &global_callbacks_client);
+  if (cmechlist->utils==NULL)
+    return SASL_NOMEM;
+
+  cmechlist->mech_list=NULL;
+  cmechlist->mech_length=0;
+
+  return SASL_OK;
+}
+
+int sasl_client_done(void)
+{
+    int result = SASL_CONTINUE;
+
+    if (_sasl_server_cleanup_hook == NULL && _sasl_client_cleanup_hook == NULL) {
+	return SASL_NOTINIT;
+    }
+
+    if (_sasl_client_cleanup_hook) {
+	result = _sasl_client_cleanup_hook();
+	
+	if (result == SASL_OK) {
+	    _sasl_client_idle_hook = NULL;	
+	    _sasl_client_cleanup_hook = NULL;
+	} else {
+	    return result;
+	}
+    }
+    
+    if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+	return result;
+    }
+    
+    sasl_common_done();
+
+    return SASL_OK;
+}
+
+static int client_done(void) {
+    cmechanism_t *cm;
+    cmechanism_t *cprevm;
+
+    if (!_sasl_client_active) {
+	return SASL_NOTINIT;
+    } else {
+	_sasl_client_active--;
+    }
+
+    if(_sasl_client_active) {
+	/* Don't de-init yet! Our refcount is nonzero. */
+	return SASL_CONTINUE;
+    }
+
+    cm = cmechlist->mech_list; /* m point to beginning of the list */
+    while (cm != NULL) {
+	cprevm = cm;
+	cm = cm->next;
+
+	if (cprevm->m.plug->mech_free) {
+	    cprevm->m.plug->mech_free(cprevm->m.plug->glob_context,
+				      cmechlist->utils);
+	}
+
+	sasl_FREE(cprevm->m.plugname);
+	sasl_FREE(cprevm);    
+    }
+    _sasl_free_utils(&cmechlist->utils);
+    sasl_FREE(cmechlist);
+
+    cmechlist = NULL;
+
+    return SASL_OK;
+}
+
+/* This is nearly identical to the version in server.c.
+   Keep in sync. */
+static int mech_compare(const sasl_client_plug_t *a,
+			const sasl_client_plug_t *b)
+{
+    unsigned sec_diff;
+    unsigned features_diff;
+
+    /* XXX  the following is fairly arbitrary, but its independent
+       of the order in which the plugins are loaded
+    */
+    sec_diff = a->security_flags ^ b->security_flags;
+    if (sec_diff & a->security_flags & SASL_SEC_NOANONYMOUS) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NOANONYMOUS) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_NOPLAINTEXT) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NOPLAINTEXT) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_MUTUAL_AUTH) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_MUTUAL_AUTH) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_NOACTIVE) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NOACTIVE) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_NODICTIONARY) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NODICTIONARY) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_FORWARD_SECRECY) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_FORWARD_SECRECY) return -1;
+
+    features_diff = a->features ^ b->features;
+    if (features_diff & a->features & SASL_FEAT_CHANNEL_BINDING) return 1;
+    if (features_diff & b->features & SASL_FEAT_CHANNEL_BINDING) return -1;
+
+    if (a->max_ssf > b->max_ssf) return 1;
+    if (a->max_ssf < b->max_ssf) return -1;
+  
+    return 0;
+}
+
+int sasl_client_add_plugin(const char *plugname,
+			   sasl_client_plug_init_t *entry_point)
+{
+    int plugcount;
+    sasl_client_plug_t *pluglist;
+    cmechanism_t *mech, *mp;
+    int result;
+    int version;
+    int lupe;
+
+    if (!plugname || !entry_point) return SASL_BADPARAM;
+
+    result = entry_point(cmechlist->utils,
+			 SASL_CLIENT_PLUG_VERSION,
+			 &version,
+			 &pluglist,
+			 &plugcount);
+
+    if (result != SASL_OK)
+    {
+	_sasl_log(NULL, SASL_LOG_WARN,
+		  "sasl_client_add_plugin(): entry_point(): failed for plugname %s: %z",
+		  plugname, result);
+	return result;
+    }
+
+    if (version != SASL_CLIENT_PLUG_VERSION)
+    {
+	_sasl_log(NULL, SASL_LOG_WARN,
+	      "version conflict in sasl_client_add_plugin for %s", plugname);
+	return SASL_BADVERS;
+    }
+
+    for (lupe=0; lupe < plugcount; lupe++, pluglist++)
+    {
+	mech = sasl_ALLOC(sizeof(cmechanism_t));
+	if (!mech) return SASL_NOMEM;
+
+	mech->m.plug = pluglist;
+	if (_sasl_strdup(plugname, &mech->m.plugname, NULL) != SASL_OK) {
+	    sasl_FREE(mech);
+	    return SASL_NOMEM;
+	}
+	mech->m.version = version;
+
+	/* sort mech_list by relative "strength" */
+	mp = cmechlist->mech_list;
+	if (!mp || mech_compare(pluglist, mp->m.plug) >= 0) {
+	    /* add mech to head of list */
+	    mech->next = cmechlist->mech_list;
+	    cmechlist->mech_list = mech;
+	} else {
+	    /* find where to insert mech into list */
+	    while (mp->next &&
+		   mech_compare(pluglist, mp->next->m.plug) <= 0) mp = mp->next;
+	    mech->next = mp->next;
+	    mp->next = mech;
+	}
+
+	cmechlist->mech_length++;
+    }
+
+    return SASL_OK;
+}
+
+static int
+client_idle(sasl_conn_t *conn)
+{
+  cmechanism_t *m;
+  if (! cmechlist)
+    return 0;
+
+  for (m = cmechlist->mech_list;
+       m;
+       m = m->next)
+    if (m->m.plug->idle
+	&&  m->m.plug->idle(m->m.plug->glob_context,
+			  conn,
+			  conn ? ((sasl_client_conn_t *)conn)->cparams : NULL))
+      return 1;
+  return 0;
+}
+
+/* initialize the SASL client drivers
+ *  callbacks      -- base callbacks for all client connections
+ * returns:
+ *  SASL_OK        -- Success
+ *  SASL_NOMEM     -- Not enough memory
+ *  SASL_BADVERS   -- Mechanism version mismatch
+ *  SASL_BADPARAM  -- error in config file
+ *  SASL_NOMECH    -- No mechanisms available
+ *  ...
+ */
+
+int sasl_client_init(const sasl_callback_t *callbacks)
+{
+  int ret;
+  const add_plugin_list_t ep_list[] = {
+      { "sasl_client_plug_init", (add_plugin_t *)sasl_client_add_plugin },
+      { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
+      { NULL, NULL }
+  };
+
+  /* lock allocation type */
+  _sasl_allocation_locked++;
+  
+  if(_sasl_client_active) {
+      /* We're already active, just increase our refcount */
+      /* xxx do something with the callback structure? */
+      _sasl_client_active++;
+      return SASL_OK;
+  }
+
+  global_callbacks_client.callbacks = callbacks;
+  global_callbacks_client.appname = NULL;
+
+  cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
+  if (cmechlist==NULL) return SASL_NOMEM;
+
+  /* We need to call client_done if we fail now */
+  _sasl_client_active = 1;
+
+  /* load plugins */
+  ret=init_mechlist();  
+  if (ret!=SASL_OK) {
+      client_done();
+      return ret;
+  }
+
+  sasl_client_add_plugin("EXTERNAL", &external_client_plug_init);
+
+  ret = _sasl_common_init(&global_callbacks_client);
+
+  if (ret == SASL_OK)
+      ret = _sasl_load_plugins(ep_list,
+			       _sasl_find_getpath_callback(callbacks),
+			       _sasl_find_verifyfile_callback(callbacks));
+  
+  if (ret == SASL_OK) {
+      _sasl_client_cleanup_hook = &client_done;
+      _sasl_client_idle_hook = &client_idle;
+
+      ret = _sasl_build_mechlist();
+  } else {
+      client_done();
+  }
+      
+  return ret;
+}
+
+static void client_dispose(sasl_conn_t *pconn)
+{
+  sasl_client_conn_t *c_conn=(sasl_client_conn_t *) pconn;
+
+  if (c_conn->mech && c_conn->mech->m.plug->mech_dispose) {
+    c_conn->mech->m.plug->mech_dispose(pconn->context,
+				     c_conn->cparams->utils);
+  }
+
+  pconn->context = NULL;
+
+  if (c_conn->clientFQDN)
+      sasl_FREE(c_conn->clientFQDN);
+
+  if (c_conn->cparams) {
+      _sasl_free_utils(&(c_conn->cparams->utils));
+      sasl_FREE(c_conn->cparams);
+  }
+
+  if (c_conn->mech_list != cmechlist->mech_list) {
+      /* free connection-specific mech_list */
+      cmechanism_t *m, *prevm;
+
+      m = c_conn->mech_list; /* m point to beginning of the list */
+
+      while (m) {
+	  prevm = m;
+	  m = m->next;
+	  sasl_FREE(prevm);    
+      }
+  }
+
+  _sasl_conn_dispose(pconn);
+}
+
+/* initialize a client exchange based on the specified mechanism
+ *  service       -- registered name of the service using SASL (e.g. "imap")
+ *  serverFQDN    -- the fully qualified domain name of the server
+ *  iplocalport   -- client IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  ipremoteport  -- server IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  prompt_supp   -- list of client interactions supported
+ *                   may also include sasl_getopt_t context & call
+ *                   NULL prompt_supp = user/pass via SASL_INTERACT only
+ *                   NULL proc = interaction supported via SASL_INTERACT
+ *  secflags      -- security flags (see above)
+ * in/out:
+ *  pconn         -- connection negotiation structure
+ *                   pointer to NULL => allocate new
+ *                   non-NULL => recycle storage and go for next available mech
+ *
+ * Returns:
+ *  SASL_OK       -- success
+ *  SASL_NOMECH   -- no mechanism meets requested properties
+ *  SASL_NOMEM    -- not enough memory
+ */
+int sasl_client_new(const char *service,
+		    const char *serverFQDN,
+		    const char *iplocalport,
+		    const char *ipremoteport,
+		    const sasl_callback_t *prompt_supp,
+		    unsigned flags,
+		    sasl_conn_t **pconn)
+{
+  int result;
+  char name[MAXHOSTNAMELEN];
+  sasl_client_conn_t *conn;
+  sasl_utils_t *utils;
+  sasl_getopt_t *getopt;
+  void *context;
+  const char *mlist = NULL;
+  int plus = 0;
+
+  if (_sasl_client_active == 0) return SASL_NOTINIT;
+  
+  /* Remember, serverFQDN, iplocalport and ipremoteport can be NULL and be valid! */
+  if (!pconn || !service)
+    return SASL_BADPARAM;
+
+  *pconn=sasl_ALLOC(sizeof(sasl_client_conn_t));
+  if (*pconn==NULL) {
+      _sasl_log(NULL, SASL_LOG_ERR,
+		"Out of memory allocating connection context");
+      return SASL_NOMEM;
+  }
+  memset(*pconn, 0, sizeof(sasl_client_conn_t));
+
+  (*pconn)->destroy_conn = &client_dispose;
+
+  conn = (sasl_client_conn_t *)*pconn;
+  
+  conn->mech = NULL;
+
+  conn->cparams=sasl_ALLOC(sizeof(sasl_client_params_t));
+  if (conn->cparams==NULL) 
+      MEMERROR(*pconn);
+  memset(conn->cparams,0,sizeof(sasl_client_params_t));
+
+  result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_CLIENT,
+			   &client_idle, serverFQDN,
+			   iplocalport, ipremoteport,
+			   prompt_supp, &global_callbacks_client);
+  if (result != SASL_OK) RETURN(*pconn, result);
+  
+  utils = _sasl_alloc_utils(*pconn, &global_callbacks_client);
+  if (utils == NULL) {
+      MEMERROR(*pconn);
+  }
+  
+  utils->conn= *pconn;
+  conn->cparams->utils = utils;
+
+  if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+    getopt(context, NULL, "client_mech_list", &mlist, NULL);
+  }
+
+  /* if we have a client_mech_list, create ordered list of
+     available mechanisms for this conn */
+  if (mlist) {
+      const char *cp;
+      cmechanism_t *mptr, *tail = NULL;
+      cmechanism_t *new;
+
+      while (*mlist) {
+	  /* find end of current mech name */
+	  for (cp = mlist; *cp && !isspace((int) *cp); cp++);
+
+	  /* search for mech name in loaded plugins */
+	  for (mptr = cmechlist->mech_list; mptr; mptr = mptr->next) {
+	      const sasl_client_plug_t *plug = mptr->m.plug;
+
+	      if (_sasl_is_equal_mech(mlist, plug->mech_name, (size_t) (cp - mlist), &plus)) {
+		  /* found a match */
+		  break;
+	      }
+	  }
+	  if (mptr) {
+	      new = sasl_ALLOC(sizeof(cmechanism_t));
+	      if (!new) {
+		  result = SASL_NOMEM;
+		  goto failed_client_new;
+	      }
+	      memcpy(&new->m, &mptr->m, sizeof(client_sasl_mechanism_t));
+	      new->next = NULL;
+
+	      if (!conn->mech_list) {
+		  conn->mech_list = new;
+		  tail = conn->mech_list;
+	      } else {
+		  tail->next = new;
+		  tail = new;
+	      }
+	      conn->mech_length++;
+	  }
+
+	  /* find next mech name */
+	  mlist = cp;
+	  while (*mlist && isspace((int) *mlist)) mlist++;
+      }
+  } else {
+      conn->mech_list = cmechlist->mech_list;
+      conn->mech_length = cmechlist->mech_length;
+  }
+
+  if (conn->mech_list == NULL) {
+      sasl_seterror(*pconn, 0, "No worthy mechs found");
+      result = SASL_NOMECH;
+      goto failed_client_new;
+  }
+
+  /* Setup the non-lazy parts of cparams, the rest is done in
+   * sasl_client_start */
+  conn->cparams->canon_user = &_sasl_canon_user_lookup;
+  conn->cparams->flags = flags;
+  conn->cparams->prompt_supp = (*pconn)->callbacks;
+  
+  /* get the clientFQDN (serverFQDN was set in _sasl_conn_init) */
+  memset(name, 0, sizeof(name));
+  if (get_fqhostname (name, MAXHOSTNAMELEN, 0) != 0) {
+      return (SASL_FAIL);
+  }
+
+  result = _sasl_strdup(name, &conn->clientFQDN, NULL);
+
+  if (result == SASL_OK) return SASL_OK;
+
+failed_client_new:
+  /* result isn't SASL_OK */
+  _sasl_conn_dispose(*pconn);
+  sasl_FREE(*pconn);
+  *pconn = NULL;
+  _sasl_log(NULL, SASL_LOG_ERR, "Out of memory in sasl_client_new");
+  return result;
+}
+
+static int have_prompts(sasl_conn_t *conn,
+			const sasl_client_plug_t *mech)
+{
+  static const unsigned long default_prompts[] = {
+    SASL_CB_AUTHNAME,
+    SASL_CB_PASS,
+    SASL_CB_LIST_END
+  };
+
+  const unsigned long *prompt;
+  sasl_callback_ft pproc;
+  void *pcontext;
+  int result;
+
+  for (prompt = (mech->required_prompts
+		 ? mech->required_prompts :
+		 default_prompts);
+       *prompt != SASL_CB_LIST_END;
+       prompt++) {
+    result = _sasl_getcallback(conn, *prompt, &pproc, &pcontext);
+    if (result != SASL_OK && result != SASL_INTERACT)
+      return 0;			/* we don't have this required prompt */
+  }
+
+  return 1; /* we have all the prompts */
+}
+
+static int
+_mech_plus_p(const char *mech, size_t len)
+{
+    return (len > 5 && strncasecmp(&mech[len - 5], "-PLUS", 5) == 0);
+}
+
+/*
+ * Order PLUS mechanisms first. Returns NUL separated list of
+ * *count items.
+ */
+static int
+_sasl_client_order_mechs(const sasl_utils_t *utils,
+			 const char *mechs,
+			 int has_cb_data,
+			 char **ordered_mechs,
+			 size_t *count,
+			 int *server_can_cb)
+{
+    char *list, *listp;
+    size_t i, mechslen, start;
+
+    *count = 0;
+    *server_can_cb = 0;
+
+    if (mechs == NULL || mechs[0] == '\0')
+        return SASL_NOMECH;
+
+    mechslen = strlen(mechs);
+
+    listp = list = utils->malloc(mechslen + 1);
+    if (list == NULL)
+	return SASL_NOMEM;
+
+    /* As per RFC 4422:
+     * SASL mechanism allowable characters are "AZ-_"
+     * separators can be any other characters and of any length
+     * even variable lengths between.
+     *
+     * But for convenience we accept lowercase ASCII.
+     *
+     * Apps should be encouraged to simply use space or comma space
+     * though
+     */
+#define ismechchar(c)   (isalnum((c)) || (c) == '_' || (c) == '-')
+    do {
+        for (i = start = 0; i <= mechslen; i++) {
+	    if (!ismechchar(mechs[i])) {
+                const char *mechp = &mechs[start];
+		size_t len = i - start;
+
+		if (len != 0 &&
+                    _mech_plus_p(mechp, len) == has_cb_data) {
+		    memcpy(listp, mechp, len);
+		    listp[len] = '\0';
+		    listp += len + 1;
+		    (*count)++;
+		    if (*server_can_cb == 0 && has_cb_data)
+			*server_can_cb = 1;
+		}
+		start = ++i;
+	    }
+	}
+	if (has_cb_data)
+	    has_cb_data = 0;
+	else
+	    break;
+    } while (1);
+
+    if (*count == 0) {
+        utils->free(list);
+        return SASL_NOMECH;
+    }
+
+    *ordered_mechs = list;
+
+    return SASL_OK;
+}
+
+static INLINE int
+_sasl_cbinding_disp(sasl_client_params_t *cparams,
+                    int mech_nego,
+                    int server_can_cb,
+                    sasl_cbinding_disp_t *cbindingdisp)
+{
+    /*
+     * If negotiating mechanisms, then we fail immediately if the
+     * client requires channel binding and the server does not
+     * advertise support. Otherwise we send "y" (which later will
+     * become "p" if we select a supporting mechanism).
+     *
+     * If the client explicitly selected a mechanism, then we only
+     * send channel bindings if they're marked critical.
+     */
+
+    *cbindingdisp = SASL_CB_DISP_NONE;
+
+    if (SASL_CB_PRESENT(cparams)) {
+        if (mech_nego) {
+	    if (!server_can_cb && SASL_CB_CRITICAL(cparams)) {
+	        return SASL_NOMECH;
+	    } else {
+                *cbindingdisp = SASL_CB_DISP_WANT;
+	    }
+        } else if (SASL_CB_CRITICAL(cparams)) {
+            *cbindingdisp = SASL_CB_DISP_USED;
+        }
+    }
+
+    return SASL_OK;
+}
+
+/* select a mechanism for a connection
+ *  mechlist      -- mechanisms server has available (punctuation ignored)
+ *  secret        -- optional secret from previous session
+ * output:
+ *  prompt_need   -- on SASL_INTERACT, list of prompts needed to continue
+ *  clientout     -- the initial client response to send to the server
+ *  mech          -- set to mechanism name
+ *
+ * Returns:
+ *  SASL_OK       -- success
+ *  SASL_NOMEM    -- not enough memory
+ *  SASL_NOMECH   -- no mechanism meets requested properties
+ *  SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ */
+
+/*
+ * SASL mechanism allowable characters are "AZ-_"
+ * separators can be any other characters and of any length
+ * even variable lengths between.
+ *
+ * But for convenience we accept lowercase ASCII.
+ *
+ * Apps should be encouraged to simply use space or comma space
+ * though
+ */
+int sasl_client_start(sasl_conn_t *conn,
+		      const char *mechlist,
+		      sasl_interact_t **prompt_need,
+		      const char **clientout,
+		      unsigned *clientoutlen,
+		      const char **mech)
+{
+    sasl_client_conn_t *c_conn = (sasl_client_conn_t *) conn;
+    char *ordered_mechs = NULL, *name;
+    cmechanism_t *m = NULL, *bestm = NULL;
+    size_t i, list_len, name_len;
+    sasl_ssf_t bestssf = 0, minssf = 0;
+    int result, server_can_cb = 0;
+    sasl_cbinding_disp_t cbindingdisp;
+    sasl_cbinding_disp_t cur_cbindingdisp;
+    sasl_cbinding_disp_t best_cbindingdisp = SASL_CB_DISP_NONE;
+
+    if (_sasl_client_active == 0) return SASL_NOTINIT;
+
+    if (!conn) return SASL_BADPARAM;
+
+    /* verify parameters */
+    if (mechlist == NULL) {
+	PARAMERROR(conn);
+    }
+
+    /* if prompt_need != NULL we've already been here
+       and just need to do the continue step again */
+
+    /* do a step */
+    /* FIXME: Hopefully they only give us our own prompt_need back */
+    if (prompt_need && *prompt_need != NULL) {
+	goto dostep;
+    }
+
+    if (conn->props.min_ssf < conn->external.ssf) {
+	minssf = 0;
+    } else {
+	minssf = conn->props.min_ssf - conn->external.ssf;
+    }
+
+    /* Order mechanisms so -PLUS are preferred */
+    result = _sasl_client_order_mechs(c_conn->cparams->utils,
+				      mechlist,
+				      SASL_CB_PRESENT(c_conn->cparams),
+				      &ordered_mechs,
+				      &list_len,
+				      &server_can_cb);
+    if (result != 0)
+	goto done;
+  
+    /*
+     * Determine channel binding disposition based on whether we
+     * are doing mechanism negotiation and whether server supports
+     * channel bindings.
+     */
+    result = _sasl_cbinding_disp(c_conn->cparams,
+				 (list_len > 1),
+                                 server_can_cb,
+				 &cbindingdisp);
+    if (result != 0)
+	goto done;
+
+    for (i = 0, name = ordered_mechs; i < list_len; i++) {
+
+	name_len = strlen(name);
+
+	/* for each mechanism in client's list */
+	for (m = c_conn->mech_list; m != NULL; m = m->next) {
+	    unsigned myflags;
+	    int plus;
+
+	    if (!_sasl_is_equal_mech(name, m->m.plug->mech_name, name_len, &plus)) {
+		continue;
+	    }
+
+	    /* Do we have the prompts for it? */
+	    if (!have_prompts(conn, m->m.plug))
+		break;
+
+	    /* Is it strong enough? */
+	    if (minssf > m->m.plug->max_ssf)
+		break;
+
+	    myflags = conn->props.security_flags;
+
+	    /* if there's an external layer with a better SSF then this is no
+	     * longer considered a plaintext mechanism
+	     */
+	    if ((conn->props.min_ssf <= conn->external.ssf) && 
+		(conn->external.ssf > 1)) {
+		myflags &= ~SASL_SEC_NOPLAINTEXT;
+	    }
+
+	    /* Does it meet our security properties? */
+	    if (((myflags ^ m->m.plug->security_flags) & myflags) != 0) {
+		break;
+	    }
+
+	    /* Can we meet it's features? */
+	    if (cbindingdisp == SASL_CB_DISP_USED &&
+		!(m->m.plug->features & SASL_FEAT_CHANNEL_BINDING)) {
+		break;
+	    }
+
+	    if ((m->m.plug->features & SASL_FEAT_NEEDSERVERFQDN)
+		&& !conn->serverFQDN) {
+		break;
+	    }
+
+	    /* Can it meet our features? */
+	    if ((conn->flags & SASL_NEED_PROXY) &&
+		!(m->m.plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+		break;
+	    }
+
+	    if ((conn->flags & SASL_NEED_HTTP) &&
+		!(m->m.plug->features & SASL_FEAT_SUPPORTS_HTTP)) {
+		break;
+	    }
+
+	    /* compare security flags, only take new mechanism if it has
+	     * all the security flags of the previous one.
+	     *
+	     * From the mechanisms we ship with, this yields the order:
+	     *
+	     * SRP
+	     * GSSAPI + KERBEROS_V4
+	     * DIGEST + OTP
+	     * CRAM + EXTERNAL
+	     * PLAIN + LOGIN + ANONYMOUS
+	     *
+	     * This might be improved on by comparing the numeric value of
+	     * the bitwise-or'd security flags, which splits DIGEST/OTP,
+	     * CRAM/EXTERNAL, and PLAIN/LOGIN from ANONYMOUS, but then we
+	     * are depending on the numeric values of the flags (which may
+	     * change, and their ordering could be considered dumb luck.
+	     */
+
+	    if (bestm &&
+		((m->m.plug->security_flags ^ bestm->m.plug->security_flags) &
+		 bestm->m.plug->security_flags)) {
+		break;
+	    }
+
+	    if (SASL_CB_PRESENT(c_conn->cparams) && plus) {
+		cur_cbindingdisp = SASL_CB_DISP_USED;
+	    } else {
+		cur_cbindingdisp = cbindingdisp;
+	    }
+
+	    if (bestm && (best_cbindingdisp > cur_cbindingdisp)) {
+		break;
+	    }
+
+#ifdef PREFER_MECH
+	    if (strcasecmp(m->m.plug->mech_name, PREFER_MECH) &&
+		bestm && m->m.plug->max_ssf <= bestssf) {
+		/* this mechanism isn't our favorite, and it's no better
+		   than what we already have! */
+		break;
+	    }
+#else
+	    if (bestm && m->m.plug->max_ssf <= bestssf) {
+		/* this mechanism is no better than what we already have! */
+		break;
+	    }
+#endif
+
+	    if (mech) {
+		*mech = m->m.plug->mech_name;
+	    }
+
+	    best_cbindingdisp = cur_cbindingdisp;
+	    bestssf = m->m.plug->max_ssf;
+	    bestm = m;
+	    break;
+	}
+	name += strlen(name) + 1;
+    }
+
+    if (bestm == NULL) {
+	sasl_seterror(conn, 0, "No worthy mechs found");
+	result = SASL_NOMECH;
+	goto done;
+    }
+
+    /* make (the rest of) cparams */
+    c_conn->cparams->service = conn->service;
+    c_conn->cparams->servicelen = (unsigned) strlen(conn->service);
+    
+    if (conn->serverFQDN) {
+	c_conn->cparams->serverFQDN = conn->serverFQDN; 
+	c_conn->cparams->slen = (unsigned) strlen(conn->serverFQDN);
+    }
+
+    c_conn->cparams->clientFQDN = c_conn->clientFQDN; 
+    c_conn->cparams->clen = (unsigned) strlen(c_conn->clientFQDN);
+
+    c_conn->cparams->external_ssf = conn->external.ssf;
+    c_conn->cparams->props = conn->props;
+    c_conn->cparams->cbindingdisp = best_cbindingdisp;
+    c_conn->mech = bestm;
+
+    /* init that plugin */
+    result = c_conn->mech->m.plug->mech_new(c_conn->mech->m.plug->glob_context,
+					  c_conn->cparams,
+					  &(conn->context));
+    if (result != SASL_OK) goto done;
+
+    /* do a step -- but only if we can do a client-send-first */
+ dostep:
+    if(clientout) {
+        if(c_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) {
+            *clientout = NULL;
+            *clientoutlen = 0;
+            result = SASL_CONTINUE;
+        } else {
+            result = sasl_client_step(conn, NULL, 0, prompt_need,
+                                      clientout, clientoutlen);
+        }
+    }
+    else
+	result = SASL_CONTINUE;
+
+ done:
+    if (ordered_mechs != NULL)
+	c_conn->cparams->utils->free(ordered_mechs);
+    RETURN(conn, result);
+}
+
+/* do a single authentication step.
+ *  serverin    -- the server message received by the client, MUST have a NUL
+ *                 sentinel, not counted by serverinlen
+ * output:
+ *  prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ *  clientout   -- the client response to send to the server
+ *
+ * returns:
+ *  SASL_OK        -- success
+ *  SASL_INTERACT  -- user interaction needed to fill in prompt_need list
+ *  SASL_BADPROT   -- server protocol incorrect/cancelled
+ *  SASL_BADSERV   -- server failed mutual auth
+ */
+
+int sasl_client_step(sasl_conn_t *conn,
+		     const char *serverin,
+		     unsigned serverinlen,
+		     sasl_interact_t **prompt_need,
+		     const char **clientout,
+		     unsigned *clientoutlen)
+{
+  sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
+  int result;
+
+  if (_sasl_client_active == 0) return SASL_NOTINIT;
+  if (!conn) return SASL_BADPARAM;
+
+  /* check parameters */
+  if ((serverin==NULL) && (serverinlen>0))
+      PARAMERROR(conn);
+
+  /* Don't do another step if the plugin told us that we're done */
+  if (conn->oparams.doneflag) {
+      _sasl_log(conn, SASL_LOG_ERR, "attempting client step after doneflag");
+      return SASL_FAIL;
+  }
+
+  if(clientout) *clientout = NULL;
+  if(clientoutlen) *clientoutlen = 0;
+
+  /* do a step */
+  result = c_conn->mech->m.plug->mech_step(conn->context,
+					 c_conn->cparams,
+					 serverin,
+					 serverinlen,
+					 prompt_need,
+					 clientout, clientoutlen,
+					 &conn->oparams);
+
+  if (result == SASL_OK) {
+      /* So we're done on this end, but if both
+       * 1. the mech does server-send-last
+       * 2. the protocol does not
+       * we need to return no data */
+      if(!*clientout && !(conn->flags & SASL_SUCCESS_DATA)) {
+	  *clientout = "";
+	  *clientoutlen = 0;
+      }
+      
+      if(!conn->oparams.maxoutbuf) {
+	  conn->oparams.maxoutbuf = conn->props.maxbufsize;
+      }
+
+      if(conn->oparams.user == NULL || conn->oparams.authid == NULL) {
+	  sasl_seterror(conn, 0,
+			"mech did not call canon_user for both authzid and authid");
+	  result = SASL_BADPROT;
+      }
+  }  
+
+  RETURN(conn,result);
+}
+
+/* returns the length of all the mechanisms
+ * added up 
+ */
+
+static unsigned mech_names_len(cmechanism_t *mech_list)
+{
+  cmechanism_t *listptr;
+  unsigned result = 0;
+
+  for (listptr = mech_list;
+       listptr;
+       listptr = listptr->next)
+    result += (unsigned) strlen(listptr->m.plug->mech_name);
+
+  return result;
+}
+
+
+int _sasl_client_listmech(sasl_conn_t *conn,
+			  const char *prefix,
+			  const char *sep,
+			  const char *suffix,
+			  const char **result,
+			  unsigned *plen,
+			  int *pcount)
+{
+    sasl_client_conn_t *c_conn = (sasl_client_conn_t *)conn;
+    cmechanism_t *m = NULL;
+    sasl_ssf_t minssf = 0;
+    int ret;
+    size_t resultlen;
+    int flag;
+    const char *mysep;
+
+    if (_sasl_client_active == 0) return SASL_NOTINIT;
+    if (!conn) return SASL_BADPARAM;
+    if (conn->type != SASL_CONN_CLIENT) PARAMERROR(conn);
+    
+    if (! result)
+	PARAMERROR(conn);
+    
+    if (plen != NULL)
+	*plen = 0;
+    if (pcount != NULL)
+	*pcount = 0;
+
+    if (sep) {
+	mysep = sep;
+    } else {
+	mysep = " ";
+    }
+
+    if (conn->props.min_ssf < conn->external.ssf) {
+	minssf = 0;
+    } else {
+	minssf = conn->props.min_ssf - conn->external.ssf;
+    }
+
+    if (!c_conn->mech_list || c_conn->mech_length <= 0) {
+	INTERROR(conn, SASL_NOMECH);
+    }
+
+    resultlen = (prefix ? strlen(prefix) : 0)
+	+ (strlen(mysep) * (c_conn->mech_length - 1))
+	+ mech_names_len(c_conn->mech_list)
+	+ (suffix ? strlen(suffix) : 0)
+	+ 1;
+    ret = _buf_alloc(&conn->mechlist_buf,
+		     &conn->mechlist_buf_len,
+		     resultlen);
+    if (ret != SASL_OK) MEMERROR(conn);
+
+    if (prefix) {
+	strcpy (conn->mechlist_buf,prefix);
+    } else {
+	*(conn->mechlist_buf) = '\0';
+    }
+
+    flag = 0;
+    for (m = c_conn->mech_list; m != NULL; m = m->next) {
+	    /* do we have the prompts for it? */
+	    if (!have_prompts(conn, m->m.plug)) {
+		continue;
+	    }
+
+	    /* is it strong enough? */
+	    if (minssf > m->m.plug->max_ssf) {
+		continue;
+	    }
+
+	    /* does it meet our security properties? */
+	    if (((conn->props.security_flags ^ m->m.plug->security_flags)
+		 & conn->props.security_flags) != 0) {
+		continue;
+	    }
+
+	    /* Can we meet it's features? */
+	    if ((m->m.plug->features & SASL_FEAT_NEEDSERVERFQDN)
+		&& !conn->serverFQDN) {
+		continue;
+	    }
+
+	    /* Can it meet our features? */
+	    if ((conn->flags & SASL_NEED_PROXY) &&
+		!(m->m.plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+		continue;
+	    }
+
+	    /* Okay, we like it, add it to the list! */
+
+	    if (pcount != NULL)
+		(*pcount)++;
+
+	    /* print seperator */
+	    if (flag) {
+		strcat(conn->mechlist_buf, mysep);
+	    } else {
+		flag = 1;
+	    }
+	    
+	    /* now print the mechanism name */
+	    strcat(conn->mechlist_buf, m->m.plug->mech_name);
+    }
+    
+  if (suffix)
+      strcat(conn->mechlist_buf,suffix);
+
+  if (plen!=NULL)
+      *plen = (unsigned) strlen(conn->mechlist_buf);
+
+  *result = conn->mechlist_buf;
+
+  return SASL_OK;
+}
+
+sasl_string_list_t *_sasl_client_mechs(void) 
+{
+  cmechanism_t *listptr;
+  sasl_string_list_t *retval = NULL, *next=NULL;
+
+  if(!_sasl_client_active) return NULL;
+
+  /* make list */
+  for (listptr = cmechlist->mech_list; listptr; listptr = listptr->next) {
+      next = sasl_ALLOC(sizeof(sasl_string_list_t));
+
+      if(!next && !retval) return NULL;
+      else if(!next) {
+	  next = retval->next;
+	  do {
+	      sasl_FREE(retval);
+	      retval = next;
+	      next = retval->next;
+	  } while(next);
+	  return NULL;
+      }
+      
+      next->d = listptr->m.plug->mech_name;
+
+      if(!retval) {
+	  next->next = NULL;
+	  retval = next;
+      } else {
+	  next->next = retval;
+	  retval = next;
+      }
+  }
+
+  return retval;
+}
+
+
+
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (
+  client_sasl_mechanism_t *m,
+  sasl_info_callback_stage_t stage,
+  void *rock __attribute__((unused))
+)
+{
+    char delimiter;
+
+    if (stage == SASL_INFO_LIST_START) {
+	printf ("List of client plugins follows\n");
+	return;
+    } else if (stage == SASL_INFO_LIST_END) {
+	return;
+    }
+
+    /* Process the mechanism */
+    printf ("Plugin \"%s\" ", m->plugname);
+
+    /* There is no delay loading for client side plugins */
+    printf ("[loaded]");
+
+    printf (", \tAPI version: %d\n", m->version);
+
+    if (m->plug != NULL) {
+	printf ("\tSASL mechanism: %s, best SSF: %d\n",
+		m->plug->mech_name,
+		m->plug->max_ssf);
+
+	printf ("\tsecurity flags:");
+	
+	delimiter = ' ';
+	if (m->plug->security_flags & SASL_SEC_NOANONYMOUS) {
+	    printf ("%cNO_ANONYMOUS", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_NOPLAINTEXT) {
+	    printf ("%cNO_PLAINTEXT", delimiter);
+	    delimiter = '|';
+	}
+	
+	if (m->plug->security_flags & SASL_SEC_NOACTIVE) {
+	    printf ("%cNO_ACTIVE", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_NODICTIONARY) {
+	    printf ("%cNO_DICTIONARY", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_FORWARD_SECRECY) {
+	    printf ("%cFORWARD_SECRECY", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_PASS_CREDENTIALS) {
+	    printf ("%cPASS_CREDENTIALS", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_MUTUAL_AUTH) {
+	    printf ("%cMUTUAL_AUTH", delimiter);
+	    delimiter = '|';
+	}
+
+
+
+	printf ("\n\tfeatures:");
+	
+	delimiter = ' ';
+	if (m->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
+	    printf ("%cWANT_CLIENT_FIRST", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_SERVER_FIRST) {
+	    printf ("%cSERVER_FIRST", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_ALLOWS_PROXY) {
+	    printf ("%cPROXY_AUTHENTICATION", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_NEEDSERVERFQDN) {
+	    printf ("%cNEED_SERVER_FQDN", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+	    printf ("%cGSS_FRAMING", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+	    printf ("%cCHANNEL_BINDING", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_SUPPORTS_HTTP) {
+	    printf ("%cSUPPORTS_HTTP", delimiter);
+	    delimiter = '|';
+	}
+    }
+
+/* Delay loading is not supported for the client side plugins:
+    if (m->f) {
+	printf ("\n\twill be loaded from \"%s\"", m->f);
+    }
+ */
+
+    printf ("\n");
+}
+
+
+/* Dump information about available client plugins */
+int sasl_client_plugin_info (
+  const char *c_mech_list,		/* space separated mechanism list or NULL for ALL */
+  sasl_client_info_callback_t *info_cb,
+  void *info_cb_rock
+)
+{
+    cmechanism_t *m;
+    client_sasl_mechanism_t plug_data;
+    char * cur_mech;
+    char * mech_list = NULL;
+    char * p;
+
+    if (info_cb == NULL) {
+	info_cb = _sasl_print_mechanism;
+    }
+
+    if (cmechlist != NULL) {
+	info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+	if (c_mech_list == NULL) {
+	    m = cmechlist->mech_list; /* m point to beginning of the list */
+
+	    while (m != NULL) {
+		memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+		info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+	    
+		m = m->next;
+	    }
+	} else {
+            mech_list = strdup (c_mech_list);
+
+	    cur_mech = mech_list;
+
+	    while (cur_mech != NULL) {
+		p = strchr (cur_mech, ' ');
+		if (p != NULL) {
+		    *p = '\0';
+		    p++;
+		}
+
+		m = cmechlist->mech_list; /* m point to beginning of the list */
+
+		while (m != NULL) {
+		    if (strcasecmp (cur_mech, m->m.plug->mech_name) == 0) {
+			memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+			info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+		    }
+	    
+		    m = m->next;
+		}
+
+		cur_mech = p;
+	    }
+
+            free (mech_list);
+	}
+
+	info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
+
+	return (SASL_OK);
+    }
+
+    return (SASL_NOTINIT);
+}

+ 2622 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/common.c

@@ -0,0 +1,2622 @@
+/* common.c - Functions that are common to server and clinet
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: common.c,v 1.134 2011/09/22 14:40:30 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef HAVE_SYSLOG
+#include <syslog.h>
+#endif
+#include <stdarg.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+static const char *implementation_string = "Cyrus SASL";
+
+#define	VSTR0(maj, min, step)	#maj "." #min "." #step
+#define	VSTR(maj, min, step)	VSTR0(maj, min, step)
+#define	SASL_VERSION_STRING	VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
+				SASL_VERSION_STEP)
+
+static int _sasl_getpath(void *context __attribute__((unused)), const char **path);
+static int _sasl_getpath_simple(void *context __attribute__((unused)), const char **path);
+static int _sasl_getconfpath(void *context __attribute__((unused)), char ** path);
+static int _sasl_getconfpath_simple(void *context __attribute__((unused)), const char **path);
+
+#if !defined(WIN32)
+static char * _sasl_get_default_unix_path(void *context __attribute__((unused)),
+                            char * env_var_name, char * default_value);
+#else
+/* NB: Always returned allocated value */
+static char * _sasl_get_default_win_path(void *context __attribute__((unused)),
+                            char * reg_attr_name, char * default_value);
+#endif
+
+
+static const char build_ident[] = "$Build: libsasl " PACKAGE "-" VERSION " $";
+
+/* It turns out to be convenient to have a shared sasl_utils_t */
+const sasl_utils_t *sasl_global_utils = NULL;
+
+/* Should be a null-terminated array that lists the available mechanisms */
+static char **global_mech_list = NULL;
+
+void *free_mutex = NULL;
+
+int (*_sasl_client_cleanup_hook)(void) = NULL;
+int (*_sasl_server_cleanup_hook)(void) = NULL;
+int (*_sasl_client_idle_hook)(sasl_conn_t *conn) = NULL;
+int (*_sasl_server_idle_hook)(sasl_conn_t *conn) = NULL;
+
+sasl_allocation_utils_t _sasl_allocation_utils={
+  (sasl_malloc_t *)  &malloc,
+  (sasl_calloc_t *)  &calloc,
+  (sasl_realloc_t *) &realloc,
+  (sasl_free_t *) &free
+};
+int _sasl_allocation_locked = 0;
+
+#define SASL_ENCODEV_EXTRA  4096
+
+/* Default getpath/getconfpath callbacks. These can be edited by sasl_set_path(). */
+static sasl_callback_t default_getpath_cb = {
+    SASL_CB_GETPATH, (sasl_callback_ft)&_sasl_getpath, NULL
+};
+static sasl_callback_t default_getconfpath_cb = {
+    SASL_CB_GETCONFPATH, (sasl_callback_ft)&_sasl_getconfpath, NULL
+};
+
+static char * default_plugin_path = NULL;
+static char * default_conf_path = NULL;
+
+static int _sasl_global_getopt(void *context,
+			       const char *plugin_name,
+			       const char *option,
+			       const char ** result,
+			       unsigned *len);
+ 
+/* Intenal mutex functions do as little as possible (no thread protection) */
+static void *sasl_mutex_alloc(void)
+{
+  return (void *)0x1;
+}
+
+static int sasl_mutex_lock(void *mutex __attribute__((unused)))
+{
+    return SASL_OK;
+}
+
+static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
+{
+    return SASL_OK;
+}
+
+static void sasl_mutex_free(void *mutex __attribute__((unused)))
+{
+    return;
+}
+
+sasl_mutex_utils_t _sasl_mutex_utils={
+  &sasl_mutex_alloc,
+  &sasl_mutex_lock,
+  &sasl_mutex_unlock,
+  &sasl_mutex_free
+};
+
+void sasl_set_mutex(sasl_mutex_alloc_t *n,
+		    sasl_mutex_lock_t *l,
+		    sasl_mutex_unlock_t *u,
+		    sasl_mutex_free_t *d)
+{
+    /* Disallow mutex function changes once sasl_client_init
+       and/or sasl_server_init is called */
+    if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+	return;
+    }
+
+    _sasl_mutex_utils.alloc=n;
+    _sasl_mutex_utils.lock=l;
+    _sasl_mutex_utils.unlock=u;
+    _sasl_mutex_utils.free=d;
+}
+
+/* copy a string to malloced memory */
+int _sasl_strdup(const char *in, char **out, size_t *outlen)
+{
+  size_t len = strlen(in);
+  if (outlen) *outlen = len;
+  *out=sasl_ALLOC((unsigned) len + 1);
+  if (! *out) return SASL_NOMEM;
+  strcpy((char *) *out, in);
+  return SASL_OK;
+}
+
+/* adds a string to the buffer; reallocing if need be */
+int _sasl_add_string(char **out, size_t *alloclen,
+		     size_t *outlen, const char *add)
+{
+  size_t addlen;
+
+  if (add==NULL) add = "(null)";
+
+  addlen=strlen(add); /* only compute once */
+  if (_buf_alloc(out, alloclen, (*outlen)+addlen)!=SASL_OK)
+    return SASL_NOMEM;
+
+  strncpy(*out + *outlen, add, addlen);
+  *outlen += addlen;
+
+  return SASL_OK;
+}
+
+/* a simpler way to set plugin path or configuration file path
+ * without the need to set sasl_getpath_t callback.
+ *
+ * This function can be called before sasl_server_init/sasl_client_init.
+ *
+ * Don't call this function without locking in a multithreaded application.
+ */  
+int sasl_set_path (int path_type, char * path)
+{
+    int result;
+
+    if (path == NULL) {
+        return (SASL_FAIL);
+    }
+
+    switch (path_type) {
+        case SASL_PATH_TYPE_PLUGIN:
+            if (default_plugin_path != NULL) {
+                sasl_FREE (default_plugin_path);
+                default_plugin_path = NULL;
+            }
+            result = _sasl_strdup (path, &default_plugin_path, NULL);
+            if (result != SASL_OK) {
+                return (result);
+            }
+
+            /* Update the default getpath_t callback */
+            default_getpath_cb.proc = (sasl_callback_ft)&_sasl_getpath_simple;
+            break;
+
+        case SASL_PATH_TYPE_CONFIG:
+            if (default_conf_path != NULL) {
+                sasl_FREE (default_conf_path);
+                default_conf_path = NULL;
+            }
+            result = _sasl_strdup (path, &default_conf_path, NULL);
+            if (result != SASL_OK) {
+                return (result);
+            }
+
+            /* Update the default getpath_t callback */
+            default_getconfpath_cb.proc = (sasl_callback_ft)&_sasl_getconfpath_simple;
+            break;
+
+        default:
+            return (SASL_FAIL);
+    }
+
+    return (SASL_OK);
+}
+
+/* return the version of the cyrus sasl library as compiled,
+ * using 32 bits: high byte is major version, second byte is minor version,
+ * low 16 bits are step #.
+ * Patch version is not available using this function,
+ * use sasl_version_info() instead.
+ */
+void sasl_version(const char **implementation, int *version) 
+{
+    if(implementation) *implementation = implementation_string;
+    /* NB: the format is not the same as in SASL_VERSION_FULL */
+    if(version) *version = (SASL_VERSION_MAJOR << 24) | 
+		           (SASL_VERSION_MINOR << 16) |
+		           (SASL_VERSION_STEP);
+}
+
+/* Extended version of sasl_version above */
+void sasl_version_info (const char **implementation, const char **version_string,
+		    int *version_major, int *version_minor, int *version_step,
+		    int *version_patch)
+{
+    if (implementation) *implementation = implementation_string;
+    if (version_string) *version_string = SASL_VERSION_STRING;
+    if (version_major) *version_major = SASL_VERSION_MAJOR;
+    if (version_minor) *version_minor = SASL_VERSION_MINOR;
+    if (version_step) *version_step = SASL_VERSION_STEP;
+    /* Version patch is always 0 for CMU SASL */
+    if (version_patch) *version_patch = 0;
+}
+
+/* security-encode a regular string.  Mostly a wrapper for sasl_encodev */
+/* output is only valid until next call to sasl_encode or sasl_encodev */
+int sasl_encode(sasl_conn_t *conn, const char *input,
+		unsigned inputlen,
+		const char **output, unsigned *outputlen)
+{
+    int result;
+    struct iovec tmp;
+
+    if(!conn) return SASL_BADPARAM;
+    if(!input || !inputlen || !output || !outputlen)
+	PARAMERROR(conn);
+    
+    /* maxoutbuf checking is done in sasl_encodev */
+
+    /* Note: We are casting a const pointer here, but it's okay
+     * because we believe people downstream of us are well-behaved, and the
+     * alternative is an absolute mess, performance-wise. */
+    tmp.iov_base = (void *)input;
+    tmp.iov_len = inputlen;
+    
+    result = sasl_encodev(conn, &tmp, 1, output, outputlen);
+
+    RETURN(conn, result);
+}
+
+/* Internal function that doesn't do any verification */
+static int
+_sasl_encodev (sasl_conn_t *conn,
+	       const struct iovec *invec,
+               unsigned numiov,
+               int * p_num_packets,     /* number of packets generated so far */
+	       const char **output,     /* previous output, if *p_num_packets > 0 */
+               unsigned *outputlen)
+{
+    int result;
+    char * new_buf;
+
+    assert (conn->oparams.encode != NULL);
+
+    if (*p_num_packets == 1) {
+        /* This is the second call to this function,
+           so we need to allocate a new output buffer
+           and copy existing data there. */
+        conn->multipacket_encoded_data.curlen = *outputlen;
+        if (conn->multipacket_encoded_data.data == NULL) {
+            conn->multipacket_encoded_data.reallen = 
+                 conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
+            conn->multipacket_encoded_data.data =
+                 sasl_ALLOC(conn->multipacket_encoded_data.reallen + 1);
+
+            if (conn->multipacket_encoded_data.data == NULL) {
+                MEMERROR(conn);
+            }
+        } else {
+            /* A buffer left from a previous sasl_encodev call.
+               Make sure it is big enough. */
+            if (conn->multipacket_encoded_data.curlen >
+                conn->multipacket_encoded_data.reallen) {
+                conn->multipacket_encoded_data.reallen = 
+                    conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
+
+	        new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
+                            conn->multipacket_encoded_data.reallen + 1);
+                if (new_buf == NULL) {
+                    MEMERROR(conn);
+                }
+                conn->multipacket_encoded_data.data = new_buf;
+            }
+        }
+
+        memcpy (conn->multipacket_encoded_data.data,
+                *output,
+                *outputlen);
+    }
+
+    result = conn->oparams.encode(conn->context,
+                                  invec,
+                                  numiov,
+				  output,
+                                  outputlen);
+
+    if (*p_num_packets > 0 && result == SASL_OK) {
+        /* Is the allocated buffer big enough? If not, grow it. */
+        if ((conn->multipacket_encoded_data.curlen + *outputlen) >
+             conn->multipacket_encoded_data.reallen) {
+            conn->multipacket_encoded_data.reallen =
+                conn->multipacket_encoded_data.curlen + *outputlen;
+	    new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
+                        conn->multipacket_encoded_data.reallen + 1);
+            if (new_buf == NULL) {
+                MEMERROR(conn);
+            }
+            conn->multipacket_encoded_data.data = new_buf;
+        }
+
+        /* Append new data to the end of the buffer */
+        memcpy (conn->multipacket_encoded_data.data +
+                conn->multipacket_encoded_data.curlen,
+                *output,
+                *outputlen);
+        conn->multipacket_encoded_data.curlen += *outputlen;
+
+        *output = conn->multipacket_encoded_data.data;
+        *outputlen = (unsigned)conn->multipacket_encoded_data.curlen;
+    }
+
+    (*p_num_packets)++;
+
+    RETURN(conn, result);
+}
+
+/* security-encode an iovec */
+/* output is only valid until the next call to sasl_encode or sasl_encodev */
+int sasl_encodev(sasl_conn_t *conn,
+		 const struct iovec *invec,
+                 unsigned numiov,
+		 const char **output,
+                 unsigned *outputlen)
+{
+    int result = SASL_OK;
+    unsigned i;
+    unsigned j;
+    size_t total_size = 0;
+    struct iovec *cur_invec = NULL;
+    struct iovec last_invec;
+    unsigned cur_numiov;
+    char * next_buf = NULL;
+    size_t remainder_len;
+    unsigned index_offset;
+    unsigned allocated = 0;
+    /* Number of generated SASL packets */
+    int num_packets = 0;
+
+    if (!conn) return SASL_BADPARAM;
+    if (! invec || ! output || ! outputlen || numiov < 1) {
+	PARAMERROR(conn);
+    }
+
+    if (!conn->props.maxbufsize) {
+	sasl_seterror(conn, 0,
+		      "called sasl_encode[v] with application that does not support security layers");
+	return SASL_TOOWEAK;
+    }
+
+    /* If oparams.encode is NULL, this means there is no SASL security
+       layer in effect, so no SASL framing is needed. */
+    if (conn->oparams.encode == NULL)  {
+	result = _iovec_to_buf(invec, numiov, &conn->encode_buf);
+	if (result != SASL_OK) INTERROR(conn, result);
+       
+	*output = conn->encode_buf->data;
+	*outputlen = (unsigned) conn->encode_buf->curlen;
+
+        RETURN(conn, result);
+    }
+
+    /* This might be better to check on a per-plugin basis, but I think
+     * it's cleaner and more effective here.  It also encourages plugins
+     * to be honest about what they accept */
+
+    last_invec.iov_base = NULL;
+    remainder_len = 0;
+    next_buf = NULL;
+    i = 0;
+    while (i < numiov) {
+        if ((total_size + invec[i].iov_len) > conn->oparams.maxoutbuf) {
+
+            /* CLAIM: total_size < conn->oparams.maxoutbuf */
+            
+            /* Fit as many bytes in last_invec, so that we have conn->oparams.maxoutbuf
+               bytes in total. */
+            last_invec.iov_len = conn->oparams.maxoutbuf - total_size;
+            /* Point to the first byte of the current record. */
+            last_invec.iov_base = invec[i].iov_base;
+
+            /* Note that total_size < conn->oparams.maxoutbuf */
+            /* The total size of the iov is bigger then the other end can accept.
+               So we allocate a new iov that contains just enough. */
+
+            /* +1 --- for the tail record */
+            cur_numiov = i + 1;
+
+            /* +1 --- just in case we need the head record */
+            if ((cur_numiov + 1) > allocated) {
+                struct iovec *new_invec;
+
+                allocated = cur_numiov + 1;
+                new_invec = sasl_REALLOC (cur_invec, sizeof(struct iovec) * allocated);
+                if (new_invec == NULL) {
+                    if (cur_invec != NULL) {
+                        sasl_FREE(cur_invec);
+                    }
+                    MEMERROR(conn);
+                }
+                cur_invec = new_invec;
+            }
+
+            if (next_buf != NULL) {
+                cur_invec[0].iov_base = next_buf;
+                cur_invec[0].iov_len = (long)remainder_len;
+                cur_numiov++;
+                index_offset = 1;
+            } else {
+                index_offset = 0;
+            }
+
+            if (i > 0) {
+                /* Copy all previous chunks */
+                /* NOTE - The starting index in invec is always 0 */
+                for (j = 0; j < i; j++) {
+                    cur_invec[j + index_offset] = invec[j];
+                }
+            }
+
+            /* Initialize the last record */
+            cur_invec[i + index_offset] = last_invec;
+
+            result = _sasl_encodev (conn,
+	                            cur_invec,
+                                    cur_numiov,
+                                    &num_packets,
+	                            output,
+                                    outputlen);
+
+            if (result != SASL_OK) {
+                goto cleanup;
+            }
+
+            /* Point to the first byte that wouldn't fit into
+               the conn->oparams.maxoutbuf buffer. */
+            /* Note, if next_buf points to the very end of the IOV record,
+               it will be reset to NULL below */
+            /* Note, that some platforms define iov_base as "void *",
+               thus the typecase below */
+            next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
+            /* Note - remainder_len is how many bytes left to be encoded in
+               the current IOV slot. */
+            remainder_len = (total_size + invec[i].iov_len) - conn->oparams.maxoutbuf;
+
+            /* Skip all consumed IOV records */
+            invec += i + 1;
+            numiov = numiov - (i + 1);
+            i = 0;
+
+            while (remainder_len > conn->oparams.maxoutbuf) {
+                last_invec.iov_base = next_buf;
+                last_invec.iov_len = conn->oparams.maxoutbuf;
+
+                /* Note, if next_buf points to the very end of the IOV record,
+                   it will be reset to NULL below */
+                /* Note, that some platforms define iov_base as "void *",
+                   thus the typecase below */
+                next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
+                remainder_len = remainder_len - conn->oparams.maxoutbuf;
+
+                result = _sasl_encodev (conn,
+	                                &last_invec,
+                                        1,
+                                        &num_packets,
+	                                output,
+                                        outputlen);
+                if (result != SASL_OK) {
+                    goto cleanup;
+                }
+            }
+
+	    total_size = remainder_len;
+
+            if (remainder_len == 0) {
+                /* Just clear next_buf */
+                next_buf = NULL;
+            }
+        } else {
+	    total_size += invec[i].iov_len;
+            i++;
+        }
+    }
+
+    /* CLAIM - The remaining data is shorter then conn->oparams.maxoutbuf. */
+
+    /* Force encoding of any partial buffer. Might not be optimal on the wire. */
+    if (next_buf != NULL) {
+        last_invec.iov_base = next_buf;
+        last_invec.iov_len = (long)remainder_len;
+
+        result = _sasl_encodev (conn,
+	                        &last_invec,
+                                1,
+                                &num_packets,
+	                        output,
+                                outputlen);
+
+        if (result != SASL_OK) {
+            goto cleanup;
+        }
+    }
+
+    if (numiov > 0) {
+        result = _sasl_encodev (conn,
+	                        invec,
+                                numiov,
+                                &num_packets,
+	                        output,
+                                outputlen);
+    }
+
+cleanup:
+    if (cur_invec != NULL) {
+        sasl_FREE(cur_invec);
+    }
+
+    RETURN(conn, result);
+}
+ 
+/* output is only valid until next call to sasl_decode */
+int sasl_decode(sasl_conn_t *conn,
+		const char *input, unsigned inputlen,
+		const char **output, unsigned *outputlen)
+{
+    int result;
+
+    if(!conn) return SASL_BADPARAM;
+    if(!input || !output || !outputlen)
+	PARAMERROR(conn);
+
+    if(!conn->props.maxbufsize) {
+	sasl_seterror(conn, 0,
+		      "called sasl_decode with application that does not support security layers");
+	RETURN(conn, SASL_TOOWEAK);
+    }
+
+    if(conn->oparams.decode == NULL)
+    {
+	/* Since we know how long the output is maximally, we can
+	 * just allocate it to begin with, and never need another
+         * allocation! */
+
+	/* However, if they pass us more than they actually can take,
+	 * we cannot help them... */
+	if(inputlen > conn->props.maxbufsize) {
+	    sasl_seterror(conn, 0,
+			  "input too large for default sasl_decode");
+	    RETURN(conn,SASL_BUFOVER);
+	}
+
+	if(!conn->decode_buf)
+	    conn->decode_buf = sasl_ALLOC(conn->props.maxbufsize + 1);
+	if(!conn->decode_buf)	
+	    MEMERROR(conn);
+	
+	memcpy(conn->decode_buf, input, inputlen);
+	conn->decode_buf[inputlen] = '\0';
+	*output = conn->decode_buf;
+	*outputlen = inputlen;
+	
+        return SASL_OK;
+    } else {
+        result = conn->oparams.decode(conn->context, input, inputlen,
+                                      output, outputlen);
+
+	/* NULL an empty buffer (for misbehaved applications) */
+	if (*outputlen == 0) *output = NULL;
+
+        RETURN(conn, result);
+    }
+
+    INTERROR(conn, SASL_FAIL);
+}
+
+
+void
+sasl_set_alloc(sasl_malloc_t *m,
+	       sasl_calloc_t *c,
+	       sasl_realloc_t *r,
+	       sasl_free_t *f)
+{
+  if (_sasl_allocation_locked++)  return;
+
+  _sasl_allocation_utils.malloc=m;
+  _sasl_allocation_utils.calloc=c;
+  _sasl_allocation_utils.realloc=r;
+  _sasl_allocation_utils.free=f;
+}
+
+void sasl_common_done(void)
+{
+    /* NOTE - the caller will need to reinitialize the values,
+       if it is going to call sasl_client_init/sasl_server_init again. */
+    if (default_plugin_path != NULL) {
+	sasl_FREE (default_plugin_path);
+	default_plugin_path = NULL;
+    }
+    if (default_conf_path != NULL) {
+	sasl_FREE (default_conf_path);
+	default_conf_path = NULL;
+    }
+
+    _sasl_canonuser_free();
+    _sasl_done_with_plugins();
+    
+    sasl_MUTEX_FREE(free_mutex);
+    free_mutex = NULL;
+    
+    _sasl_free_utils(&sasl_global_utils);
+    
+    if (global_mech_list) {
+	sasl_FREE(global_mech_list);
+	global_mech_list = NULL;
+    }
+}
+
+/* This function is for backward compatibility */
+void sasl_done(void)
+{
+    if (_sasl_server_cleanup_hook && _sasl_server_cleanup_hook() == SASL_OK) {
+	_sasl_server_idle_hook = NULL;
+	_sasl_server_cleanup_hook = NULL;
+    }
+    
+    if (_sasl_client_cleanup_hook && _sasl_client_cleanup_hook() == SASL_OK) {
+	_sasl_client_idle_hook = NULL;	
+	_sasl_client_cleanup_hook = NULL;
+    }
+    
+    if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+	return;
+    }
+
+    sasl_common_done();
+}
+
+/* fills in the base sasl_conn_t info */
+int _sasl_conn_init(sasl_conn_t *conn,
+		    const char *service,
+		    unsigned int flags,
+		    enum Sasl_conn_type type,
+		    int (*idle_hook)(sasl_conn_t *conn),
+		    const char *serverFQDN,
+		    const char *iplocalport,
+		    const char *ipremoteport,
+		    const sasl_callback_t *callbacks,
+		    const sasl_global_callbacks_t *global_callbacks) {
+  int result = SASL_OK;
+
+  conn->type = type;
+
+  result = _sasl_strdup(service, &conn->service, NULL);
+  if (result != SASL_OK) 
+      MEMERROR(conn);
+
+  memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
+  memset(&conn->external, 0, sizeof(_sasl_external_properties_t));
+
+  conn->flags = flags;
+
+  result = sasl_setprop(conn, SASL_IPLOCALPORT, iplocalport);
+  if(result != SASL_OK)
+      RETURN(conn, result);
+  
+  result = sasl_setprop(conn, SASL_IPREMOTEPORT, ipremoteport);
+  if(result != SASL_OK)
+      RETURN(conn, result);
+  
+  conn->encode_buf = NULL;
+  conn->context = NULL;
+  conn->secret = NULL;
+  conn->idle_hook = idle_hook;
+  conn->callbacks = callbacks;
+  conn->global_callbacks = global_callbacks;
+
+  memset(&conn->props, 0, sizeof(conn->props));
+
+  /* Start this buffer out as an empty string */
+  conn->error_code = SASL_OK;
+  conn->errdetail_buf = conn->error_buf = NULL;
+  conn->errdetail_buf_len = conn->error_buf_len = 150;
+
+  result = _buf_alloc(&conn->error_buf, &conn->error_buf_len, 150);     
+  if(result != SASL_OK) MEMERROR(conn);
+  result = _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, 150);
+  if(result != SASL_OK) MEMERROR(conn);
+  
+  conn->error_buf[0] = '\0';
+  conn->errdetail_buf[0] = '\0';
+  
+  conn->decode_buf = NULL;
+
+  if(serverFQDN) {
+      result = _sasl_strdup(serverFQDN, &conn->serverFQDN, NULL);
+      sasl_strlower (conn->serverFQDN);
+  } else if (conn->type == SASL_CONN_SERVER) {
+      /* We can fake it because we *are* the server */
+      char name[MAXHOSTNAMELEN];
+      memset(name, 0, sizeof(name));
+      if (get_fqhostname (name, MAXHOSTNAMELEN, 0) != 0) {
+        return (SASL_FAIL);
+      }
+      
+      result = _sasl_strdup(name, &conn->serverFQDN, NULL);
+  } else {
+      conn->serverFQDN = NULL;
+  }
+  
+
+  if(result != SASL_OK) MEMERROR( conn );
+
+  RETURN(conn, SASL_OK);
+}
+
+int _sasl_common_init(sasl_global_callbacks_t *global_callbacks)
+{
+    int result;
+
+    /* The last specified global callback always wins */
+    if (sasl_global_utils != NULL) {
+	sasl_utils_t * global_utils = (sasl_utils_t *)sasl_global_utils;
+	global_utils->getopt = &_sasl_global_getopt;
+	global_utils->getopt_context = global_callbacks;
+    }
+
+    /* Do nothing if we are already initialized */
+    if (free_mutex) {
+	return SASL_OK;
+    }
+
+    /* Setup the global utilities */
+    if(!sasl_global_utils) {
+	sasl_global_utils = _sasl_alloc_utils(NULL, global_callbacks);
+	if(sasl_global_utils == NULL) return SASL_NOMEM;
+    }
+
+    /* Init the canon_user plugin */
+    result = sasl_canonuser_add_plugin("INTERNAL", internal_canonuser_init);
+    if(result != SASL_OK) return result;    
+
+    if (!free_mutex) {
+	free_mutex = sasl_MUTEX_ALLOC();
+    }
+    if (!free_mutex) return SASL_FAIL;
+
+    return SASL_OK;
+}
+
+/* dispose connection state, sets it to NULL
+ *  checks for pointer to NULL
+ */
+void sasl_dispose(sasl_conn_t **pconn)
+{
+  int result;
+
+  if (! pconn) return;
+  if (! *pconn) return;
+
+  /* serialize disposes. this is necessary because we can't
+     dispose of conn->mutex if someone else is locked on it */
+  result = sasl_MUTEX_LOCK(free_mutex);
+  if (result!=SASL_OK) return;
+  
+  /* *pconn might have become NULL by now */
+  if (! (*pconn))
+  {
+	sasl_MUTEX_UNLOCK(free_mutex);
+	return;
+  }
+
+  (*pconn)->destroy_conn(*pconn);
+  sasl_FREE(*pconn);
+  *pconn=NULL;
+
+  sasl_MUTEX_UNLOCK(free_mutex);
+}
+
+void _sasl_conn_dispose(sasl_conn_t *conn) {
+  if (conn->serverFQDN)
+      sasl_FREE(conn->serverFQDN);
+
+  if (conn->external.auth_id)
+      sasl_FREE(conn->external.auth_id);
+
+  if(conn->encode_buf) {
+      if(conn->encode_buf->data) sasl_FREE(conn->encode_buf->data);
+      sasl_FREE(conn->encode_buf);
+  }
+
+  if(conn->error_buf)
+      sasl_FREE(conn->error_buf);
+  
+  if(conn->errdetail_buf)
+      sasl_FREE(conn->errdetail_buf);
+
+  if(conn->decode_buf)
+      sasl_FREE(conn->decode_buf);
+
+  if(conn->mechlist_buf)
+      sasl_FREE(conn->mechlist_buf);
+
+  if(conn->service)
+      sasl_FREE(conn->service);
+
+  if (conn->multipacket_encoded_data.data) {
+      sasl_FREE(conn->multipacket_encoded_data.data);
+  }
+
+  /* oparams sub-members should be freed by the plugin, in so much
+   * as they were allocated by the plugin */
+}
+
+
+/* get property from SASL connection state
+ *  propnum       -- property number
+ *  pvalue        -- pointer to value
+ * returns:
+ *  SASL_OK       -- no error
+ *  SASL_NOTDONE  -- property not available yet
+ *  SASL_BADPARAM -- bad property number or SASL context is NULL
+ */
+int sasl_getprop(sasl_conn_t *conn, int propnum, const void **pvalue)
+{
+  int result = SASL_OK;
+  sasl_getopt_t *getopt;
+  void *context;
+  
+  if (! conn) return SASL_BADPARAM;
+  if (! pvalue) PARAMERROR(conn);
+
+  switch(propnum)
+  {
+  case SASL_SSF:
+      *(sasl_ssf_t **)pvalue= &conn->oparams.mech_ssf;
+      break;      
+  case SASL_MAXOUTBUF:
+      *(unsigned **)pvalue = &conn->oparams.maxoutbuf;
+      break;
+  case SASL_GETOPTCTX:
+      result = _sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context);
+      if(result != SASL_OK) break;
+      
+      *(void **)pvalue = context;
+      break;
+  case SASL_CALLBACK:
+      *(const sasl_callback_t **)pvalue = conn->callbacks;
+      break;
+  case SASL_IPLOCALPORT:
+      if(conn->got_ip_local)
+	  *(const char **)pvalue = conn->iplocalport;
+      else {
+	  *(const char **)pvalue = NULL;
+	  result = SASL_NOTDONE;
+      }
+      break;
+  case SASL_IPREMOTEPORT:
+      if(conn->got_ip_remote)
+	  *(const char **)pvalue = conn->ipremoteport;
+      else {
+	  *(const char **)pvalue = NULL;
+	  result = SASL_NOTDONE;
+      }	  
+      break;
+  case SASL_USERNAME:
+      if(! conn->oparams.user)
+	  result = SASL_NOTDONE;
+      else
+	  *((const char **)pvalue) = conn->oparams.user;
+      break;
+  case SASL_AUTHUSER:
+      if(! conn->oparams.authid)
+	  result = SASL_NOTDONE;
+      else
+	  *((const char **)pvalue) = conn->oparams.authid;
+      break;
+  case SASL_APPNAME:
+      /* Currently we only support server side contexts, but we should
+         be able to extend this to support client side contexts as well */
+      if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
+      else
+	  *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->sparams->appname;
+      break;
+  case SASL_SERVERFQDN:
+      *((const char **)pvalue) = conn->serverFQDN;
+      break;
+  case SASL_DEFUSERREALM:
+      if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
+      else
+	  *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->user_realm;
+      break;
+  case SASL_SERVICE:
+      *((const char **)pvalue) = conn->service;
+      break;
+  case SASL_AUTHSOURCE: /* name of plugin (not name of mech) */
+      if(conn->type == SASL_CONN_CLIENT) {
+	  if(!((sasl_client_conn_t *)conn)->mech) {
+	      result = SASL_NOTDONE;
+	      break;
+	  }
+	  *((const char **)pvalue) =
+	      ((sasl_client_conn_t *)conn)->mech->m.plugname;
+      } else if (conn->type == SASL_CONN_SERVER) {
+	  if(!((sasl_server_conn_t *)conn)->mech) {
+	      result = SASL_NOTDONE;
+	      break;
+	  }
+	  *((const char **)pvalue) =
+	      ((sasl_server_conn_t *)conn)->mech->m.plugname;
+      } else {
+	  result = SASL_BADPARAM;
+      }
+      break;
+  case SASL_MECHNAME: /* name of mech */
+      if(conn->type == SASL_CONN_CLIENT) {
+	  if(!((sasl_client_conn_t *)conn)->mech) {
+	      result = SASL_NOTDONE;
+	      break;
+	  }
+	  *((const char **)pvalue) =
+	      ((sasl_client_conn_t *)conn)->mech->m.plug->mech_name;
+      } else if (conn->type == SASL_CONN_SERVER) {
+	  if(!((sasl_server_conn_t *)conn)->mech) {
+	      result = SASL_NOTDONE;
+	      break;
+	  }
+	  *((const char **)pvalue) =
+	      ((sasl_server_conn_t *)conn)->mech->m.plug->mech_name;
+      } else {
+	  result = SASL_BADPARAM;
+      }
+      
+      if(!(*pvalue) && result == SASL_OK) result = SASL_NOTDONE;
+      break;
+  case SASL_PLUGERR:
+      *((const char **)pvalue) = conn->error_buf;
+      break;
+  case SASL_DELEGATEDCREDS:
+      /* We can't really distinguish between "no delegated credentials"
+         and "authentication not finished" */
+      if(! conn->oparams.client_creds)
+	  result = SASL_NOTDONE;
+      else
+	  *((const char **)pvalue) = conn->oparams.client_creds;
+      break;
+  case SASL_GSS_PEER_NAME:
+      if(! conn->oparams.gss_peer_name)
+	  result = SASL_NOTDONE;
+      else
+	  *((const char **)pvalue) = conn->oparams.gss_peer_name;
+      break;
+  case SASL_GSS_LOCAL_NAME:
+      if(! conn->oparams.gss_peer_name)
+	  result = SASL_NOTDONE;
+      else
+	  *((const char **)pvalue) = conn->oparams.gss_local_name;
+      break;
+  case SASL_SSF_EXTERNAL:
+      *((const sasl_ssf_t **)pvalue) = &conn->external.ssf;
+      break;
+  case SASL_AUTH_EXTERNAL:
+      *((const char **)pvalue) = conn->external.auth_id;
+      break;
+  case SASL_SEC_PROPS:
+      *((const sasl_security_properties_t **)pvalue) = &conn->props;
+      break;
+  case SASL_GSS_CREDS:
+      if(conn->type == SASL_CONN_CLIENT)
+	  *(void **)pvalue = 
+              ((sasl_client_conn_t *)conn)->cparams->gss_creds;
+      else
+	  *(void **)pvalue = 
+              ((sasl_server_conn_t *)conn)->sparams->gss_creds;
+      break;
+  case SASL_HTTP_REQUEST: {
+      if (conn->type == SASL_CONN_SERVER)
+	  *(const sasl_http_request_t **)pvalue =
+	      ((sasl_server_conn_t *)conn)->sparams->http_request;
+      else
+	  *(const sasl_http_request_t **)pvalue =
+	      ((sasl_client_conn_t *)conn)->cparams->http_request;
+      break;
+  }
+  default: 
+      result = SASL_BADPARAM;
+  }
+
+  if(result == SASL_BADPARAM) {
+      PARAMERROR(conn);
+  } else if(result == SASL_NOTDONE) {
+      sasl_seterror(conn, SASL_NOLOG,
+		    "Information that was requested is not yet available.");
+      RETURN(conn, result);
+  } else if(result != SASL_OK) {
+      INTERROR(conn, result);
+  } else
+      RETURN(conn, result); 
+}
+
+/* set property in SASL connection state
+ * returns:
+ *  SASL_OK       -- value set
+ *  SASL_BADPARAM -- invalid property or value
+ */
+int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
+{
+  int result = SASL_OK;
+  char *str;
+
+  /* make sure the sasl context is valid */
+  if (!conn)
+    return SASL_BADPARAM;
+
+  switch(propnum)
+  {
+  case SASL_SSF_EXTERNAL:
+      conn->external.ssf = *((sasl_ssf_t *)value);
+      if(conn->type == SASL_CONN_SERVER) {
+	((sasl_server_conn_t*)conn)->sparams->external_ssf =
+	  conn->external.ssf;
+      } else {
+	((sasl_client_conn_t*)conn)->cparams->external_ssf =
+	  conn->external.ssf;
+      }
+      break;
+
+  case SASL_AUTH_EXTERNAL:
+      if(value && strlen(value)) {
+	  result = _sasl_strdup(value, &str, NULL);
+	  if(result != SASL_OK) MEMERROR(conn);
+      } else {
+	  str = NULL;
+      }
+
+      if(conn->external.auth_id)
+	  sasl_FREE(conn->external.auth_id);
+
+      conn->external.auth_id = str;
+
+      break;
+
+  case SASL_DEFUSERREALM:
+      if(conn->type != SASL_CONN_SERVER) {
+	sasl_seterror(conn, 0, "Tried to set realm on non-server connection");
+	result = SASL_BADPROT;
+	break;
+      }
+
+      if(value && strlen(value)) {
+	  result = _sasl_strdup(value, &str, NULL);
+	  if(result != SASL_OK) MEMERROR(conn);
+      } else {
+	  PARAMERROR(conn);
+      }
+
+      if(((sasl_server_conn_t *)conn)->user_realm)
+      	  sasl_FREE(((sasl_server_conn_t *)conn)->user_realm);
+
+      ((sasl_server_conn_t *)conn)->user_realm = str;
+      ((sasl_server_conn_t *)conn)->sparams->user_realm = str;
+
+      break;
+
+  case SASL_SEC_PROPS:
+  {
+      sasl_security_properties_t *props = (sasl_security_properties_t *)value;
+
+      if(props->maxbufsize == 0 && props->min_ssf != 0) {
+	  sasl_seterror(conn, 0,
+			"Attempt to disable security layers (maxoutbuf == 0) with min_ssf > 0");
+	  RETURN(conn, SASL_TOOWEAK);
+      }
+
+      conn->props = *props;
+
+      if(conn->type == SASL_CONN_SERVER) {
+	((sasl_server_conn_t*)conn)->sparams->props = *props;
+      } else {
+	((sasl_client_conn_t*)conn)->cparams->props = *props;
+      }
+
+      break;
+  }
+      
+  case SASL_IPREMOTEPORT:
+  {
+      const char *ipremoteport = (const char *)value;
+      if(!value) {
+	  conn->got_ip_remote = 0; 
+      } else if (_sasl_ipfromstring(ipremoteport, NULL, 0)
+		 != SASL_OK) {
+	  sasl_seterror(conn, 0, "Bad IPREMOTEPORT value");
+	  RETURN(conn, SASL_BADPARAM);
+      } else {
+	  strcpy(conn->ipremoteport, ipremoteport);
+	  conn->got_ip_remote = 1;
+      }
+      
+      if(conn->got_ip_remote) {
+	  if(conn->type == SASL_CONN_CLIENT) {
+	      ((sasl_client_conn_t *)conn)->cparams->ipremoteport
+		  = conn->ipremoteport;
+	      ((sasl_client_conn_t *)conn)->cparams->ipremlen =
+		  (unsigned) strlen(conn->ipremoteport);
+	  } else if (conn->type == SASL_CONN_SERVER) {
+	      ((sasl_server_conn_t *)conn)->sparams->ipremoteport
+		  = conn->ipremoteport;
+	      ((sasl_server_conn_t *)conn)->sparams->ipremlen =
+		  (unsigned) strlen(conn->ipremoteport);
+	  }
+      } else {
+	  if(conn->type == SASL_CONN_CLIENT) {
+	      ((sasl_client_conn_t *)conn)->cparams->ipremoteport
+		  = NULL;
+	      ((sasl_client_conn_t *)conn)->cparams->ipremlen = 0;
+	  } else if (conn->type == SASL_CONN_SERVER) {
+	      ((sasl_server_conn_t *)conn)->sparams->ipremoteport
+		  = NULL;	      
+	      ((sasl_server_conn_t *)conn)->sparams->ipremlen = 0;
+	  }
+      }
+
+      break;
+  }
+
+  case SASL_IPLOCALPORT:
+  {
+      const char *iplocalport = (const char *)value;
+      if(!value) {
+	  conn->got_ip_local = 0;	  
+      } else if (_sasl_ipfromstring(iplocalport, NULL, 0)
+		 != SASL_OK) {
+	  sasl_seterror(conn, 0, "Bad IPLOCALPORT value");
+	  RETURN(conn, SASL_BADPARAM);
+      } else {
+	  strcpy(conn->iplocalport, iplocalport);
+	  conn->got_ip_local = 1;
+      }
+
+      if(conn->got_ip_local) {
+	  if(conn->type == SASL_CONN_CLIENT) {
+	      ((sasl_client_conn_t *)conn)->cparams->iplocalport
+		  = conn->iplocalport;
+	      ((sasl_client_conn_t *)conn)->cparams->iploclen
+		  = (unsigned) strlen(conn->iplocalport);
+	  } else if (conn->type == SASL_CONN_SERVER) {
+	      ((sasl_server_conn_t *)conn)->sparams->iplocalport
+		  = conn->iplocalport;
+	      ((sasl_server_conn_t *)conn)->sparams->iploclen
+		  = (unsigned) strlen(conn->iplocalport);
+	  }
+      } else {
+	  if(conn->type == SASL_CONN_CLIENT) {
+	      ((sasl_client_conn_t *)conn)->cparams->iplocalport
+		  = NULL;
+	      ((sasl_client_conn_t *)conn)->cparams->iploclen = 0;
+	  } else if (conn->type == SASL_CONN_SERVER) {
+	      ((sasl_server_conn_t *)conn)->sparams->iplocalport
+		  = NULL;
+	      ((sasl_server_conn_t *)conn)->sparams->iploclen = 0;
+	  }
+      }
+      break;
+  }
+
+  case SASL_APPNAME:
+      /* Currently we only support server side contexts, but we should
+         be able to extend this to support client side contexts as well */
+      if(conn->type != SASL_CONN_SERVER) {
+	sasl_seterror(conn, 0, "Tried to set application name on non-server connection");
+	result = SASL_BADPROT;
+	break;
+      }
+
+      if(((sasl_server_conn_t *)conn)->appname) {
+      	  sasl_FREE(((sasl_server_conn_t *)conn)->appname);
+	  ((sasl_server_conn_t *)conn)->appname = NULL;
+      }
+
+      if(value && strlen(value)) {
+	  result = _sasl_strdup(value,
+				&(((sasl_server_conn_t *)conn)->appname),
+				NULL);
+	  if(result != SASL_OK) MEMERROR(conn);
+	  ((sasl_server_conn_t *)conn)->sparams->appname =
+              ((sasl_server_conn_t *)conn)->appname;
+	  ((sasl_server_conn_t *)conn)->sparams->applen =
+	      (unsigned) strlen(((sasl_server_conn_t *)conn)->appname);
+      } else {
+	  ((sasl_server_conn_t *)conn)->sparams->appname = NULL;
+	  ((sasl_server_conn_t *)conn)->sparams->applen = 0;
+      }
+      break;
+
+  case SASL_GSS_CREDS:
+      if(conn->type == SASL_CONN_CLIENT)
+          ((sasl_client_conn_t *)conn)->cparams->gss_creds = value;
+      else
+          ((sasl_server_conn_t *)conn)->sparams->gss_creds = value;
+      break;
+
+  case SASL_CHANNEL_BINDING: {
+    const struct sasl_channel_binding *cb = (const struct sasl_channel_binding *)value;
+
+    if (conn->type == SASL_CONN_SERVER)
+        ((sasl_server_conn_t *)conn)->sparams->cbinding = cb;
+    else
+        ((sasl_client_conn_t *)conn)->cparams->cbinding = cb;
+    break;
+  }
+
+  case SASL_HTTP_REQUEST: {
+      const sasl_http_request_t *req = (const sasl_http_request_t *)value;
+
+      if (conn->type == SASL_CONN_SERVER)
+	  ((sasl_server_conn_t *)conn)->sparams->http_request = req;
+      else
+	  ((sasl_client_conn_t *)conn)->cparams->http_request = req;
+      break;
+  }
+
+  default:
+      sasl_seterror(conn, 0, "Unknown parameter type");
+      result = SASL_BADPARAM;
+  }
+  
+  RETURN(conn, result);
+}
+
+/* this is apparently no longer a user function */
+static int sasl_usererr(int saslerr)
+{
+    /* Hide the difference in a username failure and a password failure */
+    if (saslerr == SASL_NOUSER)
+	return SASL_BADAUTH;
+
+    /* otherwise return the error given; no transform necessary */
+    return saslerr;
+}
+
+const char *sasl_errstring(int saslerr,
+			   const char *langlist __attribute__((unused)),
+			   const char **outlang)
+{
+  if (outlang) *outlang="en-us";
+
+  switch(saslerr)
+    {
+    case SASL_CONTINUE: return "another step is needed in authentication";
+    case SASL_OK:       return "successful result";
+    case SASL_FAIL:     return "generic failure";
+    case SASL_NOMEM:    return "no memory available";
+    case SASL_BUFOVER:  return "overflowed buffer";
+    case SASL_NOMECH:   return "no mechanism available";
+    case SASL_BADPROT:  return "bad protocol / cancel";
+    case SASL_NOTDONE:  return "can't request information until later in exchange";
+    case SASL_BADPARAM: return "invalid parameter supplied";
+    case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
+    case SASL_BADMAC:   return "integrity check failed";
+    case SASL_NOTINIT:  return "SASL library is not initialized";
+                             /* -- client only codes -- */
+    case SASL_INTERACT:   return "needs user interaction";
+    case SASL_BADSERV:    return "server failed mutual authentication step";
+    case SASL_WRONGMECH:  return "mechanism doesn't support requested feature";
+                             /* -- server only codes -- */
+    case SASL_BADAUTH:    return "authentication failure";
+    case SASL_NOAUTHZ:    return "authorization failure";
+    case SASL_TOOWEAK:    return "mechanism too weak for this user";
+    case SASL_ENCRYPT:    return "encryption needed to use mechanism";
+    case SASL_TRANS:      return "One time use of a plaintext password will enable requested mechanism for user";
+    case SASL_EXPIRED:    return "passphrase expired, has to be reset";
+    case SASL_DISABLED:   return "account disabled";
+    case SASL_NOUSER:     return "user not found";
+    case SASL_BADVERS:    return "version mismatch with plug-in";
+    case SASL_UNAVAIL:    return "remote authentication server unavailable";
+    case SASL_NOVERIFY:   return "user exists, but no verifier for user";
+    case SASL_PWLOCK:     return "passphrase locked";
+    case SASL_NOCHANGE:   return "requested change was not needed";
+    case SASL_WEAKPASS:   return "passphrase is too weak for security policy";
+    case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
+    case SASL_NEED_OLD_PASSWD: return "sasl_setpass needs old password in order "
+				"to perform password change";
+    case SASL_CONSTRAINT_VIOLAT: return "sasl_setpass can't store a property because "
+			        "of a constraint violation";
+    case SASL_BADBINDING: return "channel binding failure";
+
+    default:   return "undefined error!";
+    }
+
+}
+
+/* Return the sanitized error detail about the last error that occured for 
+ * a connection */
+const char *sasl_errdetail(sasl_conn_t *conn) 
+{
+    unsigned need_len;
+    const char *errstr;
+    char leader[128];
+
+    if(!conn) return NULL;
+    
+    errstr = sasl_errstring(conn->error_code, NULL, NULL);
+    snprintf(leader,128,"SASL(%d): %s: ",
+	     sasl_usererr(conn->error_code), errstr);
+    
+    need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
+    _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len);
+
+    snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
+   
+    return conn->errdetail_buf;
+}
+
+
+/* Note that this needs the global callbacks, so if you don't give getcallbacks
+ * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
+ * have client and server at the same time */
+static int _sasl_global_getopt(void *context,
+			       const char *plugin_name,
+			       const char *option,
+			       const char ** result,
+			       unsigned *len)
+{
+  const sasl_global_callbacks_t * global_callbacks;
+  const sasl_callback_t *callback;
+
+  global_callbacks = (const sasl_global_callbacks_t *) context;
+
+  if (global_callbacks && global_callbacks->callbacks) {
+      for (callback = global_callbacks->callbacks;
+	   callback->id != SASL_CB_LIST_END;
+	   callback++) {
+	if (callback->id == SASL_CB_GETOPT) {
+	  if (!callback->proc) return SASL_FAIL;
+	  if (((sasl_getopt_t *)(callback->proc))(callback->context,
+						  plugin_name,
+						  option,
+						  result,
+						  len)
+	      == SASL_OK)
+	    return SASL_OK;
+	}
+      }
+  }
+  
+  /* look it up in our configuration file */
+  *result = sasl_config_getstring(option, NULL);
+  if (*result != NULL) {
+      if (len) { *len = (unsigned) strlen(*result); }
+      return SASL_OK;
+  }
+
+  return SASL_FAIL;
+}
+
+static int
+_sasl_conn_getopt(void *context,
+		  const char *plugin_name,
+		  const char *option,
+		  const char ** result,
+		  unsigned *len)
+{
+  sasl_conn_t * conn;
+  const sasl_callback_t *callback;
+
+  if (! context)
+    return SASL_BADPARAM;
+
+  conn = (sasl_conn_t *) context;
+
+  if (conn->callbacks)
+    for (callback = conn->callbacks;
+	 callback->id != SASL_CB_LIST_END;
+	 callback++)
+      if (callback->id == SASL_CB_GETOPT
+	  && (((sasl_getopt_t *)(callback->proc))(callback->context,
+						  plugin_name,
+						  option,
+						  result,
+						  len)
+	      == SASL_OK))
+	return SASL_OK;
+
+  /* If we made it here, we didn't find an appropriate callback
+   * in the connection's callback list, or the callback we did
+   * find didn't return SASL_OK.  So we attempt to use the
+   * global callback for this connection... */
+  return _sasl_global_getopt((void *)conn->global_callbacks,
+			     plugin_name,
+			     option,
+			     result,
+			     len);
+}
+
+#ifdef HAVE_SYSLOG
+/* this is the default logging */
+static int _sasl_syslog(void *context,
+			int priority,
+			const char *message)
+{
+    int syslog_priority;
+    sasl_server_conn_t *sconn;
+
+    if (context) {
+	if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
+	    sconn = (sasl_server_conn_t *)context;
+	    if (sconn->sparams->log_level < priority) 
+		return SASL_OK;
+	}
+    }
+
+    /* set syslog priority */
+    switch(priority) {
+    case SASL_LOG_NONE:
+	return SASL_OK;
+	break;
+    case SASL_LOG_ERR:
+	syslog_priority = LOG_ERR;
+	break;
+    case SASL_LOG_WARN:
+	syslog_priority = LOG_WARNING;
+	break;
+    case SASL_LOG_NOTE:
+    case SASL_LOG_FAIL:
+	syslog_priority = LOG_NOTICE;
+	break;
+    case SASL_LOG_PASS:
+    case SASL_LOG_TRACE:
+    case SASL_LOG_DEBUG:
+    default:
+	syslog_priority = LOG_DEBUG;
+	break;
+    }
+    
+    /* do the syslog call. Do not need to call openlog? */
+    syslog(syslog_priority | LOG_AUTH, "%s", message);
+    
+    return SASL_OK;
+}
+#endif				/* HAVE_SYSLOG */
+
+static int
+_sasl_getsimple(void *context,
+		int id,
+		const char ** result,
+		size_t *len)
+{
+  const char *userid;
+  sasl_conn_t *conn;
+
+  if (! context || ! result) return SASL_BADPARAM;
+
+  conn = (sasl_conn_t *)context;
+
+  switch(id) {
+  case SASL_CB_AUTHNAME:
+    userid = getenv("USER");
+    if (userid != NULL) {
+	*result = userid;
+	if (len) *len = strlen(userid);
+	return SASL_OK;
+    }
+    userid = getenv("USERNAME");
+    if (userid != NULL) {
+	*result = userid;
+	if (len) *len = strlen(userid);
+	return SASL_OK;
+    }
+#ifdef WIN32
+    /* for win32, try using the GetUserName standard call */
+    {
+	DWORD i;
+	BOOL rval;
+	static char sender[128];
+	
+	i = sizeof(sender);
+	rval = GetUserName(sender, &i);
+	if ( rval) { /* got a userid */
+		*result = sender;
+		if (len) *len = strlen(sender);
+		return SASL_OK;
+	}
+    }
+#endif /* WIN32 */
+    return SASL_FAIL;
+  default:
+    return SASL_BADPARAM;
+  }
+}
+
+static int
+_sasl_getpath(void *context __attribute__((unused)),
+              const char ** path_dest)
+{
+#if !defined(WIN32)
+    char *path;
+#endif
+    int res = SASL_OK;
+
+    if (! path_dest) {
+        return SASL_BADPARAM;
+    }
+
+    /* Only calculate the path once. */
+    if (default_plugin_path == NULL) {
+
+#if defined(WIN32)
+        /* NB: On Windows platforms this value is always allocated */
+        default_plugin_path = _sasl_get_default_win_path(context,
+                                                         SASL_PLUGIN_PATH_ATTR,
+                                                         PLUGINDIR);
+#else
+        /* NB: On Unix platforms this value is never allocated */
+        path = _sasl_get_default_unix_path(context,
+                                           SASL_PATH_ENV_VAR,
+                                           PLUGINDIR);
+
+        res = _sasl_strdup(path, &default_plugin_path, NULL);
+#endif
+    }
+
+    if (res == SASL_OK) {
+        *path_dest = default_plugin_path;
+    }
+
+    return res;
+}
+
+static int
+_sasl_getpath_simple(void *context __attribute__((unused)),
+                     const char **path)
+{
+    if (! path) {
+        return SASL_BADPARAM;
+    }
+
+    if (default_plugin_path == NULL) {
+        return SASL_FAIL;
+    }
+
+    *path = default_plugin_path;
+
+    return SASL_OK;
+}
+
+static int
+_sasl_getconfpath(void *context __attribute__((unused)),
+                  char ** path_dest)
+{
+#if !defined(WIN32)
+    char *path;
+#endif
+    int res = SASL_OK;
+
+    if (! path_dest) {
+        return SASL_BADPARAM;
+    }
+
+  /* Only calculate the path once. */
+    if (default_conf_path == NULL) {
+
+#if defined(WIN32)
+        /* NB: On Windows platforms this value is always allocated */
+        default_conf_path = _sasl_get_default_win_path(context,
+                                                       SASL_CONF_PATH_ATTR,
+                                                       CONFIGDIR);
+#else
+        /* NB: On Unix platforms this value is never allocated */
+        path = _sasl_get_default_unix_path(context,
+                                           SASL_CONF_PATH_ENV_VAR,
+                                           CONFIGDIR);
+
+        res = _sasl_strdup(path, &default_conf_path, NULL);
+#endif
+    }
+
+    if (res == SASL_OK) {
+        *path_dest = default_conf_path;
+    }
+
+    return res;
+}
+
+static int
+_sasl_getconfpath_simple(void *context __attribute__((unused)),
+                         const char **path)
+{
+    if (! path) {
+        return SASL_BADPARAM;
+    }
+
+    if (default_conf_path == NULL) {
+        return SASL_FAIL;
+    }
+
+    *path = default_conf_path;
+
+    return SASL_OK;
+}
+
+static int
+_sasl_verifyfile(void *context __attribute__((unused)),
+		 char *file  __attribute__((unused)),
+		 int type  __attribute__((unused)))
+{
+  /* always say ok */
+  return SASL_OK;
+}
+
+
+static int
+_sasl_proxy_policy(sasl_conn_t *conn,
+		   void *context __attribute__((unused)),
+		   const char *requested_user, unsigned rlen,
+		   const char *auth_identity, unsigned alen,
+		   const char *def_realm __attribute__((unused)),
+		   unsigned urlen __attribute__((unused)),
+		   struct propctx *propctx __attribute__((unused)))
+{
+    if (!conn)
+	return SASL_BADPARAM;
+
+    if (!requested_user || *requested_user == '\0')
+	return SASL_OK;
+
+    if (!auth_identity || !requested_user || rlen != alen ||
+	(memcmp(auth_identity, requested_user, rlen) != 0)) {
+	sasl_seterror(conn, 0,
+		      "Requested identity not authenticated identity");
+	RETURN(conn, SASL_BADAUTH);
+    }
+
+    return SASL_OK;
+}
+
+int _sasl_getcallback(sasl_conn_t * conn,
+		      unsigned long callbackid,
+		      sasl_callback_ft *pproc,
+		      void **pcontext)
+{
+  const sasl_callback_t *callback;
+
+  if (!pproc || !pcontext)
+      PARAMERROR(conn);
+
+  /* Some callbacks are always provided by the library */
+  switch (callbackid) {
+  case SASL_CB_LIST_END:
+    /* Nothing ever gets to provide this */
+      INTERROR(conn, SASL_FAIL);
+  case SASL_CB_GETOPT:
+      if (conn) {
+	  *pproc = (sasl_callback_ft)&_sasl_conn_getopt;
+	  *pcontext = conn;
+      } else {
+	  *pproc = (sasl_callback_ft)&_sasl_global_getopt;
+	  *pcontext = NULL;
+      }
+      return SASL_OK;
+  }
+
+  /* If it's not always provided by the library, see if there's
+   * a version provided by the application for this connection... */
+  if (conn && conn->callbacks) {
+    for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
+	 callback++) {
+	if (callback->id == callbackid) {
+	    *pproc = callback->proc;
+	    *pcontext = callback->context;
+	    if (callback->proc) {
+		return SASL_OK;
+	    } else {
+		return SASL_INTERACT;
+	    }
+	}
+    }
+  }
+
+  /* And, if not for this connection, see if there's one
+   * for all {server,client} connections... */
+  if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
+      for (callback = conn->global_callbacks->callbacks;
+	   callback->id != SASL_CB_LIST_END;
+	   callback++) {
+	  if (callback->id == callbackid) {
+	      *pproc = callback->proc;
+	      *pcontext = callback->context;
+	      if (callback->proc) {
+		  return SASL_OK;
+	      } else {
+		  return SASL_INTERACT;
+	      }
+	  }
+      }
+  }
+
+  /* Otherwise, see if the library provides a default callback. */
+  switch (callbackid) {
+#ifdef HAVE_SYSLOG
+  case SASL_CB_LOG:
+    *pproc = (sasl_callback_ft)&_sasl_syslog;
+    *pcontext = conn;
+    return SASL_OK;
+#endif /* HAVE_SYSLOG */
+  case SASL_CB_GETPATH:
+    *pproc = default_getpath_cb.proc;
+    *pcontext = default_getpath_cb.context;
+    return SASL_OK;
+  case SASL_CB_GETCONFPATH:
+    *pproc = default_getconfpath_cb.proc;
+    *pcontext = default_getconfpath_cb.context;
+    return SASL_OK;
+  case SASL_CB_AUTHNAME:
+    *pproc = (sasl_callback_ft)&_sasl_getsimple;
+    *pcontext = conn;
+    return SASL_OK;
+  case SASL_CB_VERIFYFILE:
+    *pproc = (sasl_callback_ft)&_sasl_verifyfile;
+    *pcontext = NULL;
+    return SASL_OK;
+  case SASL_CB_PROXY_POLICY:
+    *pproc = (sasl_callback_ft)&_sasl_proxy_policy;
+    *pcontext = NULL;
+    return SASL_OK;
+  }
+
+  /* Unable to find a callback... */
+  *pproc = NULL;
+  *pcontext = NULL;
+  sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
+  RETURN(conn,SASL_FAIL);
+}
+
+
+/*
+ * This function is typically called from a plugin.
+ * It creates a string from the formatting and varargs given
+ * and calls the logging callback (syslog by default)
+ *
+ * %m will parse the value in the next argument as an errno string
+ * %z will parse the next argument as a SASL error code.
+ */
+
+void
+_sasl_log (sasl_conn_t *conn,
+	   int level,
+	   const char *fmt,
+	   ...)
+{
+  char *out=(char *) sasl_ALLOC(250);
+  size_t alloclen=100; /* current allocated length */
+  size_t outlen=0; /* current length of output buffer */
+  size_t formatlen;
+  size_t pos=0; /* current position in format string */
+  int result;
+  sasl_log_t *log_cb;
+  void *log_ctx;
+  
+  int ival;
+  unsigned int uval;
+  char *cval;
+  va_list ap; /* varargs thing */
+
+  if(!fmt) goto done;
+  if(!out) return;
+  
+  formatlen = strlen(fmt);
+
+  /* See if we have a logging callback... */
+  result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+  if (result == SASL_OK && ! log_cb)
+    result = SASL_FAIL;
+  if (result != SASL_OK) goto done;
+  
+  va_start(ap, fmt); /* start varargs */
+
+  while(pos<formatlen)
+  {
+    if (fmt[pos]!='%') /* regular character */
+    {
+      result = _buf_alloc(&out, &alloclen, outlen+1);
+      if (result != SASL_OK) goto done;
+      out[outlen]=fmt[pos];
+      outlen++;
+      pos++;
+
+    } else { /* formating thing */
+      int done=0;
+      char frmt[10];
+      int frmtpos=1;
+      char tempbuf[21];
+      frmt[0]='%';
+      pos++;
+
+      while (done==0)
+      {
+	switch(fmt[pos])
+	  {
+	  case 's': /* need to handle this */
+	    cval = va_arg(ap, char *); /* get the next arg */
+	    result = _sasl_add_string(&out, &alloclen,
+				&outlen, cval);
+	      
+	    if (result != SASL_OK) /* add the string */
+		goto done;
+
+	    done=1;
+	    break;
+
+	  case '%': /* double % output the '%' character */
+	    result = _buf_alloc(&out,&alloclen,outlen+1);
+	    if (result != SASL_OK)
+		goto done;
+	    
+	    out[outlen]='%';
+	    outlen++;
+	    done=1;
+	    break;
+
+	  case 'm': /* insert the errno string */
+	    result = _sasl_add_string(&out, &alloclen, &outlen,
+				strerror(va_arg(ap, int)));
+	    if (result != SASL_OK)
+		goto done;
+	    
+	    done=1;
+	    break;
+
+	  case 'z': /* insert the sasl error string */
+	    result = _sasl_add_string(&out, &alloclen, &outlen,
+				(char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
+	    if (result != SASL_OK)
+		goto done;
+	    
+	    done=1;
+	    break;
+
+	  case 'c':
+	    frmt[frmtpos++]=fmt[pos];
+	    frmt[frmtpos]=0;
+	    tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
+	    tempbuf[1]='\0';
+	    
+	    /* now add the character */
+	    result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+	    if (result != SASL_OK)
+		goto done;
+		
+	    done=1;
+	    break;
+
+	  case 'd':
+	  case 'i':
+	    frmt[frmtpos++]=fmt[pos];
+	    frmt[frmtpos]=0;
+	    ival = va_arg(ap, int); /* get the next arg */
+
+	    snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
+	    /* now add the string */
+	    result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+	    if (result != SASL_OK)
+		goto done;
+
+	    done=1;
+	    break;
+
+	  case 'o':
+	  case 'u':
+	  case 'x':
+	  case 'X':
+	    frmt[frmtpos++]=fmt[pos];
+	    frmt[frmtpos]=0;
+	    uval = va_arg(ap, unsigned int); /* get the next arg */
+
+	    snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
+	    /* now add the string */
+	    result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+	    if (result != SASL_OK)
+		goto done;
+
+	    done=1;
+	    break;
+
+	  default: 
+	    frmt[frmtpos++]=fmt[pos]; /* add to the formating */
+	    frmt[frmtpos]=0;	    
+	    if (frmtpos>9) 
+	      done=1;
+	  }
+	pos++;
+	if (pos>formatlen)
+	  done=1;
+      }
+
+    }
+  }
+
+  /* put 0 at end */
+  result = _buf_alloc(&out, &alloclen, outlen+1);
+  if (result != SASL_OK) goto done;
+  out[outlen]=0;
+
+  va_end(ap);    
+
+  /* send log message */
+  result = log_cb(log_ctx, level, out);
+
+ done:
+  if(out) sasl_FREE(out);
+}
+
+
+
+/* Allocate and Init a sasl_utils_t structure */
+sasl_utils_t *
+_sasl_alloc_utils(sasl_conn_t *conn,
+		  sasl_global_callbacks_t *global_callbacks)
+{
+  sasl_utils_t *utils;
+  /* set util functions - need to do rest*/
+  utils=sasl_ALLOC(sizeof(sasl_utils_t));
+  if (utils==NULL)
+    return NULL;
+
+  utils->conn = conn;
+
+  sasl_randcreate(&utils->rpool);
+
+  if (conn) {
+    utils->getopt = &_sasl_conn_getopt;
+    utils->getopt_context = conn;
+  } else {
+    utils->getopt = &_sasl_global_getopt;
+    utils->getopt_context = global_callbacks;
+  }
+
+  utils->malloc=_sasl_allocation_utils.malloc;
+  utils->calloc=_sasl_allocation_utils.calloc;
+  utils->realloc=_sasl_allocation_utils.realloc;
+  utils->free=_sasl_allocation_utils.free;
+
+  utils->mutex_alloc = _sasl_mutex_utils.alloc;
+  utils->mutex_lock = _sasl_mutex_utils.lock;
+  utils->mutex_unlock = _sasl_mutex_utils.unlock;
+  utils->mutex_free = _sasl_mutex_utils.free;
+  
+  utils->MD5Init  = &_sasl_MD5Init;
+  utils->MD5Update= &_sasl_MD5Update;
+  utils->MD5Final = &_sasl_MD5Final;
+  utils->hmac_md5 = &_sasl_hmac_md5;
+  utils->hmac_md5_init = &_sasl_hmac_md5_init;
+  utils->hmac_md5_final = &_sasl_hmac_md5_final;
+  utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
+  utils->hmac_md5_import = &_sasl_hmac_md5_import;
+  utils->mkchal = &sasl_mkchal;
+  utils->utf8verify = &sasl_utf8verify;
+  utils->rand=&sasl_rand;
+  utils->churn=&sasl_churn;  
+  utils->checkpass=NULL;
+  
+  utils->encode64=&sasl_encode64;
+  utils->decode64=&sasl_decode64;
+  
+  utils->erasebuffer=&sasl_erasebuffer;
+
+  utils->getprop=&sasl_getprop;
+  utils->setprop=&sasl_setprop;
+
+  utils->getcallback=&_sasl_getcallback;
+
+  utils->log=&_sasl_log;
+
+  utils->seterror=&sasl_seterror;
+
+#ifndef macintosh
+  /* Aux Property Utilities */
+  utils->prop_new=&prop_new;
+  utils->prop_dup=&prop_dup;
+  utils->prop_request=&prop_request;
+  utils->prop_get=&prop_get;
+  utils->prop_getnames=&prop_getnames;
+  utils->prop_clear=&prop_clear;
+  utils->prop_dispose=&prop_dispose;
+  utils->prop_format=&prop_format;
+  utils->prop_set=&prop_set;
+  utils->prop_setvals=&prop_setvals;
+  utils->prop_erase=&prop_erase;
+  utils->auxprop_store=&sasl_auxprop_store;
+#endif
+
+  /* Spares */
+  utils->spare_fptr = NULL;
+  utils->spare_fptr1 = utils->spare_fptr2 = NULL;
+  
+  return utils;
+}
+
+int
+_sasl_free_utils(const sasl_utils_t ** utils)
+{
+    sasl_utils_t *nonconst;
+
+    if(!utils) return SASL_BADPARAM;
+    if(!*utils) return SASL_OK;
+
+    /* I wish we could avoid this cast, it's pretty gratuitous but it
+     * does make life easier to have it const everywhere else. */
+    nonconst = (sasl_utils_t *)(*utils);
+
+    sasl_randfree(&(nonconst->rpool));
+    sasl_FREE(nonconst);
+
+    *utils = NULL;
+    return SASL_OK;
+}
+
+int sasl_idle(sasl_conn_t *conn)
+{
+  if (! conn) {
+    if (_sasl_server_idle_hook
+	&& _sasl_server_idle_hook(NULL))
+      return 1;
+    if (_sasl_client_idle_hook
+	&& _sasl_client_idle_hook(NULL))
+      return 1;
+    return 0;
+  }
+
+  if (conn->idle_hook)
+    return conn->idle_hook(conn);
+
+  return 0;
+}
+
+static const sasl_callback_t *
+_sasl_find_callback_by_type (const sasl_callback_t *callbacks,
+                             unsigned long id)
+{
+    if (callbacks) {
+        while (callbacks->id != SASL_CB_LIST_END) {
+            if (callbacks->id == id) {
+	        return callbacks;
+            } else {
+	        ++callbacks;
+            }
+        }
+    }
+    return NULL;
+}
+
+const sasl_callback_t *
+_sasl_find_getpath_callback(const sasl_callback_t *callbacks)
+{
+  callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
+  if (callbacks != NULL) {
+    return callbacks;
+  } else {
+    return &default_getpath_cb;
+  }
+}
+
+const sasl_callback_t *
+_sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
+{
+  callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
+  if (callbacks != NULL) {
+    return callbacks;
+  } else {
+    return &default_getconfpath_cb;
+  }
+}
+
+const sasl_callback_t *
+_sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
+{
+  static const sasl_callback_t default_verifyfile_cb = {
+    SASL_CB_VERIFYFILE,
+    (sasl_callback_ft)&_sasl_verifyfile,
+    NULL
+  };
+
+  callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
+  if (callbacks != NULL) {
+    return callbacks;
+  } else {
+    return &default_verifyfile_cb;
+  }
+}
+
+/* Basically a conditional call to realloc(), if we need more */
+int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen) 
+{
+    if(!(*rwbuf)) {
+	*rwbuf = sasl_ALLOC((unsigned)newlen);
+	if (*rwbuf == NULL) {
+	    *curlen = 0;
+	    return SASL_NOMEM;
+	}
+	*curlen = newlen;
+    } else if(*rwbuf && *curlen < newlen) {
+	size_t needed = 2*(*curlen);
+
+	while(needed < newlen)
+	    needed *= 2;
+
+        /* WARN - We will leak the old buffer on failure */
+	*rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
+	
+	if (*rwbuf == NULL) {
+	    *curlen = 0;
+	    return SASL_NOMEM;
+	}
+	*curlen = needed;
+    } 
+
+    return SASL_OK;
+}
+
+/* for the mac os x cfm glue: this lets the calling function
+   get pointers to the error buffer without having to touch the sasl_conn_t struct */
+void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
+{
+	*bufhdl = &conn->error_buf;
+	*lenhdl = &conn->error_buf_len;
+}
+
+/* convert an iovec to a single buffer */
+int _iovec_to_buf(const struct iovec *vec,
+		  unsigned numiov, buffer_info_t **output) 
+{
+    unsigned i;
+    int ret;
+    buffer_info_t *out;
+    char *pos;
+
+    if (!vec || !output) return SASL_BADPARAM;
+
+    if (!(*output)) {
+	*output = sasl_ALLOC(sizeof(buffer_info_t));
+	if (!*output) return SASL_NOMEM;
+	memset(*output,0,sizeof(buffer_info_t));
+    }
+
+    out = *output;
+    
+    out->curlen = 0;
+    for (i = 0; i < numiov; i++) {
+	out->curlen += vec[i].iov_len;
+    }
+
+    ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
+
+    if (ret != SASL_OK) return SASL_NOMEM;
+    
+    memset(out->data, 0, out->reallen);
+    pos = out->data;
+    
+    for (i = 0; i < numiov; i++) {
+	memcpy(pos, vec[i].iov_base, vec[i].iov_len);
+	pos += vec[i].iov_len;
+    }
+
+    return SASL_OK;
+}
+
+/* This code might be useful in the future, but it isn't now, so.... */
+#if 0
+int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
+		     char *out, unsigned outlen) {
+    char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+    int niflags;
+
+    if(!addr || !out) return SASL_BADPARAM;
+
+    niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
+#ifdef NI_WITHSCOPEID
+    if (addr->sa_family == AF_INET6)
+	niflags |= NI_WITHSCOPEID;
+#endif
+    if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+		    niflags) != 0)
+	return SASL_BADPARAM;
+
+    if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
+	return SASL_BUFOVER;
+
+    snprintf(out, outlen, "%s;%s", hbuf, pbuf);
+
+    return SASL_OK;
+}
+#endif
+
+int _sasl_ipfromstring(const char *addr,
+		       struct sockaddr *out, socklen_t outlen) 
+{
+    int i, j;
+    struct addrinfo hints, *ai = NULL;
+    char hbuf[NI_MAXHOST];
+    
+    /* A NULL out pointer just implies we don't do a copy, just verify it */
+
+    if(!addr) return SASL_BADPARAM;
+
+    /* Parse the address */
+    for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
+	if (i >= NI_MAXHOST)
+	    return SASL_BADPARAM;
+	hbuf[i] = addr[i];
+    }
+    hbuf[i] = '\0';
+
+    if (addr[i] == ';')
+	i++;
+    /* XXX: Do we need this check? */
+    for (j = i; addr[j] != '\0'; j++)
+	if (!isdigit((int)(addr[j])))
+	    return SASL_BADPARAM;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+    if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
+	return SASL_BADPARAM;
+
+    if (out) {
+	if (outlen < (socklen_t)ai->ai_addrlen) {
+	    freeaddrinfo(ai);
+	    return SASL_BUFOVER;
+	}
+	memcpy(out, ai->ai_addr, ai->ai_addrlen);
+    }
+
+    freeaddrinfo(ai);
+
+    return SASL_OK;
+}
+
+int _sasl_build_mechlist(void) 
+{
+    int count = 0;
+    sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
+    sasl_string_list_t *p, *q, **last, *p_next;
+
+    clist = _sasl_client_mechs();
+    slist = _sasl_server_mechs();
+
+    if(!clist) {
+	olist = slist;
+    } else {
+	int flag;
+	
+	/* append slist to clist, and set olist to clist */
+	for(p = slist; p; p = p_next) {
+	    flag = 0;
+	    p_next = p->next;
+
+	    last = &clist;
+	    for(q = clist; q; q = q->next) {
+		if(!strcmp(q->d, p->d)) {
+		    /* They match, set the flag */
+		    flag = 1;
+		    break;
+		}
+		last = &(q->next);
+	    }
+
+	    if(!flag) {
+		*last = p;
+		p->next = NULL;
+	    } else {
+		sasl_FREE(p);
+	    }
+	}
+
+	olist = clist;
+    }
+
+    if(!olist) {
+	/* This is not going to be very useful */
+	printf ("no olist");
+	return SASL_FAIL;
+    }
+
+    for (p = olist; p; p = p->next) count++;
+    
+    if(global_mech_list) {
+	sasl_FREE(global_mech_list);
+	global_mech_list = NULL;
+    }
+    
+    global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
+    if(!global_mech_list) return SASL_NOMEM;
+    
+    memset(global_mech_list, 0, (count + 1) * sizeof(char *));
+    
+    count = 0;
+    for (p = olist; p; p = p_next) {
+	p_next = p->next;
+
+	global_mech_list[count++] = (char *) p->d;
+
+    	sasl_FREE(p);
+    }
+
+    return SASL_OK;
+}
+
+const char ** sasl_global_listmech(void) 
+{
+    return (const char **)global_mech_list;
+}
+
+int sasl_listmech(sasl_conn_t *conn,
+		  const char *user,
+		  const char *prefix,
+		  const char *sep,
+		  const char *suffix,
+		  const char **result,
+		  unsigned *plen,
+		  int *pcount)
+{
+    if(!conn) {
+	return SASL_BADPARAM;
+    } else if(conn->type == SASL_CONN_SERVER) {
+	RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
+					   result, plen, pcount));
+    } else if (conn->type == SASL_CONN_CLIENT) {
+	RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
+					   result, plen, pcount));
+    }
+    
+    PARAMERROR(conn);
+}
+
+int _sasl_is_equal_mech(const char *req_mech,
+                        const char *plug_mech,
+			size_t req_mech_len,
+                        int *plus)
+{
+    size_t n;
+
+    if (req_mech_len > 5 &&
+        strcasecmp(&req_mech[req_mech_len - 5], "-PLUS") == 0) {
+        n = req_mech_len - 5;
+        *plus = 1;
+    } else {
+        n = req_mech_len;
+        *plus = 0;
+    }
+
+    return (strncasecmp(req_mech, plug_mech, n) == 0);
+}
+
+#ifndef WIN32
+static char *
+_sasl_get_default_unix_path(void *context __attribute__((unused)),
+                            char * env_var_name,
+                            char * default_value)
+{
+    char *path = NULL;
+
+    /* Honor external variable only in a safe environment */
+    if (getuid() == geteuid() && getgid() == getegid()) {
+        path = getenv(env_var_name);
+    }
+    if (! path) {
+        path = default_value;
+    }
+
+    return path;
+}
+
+#else
+/* Return NULL on failure */
+static char *
+_sasl_get_default_win_path(void *context __attribute__((unused)),
+                           char * reg_attr_name,
+                           char * default_value)
+{
+    /* Open registry entry, and find all registered SASL libraries.
+     *
+     * Registry location:
+     *
+     *     SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
+     *
+     * Key - value:
+     *
+     *     "SearchPath" - value: PATH like (';' delimited) list
+     *                    of directories where to search for plugins
+     *                    The list may contain references to environment
+     *                    variables (e.g. %PATH%).
+     *
+     */
+    HKEY  hKey;
+    DWORD ret;
+    DWORD ValueType;		    /* value type */
+    DWORD cbData;		    /* value size */
+    BYTE * ValueData;		    /* value */
+    DWORD cbExpandedData;	    /* "expanded" value size */
+    BYTE * ExpandedValueData;	    /* "expanded" value */
+    char * return_value;	    /* function return value */
+    char * tmp;
+
+    /* Initialization */
+    ExpandedValueData = NULL;
+    ValueData = NULL;
+    return_value = NULL;
+
+    /* Open the registry */
+    ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+		       SASL_ROOT_KEY,
+		       0,
+		       KEY_READ,
+		       &hKey);
+
+    if (ret != ERROR_SUCCESS) { 
+        /* no registry entry */
+        (void) _sasl_strdup (default_value, &return_value, NULL);
+        return return_value;
+    }
+
+    /* figure out value type and required buffer size */
+    /* the size will include space for terminating NUL if required */
+    RegQueryValueEx (hKey,
+		     reg_attr_name,
+		     NULL,	    /* reserved */
+		     &ValueType,
+		     NULL,
+		     &cbData);
+ 
+    /* Only accept string related types */
+    if (ValueType != REG_EXPAND_SZ &&
+	ValueType != REG_MULTI_SZ &&
+	ValueType != REG_SZ) {
+	return_value = NULL;
+	goto CLEANUP;
+    }
+
+    /* Any high water mark? */
+    ValueData = sasl_ALLOC(cbData);
+    if (ValueData == NULL) {
+	return_value = NULL;
+	goto CLEANUP;
+    };
+
+    RegQueryValueEx (hKey,
+		     reg_attr_name,
+		     NULL,	    /* reserved */
+		     &ValueType,
+		     ValueData,
+		     &cbData);
+
+    switch (ValueType) {
+    case REG_EXPAND_SZ:
+        /* : A random starting guess */
+        cbExpandedData = cbData + 1024;
+        ExpandedValueData = sasl_ALLOC(cbExpandedData);
+        if (ExpandedValueData == NULL) {
+            return_value = NULL;
+            goto CLEANUP;
+        };
+
+        cbExpandedData = ExpandEnvironmentStrings(
+                                                  ValueData,
+                                                  ExpandedValueData,
+                                                  cbExpandedData);
+
+        if (cbExpandedData == 0) {
+            /* : GetLastError() contains the reason for failure */
+            return_value = NULL;
+            goto CLEANUP;
+        }
+
+        /* : Must retry expansion with the bigger buffer */
+        if (cbExpandedData > cbData + 1024) {
+            /* : Memory leak here if can't realloc */
+            ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData);
+            if (ExpandedValueData == NULL) {
+                return_value = NULL;
+                goto CLEANUP;
+            };
+
+            cbExpandedData = ExpandEnvironmentStrings(
+                                                      ValueData,
+                                                      ExpandedValueData,
+                                                      cbExpandedData);
+
+            /* : This should not happen */
+            if (cbExpandedData == 0) {
+                /* : GetLastError() contains the reason for failure */
+                return_value = NULL;
+                goto CLEANUP;
+            }
+        }
+
+        sasl_FREE(ValueData);
+        ValueData = ExpandedValueData;
+        /* : This is to prevent automatical freeing of this block on cleanup */
+        ExpandedValueData = NULL;
+
+        break;
+
+    case REG_MULTI_SZ:
+        tmp = ValueData;
+
+        /* : We shouldn't overflow here, as the buffer is guarantied
+           : to contain at least two consequent NULs */
+        while (1) {
+            if (tmp[0] == '\0') {
+                /* : Stop the process if we found the end of the string (two consequent NULs) */
+                if (tmp[1] == '\0') {
+                    break;
+                }
+
+                /* : Replace delimiting NUL with our delimiter characted */
+                tmp[0] = PATHS_DELIMITER;
+            }
+            tmp += strlen(tmp);
+        }
+        break;
+
+    case REG_SZ:
+        /* Do nothing, it is good as is */
+        break;
+
+    default:
+        return_value = NULL;
+        goto CLEANUP;
+    }
+
+    return_value = ValueData;
+
+CLEANUP:
+    RegCloseKey(hKey);
+    if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
+    if (return_value == NULL) {
+	if (ValueData != NULL) sasl_FREE(ValueData);
+    }
+
+    return (return_value);
+}
+#endif

+ 168 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/config.c

@@ -0,0 +1,168 @@
+/* SASL Config file API
+ * Rob Siemborski
+ * Tim Martin (originally in Cyrus distribution)
+ * $Id: config.c,v 1.19 2011/11/08 17:22:40 murch Exp $
+ */
+/* 
+ * Copyright (c) 1998-2009 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "sasl.h"
+#include "saslint.h"
+
+struct configlist {
+    char *key;
+    char *value;
+};
+
+static struct configlist *configlist = NULL;
+static int nconfiglist = 0;
+
+#define CONFIGLISTGROWSIZE 100
+
+int sasl_config_init(const char *filename)
+{
+    FILE *infile;
+    int lineno = 0;
+    int alloced = 0;
+    char buf[4096];
+    char *p, *key;
+    char *tail;
+    int result;
+
+    nconfiglist=0;
+
+    infile = fopen(filename, "r");
+    if (!infile) {
+        return SASL_CONTINUE;
+    }
+    
+    while (fgets(buf, sizeof(buf), infile)) {
+	lineno++;
+
+	if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
+	for (p = buf; *p && isspace((int) *p); p++);
+	if (!*p || *p == '#') continue;
+
+	key = p;
+	while (*p && (isalnum((int) *p) || *p == '-' || *p == '_')) {
+	    if (isupper((int) *p)) *p = (char) tolower(*p);
+	    p++;
+	}
+	if (*p != ':') {
+	    fclose(infile);
+	    return SASL_FAIL;
+	}
+	*p++ = '\0';
+
+	while (*p && isspace((int) *p)) p++;
+	
+	if (!*p) {
+	    fclose(infile);
+	    return SASL_FAIL;
+	}
+
+	/* Now strip trailing spaces, if any */
+	tail = p + strlen(p) - 1;
+	while (tail > p && isspace((int) *tail)) {
+	    *tail = '\0';
+	    tail--;
+	}
+
+	if (nconfiglist == alloced) {
+	    alloced += CONFIGLISTGROWSIZE;
+	    configlist=sasl_REALLOC((char *)configlist, 
+				    alloced * sizeof(struct configlist));
+	    if (configlist == NULL) {
+		fclose(infile);
+		return SASL_NOMEM;
+	    }
+	}
+
+	result = _sasl_strdup(key,
+			      &(configlist[nconfiglist].key),
+			      NULL);
+	if (result != SASL_OK) {
+	    fclose(infile);
+	    return result;
+	}
+	result = _sasl_strdup(p,
+			      &(configlist[nconfiglist].value),
+			      NULL);
+	if (result != SASL_OK) {
+	    fclose(infile);
+	    return result;
+	}
+
+	nconfiglist++;
+    }
+    fclose(infile);
+
+    return SASL_OK;
+}
+
+const char *sasl_config_getstring(const char *key,const char *def)
+{
+    int opt;
+
+    for (opt = 0; opt < nconfiglist; opt++) {
+	if (*key == configlist[opt].key[0] &&
+	    !strcmp(key, configlist[opt].key))
+	  return configlist[opt].value;
+    }
+    return def;
+}
+
+void sasl_config_done(void)
+{
+    int opt;
+
+    for (opt = 0; opt < nconfiglist; opt++) {
+	if (configlist[opt].key) sasl_FREE(configlist[opt].key);
+	if (configlist[opt].value) sasl_FREE(configlist[opt].value);
+    }
+
+    sasl_FREE(configlist);
+    configlist = NULL;
+    nconfiglist = 0;
+}

+ 562 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/dlopen.c

@@ -0,0 +1,562 @@
+/* dlopen.c--Unix dlopen() dynamic loader interface
+ * Rob Siemborski
+ * Rob Earhart
+ * $Id: dlopen.c,v 1.52 2009/04/11 10:21:43 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <sasl.h>
+#include "saslint.h"
+
+#ifndef PIC
+#include <saslplug.h>
+#include "staticopen.h"
+#endif
+
+#ifdef DO_DLOPEN
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else /* HAVE_DIRENT_H */
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif /* ! HAVE_DIRENT_H */
+
+#ifndef NAME_MAX
+# ifdef _POSIX_NAME_MAX
+#  define NAME_MAX _POSIX_NAME_MAX
+# else
+#  define NAME_MAX 16
+# endif
+#endif
+ 
+#if NAME_MAX < 8
+#  define NAME_MAX 8
+#endif
+
+#ifdef __hpux
+#ifndef HAVE_DLFCN_H
+#include <dl.h>
+
+typedef shl_t * dll_handle;
+typedef void * dll_func;
+
+dll_handle
+dlopen(char *fname, int mode)
+{
+    shl_t h = shl_load(fname, BIND_DEFERRED, 0L);
+    shl_t *hp = NULL;
+    
+    if (h) {
+	hp = (shl_t *)malloc(sizeof (shl_t));
+	if (!hp) {
+	    shl_unload(h);
+	} else {
+	    *hp = h;
+	}
+    }
+
+    return (dll_handle)hp;
+}
+
+int
+dlclose(dll_handle hp)
+{
+    shl_t h;
+
+    if (hp != NULL) {
+	h = *((shl_t *)hp);
+	free(hp);
+	return shl_unload(h);
+    } else {
+	/* Return error */
+	return -1;
+    }
+}
+
+dll_func
+dlsym(dll_handle h, char *n)
+{
+    dll_func handle;
+    
+    if (shl_findsym ((shl_t *)h, n, TYPE_PROCEDURE, &handle))
+	return NULL;
+    
+    return (dll_func)handle;
+}
+
+char *dlerror()
+{
+    if (errno != 0) {
+	return strerror(errno);
+    }
+    return "Generic shared library error";
+}
+
+#endif /* HAVE_DLFCN_H */
+
+#ifdef __ia64
+#define SO_SUFFIX       ".so"
+#else
+#define SO_SUFFIX	".sl"
+#endif /* __ia64 */
+#elif defined(__APPLE__)
+#define SO_SUFFIX	".plugin"
+#else /* __APPLE__ */
+#define SO_SUFFIX	".so"
+#endif
+
+#define LA_SUFFIX       ".la"
+
+typedef struct lib_list 
+{
+    struct lib_list *next;
+    void *library;
+} lib_list_t;
+
+static lib_list_t *lib_list_head = NULL;
+
+#endif /* DO_DLOPEN */
+
+int _sasl_locate_entry(void *library, const char *entryname,
+		       void **entry_point) 
+{
+#ifdef DO_DLOPEN
+/* note that we still check for known problem systems in
+ * case we are cross-compiling */
+#if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
+    char adj_entryname[1024];
+#else
+#define adj_entryname entryname
+#endif
+
+    if(!entryname) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "no entryname in _sasl_locate_entry");
+	return SASL_BADPARAM;
+    }
+
+    if(!library) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "no library in _sasl_locate_entry");
+	return SASL_BADPARAM;
+    }
+
+    if(!entry_point) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "no entrypoint output pointer in _sasl_locate_entry");
+	return SASL_BADPARAM;
+    }
+
+#if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
+    snprintf(adj_entryname, sizeof adj_entryname, "_%s", entryname);
+#endif
+
+    *entry_point = NULL;
+    *entry_point = dlsym(library, adj_entryname);
+    if (*entry_point == NULL) {
+#if 0 /* This message appears to confuse people */
+	_sasl_log(NULL, SASL_LOG_DEBUG,
+		  "unable to get entry point %s: %s", adj_entryname,
+		  dlerror());
+#endif
+	return SASL_FAIL;
+    }
+
+    return SASL_OK;
+#else
+    return SASL_FAIL;
+#endif /* DO_DLOPEN */
+}
+
+#ifdef DO_DLOPEN
+
+static int _sasl_plugin_load(char *plugin, void *library,
+			     const char *entryname,
+			     int (*add_plugin)(const char *, void *)) 
+{
+    void *entry_point;
+    int result;
+    
+    result = _sasl_locate_entry(library, entryname, &entry_point);
+    if(result == SASL_OK) {
+	result = add_plugin(plugin, entry_point);
+	if(result != SASL_OK)
+	    _sasl_log(NULL, SASL_LOG_DEBUG,
+		      "_sasl_plugin_load failed on %s for plugin: %s\n",
+		      entryname, plugin);
+    }
+
+    return result;
+}
+
+/* this returns the file to actually open.
+ *  out should be a buffer of size PATH_MAX
+ *  and may be the same as in. */
+
+/* We'll use a static buffer for speed unless someone complains */
+#define MAX_LINE 2048
+
+static int _parse_la(const char *prefix, const char *in, char *out) 
+{
+    FILE *file;
+    size_t length;
+    char line[MAX_LINE];
+    char *ntmp = NULL;
+
+    if(!in || !out || !prefix || out == in) return SASL_BADPARAM;
+
+    /* Set this so we can detect failure */
+    *out = '\0';
+
+    length = strlen(in);
+
+    if (strcmp(in + (length - strlen(LA_SUFFIX)), LA_SUFFIX)) {
+	if(!strcmp(in + (length - strlen(SO_SUFFIX)),SO_SUFFIX)) {
+	    /* check for a .la file */
+	    strcpy(line, prefix);
+	    strcat(line, in);
+	    length = strlen(line);
+	    *(line + (length - strlen(SO_SUFFIX))) = '\0';
+	    strcat(line, LA_SUFFIX);
+	    file = fopen(line, "r");
+	    if(file) {
+		/* We'll get it on the .la open */
+		fclose(file);
+		return SASL_FAIL;
+	    }
+	}
+	strcpy(out, prefix);
+	strcat(out, in);
+	return SASL_OK;
+    }
+
+    strcpy(line, prefix);
+    strcat(line, in);
+
+    file = fopen(line, "r");
+    if(!file) {
+	_sasl_log(NULL, SASL_LOG_WARN,
+		  "unable to open LA file: %s", line);
+	return SASL_FAIL;
+    }
+    
+    while(!feof(file)) {
+	if(!fgets(line, MAX_LINE, file)) break;
+	if(line[strlen(line) - 1] != '\n') {
+	    _sasl_log(NULL, SASL_LOG_WARN,
+		      "LA file has too long of a line: %s", in);
+	    return SASL_BUFOVER;
+	}
+	if(line[0] == '\n' || line[0] == '#') continue;
+	if(!strncmp(line, "dlname=", sizeof("dlname=") - 1)) {
+	    /* We found the line with the name in it */
+	    char *end;
+	    char *start;
+	    size_t len;
+	    end = strrchr(line, '\'');
+	    if(!end) continue;
+	    start = &line[sizeof("dlname=")-1];
+	    len = strlen(start);
+	    if(len > 3 && start[0] == '\'') {
+		ntmp=&start[1];
+		*end='\0';
+		/* Do we have dlname="" ? */
+		if(ntmp == end) {
+		    _sasl_log(NULL, SASL_LOG_DEBUG,
+			      "dlname is empty in .la file: %s", in);
+		    return SASL_FAIL;
+		}
+		strcpy(out, prefix);
+		strcat(out, ntmp);
+	    }
+	    break;
+	}
+    }
+    if(ferror(file) || feof(file)) {
+	_sasl_log(NULL, SASL_LOG_WARN,
+		  "Error reading .la: %s\n", in);
+	fclose(file);
+	return SASL_FAIL;
+    }
+    fclose(file);
+
+    if(!(*out)) {
+	_sasl_log(NULL, SASL_LOG_WARN,
+		  "Could not find a dlname line in .la file: %s", in);
+	return SASL_FAIL;
+    }
+
+    return SASL_OK;
+}
+#endif /* DO_DLOPEN */
+
+/* loads a plugin library */
+int _sasl_get_plugin(const char *file,
+		     const sasl_callback_t *verifyfile_cb,
+		     void **libraryptr)
+{
+#ifdef DO_DLOPEN
+    int r = 0;
+    int flag;
+    void *library;
+    lib_list_t *newhead;
+    
+    r = ((sasl_verifyfile_t *)(verifyfile_cb->proc))
+		    (verifyfile_cb->context, file, SASL_VRFY_PLUGIN);
+    if (r != SASL_OK) return r;
+
+#ifdef RTLD_NOW
+    flag = RTLD_NOW;
+#else
+    flag = 0;
+#endif
+
+    newhead = sasl_ALLOC(sizeof(lib_list_t));
+    if(!newhead) return SASL_NOMEM;
+
+    if (!(library = dlopen(file, flag))) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "unable to dlopen %s: %s", file, dlerror());
+	sasl_FREE(newhead);
+	return SASL_FAIL;
+    }
+
+    newhead->library = library;
+    newhead->next = lib_list_head;
+    lib_list_head = newhead;
+
+    *libraryptr = library;
+    return SASL_OK;
+#else
+    return SASL_FAIL;
+#endif /* DO_DLOPEN */
+}
+
+/* gets the list of mechanisms */
+int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
+		       const sasl_callback_t *getpath_cb,
+		       const sasl_callback_t *verifyfile_cb)
+{
+    int result;
+    const add_plugin_list_t *cur_ep;
+#ifdef DO_DLOPEN
+    char str[PATH_MAX], tmp[PATH_MAX+2], prefix[PATH_MAX+2];
+				/* 1 for '/' 1 for trailing '\0' */
+    char c;
+    int pos;
+    const char *path=NULL;
+    int position;
+    DIR *dp;
+    struct dirent *dir;
+#endif
+#ifndef PIC
+    add_plugin_t *add_plugin;
+    _sasl_plug_type type;
+    _sasl_plug_rec *p;
+#endif
+
+    if (! entrypoints
+	|| ! getpath_cb
+	|| getpath_cb->id != SASL_CB_GETPATH
+	|| ! getpath_cb->proc
+	|| ! verifyfile_cb
+	|| verifyfile_cb->id != SASL_CB_VERIFYFILE
+	|| ! verifyfile_cb->proc)
+	return SASL_BADPARAM;
+
+#ifndef PIC
+    /* do all the static plugins first */
+
+    for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
+
+	/* What type of plugin are we looking for? */
+	if(!strcmp(cur_ep->entryname, "sasl_server_plug_init")) {
+	    type = SERVER;
+	    add_plugin = (add_plugin_t *)sasl_server_add_plugin;
+	} else if (!strcmp(cur_ep->entryname, "sasl_client_plug_init")) {
+	    type = CLIENT;
+	    add_plugin = (add_plugin_t *)sasl_client_add_plugin;
+	} else if (!strcmp(cur_ep->entryname, "sasl_auxprop_plug_init")) {
+	    type = AUXPROP;
+	    add_plugin = (add_plugin_t *)sasl_auxprop_add_plugin;
+	} else if (!strcmp(cur_ep->entryname, "sasl_canonuser_init")) {
+	    type = CANONUSER;
+	    add_plugin = (add_plugin_t *)sasl_canonuser_add_plugin;
+	} else {
+	    /* What are we looking for then? */
+	    return SASL_FAIL;
+	}
+	for (p=_sasl_static_plugins; p->type; p++) {
+	    if(type == p->type)
+	    	result = add_plugin(p->name, p->plug);
+	}
+    }
+#endif /* !PIC */
+
+/* only do the following if:
+ * 
+ * we support dlopen()
+ *  AND we are not staticly compiled
+ *      OR we are staticly compiled and TRY_DLOPEN_WHEN_STATIC is defined
+ */
+#if defined(DO_DLOPEN) && (defined(PIC) || (!defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC)))
+    /* get the path to the plugins */
+    result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
+						    &path);
+    if (result != SASL_OK) return result;
+    if (! path) return SASL_FAIL;
+
+    if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
+	return SASL_FAIL;
+    }
+
+    position=0;
+    do {
+	pos=0;
+	do {
+	    c=path[position];
+	    position++;
+	    str[pos]=c;
+	    pos++;
+	} while ((c!=':') && (c!='=') && (c!=0));
+	str[pos-1]='\0';
+
+	strcpy(prefix,str);
+	strcat(prefix,"/");
+
+	if ((dp=opendir(str)) !=NULL) /* ignore errors */    
+	{
+	    while ((dir=readdir(dp)) != NULL)
+	    {
+		size_t length;
+		void *library;
+		char *c;
+		char plugname[PATH_MAX];
+		char name[PATH_MAX];
+
+		length = NAMLEN(dir);
+		if (length < 4) 
+		    continue; /* can not possibly be what we're looking for */
+
+		if (length + pos>=PATH_MAX) continue; /* too big */
+
+		if (strcmp(dir->d_name + (length - strlen(SO_SUFFIX)),
+			   SO_SUFFIX)
+		    && strcmp(dir->d_name + (length - strlen(LA_SUFFIX)),
+			   LA_SUFFIX))
+		    continue;
+
+		memcpy(name,dir->d_name,length);
+		name[length]='\0';
+
+		result = _parse_la(prefix, name, tmp);
+		if(result != SASL_OK)
+		    continue;
+		
+		/* skip "lib" and cut off suffix --
+		   this only need be approximate */
+		strcpy(plugname, name + 3);
+		c = strchr(plugname, (int)'.');
+		if(c) *c = '\0';
+
+		result = _sasl_get_plugin(tmp, verifyfile_cb, &library);
+
+		if(result != SASL_OK)
+		    continue;
+
+		for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
+			_sasl_plugin_load(plugname, library, cur_ep->entryname,
+					  cur_ep->add_plugin);
+			/* If this fails, it's not the end of the world */
+		}
+	    }
+
+	    closedir(dp);
+	} else {
+	    _sasl_log(NULL, SASL_LOG_DEBUG,
+		      "looking for plugins in '%s', failed to open directory, error: %s",
+		      str,
+		      strerror(errno));
+	}
+
+    } while ((c!='=') && (c!=0));
+#endif /* defined(DO_DLOPEN) && (!defined(PIC) || (defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC))) */
+
+    return SASL_OK;
+}
+
+int
+_sasl_done_with_plugins(void)
+{
+#ifdef DO_DLOPEN
+    lib_list_t *libptr, *libptr_next;
+    
+    for(libptr = lib_list_head; libptr; libptr = libptr_next) {
+	libptr_next = libptr->next;
+	if(libptr->library)
+	    dlclose(libptr->library);
+	sasl_FREE(libptr);
+    }
+
+    lib_list_head = NULL;
+#endif /* DO_DLOPEN */
+    return SASL_OK;
+}

+ 410 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/external.c

@@ -0,0 +1,410 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: external.c,v 1.24 2009/03/10 16:27:52 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+#include <sasl.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#include "../plugins/plugin_common.h"
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: external.c,v 1.24 2009/03/10 16:27:52 mel Exp $";
+
+/*****************************  Server Section  *****************************/
+
+static int
+external_server_mech_new(void *glob_context __attribute__((unused)),
+			 sasl_server_params_t *sparams,
+			 const char *challenge __attribute__((unused)),
+			 unsigned challen __attribute__((unused)),
+			 void **conn_context)
+{
+    if (!conn_context
+	|| !sparams
+	|| !sparams->utils
+	|| !sparams->utils->conn)
+	return SASL_BADPARAM;
+    
+    if (!sparams->utils->conn->external.auth_id)
+	return SASL_NOMECH;
+    
+    *conn_context = NULL;
+
+    return SASL_OK;
+}
+
+static int
+external_server_mech_step(void *conn_context __attribute__((unused)),
+			  sasl_server_params_t *sparams,
+			  const char *clientin,
+			  unsigned clientinlen,
+			  const char **serverout,
+			  unsigned *serveroutlen,
+			  sasl_out_params_t *oparams)
+{
+    int result;
+    
+    if (!sparams
+	|| !sparams->utils
+	|| !sparams->utils->conn
+	|| !sparams->utils->getcallback
+	|| !serverout
+	|| !serveroutlen
+	|| !oparams)
+	return SASL_BADPARAM;
+    
+    if (!sparams->utils->conn->external.auth_id)
+	return SASL_BADPROT;
+    
+    /* xxx arbitrary limit here */
+    if (clientinlen > 16384) return SASL_BADPROT;
+
+    if ((sparams->props.security_flags & SASL_SEC_NOANONYMOUS) &&
+	(!strcmp(sparams->utils->conn->external.auth_id, "anonymous"))) {
+	sasl_seterror(sparams->utils->conn,0,"anonymous login not allowed");
+	return SASL_NOAUTHZ;
+    }
+    
+    *serverout = NULL;
+    *serveroutlen = 0;
+    
+    if (!clientin) {
+	/* No initial data; we're in a protocol which doesn't support it.
+	 * So we let the server app know that we need some... */
+	return SASL_CONTINUE;
+    }
+    
+    if (clientinlen) {		/* if we have a non-zero authorization id */
+	/* The user's trying to authorize as someone they didn't
+	 * authenticate as */
+	result = sparams->canon_user(sparams->utils->conn,
+				     clientin, 0,
+				     SASL_CU_AUTHZID, oparams);
+	if(result != SASL_OK) return result;
+	
+	result = sparams->canon_user(sparams->utils->conn,
+				     sparams->utils->conn->external.auth_id, 0,
+				     SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED, oparams);
+    } else {
+	result = sparams->canon_user(sparams->utils->conn,
+				     sparams->utils->conn->external.auth_id, 0,
+				     SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED | SASL_CU_AUTHZID, oparams);
+    }
+    
+    if (result != SASL_OK) return result;
+    
+    /* set oparams */
+    oparams->doneflag = 1;
+    oparams->mech_ssf = 0;
+    oparams->maxoutbuf = 0;
+    oparams->encode_context = NULL;
+    oparams->encode = NULL;
+    oparams->decode_context = NULL;
+    oparams->decode = NULL;
+    oparams->param_version = 0;
+
+    return SASL_OK;
+}
+
+static int
+external_server_mech_avail(void *glob_context __attribute__((unused)),
+			   sasl_server_params_t *sparams,
+			   void **conn_context __attribute__((unused)))
+{
+    if (!sparams->utils->conn->external.auth_id) {
+	/* Return Temporary Failure */
+	return SASL_NOTDONE;
+    }
+    
+    return SASL_OK;
+}
+
+static sasl_server_plug_t external_server_plugins[] =
+{
+    {
+	"EXTERNAL",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_NODICTIONARY,	/* security_flags */
+	SASL_FEAT_WANT_CLIENT_FIRST
+	| SASL_FEAT_ALLOWS_PROXY,	/* features */
+	NULL,				/* glob_context */
+	&external_server_mech_new,	/* mech_new */
+	&external_server_mech_step,	/* mech_step */
+	NULL,				/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	&external_server_mech_avail,	/* mech_avail */
+	NULL				/* spare */
+    }
+};
+
+int external_server_plug_init(const sasl_utils_t *utils,
+			      int max_version,
+			      int *out_version,
+			      sasl_server_plug_t **pluglist,
+			      int *plugcount)
+{
+    if (!out_version || !pluglist || !plugcount)
+	return SASL_BADPARAM;
+    
+    if (max_version != SASL_SERVER_PLUG_VERSION) {
+	SETERROR( utils, "EXTERNAL version mismatch" );
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = external_server_plugins;
+    *plugcount = 1;
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+typedef struct client_context 
+{
+    char *out_buf;
+    size_t out_buf_len;
+} client_context_t;
+
+static int external_client_mech_new(void *glob_context __attribute__((unused)),
+				    sasl_client_params_t *params,
+				    void **conn_context)
+{
+    client_context_t *text;
+    
+    if (!params
+	|| !params->utils
+	|| !params->utils->conn
+	|| !conn_context)
+	return SASL_BADPARAM;
+    
+    if (!params->utils->conn->external.auth_id)
+	return SASL_NOMECH;
+    
+    text = sasl_ALLOC(sizeof(client_context_t));
+    if(!text) return SASL_NOMEM;
+    
+    memset(text, 0, sizeof(client_context_t));
+    
+    *conn_context = text;
+
+    return SASL_OK;
+}
+
+static int
+external_client_mech_step(void *conn_context,
+			  sasl_client_params_t *params,
+			  const char *serverin __attribute__((unused)),
+			  unsigned serverinlen,
+			  sasl_interact_t **prompt_need,
+			  const char **clientout,
+			  unsigned *clientoutlen,
+			  sasl_out_params_t *oparams)
+{
+    client_context_t *text = (client_context_t *)conn_context;
+    const char *user = NULL;
+    int user_result = SASL_OK;
+    int result;
+    
+    if (!params
+	|| !params->utils
+	|| !params->utils->conn
+	|| !params->utils->getcallback
+	|| !clientout
+	|| !clientoutlen
+	|| !oparams)
+	return SASL_BADPARAM;
+    
+    if (!params->utils->conn->external.auth_id)
+	return SASL_BADPROT;
+    
+    if (serverinlen != 0)
+	return SASL_BADPROT;
+    
+    *clientout = NULL;
+    *clientoutlen = 0;
+    
+    /* try to get the userid */
+    if (user == NULL) {
+	user_result = _plug_get_userid(params->utils, &user, prompt_need);
+	
+	if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
+	    return user_result;
+    }
+    
+    /* free prompts we got */
+    if (prompt_need && *prompt_need) {
+	params->utils->free(*prompt_need);
+	*prompt_need = NULL;
+    }
+    
+    /* if there are prompts not filled in */
+    if (user_result == SASL_INTERACT) {
+	/* make the prompt list */
+	int result =
+	    _plug_make_prompts(params->utils, prompt_need,
+			       user_result == SASL_INTERACT ?
+			       "Please enter your authorization name" : NULL,
+			       "",
+			       NULL, NULL,
+			       NULL, NULL,
+			       NULL, NULL, NULL,
+			       NULL, NULL, NULL);
+	if (result != SASL_OK) return result;
+	
+	return SASL_INTERACT;
+    }
+    
+    *clientoutlen = user ? (unsigned) strlen(user) : 0;
+    
+    result = _buf_alloc(&text->out_buf, &text->out_buf_len, *clientoutlen + 1);
+    
+    if (result != SASL_OK) return result;
+    
+    if (user && *user) {
+	result = params->canon_user(params->utils->conn,
+				    user, 0, SASL_CU_AUTHZID, oparams);
+	if (result != SASL_OK) return result;
+	
+	result = params->canon_user(params->utils->conn,
+				    params->utils->conn->external.auth_id, 0,
+				    SASL_CU_AUTHID, oparams);
+	if (result != SASL_OK) return result;
+	
+	memcpy(text->out_buf, user, *clientoutlen);
+    } else {
+	result = params->canon_user(params->utils->conn,
+				    params->utils->conn->external.auth_id, 0,
+				    SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+	if (result != SASL_OK) return result;
+    }
+    
+    text->out_buf[*clientoutlen] = '\0';
+    
+    *clientout = text->out_buf;
+    
+    /* set oparams */
+    oparams->doneflag = 1;
+    oparams->mech_ssf = 0;
+    oparams->maxoutbuf = 0;
+    oparams->encode_context = NULL;
+    oparams->encode = NULL;
+    oparams->decode_context = NULL;
+    oparams->decode = NULL;
+    oparams->param_version = 0;
+    
+    return SASL_OK;
+}
+
+static void
+external_client_mech_dispose(void *conn_context,
+			     const sasl_utils_t *utils __attribute__((unused))) 
+{
+    client_context_t *text = (client_context_t *) conn_context;
+    
+    if (!text) return;
+    
+    if(text->out_buf) sasl_FREE(text->out_buf);
+    
+    sasl_FREE(text);
+}
+
+static const unsigned long external_required_prompts[] = {
+    SASL_CB_LIST_END
+};
+
+static sasl_client_plug_t external_client_plugins[] =
+{
+    {
+	"EXTERNAL",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_NODICTIONARY,	/* security_flags */
+	SASL_FEAT_WANT_CLIENT_FIRST
+	| SASL_FEAT_ALLOWS_PROXY,	/* features */
+	external_required_prompts,	/* required_prompts */
+	NULL,				/* glob_context */
+	&external_client_mech_new,	/* mech_new */
+	&external_client_mech_step,	/* mech_step */
+	&external_client_mech_dispose,	/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL				/* spare */
+    }
+};
+
+int external_client_plug_init(const sasl_utils_t *utils,
+			      int max_version,
+			      int *out_version,
+			      sasl_client_plug_t **pluglist,
+			      int *plugcount)
+{
+    if (!utils || !out_version || !pluglist || !plugcount)
+	return SASL_BADPARAM;
+    
+    if (max_version != SASL_CLIENT_PLUG_VERSION) {
+	SETERROR( utils, "EXTERNAL version mismatch" );
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = external_client_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+}

+ 254 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/getaddrinfo.c

@@ -0,0 +1,254 @@
+/*
+ * Mar  8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
+ * $Id: getaddrinfo.c,v 1.8 2003/03/19 18:25:28 rjs3 Exp $
+ *
+ * This module is based on ssh-1.2.27-IPv6-1.5 written by
+ * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * fake library for ssh
+ *
+ * This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
+ * These funtions are defined in rfc2133.
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For exapmle, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ * 
+ * In the case not using 'configure --enable-ipv6', this getaddrinfo.c
+ * will be used if you have broken getaddrinfo or no getaddrinfo.
+ */
+
+#include "config.h"
+#ifndef WIN32
+#include <sys/param.h>
+# ifndef macintosh
+#  include <arpa/inet.h>
+# endif /* macintosh */
+#endif /* WIN32 */
+#include <ctype.h>
+
+#ifdef WIN32
+/* : Windows socket library is missing inet_aton, emulate it with
+   : inet_addr. inet_aton return 0 if the address is uncorrect, a non zero
+   : value otherwise */
+int
+inet_aton (const char *cp, struct in_addr *inp)
+{
+    if (cp == NULL || inp == NULL) {
+	return (0);
+    }
+
+    /* : handle special case */
+    if (strcmp (cp, "255.255.255.255") == 0) {
+	inp->s_addr = (unsigned int) 0xFFFFFFFF;
+	return (1);
+    }
+
+    inp->s_addr = inet_addr (cp);
+    return (1);
+}
+#endif /* WIN32 */
+
+static struct addrinfo *
+malloc_ai(int port, unsigned long addr, int socktype, int proto)
+{
+    struct addrinfo *ai;
+
+    ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
+				   sizeof(struct sockaddr_in));
+    if (ai) {
+	memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+	ai->ai_addr = (struct sockaddr *)(ai + 1);
+	/* XXX -- ssh doesn't use sa_len */
+	ai->ai_addrlen = sizeof(struct sockaddr_in);
+#ifdef HAVE_SOCKADDR_SA_LEN
+	ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
+#endif
+	ai->ai_addr->sa_family = ai->ai_family = AF_INET;
+	((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
+	((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
+	ai->ai_socktype = socktype;
+	ai->ai_protocol = proto;
+	return ai;
+    } else {
+	return NULL;
+    }
+}
+
+char *
+gai_strerror(int ecode)
+{
+    switch (ecode) {
+    case EAI_NODATA:
+	return "no address associated with hostname.";
+    case EAI_MEMORY:
+	return "memory allocation failure.";
+    case EAI_FAMILY:
+	return "ai_family not supported.";
+    case EAI_SERVICE:
+	return "servname not supported for ai_socktype.";
+    default:
+	return "unknown error.";
+    }
+}
+
+void
+freeaddrinfo(struct addrinfo *ai)
+{
+    struct addrinfo *next;
+
+    if (ai->ai_canonname)
+	free(ai->ai_canonname);
+    do {
+	next = ai->ai_next;
+	free(ai);
+    } while ((ai = next) != NULL);
+}
+
+int
+getaddrinfo(const char *hostname, const char *servname,
+	    const struct addrinfo *hints, struct addrinfo **res)
+{
+    struct addrinfo *cur, *prev = NULL;
+    struct hostent *hp;
+    struct in_addr in;
+    int i, port = 0, socktype, proto;
+
+    if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
+	return EAI_FAMILY;
+
+    socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
+					     : SOCK_STREAM;
+    if (hints && hints->ai_protocol)
+	proto = hints->ai_protocol;
+    else {
+	switch (socktype) {
+	case SOCK_DGRAM:
+	    proto = IPPROTO_UDP;
+	    break;
+	case SOCK_STREAM:
+	    proto = IPPROTO_TCP;
+	    break;
+	default:
+	    proto = 0;
+	    break;
+	}
+    }
+    if (servname) {
+	if (isdigit((int)*servname))
+	    port = htons((short) atoi(servname));
+	else {
+	    struct servent *se;
+	    char *pe_proto;
+
+	    switch (socktype) {
+	    case SOCK_DGRAM:
+		pe_proto = "udp";
+		break;
+	    case SOCK_STREAM:
+		pe_proto = "tcp";
+		break;
+	    default:
+		pe_proto = NULL;
+		break;
+	    }
+	    /* xxx thread safety ? */
+	    if ((se = getservbyname(servname, pe_proto)) == NULL)
+		return EAI_SERVICE;
+	    port = se->s_port;
+	}
+    }
+    if (!hostname) {
+        if (hints && hints->ai_flags & AI_PASSIVE)
+            *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
+        else
+            *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
+        if (*res)
+	    return 0;
+        else
+	    return EAI_MEMORY;
+    }
+#if HAVE_INET_ATON
+    if (inet_aton(hostname, &in))
+#else
+    if ((in.s_addr = inet_addr(hostname)) != -1)
+#endif
+    {
+	*res = malloc_ai(port, in.s_addr, socktype, proto);
+	if (*res)
+	    return 0;
+	else
+	    return EAI_MEMORY;
+    }
+    if (hints && hints->ai_flags & AI_NUMERICHOST)
+	return EAI_NODATA;
+#ifndef macintosh
+    /* xxx thread safety? / gethostbyname_r */
+    if ((hp = gethostbyname(hostname)) &&
+	hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+	for (i = 0; hp->h_addr_list[i]; i++) {
+	    if ((cur = malloc_ai(port,
+				((struct in_addr *)hp->h_addr_list[i])->s_addr,
+				socktype, proto)) == NULL) {
+		if (*res)
+		    freeaddrinfo(*res);
+		return EAI_MEMORY;
+	    }
+	    if (prev)
+		prev->ai_next = cur;
+	    else
+		*res = cur;
+	    prev = cur;
+	}
+	if (hints && hints->ai_flags & AI_CANONNAME && *res) {
+	    /* NOT sasl_strdup for compatibility */
+	    if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
+		freeaddrinfo(*res);
+		return EAI_MEMORY;
+	    }
+	}
+	return 0;
+    }
+#endif
+    return EAI_NODATA;
+}

+ 108 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/getnameinfo.c

@@ -0,0 +1,108 @@
+/*
+ * Mar  8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
+ * $Id: getnameinfo.c,v 1.5 2003/02/13 19:55:54 rjs3 Exp $
+ *
+ * This module is besed on ssh-1.2.27-IPv6-1.5 written by
+ * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * fake library for ssh
+ *
+ * This file includes getnameinfo().
+ * These funtions are defined in rfc2133.
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For exapmle, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ * 
+ * In the case not using 'configure --enable-ipv6', this getnameinfo.c
+ * will be used if you have broken getnameinfo or no getnameinfo.
+ */
+
+#include "config.h"
+#ifndef WIN32
+# include <arpa/inet.h>
+#endif /* WIN32 */
+#include <stdio.h>
+#include <string.h>
+
+int
+getnameinfo(const struct sockaddr *sa, socklen_t salen __attribute__((unused)),
+	    char *host, size_t hostlen, char *serv, size_t servlen, int flags)
+{
+    struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+    struct hostent *hp;
+    char tmpserv[16];
+  
+    if (serv) {
+	sprintf(tmpserv, "%d", ntohs(sin->sin_port));
+	if (strlen(tmpserv) > servlen)
+	    return EAI_MEMORY;
+	else
+	    strcpy(serv, tmpserv);
+    }
+    if (host) {
+	if (flags & NI_NUMERICHOST) {
+	    if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
+		return EAI_MEMORY;
+	    else {
+		strcpy(host, inet_ntoa(sin->sin_addr));
+		return 0;
+	    }
+	} else {
+	    hp = gethostbyaddr((char *)&sin->sin_addr,
+			       sizeof(struct in_addr), AF_INET);
+	    if (hp) {
+		if (strlen(hp->h_name) >= hostlen)
+		    return EAI_MEMORY;
+		else {
+		    strcpy(host, hp->h_name);
+		    return 0;
+		}
+	    }
+	    else
+		return EAI_NODATA;
+	}
+    }
+    
+    return 0;
+}

+ 114 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/getsubopt.c

@@ -0,0 +1,114 @@
+/*	$NetBSD: getsubopt.c,v 1.4 1998/02/03 18:44:15 perry Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if ((!defined(WIN32))&&(!defined(macintosh)))
+#include <sys/cdefs.h>
+#endif /* WIN32 */
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)getsubopt.c	8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: getsubopt.c,v 1.4 1998/02/03 18:44:15 perry Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if (defined(WIN32)||(defined(macintosh)))
+#include "sasl.h"
+LIBSASL_API int getsubopt(char **optionp, char * const *tokens, char **valuep);
+#endif /* WIN32 */
+/*
+ * The SVID interface to getsubopt provides no way of figuring out which
+ * part of the suboptions list wasn't matched.  This makes error messages
+ * tricky...  The extern variable suboptarg is a pointer to the token
+ * which didn't match.
+ */
+char *suboptarg;
+
+int
+getsubopt(optionp, tokens, valuep)
+	char **optionp, **valuep;
+	char * const *tokens;
+{
+	int cnt;
+	char *p;
+
+	suboptarg = *valuep = NULL;
+
+	if (!optionp || !*optionp)
+		return(-1);
+
+	/* skip leading white-space, commas */
+	for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+
+	if (!*p) {
+		*optionp = p;
+		return(-1);
+	}
+
+	/* save the start of the token, and skip the rest of the token. */
+	for (suboptarg = p;
+	    *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
+
+	if (*p) {
+		/*
+		 * If there's an equals sign, set the value pointer, and
+		 * skip over the value part of the token.  Terminate the
+		 * token.
+		 */
+		if (*p == '=') {
+			*p = '\0';
+			for (*valuep = ++p;
+			    *p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
+			if (*p) 
+				*p++ = '\0';
+		} else
+			*p++ = '\0';
+		/* Skip any whitespace or commas after this token. */
+		for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+	}
+
+	/* set optionp for next round. */
+	*optionp = p;
+
+	for (cnt = 0; *tokens; ++tokens, ++cnt)
+		if (!strcmp(suboptarg, *tokens))
+			return(cnt);
+	return(-1);
+}

+ 527 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/md5.c

@@ -0,0 +1,527 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Function names changed to avoid namespace collisions: Rob Siemborski */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#include <config.h>
+#include "md5global.h"
+#include "md5.h"
+#include "hmac-md5.h"
+
+#ifndef WIN32
+# include <arpa/inet.h>
+#endif
+
+/* Constants for MD5Transform routine.
+*/
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
+static void Encode PROTO_LIST
+       ((unsigned char *, UINT4 *, unsigned int)); 
+static void Decode PROTO_LIST
+       ((UINT4 *, const unsigned char *, unsigned int)); 
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+       0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 
+};
+
+/* F, G, H and I are basic MD5 functions.
+
+        */
+#ifdef I
+/* This might be defined via NANA */
+#undef I
+#endif
+
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+
+        */
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+*/
+
+#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s));        (a) += (b);        } 
+#define GG(a, b, c, d, x, s, ac) {        (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac);        (a) = ROTATE_LEFT ((a), (s));        (a) += (b);         } 
+#define HH(a, b, c, d, x, s, ac) {        (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac);        (a) = ROTATE_LEFT ((a), (s));        (a) += (b);        } 
+#define II(a, b, c, d, x, s, ac) {        (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac);        (a) = ROTATE_LEFT ((a), (s));        (a) += (b);        } 
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+*/
+
+void _sasl_MD5Init (context)
+MD5_CTX *context; /* context */
+{
+       context->count[0] = context->count[1] = 0; 
+
+       /* Load magic initialization constants. */
+       context->state[0] = 0x67452301; 
+       context->state[1] = 0xefcdab89; 
+       context->state[2] = 0x98badcfe; 
+       context->state[3] = 0x10325476; 
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+       operation, processing another message block, and updating the context. 
+*/
+
+void _sasl_MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+const unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+       unsigned int i, index, partLen; 
+
+         /* Compute number of bytes mod 64 */
+         index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+         /* Update number of bits */
+         if ((context->count[0] += ((UINT4)inputLen << 3))
+          < ((UINT4)inputLen << 3))
+        context->count[1]++;
+         context->count[1] += ((UINT4)inputLen >> 29);
+
+       partLen = 64 - index; 
+
+         /* Transform as many times as possible.
+
+*/
+       if (inputLen >= partLen) { 
+       MD5_memcpy 
+       ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform
+       (context->state, context->buffer); 
+
+       for (i = partLen; i + 63 < inputLen; i += 64) 
+       MD5Transform (context->state, &input[i]); 
+
+       index = 0; 
+       } 
+       else 
+       i = 0; 
+
+         /* Buffer remaining input */
+         MD5_memcpy
+        ((POINTER)&context->buffer[index], (POINTER)&input[i],
+         inputLen-i);
+
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+       the message digest and zeroizing the context. 
+*/
+
+void _sasl_MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+       unsigned char bits[8]; 
+       unsigned int index, padLen; 
+
+         /* Save number of bits */
+         Encode (bits, context->count, 8);
+
+         /* Pad out to 56 mod 64. */
+	 index = (unsigned int)((context->count[0] >> 3) & 0x3f); 
+	 padLen = (index < 56) ? (56 - index) : (120 - index); 
+	 _sasl_MD5Update (context, PADDING, padLen); 
+
+         /* Append length (before padding) */
+         _sasl_MD5Update (context, bits, 8);
+
+         /* Store state in digest */
+         Encode (digest, context->state, 16);
+
+         /* Zeroize sensitive information. */
+       MD5_memset ((POINTER)context, 0, sizeof (*context)); 
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+
+static void MD5Transform (state, block)
+UINT4 state[4];
+const unsigned char block[64];
+{
+       UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 
+
+       Decode (x, block, 64); 
+
+         /* Round 1 */
+         FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+         FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+         FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+         FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+         FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+         FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+         FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+         FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+         FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+         FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+         FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+         FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+         FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+         FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+         FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+         FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+        /* Round 2 */
+         GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+         GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+         GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+         GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+         GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+         GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+         GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+         GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+         GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+         GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+         GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+	 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 
+	 GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 
+	 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 
+	 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 
+	 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 
+
+         /* Round 3 */
+         HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+         HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+         HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+         HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+         HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+         HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+         HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+         HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+         HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+         HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+         HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+         HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+         HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+         HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+         HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+         HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+         /* Round 4 */
+         II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+         II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+         II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+         II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+         II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+         II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+         II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+         II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+         II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+         II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+         II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+         II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+         II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+         II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+         II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+         II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+       state[0] += a; 
+       state[1] += b; 
+       state[2] += c; 
+       state[3] += d; 
+
+         /* Zeroize sensitive information.
+	 */
+       MD5_memset ((POINTER)x, 0, sizeof (x)); 
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+       a multiple of 4. 
+
+        */
+
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+       unsigned int i, j; 
+
+       for (i = 0, j = 0; j < len; i++, j += 4) { 
+       output[j] = (unsigned char)(input[i] & 0xff); 
+       output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); 
+       output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); 
+       output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); 
+       } 
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+       a multiple of 4. 
+
+        */
+
+static void Decode (output, input, len)
+UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+       unsigned int i, j; 
+
+       for (i = 0, j = 0; j < len; i++, j += 4) 
+       output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16)
+       | (((UINT4)input[j+3]) << 24); 
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+
+        */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+       unsigned int i; 
+
+       for (i = 0; i < len; i++) 
+	      output[i] = input[i]; 
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+*/
+
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+       unsigned int i; 
+
+       for (i = 0; i < len; i++) 
+       ((char *)output)[i] = (char)value; 
+}
+
+void _sasl_hmac_md5_init(HMAC_MD5_CTX *hmac,
+			 const unsigned char *key,
+			 int key_len)
+{
+  unsigned char k_ipad[65];    /* inner padding -
+				* key XORd with ipad
+				*/
+  unsigned char k_opad[65];    /* outer padding -
+				* key XORd with opad
+				*/
+  unsigned char tk[16];
+  int i;
+  /* if key is longer than 64 bytes reset it to key=MD5(key) */
+  if (key_len > 64) {
+    
+    MD5_CTX      tctx;
+
+    _sasl_MD5Init(&tctx); 
+    _sasl_MD5Update(&tctx, key, key_len); 
+    _sasl_MD5Final(tk, &tctx); 
+
+    key = tk; 
+    key_len = 16; 
+  } 
+
+  /*
+   * the HMAC_MD5 transform looks like:
+   *
+   * MD5(K XOR opad, MD5(K XOR ipad, text))
+   *
+   * where K is an n byte key
+   * ipad is the byte 0x36 repeated 64 times
+   * opad is the byte 0x5c repeated 64 times
+   * and text is the data being protected
+   */
+
+  /* start out by storing key in pads */
+  MD5_memset((POINTER)k_ipad, '\0', sizeof k_ipad);
+  MD5_memset((POINTER)k_opad, '\0', sizeof k_opad);
+  MD5_memcpy( k_ipad, (POINTER)key, key_len);
+  MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+  /* XOR key with ipad and opad values */
+  for (i=0; i<64; i++) {
+    k_ipad[i] ^= 0x36;
+    k_opad[i] ^= 0x5c;
+  }
+
+  _sasl_MD5Init(&hmac->ictx);                   /* init inner context */
+  _sasl_MD5Update(&hmac->ictx, k_ipad, 64);     /* apply inner pad */
+
+  _sasl_MD5Init(&hmac->octx);                   /* init outer context */
+  _sasl_MD5Update(&hmac->octx, k_opad, 64);     /* apply outer pad */
+
+  /* scrub the pads and key context (if used) */
+  MD5_memset((POINTER)&k_ipad, 0, sizeof(k_ipad));
+  MD5_memset((POINTER)&k_opad, 0, sizeof(k_opad));
+  MD5_memset((POINTER)&tk, 0, sizeof(tk));
+
+  /* and we're done. */
+}
+
+/* The precalc and import routines here rely on the fact that we pad
+ * the key out to 64 bytes and use that to initialize the md5
+ * contexts, and that updating an md5 context with 64 bytes of data
+ * leaves nothing left over; all of the interesting state is contained
+ * in the state field, and none of it is left over in the count and
+ * buffer fields.  So all we have to do is save the state field; we
+ * can zero the others when we reload it.  Which is why the decision
+ * was made to pad the key out to 64 bytes in the first place. */
+void _sasl_hmac_md5_precalc(HMAC_MD5_STATE *state,
+			    const unsigned char *key,
+			    int key_len)
+{
+  HMAC_MD5_CTX hmac;
+  unsigned lupe;
+
+  _sasl_hmac_md5_init(&hmac, key, key_len);
+  for (lupe = 0; lupe < 4; lupe++) {
+    state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
+    state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
+  }
+  MD5_memset((POINTER)&hmac, 0, sizeof(hmac));
+}
+
+
+void _sasl_hmac_md5_import(HMAC_MD5_CTX *hmac,
+		     HMAC_MD5_STATE *state)
+{
+  unsigned lupe;
+  MD5_memset((POINTER)hmac, 0, sizeof(HMAC_MD5_CTX));
+  for (lupe = 0; lupe < 4; lupe++) {
+    hmac->ictx.state[lupe] = ntohl(state->istate[lupe]);
+    hmac->octx.state[lupe] = ntohl(state->ostate[lupe]);
+  }
+  /* Init the counts to account for our having applied
+   * 64 bytes of key; this works out to 0x200 (64 << 3; see
+   * MD5Update above...) */
+  hmac->ictx.count[0] = hmac->octx.count[0] = 0x200;
+}
+
+void _sasl_hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
+			  HMAC_MD5_CTX *hmac)
+{
+  _sasl_MD5Final(digest, &hmac->ictx);  /* Finalize inner md5 */
+  _sasl_MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */
+  _sasl_MD5Final(digest, &hmac->octx); /* Finalize outer md5 */
+}
+
+
+void _sasl_hmac_md5(text, text_len, key, key_len, digest)
+const unsigned char* text; /* pointer to data stream */
+int text_len; /* length of data stream */
+const unsigned char* key; /* pointer to authentication key */
+int key_len; /* length of authentication key */
+unsigned char *digest; /* caller digest to be filled in */
+{
+  MD5_CTX context; 
+
+  unsigned char k_ipad[65];    /* inner padding -
+				* key XORd with ipad
+				*/
+  unsigned char k_opad[65];    /* outer padding -
+				* key XORd with opad
+				*/
+  unsigned char tk[16];
+  int i;
+  /* if key is longer than 64 bytes reset it to key=MD5(key) */
+  if (key_len > 64) {
+    
+    MD5_CTX      tctx;
+
+    _sasl_MD5Init(&tctx); 
+    _sasl_MD5Update(&tctx, key, key_len); 
+    _sasl_MD5Final(tk, &tctx); 
+
+    key = tk; 
+    key_len = 16; 
+  } 
+
+  /*
+   * the HMAC_MD5 transform looks like:
+   *
+   * MD5(K XOR opad, MD5(K XOR ipad, text))
+   *
+   * where K is an n byte key
+   * ipad is the byte 0x36 repeated 64 times
+   * opad is the byte 0x5c repeated 64 times
+   * and text is the data being protected
+   */
+
+  /* start out by storing key in pads */
+  MD5_memset(k_ipad, '\0', sizeof k_ipad);
+  MD5_memset(k_opad, '\0', sizeof k_opad);
+  MD5_memcpy( k_ipad, (POINTER)key, key_len);
+  MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+  /* XOR key with ipad and opad values */
+  for (i=0; i<64; i++) {
+    k_ipad[i] ^= 0x36;
+    k_opad[i] ^= 0x5c;
+  }
+  /*
+   * perform inner MD5
+   */
+
+  _sasl_MD5Init(&context);                   /* init context for 1st
+					       * pass */
+  _sasl_MD5Update(&context, k_ipad, 64);      /* start with inner pad */
+  _sasl_MD5Update(&context, text, text_len); /* then text of datagram */
+  _sasl_MD5Final(digest, &context);          /* finish up 1st pass */
+
+  /*
+   * perform outer MD5
+   */
+  _sasl_MD5Init(&context);                   /* init context for 2nd
+					* pass */
+  _sasl_MD5Update(&context, k_opad, 64);     /* start with outer pad */
+  _sasl_MD5Update(&context, digest, 16);     /* then results of 1st
+					* hash */
+  _sasl_MD5Final(digest, &context);          /* finish up 2nd pass */
+
+}

+ 528 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/saslint.h

@@ -0,0 +1,528 @@
+/* saslint.h - internal SASL library definitions
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: saslint.h,v 1.73 2011/09/01 14:12:53 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SASLINT_H
+#define SASLINT_H
+
+#include <config.h>
+#include "sasl.h"
+#include "saslplug.h"
+#include "saslutil.h"
+#include "prop.h"
+
+#ifndef INLINE
+#if defined (WIN32)
+/* Visual Studio: "inline" keyword is not available in C, only in C++ */
+#define INLINE __inline
+#else
+#define INLINE  inline
+#endif
+#endif
+
+/* #define'd constants */
+#define CANON_BUF_SIZE 1024
+
+/* Error Handling Foo */
+/* Helpful Hints:
+ *  -Error strings are set as soon as possible (first function in stack trace
+ *   with a pointer to the sasl_conn_t.
+ *  -Error codes are set as late as possible (only in the sasl api functions),
+ *   though "as often as possible" also comes to mind to ensure correctness
+ *  -Errors from calls to _buf_alloc, _sasl_strdup, etc are assumed to be
+ *   memory errors.
+ *  -Only errors (error codes < SASL_OK) should be remembered
+ */
+#define RETURN(conn, val) { if(conn && (val) < SASL_OK) \
+                               (conn)->error_code = (val); \
+                            return (val); }
+#define MEMERROR(conn) {\
+    if(conn) sasl_seterror( (conn), 0, \
+                   "Out of Memory in " __FILE__ " near line %d", __LINE__ ); \
+    RETURN(conn, SASL_NOMEM) }
+#define PARAMERROR(conn) {\
+    if(conn) sasl_seterror( (conn), SASL_NOLOG, \
+                  "Parameter error in " __FILE__ " near line %d", __LINE__ ); \
+    RETURN(conn, SASL_BADPARAM) }
+#define INTERROR(conn, val) {\
+    if(conn) sasl_seterror( (conn), 0, \
+                   "Internal Error %d in " __FILE__ " near line %d", (val),\
+		   __LINE__ ); \
+    RETURN(conn, (val)) }
+
+#ifndef PATH_MAX
+# ifdef WIN32
+#  define PATH_MAX MAX_PATH
+# else
+#  ifdef _POSIX_PATH_MAX
+#   define PATH_MAX _POSIX_PATH_MAX
+#  else
+#   define PATH_MAX 1024         /* arbitrary; probably big enough.
+                                  * will probably only be 256+64 on
+                                  * pre-posix machines */
+#  endif /* _POSIX_PATH_MAX */
+# endif /* WIN32 */
+#endif
+
+/* : Define directory delimiter in SASL_PATH/SASL_CONF_PATH variables */
+#ifdef WIN32
+#define PATHS_DELIMITER	';'
+#else
+#define PATHS_DELIMITER	':'
+#endif
+
+/* Datatype Definitions */
+typedef struct {
+  const sasl_callback_t *callbacks;
+  const char *appname;
+} sasl_global_callbacks_t;
+
+typedef struct _sasl_external_properties 
+{
+    sasl_ssf_t ssf;
+    char *auth_id;
+} _sasl_external_properties_t;
+
+typedef struct sasl_string_list
+{
+    const char *d;
+    struct sasl_string_list *next;
+} sasl_string_list_t;
+
+typedef struct buffer_info
+{ 
+    char *data;
+    size_t curlen;
+    size_t reallen;
+} buffer_info_t;
+
+typedef int add_plugin_t(const char *, void *);
+
+typedef struct add_plugin_list 
+{
+    const char *entryname;
+    add_plugin_t *add_plugin;
+} add_plugin_list_t;
+
+enum Sasl_conn_type { SASL_CONN_UNKNOWN = 0,
+		      SASL_CONN_SERVER = 1,
+                      SASL_CONN_CLIENT = 2 };
+
+struct sasl_conn {
+  enum Sasl_conn_type type;
+
+  void (*destroy_conn)(sasl_conn_t *); /* destroy function */
+
+  char *service;
+
+  unsigned int flags;  /* flags passed to sasl_*_new */
+
+  /* IP information.  A buffer of size 52 is adequate for this in its
+     longest format (see sasl.h) */
+  int got_ip_local, got_ip_remote;
+  char iplocalport[NI_MAXHOST + NI_MAXSERV];
+  char ipremoteport[NI_MAXHOST + NI_MAXSERV];
+
+  void *context;
+  sasl_out_params_t oparams;
+
+  sasl_security_properties_t props;
+  _sasl_external_properties_t external;
+
+  sasl_secret_t *secret;
+
+  int (*idle_hook)(sasl_conn_t *conn);
+  const sasl_callback_t *callbacks;
+  const sasl_global_callbacks_t *global_callbacks; /* global callbacks
+						    * connection */
+  char *serverFQDN;
+
+  /* Pointers to memory that we are responsible for */
+  buffer_info_t *encode_buf;
+
+  int error_code;
+  char *error_buf, *errdetail_buf;
+  size_t error_buf_len, errdetail_buf_len;
+  char *mechlist_buf;
+  size_t mechlist_buf_len;
+
+  char *decode_buf;
+
+  char user_buf[CANON_BUF_SIZE+1], authid_buf[CANON_BUF_SIZE+1];
+
+  /* Allocated by sasl_encodev if the output contains multiple SASL packet. */
+  buffer_info_t multipacket_encoded_data;
+};
+
+/* Server Conn Type Information */
+
+typedef struct mechanism
+{
+    server_sasl_mechanism_t m;
+    struct mechanism *next;
+} mechanism_t;
+
+typedef struct mech_list {
+  const sasl_utils_t *utils;  /* gotten from plug_init */
+
+  void *mutex;            /* mutex for this data */ 
+  mechanism_t *mech_list; /* list of loaded mechanisms */
+  int mech_length;        /* number of loaded mechanisms */
+} mech_list_t;
+
+typedef struct context_list 
+{
+    mechanism_t *mech;
+    void *context;     /* if NULL, this mech is disabled for this connection
+			* otherwise, use this context instead of a call
+			* to mech_new */
+    struct context_list *next;
+} context_list_t;
+
+typedef struct sasl_server_conn {
+    sasl_conn_t base; /* parts common to server + client */
+
+    char *appname; /* application name buffer (for sparams) */
+    char *user_realm; /* domain the user authenticating is in */
+    int sent_last; /* Have we already done the last send? */
+    int authenticated;
+    mechanism_t *mech; /* mechanism trying to use */
+    sasl_server_params_t *sparams;
+    context_list_t *mech_contexts;
+    mechanism_t *mech_list; /* list of available mechanisms */
+    int mech_length;        /* number of available mechanisms */
+} sasl_server_conn_t;
+
+/* Client Conn Type Information */
+
+typedef struct cmechanism
+{
+    client_sasl_mechanism_t m;
+    struct cmechanism *next;  
+} cmechanism_t;
+
+typedef struct cmech_list {
+  const sasl_utils_t *utils; 
+
+  void *mutex;            /* mutex for this data */ 
+  cmechanism_t *mech_list; /* list of mechanisms */
+  int mech_length;       /* number of mechanisms */
+
+} cmech_list_t;
+
+typedef struct sasl_client_conn {
+  sasl_conn_t base; /* parts common to server + client */
+
+  cmechanism_t *mech;
+  sasl_client_params_t *cparams;
+
+  char *clientFQDN;
+
+  cmechanism_t *mech_list; /* list of available mechanisms */
+  int mech_length;	   /* number of available mechanisms */
+} sasl_client_conn_t;
+
+typedef struct sasl_allocation_utils {
+  sasl_malloc_t *malloc;
+  sasl_calloc_t *calloc;
+  sasl_realloc_t *realloc;
+  sasl_free_t *free;
+} sasl_allocation_utils_t;
+
+typedef struct sasl_mutex_utils {
+  sasl_mutex_alloc_t *alloc;
+  sasl_mutex_lock_t *lock;
+  sasl_mutex_unlock_t *unlock;
+  sasl_mutex_free_t *free;
+} sasl_mutex_utils_t;
+
+typedef struct sasl_log_utils_s {
+  sasl_log_t *log;
+} sasl_log_utils_t;
+
+typedef int sasl_plaintext_verifier(sasl_conn_t *conn,
+				    const char *userid,
+				    const char *passwd,
+				    const char *service,
+				    const char *user_realm);
+
+struct sasl_verify_password_s {
+    char *name;
+    sasl_plaintext_verifier *verify;
+};
+
+/*
+ * globals & constants
+ */
+/*
+ * common.c
+ */
+LIBSASL_API const sasl_utils_t *sasl_global_utils;
+
+extern int (*_sasl_client_idle_hook)(sasl_conn_t *conn);
+extern int (*_sasl_server_idle_hook)(sasl_conn_t *conn);
+
+/* These return SASL_OK if we've actually finished cleanup, 
+ * SASL_NOTINIT if that part of the library isn't initialized, and
+ * SASL_CONTINUE if we need to call them again */
+extern int (*_sasl_client_cleanup_hook)(void);
+extern int (*_sasl_server_cleanup_hook)(void);
+
+extern sasl_allocation_utils_t _sasl_allocation_utils;
+extern sasl_mutex_utils_t _sasl_mutex_utils;
+extern int _sasl_allocation_locked;
+
+void sasl_common_done(void);
+
+extern int _sasl_is_equal_mech(const char *req_mech,
+                               const char *plug_mech,
+                               size_t req_mech_len,
+                               int *plus);
+
+/*
+ * checkpw.c
+ */
+extern struct sasl_verify_password_s _sasl_verify_password[];
+
+/*
+ * server.c
+ */
+/* (this is a function call to ensure this is read-only to the outside) */
+extern int _is_sasl_server_active(void);
+
+/*
+ * Allocation and Mutex utility macros
+ */
+#define sasl_ALLOC(__size__) (_sasl_allocation_utils.malloc((__size__)))
+#define sasl_CALLOC(__nelem__, __size__) \
+	(_sasl_allocation_utils.calloc((__nelem__), (__size__)))
+#define sasl_REALLOC(__ptr__, __size__) \
+	(_sasl_allocation_utils.realloc((__ptr__), (__size__)))
+#define sasl_FREE(__ptr__) (_sasl_allocation_utils.free((__ptr__)))
+
+#define sasl_MUTEX_ALLOC() (_sasl_mutex_utils.alloc())
+#define sasl_MUTEX_LOCK(__mutex__) (_sasl_mutex_utils.lock((__mutex__)))
+#define sasl_MUTEX_UNLOCK(__mutex__) (_sasl_mutex_utils.unlock((__mutex__)))
+#define sasl_MUTEX_FREE(__mutex__) \
+	(_sasl_mutex_utils.free((__mutex__)))
+
+/* function prototypes */
+/*
+ * dlopen.c and staticopen.c
+ */
+/*
+ * The differences here are:
+ * _sasl_load_plugins loads all plugins from all files
+ * _sasl_get_plugin loads the LIBRARY for an individual file
+ * _sasl_done_with_plugins frees the LIBRARIES loaded by the above 2
+ * _sasl_locate_entry locates an entrypoint in a given library
+ */
+extern int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
+			       const sasl_callback_t *getpath_callback,
+			       const sasl_callback_t *verifyfile_callback);
+extern int _sasl_get_plugin(const char *file,
+			    const sasl_callback_t *verifyfile_cb,
+			    void **libraryptr);
+extern int _sasl_locate_entry(void *library, const char *entryname,
+                              void **entry_point);
+extern int _sasl_done_with_plugins();
+
+/*
+ * common.c
+ */
+extern const sasl_callback_t *
+_sasl_find_getpath_callback(const sasl_callback_t *callbacks);
+
+extern const sasl_callback_t *
+_sasl_find_getconfpath_callback(const sasl_callback_t *callbacks);
+
+extern const sasl_callback_t *
+_sasl_find_verifyfile_callback(const sasl_callback_t *callbacks);
+
+extern int _sasl_common_init(sasl_global_callbacks_t *global_callbacks);
+
+extern int _sasl_conn_init(sasl_conn_t *conn,
+			   const char *service,
+			   unsigned int flags,
+			   enum Sasl_conn_type type,
+			   int (*idle_hook)(sasl_conn_t *conn),
+			   const char *serverFQDN,
+			   const char *iplocalport,
+			   const char *ipremoteport,
+			   const sasl_callback_t *callbacks,
+			   const sasl_global_callbacks_t *global_callbacks);
+extern void _sasl_conn_dispose(sasl_conn_t *conn);
+
+extern sasl_utils_t *
+_sasl_alloc_utils(sasl_conn_t *conn,
+		  sasl_global_callbacks_t *global_callbacks);
+extern int _sasl_free_utils(const sasl_utils_t ** utils);
+
+extern int
+_sasl_getcallback(sasl_conn_t * conn,
+		  unsigned long callbackid,
+		  sasl_callback_ft * pproc,
+		  void **pcontext);
+
+extern void
+_sasl_log(sasl_conn_t *conn,
+	  int level,
+	  const char *fmt,
+	  ...);
+
+void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl);
+int _sasl_add_string(char **out, size_t *alloclen,
+		     size_t *outlen, const char *add);
+
+/* More Generic Utilities in common.c */
+extern int _sasl_strdup(const char *in, char **out, size_t *outlen);
+
+/* Basically a conditional call to realloc(), if we need more */
+int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen);
+
+/* convert an iovec to a single buffer */
+int _iovec_to_buf(const struct iovec *vec,
+		  unsigned numiov, buffer_info_t **output);
+
+/* Convert between string formats and sockaddr formats */
+int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
+		     char *out, unsigned outlen);
+int _sasl_ipfromstring(const char *addr, struct sockaddr *out,
+		       socklen_t outlen);
+
+/*
+ * external plugin (external.c)
+ */
+int external_client_plug_init(const sasl_utils_t *utils,
+			      int max_version,
+			      int *out_version,
+			      sasl_client_plug_t **pluglist,
+			      int *plugcount);
+int external_server_plug_init(const sasl_utils_t *utils,
+			      int max_version,
+			      int *out_version,
+			      sasl_server_plug_t **pluglist,
+			      int *plugcount);
+
+/* Mech Listing Functions */
+int _sasl_build_mechlist(void);
+int _sasl_server_listmech(sasl_conn_t *conn,
+			  const char *user,
+			  const char *prefix,
+			  const char *sep,
+			  const char *suffix,
+			  const char **result,
+			  unsigned *plen,
+			  int *pcount);
+int _sasl_client_listmech(sasl_conn_t *conn,
+			  const char *prefix,
+			  const char *sep,
+			  const char *suffix,
+			  const char **result,
+			  unsigned *plen,
+			  int *pcount);
+/* Just create a straight list of them */
+sasl_string_list_t *_sasl_client_mechs(void);
+sasl_string_list_t *_sasl_server_mechs(void);
+
+/*
+ * config file declarations (config.c)
+ */
+extern const char *sasl_config_getstring(const char *key,const char *def);
+
+/* checkpw.c */
+#ifdef DO_SASL_CHECKAPOP
+extern int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
+				     const char *userstr,
+				     const char *challenge,
+				     const char *response,
+				     const char *user_realm);
+#endif /* DO_SASL_CHECKAPOP */
+
+/* Auxprop Plugin (sasldb.c) */
+extern int sasldb_auxprop_plug_init(const sasl_utils_t *utils,
+				    int max_version,
+				    int *out_version,
+				    sasl_auxprop_plug_t **plug,
+				    const char *plugname);
+
+/*
+ * auxprop.c
+ */
+extern int _sasl_auxprop_add_plugin(void *p, void *library);
+extern void _sasl_auxprop_free(void);
+extern int _sasl_auxprop_lookup(sasl_server_params_t *sparams,
+				 unsigned flags,
+				 const char *user, unsigned ulen);
+
+/*
+ * canonusr.c
+ */
+void _sasl_canonuser_free();
+extern int internal_canonuser_init(const sasl_utils_t *utils,
+				   int max_version,
+				   int *out_version,
+				   sasl_canonuser_plug_t **plug,
+				   const char *plugname);
+extern int _sasl_canon_user(sasl_conn_t *conn,
+			    const char *user,
+			    unsigned ulen,
+			    unsigned flags,
+			    sasl_out_params_t *oparams);
+int _sasl_canon_user_lookup (sasl_conn_t *conn,
+			     const char *user,
+			     unsigned ulen,
+			     unsigned flags,
+			     sasl_out_params_t *oparams);
+
+/*
+ * saslutil.c
+ */
+int get_fqhostname(
+  char *name,  
+  int namelen,
+  int abort_if_no_fqdn
+  );
+
+#endif /* SASLINT_H */

+ 812 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/saslutil.c

@@ -0,0 +1,812 @@
+/* saslutil.c
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: saslutil.c,v 1.52 2011/09/22 14:43:01 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#if defined(WIN32)
+#define _CRT_RAND_S
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include "saslint.h"
+#include <saslutil.h>
+
+/*  Contains:
+ *
+ * sasl_decode64 
+ * sasl_encode64
+ * sasl_mkchal
+ * sasl_utf8verify
+ * sasl_randcreate
+ * sasl_randfree
+ * sasl_randseed
+ * sasl_rand
+ * sasl_churn
+ * sasl_erasebuffer
+ */
+
+#ifdef sun
+/* gotta define gethostname ourselves on suns */
+extern int gethostname(char *, int);
+#endif
+
+char *encode_table;
+char *decode_table;
+
+#define RPOOL_SIZE 3
+struct sasl_rand_s {
+    unsigned short pool[RPOOL_SIZE];
+    /* since the init time might be really bad let's make this lazy */
+    int initialized; 
+};
+
+#define CHAR64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+
+static char basis_64[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????";
+
+static char index_64[128] = {
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+/* base64 encode
+ *  in      -- input data
+ *  inlen   -- input data length
+ *  out     -- output buffer (will be NUL terminated)
+ *  outmax  -- max size of output buffer
+ * result:
+ *  outlen  -- gets actual length of output buffer (optional)
+ * 
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+
+int sasl_encode64(const char *_in,
+		  unsigned inlen,
+		  char *_out,
+		  unsigned outmax,
+		  unsigned *outlen)
+{
+    const unsigned char *in = (const unsigned char *)_in;
+    unsigned char *out = (unsigned char *)_out;
+    unsigned char oval;
+    char *blah;
+    unsigned olen;
+
+    /* check params */
+    if ((inlen > 0) && (in == NULL)) return SASL_BADPARAM;
+    
+    /* Will it fit? */
+    olen = (inlen + 2) / 3 * 4;
+    if (outlen) {
+	*outlen = olen;
+    }
+    if (outmax <= olen) {
+	return SASL_BUFOVER;
+    }
+
+    /* Do the work... */
+    blah = (char *) out;
+    while (inlen >= 3) {
+      /* user provided max buffer size; make sure we don't go over it */
+        *out++ = basis_64[in[0] >> 2];
+        *out++ = basis_64[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+        *out++ = basis_64[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+        *out++ = basis_64[in[2] & 0x3f];
+        in += 3;
+        inlen -= 3;
+    }
+    if (inlen > 0) {
+      /* user provided max buffer size; make sure we don't go over it */
+        *out++ = basis_64[in[0] >> 2];
+        oval = (in[0] << 4) & 0x30;
+        if (inlen > 1) oval |= in[1] >> 4;
+        *out++ = basis_64[oval];
+        *out++ = (inlen < 2) ? '=' : basis_64[(in[1] << 2) & 0x3c];
+        *out++ = '=';
+    }
+
+    *out = '\0';
+    
+    return SASL_OK;
+}
+
+/* base64 decode
+ *  in     -- input data
+ *  inlen  -- length of input data
+ *  out    -- output data (may be same as in, must have enough space)
+ *  outmax  -- max size of output buffer
+ * result:
+ *  outlen -- actual output length
+ *
+ * returns:
+ * SASL_BADPROT on bad base64,
+ * SASL_BUFOVER if result won't fit,
+ * SASL_CONTINUE on a partial block,
+ * SASL_OK on success
+ */
+
+int sasl_decode64(const char *in,
+                  unsigned inlen,
+                  char *out,
+                  unsigned outmax,  /* size of the buffer, not counting the NUL */
+                  unsigned *outlen)
+{
+    unsigned len = 0;
+    unsigned j;
+    int c[4];
+    int saw_equal = 0;
+
+    /* check parameters */
+    if (out == NULL) return SASL_FAIL;
+
+    if (inlen > 0 && *in == '\r') return SASL_FAIL;
+
+    while (inlen > 3) {
+        /* No data is valid after an '=' character */
+        if (saw_equal) {
+            return SASL_BADPROT;
+        }
+
+	for (j = 0; j < 4; j++) {
+	    c[j] = in[0];
+	    in++;
+	    inlen--;
+	}
+
+        if (CHAR64(c[0]) == -1 || CHAR64(c[1]) == -1) return SASL_BADPROT;
+        if (c[2] != '=' && CHAR64(c[2]) == -1) return SASL_BADPROT;
+        if (c[3] != '=' && CHAR64(c[3]) == -1) return SASL_BADPROT;
+        /* No data is valid after a '=' character, unless it is another '=' */
+        if (c[2] == '=' && c[3] != '=') return SASL_BADPROT;
+        if (c[2] == '=' || c[3] == '=') {
+            saw_equal = 1;
+        }
+
+        *out++ = (CHAR64(c[0]) << 2) | (CHAR64(c[1]) >> 4);
+        if (++len >= outmax) return SASL_BUFOVER;
+        if (c[2] != '=') {
+            *out++ = ((CHAR64(c[1]) << 4) & 0xf0) | (CHAR64(c[2]) >> 2);
+            if (++len >= outmax) return SASL_BUFOVER;
+            if (c[3] != '=') {
+                *out++ = ((CHAR64(c[2]) << 6) & 0xc0) | CHAR64(c[3]);
+                if (++len >= outmax) return SASL_BUFOVER;
+            }
+        }
+    }
+
+    *out = '\0'; /* NUL terminate the output string */
+
+    if (outlen) *outlen = len;
+
+    if (inlen != 0) {
+        if (saw_equal) {
+            /* Unless there is CRLF at the end? */
+            return SASL_BADPROT;
+        } else {
+	    return (SASL_CONTINUE);
+        }
+    }
+
+    return SASL_OK;
+}
+
+/* make a challenge string (NUL terminated)
+ *  buf      -- buffer for result
+ *  maxlen   -- max length of result
+ *  hostflag -- 0 = don't include hostname, 1 = include hostname
+ * returns final length or 0 if not enough space
+ */
+
+int sasl_mkchal(sasl_conn_t *conn,
+		char *buf,
+		unsigned maxlen,
+		unsigned hostflag)
+{
+  sasl_rand_t *pool = NULL;
+  unsigned long randnum;
+  int ret;
+  time_t now;
+  unsigned len;
+
+  len = 4			/* <.>\0 */
+    + (2 * 20);			/* 2 numbers, 20 => max size of 64bit
+				 * ulong in base 10 */
+  if (hostflag && conn->serverFQDN)
+    len += (unsigned) strlen(conn->serverFQDN) + 1 /* for the @ */;
+
+  if (maxlen < len)
+    return 0;
+
+  ret = sasl_randcreate(&pool);
+  if(ret != SASL_OK) return 0; /* xxx sasl return code? */
+
+  sasl_rand(pool, (char *)&randnum, sizeof(randnum));
+  sasl_randfree(&pool);
+
+  time(&now);
+
+  if (hostflag && conn->serverFQDN)
+    snprintf(buf,maxlen, "<%lu.%lu@%s>", randnum, now, conn->serverFQDN);
+  else
+    snprintf(buf,maxlen, "<%lu.%lu>", randnum, now);
+
+  return (int) strlen(buf);
+}
+
+  /* borrowed from larry. probably works :)
+   * probably is also in acap server somewhere
+   */
+int sasl_utf8verify(const char *str, unsigned len)
+{
+  unsigned i;
+  for (i = 0; i < len; i++) {
+    /* how many octets? */
+    int seqlen = 0;
+    while (str[i] & (0x80 >> seqlen)) ++seqlen;
+    if (seqlen == 0) continue; /* this is a valid US-ASCII char */
+    if (seqlen == 1) return SASL_BADPROT; /* this shouldn't happen here */
+    if (seqlen > 6) return SASL_BADPROT; /* illegal */
+    while (--seqlen)
+      if ((str[++i] & 0xC0) != 0xF0) return SASL_BADPROT; /* needed a 10 octet */
+  }
+  return SASL_OK;
+}      
+
+/* 
+ * To see why this is really bad see RFC 1750
+ *
+ * unfortunatly there currently is no way to make 
+ * cryptographically secure pseudo random numbers
+ * without specialized hardware etc...
+ * thus, this is for nonce use only
+ */
+void getranddata(unsigned short ret[RPOOL_SIZE])
+{
+    long curtime;
+    
+    memset(ret, 0, RPOOL_SIZE*sizeof(unsigned short));
+
+#ifdef DEV_RANDOM    
+    {
+	int fd;
+
+	fd = open(DEV_RANDOM, O_RDONLY);
+	if(fd != -1) {
+	    unsigned char *buf = (unsigned char *)ret;
+	    ssize_t bytesread = 0;
+	    size_t bytesleft = RPOOL_SIZE*sizeof(unsigned short);
+	    
+	    do {
+		bytesread = read(fd, buf, bytesleft);
+		if(bytesread == -1 && errno == EINTR) continue;
+		else if(bytesread <= 0) break;
+		bytesleft -= bytesread;
+		buf += bytesread;
+	    } while(bytesleft != 0);
+		
+	    close(fd);
+	}
+    }
+#endif
+
+#ifdef HAVE_GETPID
+    ret[0] ^= (unsigned short) getpid();
+#endif
+
+#ifdef HAVE_GETTIMEOFDAY
+    {
+	struct timeval tv;
+	
+	/* xxx autoconf macro */
+#ifdef _SVID_GETTOD
+	if (!gettimeofday(&tv))
+#else
+	if (!gettimeofday(&tv, NULL))
+#endif
+	{
+	    /* longs are guaranteed to be at least 32 bits; we need
+	       16 bits in each short */
+	    ret[0] ^= (unsigned short) (tv.tv_sec & 0xFFFF);
+	    ret[1] ^= (unsigned short) (clock() & 0xFFFF);
+	    ret[1] ^= (unsigned short) (tv.tv_usec >> 16);
+	    ret[2] ^= (unsigned short) (tv.tv_usec & 0xFFFF);
+	    return;
+	}
+    }
+#endif /* HAVE_GETTIMEOFDAY */
+    
+    /* if all else fails just use time() */
+    curtime = (long) time(NULL); /* better be at least 32 bits */
+    
+    ret[0] ^= (unsigned short) (curtime >> 16);
+    ret[1] ^= (unsigned short) (curtime & 0xFFFF);
+    ret[2] ^= (unsigned short) (clock() & 0xFFFF);
+    
+    return;
+}
+
+int sasl_randcreate(sasl_rand_t **rpool)
+{
+  (*rpool)=sasl_ALLOC(sizeof(sasl_rand_t));
+  if ((*rpool) == NULL) return SASL_NOMEM;
+
+  /* init is lazy */
+  (*rpool)->initialized = 0;
+
+  return SASL_OK;
+}
+
+void sasl_randfree(sasl_rand_t **rpool)
+{
+    sasl_FREE(*rpool);
+}
+
+void sasl_randseed (sasl_rand_t *rpool, const char *seed, unsigned len)
+{
+    /* is it acceptable to just use the 1st 3 char's given??? */
+    unsigned int lup;
+
+    /* check params */
+    if (seed == NULL) return;
+    if (rpool == NULL) return;
+
+    rpool->initialized = 1;
+
+    if (len > sizeof(unsigned short)*RPOOL_SIZE)
+      len = sizeof(unsigned short)*RPOOL_SIZE;
+
+    for (lup = 0; lup < len; lup += 2)
+	rpool->pool[lup/2] = (seed[lup] << 8) + seed[lup + 1];
+}
+
+static void randinit(sasl_rand_t *rpool)
+{
+    if (!rpool) return;
+    
+    if (!rpool->initialized) {
+	getranddata(rpool->pool);
+	rpool->initialized = 1;
+#if !(defined(WIN32)||defined(macintosh))
+#ifndef HAVE_JRAND48
+    {
+      /* xxx varies by platform */
+	unsigned int *foo = (unsigned int *)rpool->pool;
+	srandom(*foo);
+    }
+#endif /* HAVE_JRAND48 */
+#elif defined(WIN32)
+    {
+	unsigned int *foo = (unsigned int *)rpool->pool;
+	srand(*foo);
+    }
+#endif /* WIN32 */
+    }
+
+}
+
+void sasl_rand (sasl_rand_t *rpool, char *buf, unsigned len)
+{
+    unsigned int lup;
+#if defined(WIN32) && !defined(__MINGW32__)
+    unsigned int randomValue;
+#endif
+
+    /* check params */
+    if (!rpool || !buf) return;
+    
+    /* init if necessary */
+    randinit(rpool);
+
+    for (lup = 0; lup < len; lup++) {
+#if defined(__MINGW32__)
+	buf[lup] = (char) (rand() >> 8);
+#elif defined(WIN32)
+	if (rand_s(&randomValue) != 0) {
+	    randomValue = rand();
+	}
+
+	buf[lup] = (char) (randomValue >> 8);
+#elif defined(macintosh)
+	buf[lup] = (char) (rand() >> 8);
+#else /* !WIN32 && !macintosh */
+#ifdef HAVE_JRAND48
+	buf[lup] = (char) (jrand48(rpool->pool) >> 8);
+#else
+	buf[lup] = (char) (random() >> 8);
+#endif /* HAVE_JRAND48 */
+#endif /* WIN32 */
+    }
+}
+
+/* this function is just a bad idea all around, since we're not trying to
+   implement a true random number generator */
+void sasl_churn (sasl_rand_t *rpool, const char *data, unsigned len)
+{
+    unsigned int lup;
+    
+    /* check params */
+    if (!rpool || !data) return;
+    
+    /* init if necessary */
+    randinit(rpool);
+    
+    for (lup=0; lup<len; lup++)
+	rpool->pool[lup % RPOOL_SIZE] ^= data[lup];
+}
+
+void sasl_erasebuffer(char *buf, unsigned len) {
+    memset(buf, 0, len);
+}
+
+/* Lowercase string in place */
+char *sasl_strlower (
+  char *val
+)
+{
+    int i;
+
+    if (val == NULL) {
+	return (NULL);
+    }
+
+/* don't use tolower(), as it is locale dependent */
+
+    for (i = 0; val[i] != '\0'; i++) {
+	if (val[i] >= 'A' && val[i] <= 'Z') {
+	    val[i] = val[i] - 'A' + 'a';
+	}
+    }
+
+    return (val);
+}
+
+/* A version of gethostname that tries hard to return a FQDN */
+int get_fqhostname(
+  char *name,  
+  int namelen,
+  int abort_if_no_fqdn
+)
+{
+    int return_value;
+    struct addrinfo hints;
+    struct addrinfo *result;
+
+    return_value = gethostname (name, namelen);
+    if (return_value != 0) {
+	return (return_value);
+    }
+
+    if (strchr (name, '.') != NULL) {
+	goto LOWERCASE;
+    }
+
+/* gethostname hasn't returned a FQDN, we have to canonify it ourselves */
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_flags = AI_CANONNAME;
+    hints.ai_socktype = SOCK_STREAM;	/* TCP only */
+/* A value of zero for ai_protocol indicates the caller will accept any protocol. or IPPROTO_TCP? */
+    hints.ai_protocol = 0;  /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+    hints.ai_addrlen = 0;
+    hints.ai_canonname = NULL;
+    hints.ai_addr = NULL;
+    hints.ai_next = NULL;
+
+    if (getaddrinfo(name,
+		  NULL,		/* don't care abour service/port */
+		  &hints,
+		  &result) != 0) {
+        if (abort_if_no_fqdn) {
+	    /* errno on Unix, WSASetLastError on Windows are already done by the function */
+	    return (-1);
+	} else {
+	    goto LOWERCASE;
+	}
+    }
+
+    if (result == NULL || result->ai_canonname == NULL) {
+	freeaddrinfo (result);
+        if (abort_if_no_fqdn) {
+#ifdef WIN32
+	    WSASetLastError (WSANO_DATA);
+#elif defined(ENODATA)
+	    errno = ENODATA;
+#elif defined(EADDRNOTAVAIL)
+	    errno = EADDRNOTAVAIL;
+#endif
+	    return (-1);
+	} else {
+	    goto LOWERCASE;
+	}
+    }
+
+    if (strchr (result->ai_canonname, '.') == NULL) {
+	freeaddrinfo (result);
+        if (abort_if_no_fqdn) {
+#ifdef WIN32
+	    WSASetLastError (WSANO_DATA);
+#elif defined(ENODATA)
+	    errno = ENODATA;
+#elif defined(EADDRNOTAVAIL)
+	    errno = EADDRNOTAVAIL;
+#endif
+	    return (-1);
+	} else {
+	    goto LOWERCASE;
+	}
+    }
+
+
+/* Do we need to check for buffer overflow and set errno? */
+    strncpy (name, result->ai_canonname, namelen);
+    freeaddrinfo (result);
+
+LOWERCASE:
+    sasl_strlower (name);
+    return (0);
+}
+
+#ifdef WIN32
+/***************************************************************************** 
+ * 
+ *  MODULE NAME : GETOPT.C 
+ * 
+ *  COPYRIGHTS: 
+ *             This module contains code made available by IBM 
+ *             Corporation on an AS IS basis.  Any one receiving the 
+ *             module is considered to be licensed under IBM copyrights 
+ *             to use the IBM-provided source code in any way he or she 
+ *             deems fit, including copying it, compiling it, modifying 
+ *             it, and redistributing it, with or without 
+ *             modifications.  No license under any IBM patents or 
+ *             patent applications is to be implied from this copyright 
+ *             license. 
+ * 
+ *             A user of the module should understand that IBM cannot 
+ *             provide technical support for the module and will not be 
+ *             responsible for any consequences of use of the program. 
+ * 
+ *             Any notices, including this one, are not to be removed 
+ *             from the module without the prior written consent of 
+ *             IBM. 
+ * 
+ *  AUTHOR:   Original author: 
+ *                 G. R. Blair (BOBBLAIR at AUSVM1) 
+ *                 Internet: bobblair@bobblair.austin.ibm.com 
+ * 
+ *            Extensively revised by: 
+ *                 John Q. Walker II, Ph.D. (JOHHQ at RALVM6) 
+ *                 Internet: johnq@ralvm6.vnet.ibm.com 
+ * 
+ *****************************************************************************/ 
+ 
+/****************************************************************************** 
+ * getopt() 
+ * 
+ * The getopt() function is a command line parser.  It returns the next 
+ * option character in argv that matches an option character in opstring. 
+ * 
+ * The argv argument points to an array of argc+1 elements containing argc 
+ * pointers to character strings followed by a null pointer. 
+ * 
+ * The opstring argument points to a string of option characters; if an 
+ * option character is followed by a colon, the option is expected to have 
+ * an argument that may or may not be separated from it by white space. 
+ * The external variable optarg is set to point to the start of the option 
+ * argument on return from getopt(). 
+ * 
+ * The getopt() function places in optind the argv index of the next argument 
+ * to be processed.  The system initializes the external variable optind to 
+ * 1 before the first call to getopt(). 
+ * 
+ * When all options have been processed (that is, up to the first nonoption 
+ * argument), getopt() returns EOF.  The special option "--" may be used to 
+ * delimit the end of the options; EOF will be returned, and "--" will be 
+ * skipped. 
+ * 
+ * The getopt() function returns a question mark (?) when it encounters an 
+ * option character not included in opstring.  This error message can be 
+ * disabled by setting opterr to zero.  Otherwise, it returns the option 
+ * character that was detected. 
+ * 
+ * If the special option "--" is detected, or all options have been 
+ * processed, EOF is returned. 
+ * 
+ * Options are marked by either a minus sign (-) or a slash (/). 
+ * 
+ * No errors are defined. 
+ *****************************************************************************/ 
+ 
+#include <string.h>                 /* for strchr() */ 
+ 
+/* static (global) variables that are specified as exported by getopt() */ 
+__declspec(dllexport) char *optarg = NULL;    /* pointer to the start of the option argument  */ 
+__declspec(dllexport) int   optind = 1;       /* number of the next argv[] to be evaluated    */ 
+__declspec(dllexport) int   opterr = 1;       /* non-zero if a question mark should be returned */
+
+ 
+/* handle possible future character set concerns by putting this in a macro */ 
+#define _next_char(string)  (char)(*(string+1)) 
+ 
+int getopt(int argc, char *argv[], char *opstring) 
+{ 
+    static char *pIndexPosition = NULL; /* place inside current argv string */ 
+    char *pArgString = NULL;        /* where to start from next */ 
+    char *pOptString;               /* the string in our program */ 
+ 
+ 
+    if (pIndexPosition != NULL) { 
+        /* we last left off inside an argv string */ 
+        if (*(++pIndexPosition)) { 
+            /* there is more to come in the most recent argv */ 
+            pArgString = pIndexPosition; 
+        } 
+    } 
+ 
+    if (pArgString == NULL) { 
+        /* we didn't leave off in the middle of an argv string */ 
+        if (optind >= argc) { 
+            /* more command-line arguments than the argument count */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* used up all command-line arguments */ 
+        } 
+ 
+        /*--------------------------------------------------------------------- 
+         * If the next argv[] is not an option, there can be no more options. 
+         *-------------------------------------------------------------------*/ 
+        pArgString = argv[optind++]; /* set this to the next argument ptr */ 
+ 
+        if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */ 
+            ('-' != *pArgString)) { 
+            --optind;               /* point to current arg once we're done */ 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* used up all the command-line flags */ 
+        } 
+ 
+        /* check for special end-of-flags markers */ 
+        if ((strcmp(pArgString, "-") == 0) || 
+            (strcmp(pArgString, "--") == 0)) { 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* encountered the special flag */ 
+        } 
+ 
+        pArgString++;               /* look past the / or - */ 
+    } 
+ 
+    if (':' == *pArgString) {       /* is it a colon? */ 
+        /*--------------------------------------------------------------------- 
+         * Rare case: if opterr is non-zero, return a question mark; 
+         * otherwise, just return the colon we're on. 
+         *-------------------------------------------------------------------*/ 
+        return (opterr ? (int)'?' : (int)':'); 
+    } 
+    else if ((pOptString = strchr(opstring, *pArgString)) == 0) { 
+        /*--------------------------------------------------------------------- 
+         * The letter on the command-line wasn't any good. 
+         *-------------------------------------------------------------------*/ 
+        optarg = NULL;              /* no argument follows the option */ 
+        pIndexPosition = NULL;      /* not in the middle of anything */ 
+        return (opterr ? (int)'?' : (int)*pArgString); 
+    } 
+    else { 
+        /*--------------------------------------------------------------------- 
+         * The letter on the command-line matches one we expect to see 
+         *-------------------------------------------------------------------*/ 
+        if (':' == _next_char(pOptString)) { /* is the next letter a colon? */ 
+            /* It is a colon.  Look for an argument string. */ 
+            if ('\0' != _next_char(pArgString)) {  /* argument in this argv? */ 
+                optarg = &pArgString[1];   /* Yes, it is */ 
+            } 
+            else { 
+                /*------------------------------------------------------------- 
+                 * The argument string must be in the next argv. 
+                 * But, what if there is none (bad input from the user)? 
+                 * In that case, return the letter, and optarg as NULL. 
+                 *-----------------------------------------------------------*/ 
+                if (optind < argc) 
+                    optarg = argv[optind++]; 
+                else { 
+                    optarg = NULL; 
+                    return (opterr ? (int)'?' : (int)*pArgString); 
+                } 
+            } 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+        } 
+        else { 
+            /* it's not a colon, so just return the letter */ 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = pArgString;    /* point to the letter we're on */ 
+        } 
+        return (int)*pArgString;    /* return the letter that matched */ 
+    } 
+} 
+
+#ifndef PASSWORD_MAX
+#  define PASSWORD_MAX 255
+#endif
+
+#include <conio.h>
+char *
+getpass(prompt)
+const char *prompt;
+{
+	register char *p;
+	register int c;
+	static char pbuf[PASSWORD_MAX];
+
+	fprintf(stderr, "%s", prompt); (void) fflush(stderr);
+	for (p=pbuf; (c = _getch())!=13 && c!=EOF;) {
+		if (p < &pbuf[sizeof(pbuf)-1])
+			*p++ = (char) c;
+	}
+	*p = '\0';
+	fprintf(stderr, "\n"); (void) fflush(stderr);
+	return(pbuf);
+}
+
+
+
+#endif /* WIN32 */

+ 2398 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/server.c

@@ -0,0 +1,2398 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: server.c,v 1.177 2011/11/08 17:22:40 murch Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* local functions/structs don't start with sasl
+ */
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifndef macintosh
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sasl.h"
+#include "saslint.h"
+#include "saslplug.h"
+#include "saslutil.h"
+
+#define DEFAULT_CHECKPASS_MECH "auxprop"
+
+/* Contains functions:
+ * 
+ * sasl_server_init
+ * sasl_server_new
+ * sasl_listmech
+ * sasl_server_start
+ * sasl_server_step
+ * sasl_checkpass
+ * sasl_checkapop
+ * sasl_user_exists
+ * sasl_setpass
+ */
+
+/* if we've initialized the server sucessfully */
+static int _sasl_server_active = 0;
+
+/* For access by other modules */
+int _is_sasl_server_active(void) { return _sasl_server_active; }
+
+static int _sasl_checkpass(sasl_conn_t *conn, 
+			   const char *user, unsigned userlen,
+			   const char *pass, unsigned passlen);
+
+static mech_list_t *mechlist = NULL; /* global var which holds the list */
+
+static sasl_global_callbacks_t global_callbacks;
+
+/* set the password for a user
+ *  conn        -- SASL connection
+ *  user        -- user name
+ *  pass        -- plaintext password, may be NULL to remove user
+ *  passlen     -- length of password, 0 = strlen(pass)
+ *  oldpass     -- NULL will sometimes work
+ *  oldpasslen  -- length of password, 0 = strlen(oldpass)
+ *  flags       -- see flags below
+ * 
+ * returns:
+ *  SASL_NOCHANGE  -- proper entry already exists
+ *  SASL_NOMECH    -- no authdb supports password setting as configured
+ *  SASL_NOVERIFY  -- user exists, but no settable password present
+ *  SASL_DISABLED  -- account disabled
+ *  SASL_PWLOCK    -- password locked
+ *  SASL_WEAKPASS  -- password too weak for security policy
+ *  SASL_NOUSERPASS -- user-supplied passwords not permitted
+ *  SASL_FAIL      -- OS error
+ *  SASL_BADPARAM  -- password too long
+ *  SASL_OK        -- successful
+ */
+
+int sasl_setpass(sasl_conn_t *conn,
+		 const char *user,
+		 const char *pass,
+		 unsigned passlen,
+		 const char *oldpass,
+		 unsigned oldpasslen,
+		 unsigned flags)
+{
+    int result = SASL_OK, tmpresult;
+    sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
+    const char *password_request[] = { SASL_AUX_PASSWORD_PROP, NULL };
+    const char *user_delete_request[] = { SASL_AUX_PASSWORD_PROP, SASL_AUX_ALL, NULL };
+    sasl_server_userdb_setpass_t *setpass_cb = NULL;
+    void *context = NULL;
+    int tried_setpass = 0;
+    int failed = 0;
+    mechanism_t *sm;
+    server_sasl_mechanism_t *m;
+    char *current_mech;
+     
+    if (!_sasl_server_active || !mechlist) return SASL_NOTINIT;
+
+    /* check params */
+    if (!conn) return SASL_BADPARAM;
+    if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
+     
+    if ((!(flags & SASL_SET_DISABLE) && passlen == 0)
+        || ((flags & SASL_SET_CREATE) && (flags & SASL_SET_DISABLE)))
+	PARAMERROR(conn);
+
+    /* Check that we have an active SASL mechanism */
+    if (sasl_getprop (conn,
+		      SASL_MECHNAME,
+		      (const void **) &current_mech) != SASL_OK) {
+	current_mech = NULL;
+    }
+
+    if ( (flags & SASL_SET_CURMECH_ONLY) &&
+	 (current_mech == NULL) ) {
+	sasl_seterror( conn, SASL_NOLOG,
+                  "No current SASL mechanism available");
+	RETURN(conn, SASL_BADPARAM);
+    }
+
+    /* Do we want to store SASL_AUX_PASSWORD_PROP (plain text)?  and
+     * Do we have an auxprop backend that can store properties?
+     */
+    if ((flags & SASL_SET_DISABLE || !(flags & SASL_SET_NOPLAIN)) &&
+	sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
+
+	tried_setpass++;
+
+	if (flags & SASL_SET_DISABLE) {
+	    pass = NULL;
+	    passlen = 0;
+	    result = prop_request(s_conn->sparams->propctx, user_delete_request);
+	} else {
+	    result = prop_request(s_conn->sparams->propctx, password_request);
+	}
+	if (result == SASL_OK) {
+	    /* NOTE: When deleting users, this will work in a backward compatible way */
+	    result = prop_set(s_conn->sparams->propctx, SASL_AUX_PASSWORD_PROP,
+			      pass, passlen);
+	}
+	if (result == SASL_OK && flags & SASL_SET_DISABLE) {
+	    result = prop_set(s_conn->sparams->propctx, SASL_AUX_ALL,
+			      NULL, 0);
+	}
+	if (result == SASL_OK) {
+	    result = sasl_auxprop_store(conn, s_conn->sparams->propctx, user);
+	}
+	if (result != SASL_OK) {
+	    _sasl_log(conn, SASL_LOG_ERR,
+		      "setpass failed for %s: %z",
+		      user, result);
+	    failed++;
+	} else {
+	    _sasl_log(conn, SASL_LOG_NOTE,
+		      "setpass succeeded for %s", user);
+	}
+    }
+
+    /* We want to preserve the current value of result, so we use tmpresult below */
+
+    /* call userdb callback function */
+    tmpresult = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_SETPASS,
+			       (sasl_callback_ft *)&setpass_cb, &context);
+    if (tmpresult == SASL_OK && setpass_cb) {
+
+	tried_setpass++;
+
+	tmpresult = setpass_cb(conn, context, user, pass, passlen,
+			    s_conn->sparams->propctx, flags);
+	if(tmpresult != SASL_OK) {
+	    if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
+		if (result == SASL_OK) {
+		    result = tmpresult;
+		}
+	    } else {
+		result = tmpresult;
+	    }
+	    _sasl_log(conn, SASL_LOG_ERR,
+		      "setpass callback failed for %s: %z",
+		      user, tmpresult);
+	    failed++;
+	} else {
+	    _sasl_log(conn, SASL_LOG_NOTE,
+		      "setpass callback succeeded for %s", user);
+	}
+    }
+
+    /* now we let the mechanisms set their secrets */
+    for (sm = s_conn->mech_list; sm; sm = sm->next) {
+	m = &sm->m;
+
+	if (!m->plug->setpass) {
+	    /* can't set pass for this mech */
+	    continue;
+	}
+
+	/* Invoke only one setpass for the currently selected mechanism,
+	   if SASL_SET_CURMECH_ONLY is specified */
+	if ((flags & SASL_SET_CURMECH_ONLY) &&
+	    (strcmp(current_mech, m->plug->mech_name) != 0)) {
+	    continue;
+	}
+
+	tried_setpass++;
+
+	tmpresult = m->plug->setpass(m->plug->glob_context,
+				     ((sasl_server_conn_t *)conn)->sparams,
+				     user,
+				     pass,
+				     passlen,
+				     oldpass, oldpasslen,
+				     flags);
+	if (tmpresult == SASL_OK) {
+	    _sasl_log(conn, SASL_LOG_NOTE,
+		      "%s: set secret for %s", m->plug->mech_name, user);
+
+	    m->condition = SASL_OK; /* if we previously thought the
+				       mechanism didn't have any user secrets 
+				       we now think it does */
+
+	} else if (tmpresult == SASL_NOCHANGE) {
+	    _sasl_log(conn, SASL_LOG_NOTE,
+		      "%s: secret not changed for %s", m->plug->mech_name, user);
+	} else if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
+	    _sasl_log(conn, SASL_LOG_ERR,
+		      "%s: failed to set secret for %s: constrain violation",
+		      m->plug->mech_name, user);
+	    if (result == SASL_OK) {
+		result = tmpresult;
+	    }
+	    failed++;
+	} else {
+	    result = tmpresult;
+	    _sasl_log(conn, SASL_LOG_ERR,
+		      "%s: failed to set secret for %s: %z (%m)",
+		      m->plug->mech_name, user, tmpresult,
+#ifndef WIN32
+		      errno
+#else
+		      GetLastError()
+#endif
+		      );
+	    failed++;
+	}
+    }
+
+    if (!tried_setpass) {
+	_sasl_log(conn, SASL_LOG_WARN,
+		  "secret not changed for %s: "
+		  "no writable auxprop plugin or setpass callback found",
+		  user);
+    } else if (result == SASL_CONSTRAINT_VIOLAT) {
+	/* If not all setpass failed with SASL_CONSTRAINT_VIOLAT - 
+	   ignore SASL_CONSTRAINT_VIOLAT */
+	if (failed < tried_setpass) {
+	    result = SASL_OK;
+	}
+    }
+
+    RETURN(conn, result);
+}
+
+/* local mechanism which disposes of server */
+static void server_dispose(sasl_conn_t *pconn)
+{
+    sasl_server_conn_t *s_conn=  (sasl_server_conn_t *) pconn;
+    context_list_t *cur, *cur_next;
+
+    /* Just sanity check that sasl_server_done wasn't called yet */
+    if (_sasl_server_active != 0) {
+	if (s_conn->mech) {
+	    void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
+
+	    mech_dispose = s_conn->mech->m.plug->mech_dispose;
+
+	    if (mech_dispose) {
+		mech_dispose(pconn->context, s_conn->sparams->utils);
+	    }
+	}
+	pconn->context = NULL;
+
+	for(cur = s_conn->mech_contexts; cur; cur=cur_next) {
+	    cur_next = cur->next;
+	    if (cur->context) {
+		cur->mech->m.plug->mech_dispose(cur->context, s_conn->sparams->utils);
+	    }
+	    sasl_FREE(cur);
+	}  
+	s_conn->mech_contexts = NULL;
+    }
+  
+    _sasl_free_utils(&s_conn->sparams->utils);
+
+    if (s_conn->sparams->propctx) {
+	prop_dispose(&s_conn->sparams->propctx);
+    }
+
+    if (s_conn->appname) {
+	sasl_FREE(s_conn->appname);
+    }
+
+    if (s_conn->user_realm) {
+	sasl_FREE(s_conn->user_realm);
+    }
+
+    if (s_conn->sparams) {
+	sasl_FREE(s_conn->sparams);
+    }
+
+    if (s_conn->mech_list != mechlist->mech_list) {
+	/* free connection-specific mech_list */
+	mechanism_t *m, *prevm;
+
+	m = s_conn->mech_list; /* m point to beginning of the list */
+
+	while (m) {
+	     prevm = m;
+	     m = m->next;
+	     sasl_FREE(prevm);
+	}
+    }
+
+    _sasl_conn_dispose(pconn);
+}
+
+static int init_mechlist(void)
+{
+    sasl_utils_t *newutils = NULL;
+
+    /* set util functions - need to do rest */
+    newutils = _sasl_alloc_utils(NULL, &global_callbacks);
+    if (newutils == NULL)
+	return SASL_NOMEM;
+
+    newutils->checkpass = &_sasl_checkpass;
+
+    mechlist->utils = newutils;
+    mechlist->mech_list = NULL;
+    mechlist->mech_length = 0;
+
+    return SASL_OK;
+}
+
+static int mech_compare(const sasl_server_plug_t *a,
+			const sasl_server_plug_t *b)
+{
+    unsigned sec_diff;
+    unsigned features_diff;
+
+    /* XXX  the following is fairly arbitrary, but its independent
+       of the order in which the plugins are loaded
+    */
+    sec_diff = a->security_flags ^ b->security_flags;
+    if (sec_diff & a->security_flags & SASL_SEC_NOANONYMOUS) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NOANONYMOUS) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_NOPLAINTEXT) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NOPLAINTEXT) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_MUTUAL_AUTH) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_MUTUAL_AUTH) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_NOACTIVE) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NOACTIVE) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_NODICTIONARY) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_NODICTIONARY) return -1;
+    if (sec_diff & a->security_flags & SASL_SEC_FORWARD_SECRECY) return 1;
+    if (sec_diff & b->security_flags & SASL_SEC_FORWARD_SECRECY) return -1;
+
+    features_diff = a->features ^ b->features;
+    if (features_diff & a->features & SASL_FEAT_CHANNEL_BINDING) return 1;
+    if (features_diff & b->features & SASL_FEAT_CHANNEL_BINDING) return -1;
+
+    if (a->max_ssf > b->max_ssf) return 1;
+    if (a->max_ssf < b->max_ssf) return -1;
+
+    return 0;
+}
+
+/*
+ * parameters:
+ *  p - entry point
+ */
+int sasl_server_add_plugin(const char *plugname,
+			   sasl_server_plug_init_t *p)
+{
+    int plugcount;
+    sasl_server_plug_t *pluglist;
+    sasl_server_plug_init_t *entry_point;
+    int result;
+    int version;
+    int lupe;
+
+    if(!plugname || !p) return SASL_BADPARAM;
+
+    entry_point = (sasl_server_plug_init_t *)p;
+
+    /* call into the shared library asking for information about it */
+    /* version is filled in with the version of the plugin */
+    result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION, &version,
+			 &pluglist, &plugcount);
+
+    if ((result != SASL_OK) && (result != SASL_NOUSER)
+        && (result != SASL_CONTINUE)) {
+	_sasl_log(NULL, SASL_LOG_DEBUG,
+		  "%s_client_plug_init() failed in sasl_server_add_plugin(): %z\n",
+		  plugname, result);
+	return result;
+    }
+
+    /* Make sure plugin is using the same SASL version as us */
+    if (version != SASL_SERVER_PLUG_VERSION)
+    {
+	_sasl_log(NULL,
+		  SASL_LOG_ERR,
+		  "version mismatch on  sasl_server_add_plugin for '%s': %d expected, but %d reported",
+		  plugname,
+		  SASL_SERVER_PLUG_VERSION,
+		  version);
+	return SASL_BADVERS;
+    }
+
+    for (lupe=0;lupe < plugcount ;lupe++, pluglist++)
+    {
+	mechanism_t *mech, *mp;
+
+	mech = sasl_ALLOC(sizeof(mechanism_t));
+	if (! mech) return SASL_NOMEM;
+        memset (mech, 0, sizeof(mechanism_t));
+
+	mech->m.plug = pluglist;
+	if(_sasl_strdup(plugname, &mech->m.plugname, NULL) != SASL_OK) {
+	    sasl_FREE(mech);
+	    return SASL_NOMEM;
+	}
+	mech->m.version = version;
+
+	/* whether this mech actually has any users in it's db */
+	mech->m.condition = result; /* SASL_OK, SASL_CONTINUE or SASL_NOUSER */
+
+        /* mech->m.f = NULL; */
+
+	/* sort mech_list by relative "strength" */
+	mp = mechlist->mech_list;
+	if (!mp || mech_compare(pluglist, mp->m.plug) >= 0) {
+	    /* add mech to head of list */
+	    mech->next = mechlist->mech_list;
+	    mechlist->mech_list = mech;
+	} else {
+	    /* find where to insert mech into list */
+	    while (mp->next &&
+		   mech_compare(pluglist, mp->next->m.plug) <= 0) mp = mp->next;
+	    mech->next = mp->next;
+	    mp->next = mech;
+	}
+	mechlist->mech_length++;
+    }
+
+    return SASL_OK;
+}
+
+int sasl_server_done(void)
+{
+    int result = SASL_CONTINUE;
+
+    if (_sasl_server_cleanup_hook == NULL && _sasl_client_cleanup_hook == NULL) {
+	return SASL_NOTINIT;
+    }
+
+    if (_sasl_server_cleanup_hook) {
+	result = _sasl_server_cleanup_hook();
+	
+	if (result == SASL_OK) {
+	    _sasl_server_idle_hook = NULL;
+	    _sasl_server_cleanup_hook = NULL;
+	} else {
+	    return result;
+	}
+    }
+    
+    if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+	return result;
+    }
+    
+    sasl_common_done();
+
+    return SASL_OK;
+}
+
+static int server_done(void) {
+  mechanism_t *m;
+  mechanism_t *prevm;
+
+  if(_sasl_server_active == 0)
+      return SASL_NOTINIT;
+  else
+      _sasl_server_active--;
+  
+  if(_sasl_server_active) {
+      /* Don't de-init yet! Our refcount is nonzero. */
+      return SASL_CONTINUE;
+  }
+
+  if (mechlist != NULL)
+  {
+      m=mechlist->mech_list; /* m point to beginning of the list */
+
+      while (m!=NULL)
+      {
+	  prevm=m;
+	  m=m->next;
+    
+	  if (prevm->m.plug->mech_free) {
+	      prevm->m.plug->mech_free(prevm->m.plug->glob_context,
+				     mechlist->utils);
+	  }
+
+	  sasl_FREE(prevm->m.plugname);
+	  sasl_FREE(prevm);    
+      }
+      _sasl_free_utils(&mechlist->utils);
+      sasl_FREE(mechlist);
+      mechlist = NULL;
+  }
+
+  /* Free the auxprop plugins */
+  _sasl_auxprop_free();
+
+  global_callbacks.callbacks = NULL;
+  global_callbacks.appname = NULL;
+
+  sasl_config_done();
+
+  return SASL_OK;
+}
+
+static int server_idle(sasl_conn_t *conn)
+{
+    sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
+    mechanism_t *m;
+
+    if (! mechlist) {
+	return 0;
+    }
+
+    for (m = s_conn->mech_list;
+	 m != NULL;
+	 m = m->next) {
+	if (m->m.plug->idle
+	    &&  m->m.plug->idle(m->m.plug->glob_context,
+				conn,
+				conn ? ((sasl_server_conn_t *)conn)->sparams : NULL)) {
+	    return 1;
+	}
+    }
+
+    return 0;
+}
+
+static int load_config(const sasl_callback_t *verifyfile_cb)
+{
+    int result;
+    const char *path_to_config = NULL;
+    size_t path_len;
+    char *config_filename = NULL;
+    size_t len;
+    const sasl_callback_t *getconfpath_cb = NULL;
+    const char * next;
+
+    /* If appname was not provided, behave as if there is no config file 
+        (see also sasl_config_init() */
+    if (global_callbacks.appname == NULL) {
+        return SASL_CONTINUE;
+    }
+
+    /* get the path to the config file */
+    getconfpath_cb = _sasl_find_getconfpath_callback( global_callbacks.callbacks );
+    if (getconfpath_cb == NULL) return SASL_BADPARAM;
+
+    /* getconfpath_cb->proc MUST be a sasl_getconfpath_t; if only C had a type
+       system */
+    result = ((sasl_getconfpath_t *)(getconfpath_cb->proc))(getconfpath_cb->context,
+							    (char **) &path_to_config);
+    if (result != SASL_OK) goto done;
+    if (path_to_config == NULL) path_to_config = "";
+
+    next = path_to_config;
+
+    while (next != NULL) {
+        next = strchr(path_to_config, PATHS_DELIMITER);
+
+        /* length = length of path + '/' + length of appname + ".conf" + 1
+            for '\0' */
+
+        if (next != NULL) {
+            path_len = next - path_to_config;
+            next++; /* Skip to the next path */
+        } else {
+            path_len = strlen(path_to_config);
+        }
+
+        len = path_len + 2 + strlen(global_callbacks.appname) + 5 + 1;
+
+        if (len > PATH_MAX ) {
+            result = SASL_FAIL;
+            goto done;
+        }
+
+        /* construct the filename for the config file */
+        config_filename = sasl_ALLOC((unsigned)len);
+        if (! config_filename) {
+            result = SASL_NOMEM;
+            goto done;
+        }
+
+        snprintf(config_filename, len, "%.*s%c%s.conf", path_len, path_to_config, 
+	        HIER_DELIMITER, global_callbacks.appname);
+
+        /* Ask the application if it's safe to use this file */
+        result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context,
+					        config_filename, SASL_VRFY_CONF);
+
+        /* returns SASL_CONTINUE if the config file doesn't exist */
+        if (result == SASL_OK) {
+            result = sasl_config_init(config_filename);
+
+            if (result != SASL_CONTINUE) {
+                /* We are done */
+                break;
+            }
+        }
+
+        if (config_filename) {
+            sasl_FREE(config_filename);
+            config_filename = NULL;
+        }
+
+        path_to_config = next;
+    }
+
+ done:
+    if (config_filename) sasl_FREE(config_filename);
+
+    return result;
+}
+
+/*
+ * Verify that all the callbacks are valid
+ */
+static int verify_server_callbacks(const sasl_callback_t *callbacks)
+{
+    if (callbacks == NULL) return SASL_OK;
+
+    while (callbacks->id != SASL_CB_LIST_END) {
+	if (callbacks->proc==NULL) return SASL_FAIL;
+
+	callbacks++;
+    }
+
+    return SASL_OK;
+}
+
+static char *grab_field(char *line, char **eofield)
+{
+    int d = 0;
+    char *field;
+
+    while (isspace((int) *line)) line++;
+
+    /* find end of field */
+    while (line[d] && !isspace(((int) line[d]))) d++;
+    field = sasl_ALLOC(d + 1);
+    if (!field) { return NULL; }
+    memcpy(field, line, d);
+    field[d] = '\0';
+    *eofield = line + d;
+    
+    return field;
+}
+
+struct secflag_map_s {
+    char *name;
+    int value;
+};
+
+struct secflag_map_s secflag_map[] = {
+    { "noplaintext", SASL_SEC_NOPLAINTEXT },
+    { "noactive", SASL_SEC_NOACTIVE },
+    { "nodictionary", SASL_SEC_NODICTIONARY },
+    { "forward_secrecy", SASL_SEC_FORWARD_SECRECY },
+    { "noanonymous", SASL_SEC_NOANONYMOUS },
+    { "pass_credentials", SASL_SEC_PASS_CREDENTIALS },
+    { "mutual_auth", SASL_SEC_MUTUAL_AUTH },
+    { NULL, 0x0 }
+};
+
+static int parse_mechlist_file(const char *mechlistfile)
+{
+    FILE *f;
+    char buf[1024];
+    char *t, *ptr;
+    int r = 0;
+
+    f = fopen(mechlistfile, "r");
+    if (!f) return SASL_FAIL;
+
+    r = SASL_OK;
+    while (fgets(buf, sizeof(buf), f) != NULL) {
+	mechanism_t *n = sasl_ALLOC(sizeof(mechanism_t));
+	sasl_server_plug_t *nplug;
+
+	if (n == NULL) { r = SASL_NOMEM; break; }
+	n->m.version = SASL_SERVER_PLUG_VERSION;
+	n->m.condition = SASL_CONTINUE;
+	nplug = sasl_ALLOC(sizeof(sasl_server_plug_t));
+	if (nplug == NULL) { r = SASL_NOMEM; break; }
+	memset(nplug, 0, sizeof(sasl_server_plug_t));
+
+	/* each line is:
+	   plugin-file WS mech_name WS max_ssf *(WS security_flag) RET
+	*/
+	
+	/* grab file */
+	n->m.f = grab_field(buf, &ptr);
+
+	/* grab mech_name */
+	nplug->mech_name = grab_field(ptr, &ptr);
+
+	/* grab max_ssf */
+	nplug->max_ssf = strtol(ptr, &ptr, 10);
+
+	/* grab security flags */
+	while (*ptr != '\n') {
+	    struct secflag_map_s *map;
+
+	    /* read security flag */
+	    t = grab_field(ptr, &ptr);
+	    map = secflag_map;
+	    while (map->name) {
+		if (!strcasecmp(t, map->name)) {
+		    nplug->security_flags |= map->value;
+		    break;
+		}
+		map++;
+	    }
+	    if (!map->name) {
+		_sasl_log(NULL, SASL_LOG_ERR,
+			  "%s: couldn't identify flag '%s'",
+			  nplug->mech_name, t);
+	    }
+	    free(t);
+	}
+
+	/* insert mechanism into mechlist */
+	n->m.plug = nplug;
+	n->next = mechlist->mech_list;
+	mechlist->mech_list = n;
+	mechlist->mech_length++;
+    }
+
+    fclose(f);
+    return r;
+}
+
+/* initialize server drivers, done once per process
+ *  callbacks      -- callbacks for all server connections; must include
+ *                    getopt callback
+ *  appname        -- name of calling application
+ *                    (for lower level logging and reading of the configuration file)
+ * results:
+ *  state          -- server state
+ * returns:
+ *  SASL_OK        -- success
+ *  SASL_BADPARAM  -- error in config file
+ *  SASL_NOMEM     -- memory failure
+ *  SASL_BADVERS   -- Mechanism version mismatch
+ */
+
+int sasl_server_init(const sasl_callback_t *callbacks,
+		     const char *appname)
+{
+    int ret;
+    const sasl_callback_t *vf;
+    const char *pluginfile = NULL;
+#ifdef PIC
+    sasl_getopt_t *getopt;
+    void *context;
+#endif
+
+    const add_plugin_list_t ep_list[] = {
+	{ "sasl_server_plug_init", (add_plugin_t *)sasl_server_add_plugin },
+	{ "sasl_auxprop_plug_init", (add_plugin_t *)sasl_auxprop_add_plugin },
+	{ "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
+	{ NULL, NULL }
+    };
+
+    /* lock allocation type */
+    _sasl_allocation_locked++;
+
+    /* we require the appname (if present) to be short enough to be a path */
+    if (appname != NULL && strlen(appname) >= PATH_MAX)
+	return SASL_BADPARAM;
+
+    if (_sasl_server_active) {
+	/* We're already active, just increase our refcount */
+	/* xxx do something with the callback structure? */
+	_sasl_server_active++;
+	return SASL_OK;
+    }
+    
+    ret = _sasl_common_init(&global_callbacks);
+    if (ret != SASL_OK)
+	return ret;
+ 
+    /* verify that the callbacks look ok */
+    ret = verify_server_callbacks(callbacks);
+    if (ret != SASL_OK)
+	return ret;
+
+    global_callbacks.callbacks = callbacks;
+    
+    /* A shared library calling sasl_server_init will pass NULL as appname.
+       This should retain the original appname. */
+    if (appname != NULL) {
+        global_callbacks.appname = appname;
+    }
+
+    /* If we fail now, we have to call server_done */
+    _sasl_server_active = 1;
+
+    /* allocate mechlist and set it to empty */
+    mechlist = sasl_ALLOC(sizeof(mech_list_t));
+    if (mechlist == NULL) {
+	server_done();
+	return SASL_NOMEM;
+    }
+
+    ret = init_mechlist();
+    if (ret != SASL_OK) {
+	server_done();
+	return ret;
+    }
+
+    vf = _sasl_find_verifyfile_callback(callbacks);
+
+    /* load config file if applicable */
+    ret = load_config(vf);
+    if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) {
+	server_done();
+	return ret;
+    }
+
+    /* load internal plugins */
+    sasl_server_add_plugin("EXTERNAL", &external_server_plug_init);
+
+#ifdef PIC
+    /* delayed loading of plugins? (DSO only, as it doesn't
+     * make much [any] sense to delay in the static library case) */
+    if (_sasl_getcallback(NULL, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) 
+	   == SASL_OK) {
+	/* No sasl_conn_t was given to getcallback, so we provide the
+	 * global callbacks structure */
+	ret = getopt(&global_callbacks, NULL, "plugin_list", &pluginfile, NULL);
+    }
+#endif
+    
+    if (pluginfile != NULL) {
+	/* this file should contain a list of plugins available.
+	   we'll load on demand. */
+
+	/* Ask the application if it's safe to use this file */
+	ret = ((sasl_verifyfile_t *)(vf->proc))(vf->context,
+						pluginfile,
+						SASL_VRFY_CONF);
+	if (ret != SASL_OK) {
+	    _sasl_log(NULL, SASL_LOG_ERR,
+		      "unable to load plugin list %s: %z", pluginfile, ret);
+	}
+	
+	if (ret == SASL_OK) {
+	    ret = parse_mechlist_file(pluginfile);
+	}
+    } else {
+	/* load all plugins now */
+	ret = _sasl_load_plugins(ep_list,
+				 _sasl_find_getpath_callback(callbacks),
+				 _sasl_find_verifyfile_callback(callbacks));
+    }
+
+    if (ret == SASL_OK) {
+	_sasl_server_cleanup_hook = &server_done;
+	_sasl_server_idle_hook = &server_idle;
+
+	ret = _sasl_build_mechlist();
+    } else {
+	server_done();
+    }
+
+    return ret;
+}
+
+/*
+ * Once we have the users plaintext password we 
+ * may want to transition them. That is put entries
+ * for them in the passwd database for other
+ * stronger mechanism
+ *
+ * for example PLAIN -> CRAM-MD5
+ */
+static int
+_sasl_transition(sasl_conn_t * conn,
+		 const char * pass,
+		 unsigned passlen)
+{
+    const char *dotrans = "n";
+    sasl_getopt_t *getopt;
+    int result = SASL_OK;
+    void *context;
+    unsigned flags = 0;
+
+    if (! conn)
+	return SASL_BADPARAM;
+
+    if (! conn->oparams.authid)
+	PARAMERROR(conn);
+
+    /* check if this is enabled: default to false */
+    if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK)
+    {
+	getopt(context, NULL, "auto_transition", &dotrans, NULL);
+	if (dotrans == NULL) dotrans = "n";
+    }
+
+
+    if (!strcmp(dotrans, "noplain")) flags |= SASL_SET_NOPLAIN;
+
+    if (flags || *dotrans == '1' || *dotrans == 'y' ||
+	(*dotrans == 'o' && dotrans[1] == 'n') || *dotrans == 't') {
+	/* ok, it's on! */
+	_sasl_log(conn, SASL_LOG_NOTE, 
+		  "transitioning user %s to auxprop database",
+		  conn->oparams.authid);
+	result = sasl_setpass(conn,
+			      conn->oparams.authid,
+			      pass,
+			      passlen,
+			      NULL, 0, SASL_SET_CREATE | flags);
+    }
+
+    RETURN(conn,result);
+}
+
+
+/* create context for a single SASL connection
+ *  service        -- registered name of the service using SASL (e.g. "imap")
+ *  serverFQDN     -- Fully qualified domain name of server.  NULL means use
+ *                    gethostname() or equivalent.
+ *                    Useful for multi-homed servers.
+ *  user_realm     -- permits multiple user realms on server, NULL = default
+ *  iplocalport    -- server IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  ipremoteport   -- client IPv4/IPv6 domain literal string with port
+ *                    (if NULL, then mechanisms requiring IPaddr are disabled)
+ *  callbacks      -- callbacks (e.g., authorization, lang, new getopt context)
+ *  flags          -- usage flags (see above)
+ * returns:
+ *  pconn          -- new connection context
+ *
+ * returns:
+ *  SASL_OK        -- success
+ *  SASL_NOMEM     -- not enough memory
+ */
+
+int sasl_server_new(const char *service,
+		    const char *serverFQDN,
+		    const char *user_realm,
+		    const char *iplocalport,
+		    const char *ipremoteport,
+		    const sasl_callback_t *callbacks,
+		    unsigned flags,
+		    sasl_conn_t **pconn)
+{
+  int result;
+  sasl_server_conn_t *serverconn;
+  sasl_utils_t *utils;
+  sasl_getopt_t *getopt;
+  void *context;
+  const char *log_level, *auto_trans;
+  const char *mlist = NULL;
+  int plus = 0;
+
+  if (_sasl_server_active==0) return SASL_NOTINIT;
+  if (! pconn) return SASL_FAIL;
+  if (! service) return SASL_FAIL;
+
+  *pconn=sasl_ALLOC(sizeof(sasl_server_conn_t));
+  if (*pconn==NULL) return SASL_NOMEM;
+
+  memset(*pconn, 0, sizeof(sasl_server_conn_t));
+
+  serverconn = (sasl_server_conn_t *)*pconn;
+
+  /* make sparams */
+  serverconn->sparams=sasl_ALLOC(sizeof(sasl_server_params_t));
+  if (serverconn->sparams==NULL)
+      MEMERROR(*pconn);
+
+  memset(serverconn->sparams, 0, sizeof(sasl_server_params_t));
+
+  (*pconn)->destroy_conn = &server_dispose;
+  result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_SERVER,
+			   &server_idle, serverFQDN,
+			   iplocalport, ipremoteport,
+			   callbacks, &global_callbacks);
+  if (result != SASL_OK)
+      goto done_error;
+
+
+  /* set util functions - need to do rest */
+  utils=_sasl_alloc_utils(*pconn, &global_callbacks);
+  if (!utils) {
+      result = SASL_NOMEM;
+      goto done_error;
+  }
+  
+  utils->checkpass = &_sasl_checkpass;
+
+  /* Setup the propctx -> We'll assume the default size */
+  serverconn->sparams->propctx=prop_new(0);
+  if(!serverconn->sparams->propctx) {
+      result = SASL_NOMEM;
+      goto done_error;
+  }
+
+  serverconn->sparams->service = (*pconn)->service;
+  serverconn->sparams->servicelen = (unsigned) strlen((*pconn)->service);
+
+  if (global_callbacks.appname && global_callbacks.appname[0] != '\0') {
+    result = _sasl_strdup (global_callbacks.appname,
+			   &serverconn->appname,
+			   NULL);
+    if (result != SASL_OK) {
+      result = SASL_NOMEM;
+      goto done_error;
+    }
+    serverconn->sparams->appname = serverconn->appname;
+    serverconn->sparams->applen = (unsigned) strlen(serverconn->sparams->appname);
+  } else {
+    serverconn->appname = NULL;
+    serverconn->sparams->appname = NULL;
+    serverconn->sparams->applen = 0;
+  }
+
+  serverconn->sparams->serverFQDN = (*pconn)->serverFQDN;
+  serverconn->sparams->slen = (unsigned) strlen((*pconn)->serverFQDN);
+
+  if (user_realm) {
+      result = _sasl_strdup(user_realm, &serverconn->user_realm, NULL);
+      serverconn->sparams->urlen = (unsigned) strlen(user_realm);
+      serverconn->sparams->user_realm = serverconn->user_realm;
+  } else {
+      serverconn->user_realm = NULL;
+      /* the sparams is already zeroed */
+  }
+
+  serverconn->sparams->callbacks = callbacks;
+
+  log_level = auto_trans = NULL;
+  if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+    getopt(context, NULL, "log_level", &log_level, NULL);
+    getopt(context, NULL, "auto_transition", &auto_trans, NULL);
+    getopt(context, NULL, "mech_list", &mlist, NULL);
+  }
+  serverconn->sparams->log_level = log_level ? atoi(log_level) : SASL_LOG_ERR;
+
+  serverconn->sparams->utils = utils;
+
+  if (auto_trans &&
+      (*auto_trans == '1' || *auto_trans == 'y' || *auto_trans == 't' ||
+       (*auto_trans == 'o' && auto_trans[1] == 'n') ||
+       !strcmp(auto_trans, "noplain")) &&
+      sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
+      serverconn->sparams->transition = &_sasl_transition;
+  }
+
+  /* if we have a mech_list, create ordered list of avail mechs for this conn */
+  if (mlist) {
+      const char *cp;
+      mechanism_t *mptr, *tail = NULL;
+
+      while (*mlist) {
+	  /* find end of current mech name */
+	  for (cp = mlist; *cp && !isspace((int) *cp); cp++);
+
+	  /* search for mech name in loaded plugins */
+	  for (mptr = mechlist->mech_list; mptr; mptr = mptr->next) {
+	      const sasl_server_plug_t *plug = mptr->m.plug;
+
+	      if (_sasl_is_equal_mech(mlist, plug->mech_name, (size_t) (cp - mlist), &plus)) {
+		  /* found a match */
+		  break;
+	      }
+	  }
+	  if (mptr) {
+	      mechanism_t *new = sasl_ALLOC(sizeof(mechanism_t));
+	      if (!new) return SASL_NOMEM;
+
+	      memcpy(&new->m, &mptr->m, sizeof(server_sasl_mechanism_t));
+	      new->next = NULL;
+
+	      if (!serverconn->mech_list) {
+		  serverconn->mech_list = new;
+		  tail = serverconn->mech_list;
+	      }
+	      else {
+		  tail->next = new;
+		  tail = new;
+	      }
+	      serverconn->mech_length++;
+	  }
+
+	  /* find next mech name */
+	  mlist = cp;
+	  while (*mlist && isspace((int) *mlist)) mlist++;
+      }
+  }
+  else {
+      serverconn->mech_list = mechlist->mech_list;
+      serverconn->mech_length = mechlist->mech_length;
+  }
+
+  serverconn->sparams->canon_user = &_sasl_canon_user_lookup;
+  serverconn->sparams->props = serverconn->base.props;
+  serverconn->sparams->flags = flags;
+
+  if(result == SASL_OK) return SASL_OK;
+
+ done_error:
+  _sasl_conn_dispose(*pconn);
+  sasl_FREE(*pconn);
+  *pconn = NULL;
+  return result;
+}
+
+/*
+ * The rule is:
+ * IF mech strength + external strength < min ssf THEN FAIL.
+ * We also have to look at the security properties and make sure
+ * that this mechanism has everything we want.
+ */
+static int mech_permitted(sasl_conn_t *conn,
+			  mechanism_t *mech)
+{
+    sasl_server_conn_t *s_conn = (sasl_server_conn_t *)conn;
+    const sasl_server_plug_t *plug;
+    int ret;
+    int myflags;
+    context_list_t *cur;
+    context_list_t *mech_context_list_entry = NULL;
+    void *context = NULL;
+    sasl_ssf_t minssf = 0;
+
+    if(!conn) return SASL_NOMECH;
+
+    if(! mech || ! mech->m.plug) {
+	PARAMERROR(conn);
+	return SASL_NOMECH;
+    }
+    
+    plug = mech->m.plug;
+
+    /* setup parameters for the call to mech_avail */
+    s_conn->sparams->serverFQDN=conn->serverFQDN;
+    s_conn->sparams->service=conn->service;
+    s_conn->sparams->user_realm=s_conn->user_realm;
+    s_conn->sparams->props=conn->props;
+    s_conn->sparams->external_ssf=conn->external.ssf;
+
+    /* Check if we have banished this one already */
+    for (cur = s_conn->mech_contexts; cur; cur=cur->next) {
+	if (cur->mech == mech) {
+	    /* If it's not mech_avail'd, then stop now */
+	    if (!cur->context) {
+		return SASL_NOMECH;
+	    } else {
+		context = cur->context;
+		mech_context_list_entry = cur;
+	    }
+	    break;
+	}
+    }
+    
+    if (conn->props.min_ssf < conn->external.ssf) {
+	minssf = 0;
+    } else {
+	minssf = conn->props.min_ssf - conn->external.ssf;
+    }
+    
+    /* Generic mechanism */
+    if (plug->max_ssf < minssf) {
+	sasl_seterror(conn, SASL_NOLOG,
+		      "mech %s is too weak", plug->mech_name);
+	return SASL_TOOWEAK; /* too weak */
+    }
+
+    if (plug->mech_avail
+        && (ret = plug->mech_avail(plug->glob_context,
+				   s_conn->sparams,
+				   (void **)&context)) != SASL_OK ) {
+	if (ret == SASL_NOMECH) {
+	    /* Mark this mech as no good for this connection */
+	    cur = sasl_ALLOC(sizeof(context_list_t));
+	    if (!cur) {
+		MEMERROR(conn);
+		return SASL_NOMECH;
+	    }
+	    cur->context = NULL;
+	    cur->mech = mech;
+	    cur->next = s_conn->mech_contexts;
+	    s_conn->mech_contexts = cur;
+	}
+	
+	/* SASL_NOTDONE might also get us here */
+
+	/* Error should be set by mech_avail call */
+	return SASL_NOMECH;
+    } else if (context) {
+	if (mech_context_list_entry != NULL) {
+	    /* Update the context. It shouldn't have changed, but who knows */
+	    mech_context_list_entry->context = context;
+	} else {
+	    /* Save this context */
+	    cur = sasl_ALLOC(sizeof(context_list_t));
+	    if (!cur) {
+		MEMERROR(conn);
+		return SASL_NOMECH;
+	    }
+	    cur->context = context;
+	    cur->mech = mech;
+	    cur->next = s_conn->mech_contexts;
+	    s_conn->mech_contexts = cur;
+	}
+    }
+    
+    /* Generic mechanism */
+    if (plug->max_ssf < minssf) {
+	sasl_seterror(conn, SASL_NOLOG, "too weak");
+	return SASL_TOOWEAK; /* too weak */
+    }
+
+    /* if there are no users in the secrets database we can't use this 
+       mechanism */
+    if (mech->m.condition == SASL_NOUSER) {
+	sasl_seterror(conn, 0, "no users in secrets db");
+	return SASL_NOMECH;
+    }
+
+    /* Can it meet our features? */
+    if ((conn->flags & SASL_NEED_PROXY) &&
+	!(plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+	return SASL_NOMECH;
+    }
+    if ((conn->flags & SASL_NEED_HTTP) &&
+	!(plug->features & SASL_FEAT_SUPPORTS_HTTP)) {
+	return SASL_NOMECH;
+    }
+    
+    /* security properties---if there are any flags that differ and are
+       in what the connection are requesting, then fail */
+    
+    /* special case plaintext */
+    myflags = conn->props.security_flags;
+
+    /* if there's an external layer this is no longer plaintext */
+    if ((conn->props.min_ssf <= conn->external.ssf) && 
+	(conn->external.ssf > 1)) {
+	myflags &= ~SASL_SEC_NOPLAINTEXT;
+    }
+
+    /* do we want to special case SASL_SEC_PASS_CREDENTIALS? nah.. */
+    if ((myflags &= (myflags ^ plug->security_flags)) != 0) {
+	sasl_seterror(conn, SASL_NOLOG,
+		      "security flags do not match required");
+	return (myflags & SASL_SEC_NOPLAINTEXT) ? SASL_ENCRYPT : SASL_NOMECH;
+    }
+
+    /* Check Features */
+    if (plug->features & SASL_FEAT_GETSECRET) {
+	/* We no longer support sasl_server_{get,put}secret */
+	sasl_seterror(conn, 0,
+		      "mech %s requires unprovided secret facility",
+		      plug->mech_name);
+	return SASL_NOMECH;
+    }
+
+    return SASL_OK;
+}
+
+/*
+ * make the authorization 
+ *
+ */
+
+static int do_authorization(sasl_server_conn_t *s_conn)
+{
+    int ret;
+    sasl_authorize_t *authproc;
+    void *auth_context;
+    
+    /* now let's see if authname is allowed to proxy for username! */
+    
+    /* check the proxy callback */
+    if (_sasl_getcallback(&s_conn->base, SASL_CB_PROXY_POLICY,
+			  (sasl_callback_ft *)&authproc, &auth_context) != SASL_OK) {
+	INTERROR(&s_conn->base, SASL_NOAUTHZ);
+    }
+
+    ret = authproc(&(s_conn->base), auth_context,
+		   s_conn->base.oparams.user, s_conn->base.oparams.ulen,
+		   s_conn->base.oparams.authid, s_conn->base.oparams.alen,
+		   s_conn->user_realm,
+		   (s_conn->user_realm ? (unsigned) strlen(s_conn->user_realm) : 0),
+		   s_conn->sparams->propctx);
+
+    RETURN(&s_conn->base, ret);
+}
+
+
+/* start a mechanism exchange within a connection context
+ *  mech           -- the mechanism name client requested
+ *  clientin       -- client initial response (NUL terminated), NULL if empty
+ *  clientinlen    -- length of initial response
+ *  serverout      -- initial server challenge, NULL if done 
+ *                    (library handles freeing this string)
+ *  serveroutlen   -- length of initial server challenge
+ * output:
+ *  pconn          -- the connection negotiation state on success
+ *
+ * Same returns as sasl_server_step() or
+ * SASL_NOMECH if mechanism not available.
+ */
+int sasl_server_start(sasl_conn_t *conn,
+		      const char *mech,
+		      const char *clientin,
+		      unsigned clientinlen,
+		      const char **serverout,
+		      unsigned *serveroutlen)
+{
+    sasl_server_conn_t *s_conn=(sasl_server_conn_t *) conn;
+    int result;
+    context_list_t *cur, **prev;
+    mechanism_t *m;
+    size_t mech_len;
+    int plus = 0;
+
+    if (_sasl_server_active==0) return SASL_NOTINIT;
+
+    /* check parameters */
+    if(!conn) return SASL_BADPARAM;
+    
+    if (!mech || ((clientin == NULL) && (clientinlen > 0)))
+	PARAMERROR(conn);
+
+    if (serverout) *serverout = NULL;
+    if (serveroutlen) *serveroutlen = 0;
+
+    /* make sure mech is valid mechanism
+       if not return appropriate error */
+    m = s_conn->mech_list;
+    mech_len = strlen(mech);
+
+    while (m != NULL) {
+	if (_sasl_is_equal_mech(mech, m->m.plug->mech_name, mech_len, &plus)) {
+	    break;
+	}
+
+	m = m->next;
+    }
+  
+    if (m == NULL) {
+	sasl_seterror(conn, 0, "Couldn't find mech %s", mech);
+	result = SASL_NOMECH;
+	goto done;
+    }
+
+    /* Make sure that we're willing to use this mech */
+    if ((result = mech_permitted(conn, m)) != SASL_OK) {
+	goto done;
+    }
+
+    if (m->m.condition == SASL_CONTINUE) {
+	sasl_server_plug_init_t *entry_point;
+	void *library = NULL;
+	sasl_server_plug_t *pluglist;
+	int version, plugcount;
+	int l = 0;
+
+	/* need to load this plugin */
+	result = _sasl_get_plugin(m->m.f,
+		    _sasl_find_verifyfile_callback(global_callbacks.callbacks),
+				  &library);
+
+	if (result == SASL_OK) {
+	    result = _sasl_locate_entry(library, "sasl_server_plug_init",
+					(void **)&entry_point);
+	}
+
+	if (result == SASL_OK) {
+	    result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION,
+				 &version, &pluglist, &plugcount);
+	}
+
+	if (result == SASL_OK) {
+	    /* find the correct mechanism in this plugin */
+	    for (l = 0; l < plugcount; l++) {
+		if (!strcasecmp(pluglist[l].mech_name, 
+				m->m.plug->mech_name)) break;
+	    }
+	    if (l == plugcount) {
+		result = SASL_NOMECH;
+	    }
+	}
+	if (result == SASL_OK) {
+	    /* check that the parameters are the same */
+	    if ((pluglist[l].max_ssf != m->m.plug->max_ssf) ||
+		(pluglist[l].security_flags != m->m.plug->security_flags)) {
+		_sasl_log(conn, SASL_LOG_ERR, 
+			  "%s: security parameters don't match mechlist file",
+			  pluglist[l].mech_name);
+		result = SASL_NOMECH;
+	    }
+	}
+	if (result == SASL_OK) {
+	    /* copy mechlist over */
+	    sasl_FREE((sasl_server_plug_t *) m->m.plug);
+	    m->m.plug = &pluglist[l];
+	    m->m.condition = SASL_OK;
+	}
+
+	if (result != SASL_OK) {
+	    /* The library will eventually be freed, don't sweat it */
+	    RETURN(conn, result);
+	}
+    }
+
+    if (conn->context) {
+	s_conn->mech->m.plug->mech_dispose(conn->context,
+					   s_conn->sparams->utils);
+	conn->context = NULL;
+    }
+
+    /* We used to setup sparams HERE, but now it's done
+       inside of mech_permitted (which is called above) */
+    prev = &s_conn->mech_contexts;
+    for (cur = *prev; cur; prev=&cur->next,cur=cur->next) {
+	if (cur->mech == m) {
+	    if (!cur->context) {
+		sasl_seterror(conn, 0,
+			      "Got past mech_permitted with a disallowed mech!");
+		return SASL_NOMECH;
+	    }
+	    /* If we find it, we need to pull cur out of the
+	       list so it won't be freed later! */
+	    *prev = cur->next;
+	    conn->context = cur->context;
+	    sasl_FREE(cur);
+	    break;
+	}
+    }
+
+    s_conn->mech = m;
+    
+    if (!conn->context) {
+	/* Note that we don't hand over a new challenge */
+	result = s_conn->mech->m.plug->mech_new(s_conn->mech->m.plug->glob_context,
+						s_conn->sparams,
+						NULL,
+						0,
+						&(conn->context));
+    } else {
+	/* the work was already done by mech_avail! */
+	result = SASL_OK;
+    }
+    
+    if (result == SASL_OK) {
+         if (clientin) {
+            if (s_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) {
+                /* Remote sent first, but mechanism does not support it.
+                 * RFC 2222 says we fail at this point. */
+                sasl_seterror(conn,
+			      0,
+                              "Remote sent first but mech does not allow it.");
+                result = SASL_BADPROT;
+            } else {
+                /* Mech wants client-first, so let them have it */
+                result = sasl_server_step(conn,
+                                          clientin,
+					  clientinlen,
+                                          serverout,
+					  serveroutlen);
+            }
+        } else {
+            if (s_conn->mech->m.plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
+                /* Mech wants client first anyway, so we should do that */
+		if (serverout) *serverout = "";
+		if (serveroutlen) *serveroutlen = 0;
+                result = SASL_CONTINUE;
+            } else {
+                /* Mech wants server-first, so let them have it */
+                result = sasl_server_step(conn,
+                                          clientin,
+					  clientinlen,
+                                          serverout,
+					  serveroutlen);
+            }
+	}
+    }
+
+ done:
+    if (  result != SASL_OK
+       && result != SASL_CONTINUE
+       && result != SASL_INTERACT) {
+	if (conn->context) {
+	    s_conn->mech->m.plug->mech_dispose(conn->context,
+					       s_conn->sparams->utils);
+	    conn->context = NULL;
+	}
+	conn->oparams.doneflag = 0;
+    }
+    
+    RETURN(conn,result);
+}
+
+
+/* perform one step of the SASL exchange
+ *  clientinlen & clientin -- client data
+ *                      NULL on first step if no optional client step
+ *  serveroutlen & serverout -- set to the server data to transmit
+ *                        to the client in the next step
+ *                        (library handles freeing this)
+ *
+ * returns:
+ *  SASL_OK        -- exchange is complete.
+ *  SASL_CONTINUE  -- indicates another step is necessary.
+ *  SASL_TRANS     -- entry for user exists, but not for mechanism
+ *                    and transition is possible
+ *  SASL_BADPARAM  -- service name needed
+ *  SASL_BADPROT   -- invalid input from client
+ *  ...
+ */
+
+int sasl_server_step(sasl_conn_t *conn,
+		     const char *clientin,
+		     unsigned clientinlen,
+		     const char **serverout,
+		     unsigned *serveroutlen)
+{
+    int ret;
+    sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;  /* cast */
+
+    /* check parameters */
+    if (_sasl_server_active==0) return SASL_NOTINIT;
+    if (!conn) return SASL_BADPARAM;
+    if ((clientin==NULL) && (clientinlen>0))
+	PARAMERROR(conn);
+
+    /* If we've already done the last send, return! */
+    if (s_conn->sent_last == 1) {
+	return SASL_OK;
+    }
+
+    /* Don't do another step if the plugin told us that we're done */
+    if (conn->oparams.doneflag) {
+	_sasl_log(conn, SASL_LOG_ERR, "attempting server step after doneflag");
+	return SASL_FAIL;
+    }
+
+    if (serverout) *serverout = NULL;
+    if (serveroutlen) *serveroutlen = 0;
+
+    ret = s_conn->mech->m.plug->mech_step(conn->context,
+					s_conn->sparams,
+					clientin,
+					clientinlen,
+					serverout,
+					serveroutlen,
+					&conn->oparams);
+
+    if (ret == SASL_OK) {
+	ret = do_authorization(s_conn);
+    }
+
+    if (ret == SASL_OK) {
+	/* if we're done, we need to watch out for the following:
+	 * 1. the mech does server-send-last
+	 * 2. the protocol does not
+	 *
+	 * in this case, return SASL_CONTINUE and remember we are done.
+	 */
+	if(*serverout && !(conn->flags & SASL_SUCCESS_DATA)) {
+	    s_conn->sent_last = 1;
+	    ret = SASL_CONTINUE;
+	}
+	if(!conn->oparams.maxoutbuf) {
+	    conn->oparams.maxoutbuf = conn->props.maxbufsize;
+	}
+
+        /* Validate channel bindings */
+	switch (conn->oparams.cbindingdisp) {
+	case SASL_CB_DISP_NONE:
+	    if (SASL_CB_CRITICAL(s_conn->sparams)) {
+		sasl_seterror(conn, 0,
+			      "server requires channel binding but client provided none");
+		ret = SASL_BADBINDING;
+	    }
+	    break;
+	case SASL_CB_DISP_WANT:
+	    if (SASL_CB_PRESENT(s_conn->sparams)) {
+		sasl_seterror(conn, 0,
+			      "client incorrectly assumed server had no channel binding");
+		ret = SASL_BADAUTH;
+	    }
+	    break;
+	case SASL_CB_DISP_USED:
+	    if (!SASL_CB_PRESENT(s_conn->sparams)) {
+		sasl_seterror(conn, 0,
+			      "client provided channel binding but server had none");
+		ret = SASL_BADBINDING;
+	    } else if (strcmp(conn->oparams.cbindingname,
+		       s_conn->sparams->cbinding->name) != 0) {
+		sasl_seterror(conn, 0,
+			      "client channel binding %s does not match server %s",
+			      conn->oparams.cbindingname, s_conn->sparams->cbinding->name);
+		ret = SASL_BADBINDING;
+	    }
+	    break;
+	}
+
+        if (ret == SASL_OK &&
+	    (conn->oparams.user == NULL || conn->oparams.authid == NULL)) {
+	    sasl_seterror(conn, 0,
+			  "mech did not call canon_user for both authzid " \
+			  "and authid");
+	    ret = SASL_BADPROT;
+	}	
+    }
+    
+    if (  ret != SASL_OK
+       && ret != SASL_CONTINUE
+       && ret != SASL_INTERACT) {
+	if (conn->context) {
+	    s_conn->mech->m.plug->mech_dispose(conn->context,
+					     s_conn->sparams->utils);
+	    conn->context = NULL;
+	}
+	conn->oparams.doneflag = 0;
+    }
+
+    RETURN(conn, ret);
+}
+
+/* returns the length of all the mechanisms
+ * added up 
+ */
+
+static unsigned mech_names_len(mechanism_t *mech_list)
+{
+  mechanism_t *listptr;
+  unsigned result = 0;
+
+  for (listptr = mech_list;
+       listptr;
+       listptr = listptr->next)
+    result += (unsigned) strlen(listptr->m.plug->mech_name);
+
+  return result;
+}
+
+/* This returns a list of mechanisms in a NUL-terminated string
+ *
+ * The default behavior is to separate with spaces if sep == NULL
+ */
+int _sasl_server_listmech(sasl_conn_t *conn,
+			  const char *user __attribute__((unused)),
+			  const char *prefix,
+			  const char *sep,
+			  const char *suffix,
+			  const char **result,
+			  unsigned *plen,
+			  int *pcount)
+{
+  sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;  /* cast */
+  int lup;
+  mechanism_t *listptr;
+  int ret;
+  size_t resultlen;
+  int flag;
+  const char *mysep;
+
+  /* if there hasn't been a sasl_sever_init() fail */
+  if (_sasl_server_active==0) return SASL_NOTINIT;
+  if (!conn) return SASL_BADPARAM;
+  if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
+  
+  if (! result)
+      PARAMERROR(conn);
+
+  if (plen != NULL)
+      *plen = 0;
+  if (pcount != NULL)
+      *pcount = 0;
+
+  if (sep) {
+      mysep = sep;
+  } else {
+      mysep = " ";
+  }
+
+  if (!s_conn->mech_list || s_conn->mech_length <= 0)
+      INTERROR(conn, SASL_NOMECH);
+
+  resultlen = (prefix ? strlen(prefix) : 0)
+            + (strlen(mysep) * (s_conn->mech_length - 1) * 2)
+	    + (mech_names_len(s_conn->mech_list) * 2) /* including -PLUS variant */
+	    + (s_conn->mech_length * (sizeof("-PLUS") - 1))
+            + (suffix ? strlen(suffix) : 0)
+	    + 1;
+
+  ret = _buf_alloc(&conn->mechlist_buf,
+		   &conn->mechlist_buf_len, resultlen);
+  if(ret != SASL_OK) MEMERROR(conn);
+
+  if (prefix)
+    strcpy (conn->mechlist_buf,prefix);
+  else
+    *(conn->mechlist_buf) = '\0';
+
+  listptr = s_conn->mech_list;
+   
+  flag = 0;
+  /* make list */
+  for (lup = 0; lup < s_conn->mech_length; lup++) {
+      /* currently, we don't use the "user" parameter for anything */
+      if (mech_permitted(conn, listptr) == SASL_OK) {
+
+          /*
+           * If the server would never succeed in the authentication of
+           * the non-PLUS-variant due to policy reasons, it MUST advertise
+           * only the PLUS-variant.
+           */
+	  if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
+	      SASL_CB_PRESENT(s_conn->sparams)) {
+	    if (pcount != NULL) {
+		(*pcount)++;
+	    }
+	    if (flag) {
+              strcat(conn->mechlist_buf, mysep);
+	    } else {
+              flag = 1;
+	    }
+	    strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+	    strcat(conn->mechlist_buf, "-PLUS");
+	  }
+
+          /*
+           * If the server cannot support channel binding, it SHOULD
+           * advertise only the non-PLUS-variant. Here, supporting channel
+           * binding means the underlying SASL mechanism supports it and
+           * the application has set some channel binding data.
+           */
+          if (!SASL_CB_PRESENT(s_conn->sparams) ||
+              !SASL_CB_CRITICAL(s_conn->sparams)) {
+            if (pcount != NULL) {
+	      (*pcount)++;
+	    }
+	    if (flag) {
+              strcat(conn->mechlist_buf, mysep);
+	    } else {
+              flag = 1;
+	    }
+	    strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+          }
+      }
+
+      listptr = listptr->next;
+  }
+
+  if (suffix)
+      strcat(conn->mechlist_buf,suffix);
+
+  if (plen!=NULL)
+      *plen = (unsigned) strlen(conn->mechlist_buf);
+
+  *result = conn->mechlist_buf;
+
+  return SASL_OK;  
+}
+
+sasl_string_list_t *_sasl_server_mechs(void) 
+{
+  mechanism_t *listptr;
+  sasl_string_list_t *retval = NULL, *next=NULL;
+
+  if(!_sasl_server_active) return NULL;
+
+  /* make list */
+  for (listptr = mechlist->mech_list; listptr; listptr = listptr->next) {
+      next = sasl_ALLOC(sizeof(sasl_string_list_t));
+
+      if(!next && !retval) return NULL;
+      else if(!next) {
+	  next = retval->next;
+	  do {
+	      sasl_FREE(retval);
+	      retval = next;
+	      next = retval->next;
+	  } while(next);
+	  return NULL;
+      }
+      
+      next->d = listptr->m.plug->mech_name;
+
+      if(!retval) {
+	  next->next = NULL;
+	  retval = next;
+      } else {
+	  next->next = retval;
+	  retval = next;
+      }
+  }
+
+  return retval;
+}
+
+#define EOSTR(s,n) (((s)[n] == '\0') || ((s)[n] == ' ') || ((s)[n] == '\t'))
+static int is_mech(const char *t, const char *m)
+{
+    size_t sl = strlen(m);
+    return ((!strncasecmp(m, t, sl)) && EOSTR(t, sl));
+}
+
+/* returns OK if it's valid */
+static int _sasl_checkpass(sasl_conn_t *conn,
+			   const char *user,
+			   unsigned userlen,
+			   const char *pass,
+			   unsigned passlen)
+{
+    sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
+    int result;
+    sasl_getopt_t *getopt;
+    sasl_server_userdb_checkpass_t *checkpass_cb;
+    void *context;
+    const char *mlist = NULL, *mech = NULL;
+    struct sasl_verify_password_s *v;
+    const char *service = conn->service;
+
+    if (!userlen) userlen = (unsigned) strlen(user);
+    if (!passlen) passlen = (unsigned) strlen(pass);
+
+    /* call userdb callback function, if available */
+    result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_CHECKPASS,
+			       (sasl_callback_ft *)&checkpass_cb, &context);
+    if(result == SASL_OK && checkpass_cb) {
+	result = checkpass_cb(conn, context, user, pass, passlen,
+			      s_conn->sparams->propctx);
+	if(result == SASL_OK)
+	    return SASL_OK;
+    }
+
+    /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
+    if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
+            == SASL_OK) {
+        getopt(context, NULL, "pwcheck_method", &mlist, NULL);
+    }
+
+    if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
+
+    result = SASL_NOMECH;
+
+    mech = mlist;
+    while (*mech && result != SASL_OK) {
+	for (v = _sasl_verify_password; v->name; v++) {
+	    if(is_mech(mech, v->name)) {
+		result = v->verify(conn, user, pass, service,
+				   s_conn->user_realm);
+		break;
+	    }
+	}
+	if (result != SASL_OK) {
+	    /* skip to next mech in list */
+	    while (*mech && !isspace((int) *mech)) mech++;
+	    while (*mech && isspace((int) *mech)) mech++;
+	}
+	else if (!is_mech(mech, "auxprop") && s_conn->sparams->transition) {
+	    s_conn->sparams->transition(conn, pass, passlen);
+	}
+    }
+
+    if (result == SASL_NOMECH) {
+	/* no mechanism available ?!? */
+	_sasl_log(conn, SASL_LOG_ERR, "unknown password verifier(s) %s", mlist);
+    }
+
+    if (result != SASL_OK)
+	sasl_seterror(conn, SASL_NOLOG, "checkpass failed");
+
+    RETURN(conn, result);
+}
+
+/* check if a plaintext password is valid
+ *   if user is NULL, check if plaintext passwords are enabled
+ * inputs:
+ *  user          -- user to query in current user_domain
+ *  userlen       -- length of username, 0 = strlen(user)
+ *  pass          -- plaintext password to check
+ *  passlen       -- length of password, 0 = strlen(pass)
+ * returns 
+ *  SASL_OK       -- success
+ *  SASL_NOMECH   -- mechanism not supported
+ *  SASL_NOVERIFY -- user found, but no verifier
+ *  SASL_NOUSER   -- user not found
+ */
+int sasl_checkpass(sasl_conn_t *conn,
+		   const char *user,
+		   unsigned userlen,
+		   const char *pass,
+		   unsigned passlen)
+{
+    int result;
+    
+    if (_sasl_server_active==0) return SASL_NOTINIT;
+    
+    /* check if it's just a query if we are enabled */
+    if (!user)
+	return SASL_OK;
+
+    if (!conn) return SASL_BADPARAM;
+    
+    /* check params */
+    if (pass == NULL)
+	PARAMERROR(conn);
+
+    /* canonicalize the username */
+    result = _sasl_canon_user(conn, user, userlen,
+			      SASL_CU_AUTHID | SASL_CU_AUTHZID,
+			      &(conn->oparams));
+    if(result != SASL_OK) RETURN(conn, result);
+    user = conn->oparams.user;
+
+    /* Check the password and lookup additional properties */
+    result = _sasl_checkpass(conn, user, userlen, pass, passlen);
+
+    /* Do authorization */
+    if(result == SASL_OK) {
+      result = do_authorization((sasl_server_conn_t *)conn);
+    }
+
+    RETURN(conn,result);
+}
+
+/* check if a user exists on server
+ *  conn          -- connection context (may be NULL, used to hold last error)
+ *  service       -- registered name of the service using SASL (e.g. "imap")
+ *  user_realm    -- permits multiple user realms on server, NULL = default
+ *  user          -- NUL terminated user name
+ *
+ * returns:
+ *  SASL_OK       -- success
+ *  SASL_DISABLED -- account disabled [FIXME: currently not detected]
+ *  SASL_NOUSER   -- user not found
+ *  SASL_NOVERIFY -- user found, but no usable mechanism [FIXME: not supported]
+ *  SASL_NOMECH   -- no mechanisms enabled
+ *  SASL_UNAVAIL  -- remote authentication server unavailable, try again later
+ */
+int sasl_user_exists(sasl_conn_t *conn,
+		     const char *service,
+		     const char *user_realm,
+		     const char *user) 
+{
+    int result=SASL_NOMECH;
+    const char *mlist = NULL, *mech = NULL;
+    void *context;
+    sasl_getopt_t *getopt;
+    struct sasl_verify_password_s *v;
+    
+    /* check params */
+    if (_sasl_server_active==0) return SASL_NOTINIT;
+    if (!conn) return SASL_BADPARAM;
+    if (!user || conn->type != SASL_CONN_SERVER) 
+	PARAMERROR(conn);
+
+    if(!service) service = conn->service;
+    
+    /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
+    if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
+            == SASL_OK) {
+        getopt(context, NULL, "pwcheck_method", &mlist, NULL);
+    }
+
+    if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
+
+    result = SASL_NOMECH;
+
+    mech = mlist;
+    while (*mech && result != SASL_OK) {
+	for (v = _sasl_verify_password; v->name; v++) {
+	    if(is_mech(mech, v->name)) {
+		result = v->verify(conn, user, NULL, service, user_realm);
+		break;
+	    }
+	}
+	if (result != SASL_OK) {
+	    /* skip to next mech in list */
+	    while (*mech && !isspace((int) *mech)) mech++;
+	    while (*mech && isspace((int) *mech)) mech++;
+	}
+    }
+
+    /* Screen out the SASL_BADPARAM response
+     * we'll get from not giving a password */
+    if (result == SASL_BADPARAM) {
+	result = SASL_OK;
+    }
+
+    if (result == SASL_NOMECH) {
+	/* no mechanism available ?!? */
+	_sasl_log(conn, SASL_LOG_ERR, "no plaintext password verifier?");
+	sasl_seterror(conn, SASL_NOLOG, "no plaintext password verifier?");
+    }
+
+    RETURN(conn, result);
+}
+
+/* check if an apop exchange is valid
+ *  (note this is an optional part of the SASL API)
+ *  if challenge is NULL, just check if APOP is enabled
+ * inputs:
+ *  challenge     -- challenge which was sent to client
+ *  challen       -- length of challenge, 0 = strlen(challenge)
+ *  response      -- client response, "<user> <digest>" (RFC 1939)
+ *  resplen       -- length of response, 0 = strlen(response)
+ * returns 
+ *  SASL_OK       -- success
+ *  SASL_BADAUTH  -- authentication failed
+ *  SASL_BADPARAM -- missing challenge
+ *  SASL_BADPROT  -- protocol error (e.g., response in wrong format)
+ *  SASL_NOVERIFY -- user found, but no verifier
+ *  SASL_NOMECH   -- mechanism not supported
+ *  SASL_NOUSER   -- user not found
+ */
+int sasl_checkapop(sasl_conn_t *conn,
+#ifdef DO_SASL_CHECKAPOP
+ 		   const char *challenge,
+ 		   unsigned challen __attribute__((unused)),
+ 		   const char *response,
+ 		   unsigned resplen __attribute__((unused)))
+#else
+ 		   const char *challenge __attribute__((unused)),
+ 		   unsigned challen __attribute__((unused)),
+ 		   const char *response __attribute__((unused)),
+ 		   unsigned resplen __attribute__((unused)))
+#endif
+{
+#ifdef DO_SASL_CHECKAPOP
+    sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
+    char *user, *user_end;
+    const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
+    size_t user_len;
+    int result;
+
+    if (_sasl_server_active==0)
+	return SASL_NOTINIT;
+
+    /* check if it's just a query if we are enabled */
+    if(!challenge)
+	return SASL_OK;
+
+    /* check params */
+    if (!conn) return SASL_BADPARAM;
+    if (!response)
+	PARAMERROR(conn);
+
+    /* Parse out username and digest.
+     *
+     * Per RFC 1939, response must be "<user> <digest>", where
+     * <digest> is a 16-octet value which is sent in hexadecimal
+     * format, using lower-case ASCII characters.
+     */
+    user_end = strrchr(response, ' ');
+    if (!user_end || strspn(user_end + 1, "0123456789abcdef") != 32) 
+    {
+        sasl_seterror(conn, 0, "Bad Digest");
+        RETURN(conn,SASL_BADPROT);
+    }
+ 
+    user_len = (size_t)(user_end - response);
+    user = sasl_ALLOC(user_len + 1);
+    memcpy(user, response, user_len);
+    user[user_len] = '\0';
+
+    result = prop_request(s_conn->sparams->propctx, password_request);
+    if(result != SASL_OK) 
+    {
+        sasl_FREE(user);
+        RETURN(conn, result);
+    }
+
+    /* erase the plaintext password */
+    s_conn->sparams->utils->prop_erase(s_conn->sparams->propctx,
+				       password_request[0]);
+
+    /* canonicalize the username and lookup any associated properties */
+    result = _sasl_canon_user_lookup (conn,
+				      user,
+				      user_len,
+				      SASL_CU_AUTHID | SASL_CU_AUTHZID,
+				      &(conn->oparams));
+    sasl_FREE(user);
+
+    if(result != SASL_OK) RETURN(conn, result);
+
+    /* Do APOP verification */
+    result = _sasl_auxprop_verify_apop(conn, conn->oparams.authid,
+	challenge, user_end + 1, s_conn->user_realm);
+
+    /* Do authorization */
+    if(result == SASL_OK) {
+      result = do_authorization((sasl_server_conn_t *)conn);
+    } else {
+        /* If verification failed, we don't want to encourage getprop to work */
+	conn->oparams.user = NULL;
+	conn->oparams.authid = NULL;
+    }
+
+    RETURN(conn, result);
+#else /* sasl_checkapop was disabled at compile time */
+    sasl_seterror(conn, SASL_NOLOG,
+	"sasl_checkapop called, but was disabled at compile time");
+    RETURN(conn, SASL_NOMECH);
+#endif /* DO_SASL_CHECKAPOP */
+}
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (
+  server_sasl_mechanism_t *m,
+  sasl_info_callback_stage_t stage,
+  void *rock __attribute__((unused))
+)
+{
+    char delimiter;
+
+    if (stage == SASL_INFO_LIST_START) {
+	printf ("List of server plugins follows\n");
+	return;
+    } else if (stage == SASL_INFO_LIST_END) {
+	return;
+    }
+
+    /* Process the mechanism */
+    printf ("Plugin \"%s\" ", m->plugname);
+
+    switch (m->condition) {
+	case SASL_OK:
+	    printf ("[loaded]");
+	    break;
+
+	case SASL_CONTINUE:
+	    printf ("[delayed]");
+	    break;
+
+	case SASL_NOUSER:
+	    printf ("[no users]");
+	    break;
+
+	default:
+	    printf ("[unknown]");
+	    break;
+    }
+
+    printf (", \tAPI version: %d\n", m->version);
+
+    if (m->plug != NULL) {
+	printf ("\tSASL mechanism: %s, best SSF: %d, supports setpass: %s\n",
+		m->plug->mech_name,
+		m->plug->max_ssf,
+		(m->plug->setpass != NULL) ? "yes" : "no"
+		);
+
+
+	printf ("\tsecurity flags:");
+	
+	delimiter = ' ';
+	if (m->plug->security_flags & SASL_SEC_NOANONYMOUS) {
+	    printf ("%cNO_ANONYMOUS", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_NOPLAINTEXT) {
+	    printf ("%cNO_PLAINTEXT", delimiter);
+	    delimiter = '|';
+	}
+	
+	if (m->plug->security_flags & SASL_SEC_NOACTIVE) {
+	    printf ("%cNO_ACTIVE", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_NODICTIONARY) {
+	    printf ("%cNO_DICTIONARY", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_FORWARD_SECRECY) {
+	    printf ("%cFORWARD_SECRECY", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_PASS_CREDENTIALS) {
+	    printf ("%cPASS_CREDENTIALS", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->security_flags & SASL_SEC_MUTUAL_AUTH) {
+	    printf ("%cMUTUAL_AUTH", delimiter);
+	    delimiter = '|';
+	}
+
+
+
+	printf ("\n\tfeatures:");
+
+	delimiter = ' ';
+	if (m->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
+	    printf ("%cWANT_CLIENT_FIRST", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_SERVER_FIRST) {
+	    printf ("%cSERVER_FIRST", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_ALLOWS_PROXY) {
+	    printf ("%cPROXY_AUTHENTICATION", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_DONTUSE_USERPASSWD) {
+	    printf ("%cDONTUSE_USERPASSWD", delimiter);
+	    delimiter = '|';
+	}
+
+	if (m->plug->features & SASL_FEAT_NEEDSERVERFQDN) {
+	    printf ("%cNEED_SERVER_FQDN", delimiter);
+	    delimiter = '|';
+	}
+
+        /* Is this one used? */
+        if (m->plug->features & SASL_FEAT_SERVICE) {
+	    printf ("%cSERVICE", delimiter);
+	    delimiter = '|';
+	}
+
+        if (m->plug->features & SASL_FEAT_GETSECRET) {
+	    printf ("%cNEED_GETSECRET", delimiter);
+	    delimiter = '|';
+	}
+
+        if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+	    printf ("%cGSS_FRAMING", delimiter);
+	    delimiter = '|';
+	}
+
+        if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+	    printf ("%cCHANNEL_BINDING", delimiter);
+	    delimiter = '|';
+	}
+
+        if (m->plug->features & SASL_FEAT_SUPPORTS_HTTP) {
+	    printf ("%cSUPPORTS_HTTP", delimiter);
+	    delimiter = '|';
+	}
+    }
+
+    if (m->f) {
+	printf ("\n\twill be loaded from \"%s\"", m->f);
+    }
+
+    printf ("\n");
+}
+
+/* Dump information about available server plugins (separate functions should be
+   used for canon and auxprop plugins */
+int sasl_server_plugin_info (
+  const char *c_mech_list,		/* space separated mechanism list or NULL for ALL */
+  sasl_server_info_callback_t *info_cb,
+  void *info_cb_rock
+)
+{
+    mechanism_t *m;
+    server_sasl_mechanism_t plug_data;
+    char * cur_mech;
+    char *mech_list = NULL;
+    char * p;
+
+    if (info_cb == NULL) {
+	info_cb = _sasl_print_mechanism;
+    }
+
+    if (mechlist != NULL) {
+	info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+	if (c_mech_list == NULL) {
+	    m = mechlist->mech_list; /* m point to beginning of the list */
+
+	    while (m != NULL) {
+		memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+		info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+	    
+		m = m->next;
+	    }
+	} else {
+            mech_list = strdup(c_mech_list);
+
+	    cur_mech = mech_list;
+
+	    while (cur_mech != NULL) {
+		p = strchr (cur_mech, ' ');
+		if (p != NULL) {
+		    *p = '\0';
+		    p++;
+		}
+
+		m = mechlist->mech_list; /* m point to beginning of the list */
+
+		while (m != NULL) {
+		    if (strcasecmp (cur_mech, m->m.plug->mech_name) == 0) {
+			memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+			info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+		    }
+	    
+		    m = m->next;
+		}
+
+		cur_mech = p;
+	    }
+
+            free (mech_list);
+	}
+
+	info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
+
+	return (SASL_OK);
+    }
+
+    return (SASL_NOTINIT);
+}

+ 263 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/seterror.c

@@ -0,0 +1,263 @@
+/* seterror.c - sasl_seterror split out because glue libraries
+ *              can't pass varargs lists
+ * Rob Siemborski
+ * Tim Martin
+ * split from common.c by Rolf Braun
+ * $Id: seterror.c,v 1.10 2011/09/01 14:12:53 mel Exp $
+ */
+
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef HAVE_SYSLOG
+#include <syslog.h>
+#endif
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#ifdef WIN32
+/* need to handle the fact that errno has been defined as a function
+   in a dll, not an extern int */
+# ifdef errno
+#  undef errno
+# endif /* errno */
+#endif /* WIN32 */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* this is apparently no longer a user function */
+static int _sasl_seterror_usererr(int saslerr)
+{
+    /* Hide the difference in a username failure and a password failure */
+    if (saslerr == SASL_NOUSER)
+	return SASL_BADAUTH;
+
+    /* otherwise return the error given; no transform necessary */
+    return saslerr;
+}
+
+/* set the error string which will be returned by sasl_errdetail() using  
+ *  syslog()-style formatting (e.g. printf-style with %m as the string form
+ *  of an errno error)
+ * 
+ *  primarily for use by server callbacks such as the sasl_authorize_t
+ *  callback and internally to plug-ins
+ *
+ * This will also trigger a call to the SASL logging callback (if any)
+ * with a level of SASL_LOG_FAIL unless the SASL_NOLOG flag is set.
+ *
+ * Messages should be sensitive to the current language setting.  If there
+ * is no SASL_CB_LANGUAGE callback messages MUST be US-ASCII otherwise UTF-8
+ * is used and use of RFC 2482 for mixed-language text is encouraged.
+ * 
+ * if conn is NULL, function does nothing
+ */
+void sasl_seterror(sasl_conn_t *conn,
+		   unsigned flags,
+		   const char *fmt, ...) 
+{
+  size_t outlen=0; /* current length of output buffer */
+  size_t pos = 0; /* current position in format string */
+  size_t formatlen;
+  int result;
+  sasl_log_t *log_cb = NULL;
+  void *log_ctx;
+  int ival;
+  char *cval;
+  va_list ap; /* varargs thing */
+  char **error_buf;
+  size_t *error_buf_len;
+
+  if(!conn) {
+#ifndef SASL_OSX_CFMGLUE
+      if(!(flags & SASL_NOLOG)) {
+	  /* See if we have a logging callback... */
+	  result = _sasl_getcallback(NULL, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+	  if (result == SASL_OK && ! log_cb)
+	      result = SASL_FAIL;
+	  if (result != SASL_OK)
+	      return;
+	  
+	  log_cb(log_ctx, SASL_LOG_FAIL,
+		 "No sasl_conn_t passed to sasl_seterror");
+      }  
+#endif /* SASL_OSX_CFMGLUE */
+      return;
+  } else if(!fmt) return;    
+
+/* we need to use a back end function to get the buffer because the
+   cfm glue can't be rooting around in the internal structs */
+  _sasl_get_errorbuf(conn, &error_buf, &error_buf_len);
+
+  formatlen = strlen(fmt);
+
+  va_start(ap, fmt); /* start varargs */
+
+  while(pos<formatlen)
+  {
+    if (fmt[pos]!='%') /* regular character */
+    {
+      result = _buf_alloc(error_buf, error_buf_len, outlen+1);
+      if (result != SASL_OK)
+	return;
+      (*error_buf)[outlen]=fmt[pos];
+      outlen++;
+      pos++;
+    } else { /* formating thing */
+      int done=0;
+      char frmt[10];
+      int frmtpos=1;
+      char tempbuf[21];
+      frmt[0]='%';
+      pos++;
+
+      while (done==0)
+      {
+	switch(fmt[pos])
+	  {
+	  case 's': /* need to handle this */
+	    cval = va_arg(ap, char *); /* get the next arg */
+	    result = _sasl_add_string(error_buf, error_buf_len,
+				      &outlen, cval);
+	      
+	    if (result != SASL_OK) /* add the string */
+	      return;
+
+	    done=1;
+	    break;
+
+	  case '%': /* double % output the '%' character */
+	    result = _buf_alloc(error_buf, error_buf_len, outlen+1);
+	    if (result != SASL_OK)
+	      return;
+	    (*error_buf)[outlen]='%';
+	    outlen++;
+	    done=1;
+	    break;
+
+	  case 'm': /* insert the errno string */
+	    result = _sasl_add_string(error_buf, error_buf_len,
+				      &outlen,
+				      strerror(va_arg(ap, int)));
+	    if (result != SASL_OK)
+	      return;
+	    done=1;
+	    break;
+
+	  case 'z': /* insert the sasl error string */
+	    result = _sasl_add_string(error_buf, error_buf_len,	&outlen,
+			 (char *)sasl_errstring(_sasl_seterror_usererr(
+					        va_arg(ap, int)),NULL,NULL));
+	    if (result != SASL_OK)
+	      return;
+	    done=1;
+	    break;
+
+	  case 'c':
+	    frmt[frmtpos++]=fmt[pos];
+	    frmt[frmtpos]=0;
+	    tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
+	    tempbuf[1]='\0';
+	    
+	    /* now add the character */
+	    result = _sasl_add_string(error_buf, error_buf_len,
+				      &outlen, tempbuf);
+	    if (result != SASL_OK)
+	      return;
+	    done=1;
+	    break;
+
+	  case 'd':
+	  case 'i':
+	    frmt[frmtpos++]=fmt[pos];
+	    frmt[frmtpos]=0;
+	    ival = va_arg(ap, int); /* get the next arg */
+
+	    snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
+	    /* now add the string */
+	    result = _sasl_add_string(error_buf, error_buf_len,
+				      &outlen, tempbuf);
+	    if (result != SASL_OK)
+	      return;
+	    done=1;
+
+	    break;
+	  default: 
+	    frmt[frmtpos++]=fmt[pos]; /* add to the formating */
+	    frmt[frmtpos]=0;	    
+	    if (frmtpos>9) 
+	      done=1;
+	  }
+	pos++;
+	if (pos>formatlen)
+	  done=1;
+      }
+
+    }
+  }
+
+  (*error_buf)[outlen]='\0'; /* put 0 at end */
+
+  va_end(ap);  
+
+#ifndef SASL_OSX_CFMGLUE
+  if(!(flags & SASL_NOLOG)) {
+      /* See if we have a logging callback... */
+      result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+      if (result == SASL_OK && ! log_cb)
+	  result = SASL_FAIL;
+      if (result != SASL_OK)
+	  return;
+      
+      result = log_cb(log_ctx, SASL_LOG_FAIL, conn->error_buf);
+  }
+#endif /* SASL_OSX_CFMGLUE */
+}

+ 784 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/snprintf.c

@@ -0,0 +1,784 @@
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ * 
+ *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats. 
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ **************************************************************/
+
+#include <config.h>
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+#include <string.h>
+# include <ctype.h>
+#include <sys/types.h>
+
+/* varargs declarations: */
+
+#if defined(HAVE_STDARG_H)
+# include <stdarg.h>
+# define HAVE_STDARGS    /* let's hope that works everywhere (mj) */
+# define VA_LOCAL_DECL   va_list ap
+# define VA_START(f)     va_start(ap, f)
+# define VA_SHIFT(v,t)  ;   /* no-op for ANSI */
+# define VA_END          va_end(ap)
+#else
+# if defined(HAVE_VARARGS_H)
+#  include <varargs.h>
+#  undef HAVE_STDARGS
+#  define VA_LOCAL_DECL   va_list ap
+#  define VA_START(f)     va_start(ap)      /* f is ignored! */
+#  define VA_SHIFT(v,t) v = va_arg(ap,t)
+#  define VA_END        va_end(ap)
+# else
+/*XX ** NO VARARGS ** XX*/
+# endif
+#endif
+
+/*int snprintf (char *str, size_t count, const char *fmt, ...);*/
+/*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
+
+static void dopr (char *buffer, size_t maxlen, const char *format, 
+                  va_list args);
+static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max);
+static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
+		    long value, int base, int min, int max, int flags);
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+		   long double fvalue, int min, int max, int flags);
+static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS 	(1 << 0)
+#define DP_F_PLUS  	(1 << 1)
+#define DP_F_SPACE 	(1 << 2)
+#define DP_F_NUM   	(1 << 3)
+#define DP_F_ZERO  	(1 << 4)
+#define DP_F_UP    	(1 << 5)
+#define DP_F_UNSIGNED 	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT   1
+#define DP_C_LONG    2
+#define DP_C_LDOUBLE 3
+
+#define char_to_int(p) (p - '0')
+#define MAX(p,q) ((p >= q) ? p : q)
+
+static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
+{
+  char ch;
+  long value;
+  long double fvalue;
+  char *strvalue;
+  int min;
+  int max;
+  int state;
+  int flags;
+  int cflags;
+  size_t currlen;
+  
+  state = DP_S_DEFAULT;
+  currlen = flags = cflags = min = 0;
+  max = -1;
+  ch = *format++;
+
+  while (state != DP_S_DONE)
+  {
+    if ((ch == '\0') || (currlen >= maxlen)) 
+      state = DP_S_DONE;
+
+    switch(state) 
+    {
+    case DP_S_DEFAULT:
+      if (ch == '%') 
+	state = DP_S_FLAGS;
+      else 
+	dopr_outch (buffer, &currlen, maxlen, ch);
+      ch = *format++;
+      break;
+    case DP_S_FLAGS:
+      switch (ch) 
+      {
+      case '-':
+	flags |= DP_F_MINUS;
+        ch = *format++;
+	break;
+      case '+':
+	flags |= DP_F_PLUS;
+        ch = *format++;
+	break;
+      case ' ':
+	flags |= DP_F_SPACE;
+        ch = *format++;
+	break;
+      case '#':
+	flags |= DP_F_NUM;
+        ch = *format++;
+	break;
+      case '0':
+	flags |= DP_F_ZERO;
+        ch = *format++;
+	break;
+      default:
+	state = DP_S_MIN;
+	break;
+      }
+      break;
+    case DP_S_MIN:
+      if (isdigit((unsigned char)ch)) 
+      {
+	min = 10*min + char_to_int (ch);
+	ch = *format++;
+      } 
+      else if (ch == '*') 
+      {
+	min = va_arg (args, int);
+	ch = *format++;
+	state = DP_S_DOT;
+      } 
+      else 
+	state = DP_S_DOT;
+      break;
+    case DP_S_DOT:
+      if (ch == '.') 
+      {
+	state = DP_S_MAX;
+	ch = *format++;
+      } 
+      else 
+	state = DP_S_MOD;
+      break;
+    case DP_S_MAX:
+      if (isdigit((unsigned char)ch)) 
+      {
+	if (max < 0)
+	  max = 0;
+	max = 10*max + char_to_int (ch);
+	ch = *format++;
+      } 
+      else if (ch == '*') 
+      {
+	max = va_arg (args, int);
+	ch = *format++;
+	state = DP_S_MOD;
+      } 
+      else 
+	state = DP_S_MOD;
+      break;
+    case DP_S_MOD:
+      /* Currently, we don't support Long Long, bummer */
+      switch (ch) 
+      {
+      case 'h':
+	cflags = DP_C_SHORT;
+	ch = *format++;
+	break;
+      case 'l':
+	cflags = DP_C_LONG;
+	ch = *format++;
+	break;
+      case 'L':
+	cflags = DP_C_LDOUBLE;
+	ch = *format++;
+	break;
+      default:
+	break;
+      }
+      state = DP_S_CONV;
+      break;
+    case DP_S_CONV:
+      switch (ch) 
+      {
+      case 'd':
+      case 'i':
+	if (cflags == DP_C_SHORT) 
+	  value = va_arg (args, short int);
+	else if (cflags == DP_C_LONG)
+	  value = va_arg (args, long int);
+	else
+	  value = va_arg (args, int);
+	fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+	break;
+      case 'o':
+	flags |= DP_F_UNSIGNED;
+	if (cflags == DP_C_SHORT)
+	  value = va_arg (args, unsigned short int);
+	else if (cflags == DP_C_LONG)
+	  value = va_arg (args, unsigned long int);
+	else
+	  value = va_arg (args, unsigned int);
+	fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
+	break;
+      case 'u':
+	flags |= DP_F_UNSIGNED;
+	if (cflags == DP_C_SHORT)
+	  value = va_arg (args, unsigned short int);
+	else if (cflags == DP_C_LONG)
+	  value = va_arg (args, unsigned long int);
+	else
+	  value = va_arg (args, unsigned int);
+	fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+	break;
+      case 'X':
+	flags |= DP_F_UP;
+      case 'x':
+	flags |= DP_F_UNSIGNED;
+	if (cflags == DP_C_SHORT)
+	  value = va_arg (args, unsigned short int);
+	else if (cflags == DP_C_LONG)
+	  value = va_arg (args, unsigned long int);
+	else
+	  value = va_arg (args, unsigned int);
+	fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
+	break;
+      case 'f':
+	if (cflags == DP_C_LDOUBLE)
+	  fvalue = va_arg (args, long double);
+	else
+	  fvalue = va_arg (args, double);
+	/* um, floating point? */
+	fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+	break;
+      case 'E':
+	flags |= DP_F_UP;
+      case 'e':
+	if (cflags == DP_C_LDOUBLE)
+	  fvalue = va_arg (args, long double);
+	else
+	  fvalue = va_arg (args, double);
+	break;
+      case 'G':
+	flags |= DP_F_UP;
+      case 'g':
+	if (cflags == DP_C_LDOUBLE)
+	  fvalue = va_arg (args, long double);
+	else
+	  fvalue = va_arg (args, double);
+	break;
+      case 'c':
+	dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
+	break;
+      case 's':
+	strvalue = va_arg (args, char *);
+	if (max < 0) 
+	  max = maxlen; /* ie, no max */
+	fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
+	break;
+      case 'p':
+	strvalue = va_arg (args, void *);
+	fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+	break;
+      case 'n':
+	if (cflags == DP_C_SHORT) 
+	{
+	  short int *num;
+	  num = va_arg (args, short int *);
+	  *num = currlen;
+        } 
+	else if (cflags == DP_C_LONG) 
+	{
+	  long int *num;
+	  num = va_arg (args, long int *);
+	  *num = currlen;
+        } 
+	else 
+	{
+	  int *num;
+	  num = va_arg (args, int *);
+	  *num = currlen;
+        }
+	break;
+      case '%':
+	dopr_outch (buffer, &currlen, maxlen, ch);
+	break;
+      case 'w':
+	/* not supported yet, treat as next char */
+	ch = *format++;
+	break;
+      default:
+	/* Unknown, skip */
+	break;
+      }
+      ch = *format++;
+      state = DP_S_DEFAULT;
+      flags = cflags = min = 0;
+      max = -1;
+      break;
+    case DP_S_DONE:
+      break;
+    default:
+      /* hmm? */
+      break; /* some picky compilers need this */
+    }
+  }
+  if (currlen < maxlen - 1) 
+    buffer[currlen] = '\0';
+  else 
+    buffer[maxlen - 1] = '\0';
+}
+
+static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max)
+{
+  int padlen, strln;     /* amount to pad */
+  int cnt = 0;
+  
+  if (value == 0)
+  {
+    value = "<NULL>";
+  }
+
+  for (strln = 0; value[strln]; ++strln); /* strlen */
+  padlen = min - strln;
+  if (padlen < 0) 
+    padlen = 0;
+  if (flags & DP_F_MINUS) 
+    padlen = -padlen; /* Left Justify */
+
+  while ((padlen > 0) && (cnt < max)) 
+  {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    --padlen;
+    ++cnt;
+  }
+  while (*value && (cnt < max)) 
+  {
+    dopr_outch (buffer, currlen, maxlen, *value++);
+    ++cnt;
+  }
+  while ((padlen < 0) && (cnt < max)) 
+  {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    ++padlen;
+    ++cnt;
+  }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
+		    long value, int base, int min, int max, int flags)
+{
+  int signvalue = 0;
+  unsigned long uvalue;
+  char convert[20];
+  int place = 0;
+  int spadlen = 0; /* amount to space pad */
+  int zpadlen = 0; /* amount to zero pad */
+  int caps = 0;
+  
+  if (max < 0)
+    max = 0;
+
+  uvalue = value;
+
+  if(!(flags & DP_F_UNSIGNED))
+  {
+    if( value < 0 ) {
+      signvalue = '-';
+      uvalue = -value;
+    }
+    else
+      if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+	signvalue = '+';
+    else
+      if (flags & DP_F_SPACE)
+	signvalue = ' ';
+  }
+  
+  if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+  do {
+    convert[place++] =
+      (caps? "0123456789ABCDEF":"0123456789abcdef")
+      [uvalue % (unsigned)base  ];
+    uvalue = (uvalue / (unsigned)base );
+  } while(uvalue && (place < 20));
+  if (place == 20) place--;
+  convert[place] = 0;
+
+  zpadlen = max - place;
+  spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+  if (zpadlen < 0) zpadlen = 0;
+  if (spadlen < 0) spadlen = 0;
+  if (flags & DP_F_ZERO)
+  {
+    zpadlen = MAX(zpadlen, spadlen);
+    spadlen = 0;
+  }
+  if (flags & DP_F_MINUS) 
+    spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+  dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+      zpadlen, spadlen, min, max, place));
+#endif
+
+  /* Spaces */
+  while (spadlen > 0) 
+  {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    --spadlen;
+  }
+
+  /* Sign */
+  if (signvalue) 
+    dopr_outch (buffer, currlen, maxlen, signvalue);
+
+  /* Zeros */
+  if (zpadlen > 0) 
+  {
+    while (zpadlen > 0)
+    {
+      dopr_outch (buffer, currlen, maxlen, '0');
+      --zpadlen;
+    }
+  }
+
+  /* Digits */
+  while (place > 0) 
+    dopr_outch (buffer, currlen, maxlen, convert[--place]);
+  
+  /* Left Justified spaces */
+  while (spadlen < 0) {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    ++spadlen;
+  }
+}
+
+static long double abs_val (long double value)
+{
+  long double result = value;
+
+  if (value < 0)
+    result = -value;
+
+  return result;
+}
+
+static long double pow10 (int exp)
+{
+  long double result = 1;
+
+  while (exp)
+  {
+    result *= 10;
+    exp--;
+  }
+  
+  return result;
+}
+
+static long round (long double value)
+{
+  long intpart;
+
+  intpart = value;
+  value = value - intpart;
+  if (value >= 0.5)
+    intpart++;
+
+  return intpart;
+}
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+		   long double fvalue, int min, int max, int flags)
+{
+  int signvalue = 0;
+  long double ufvalue;
+  char iconvert[20];
+  char fconvert[20];
+  int iplace = 0;
+  int fplace = 0;
+  int padlen = 0; /* amount to pad */
+  int zpadlen = 0; 
+  int caps = 0;
+  long intpart;
+  long fracpart;
+  
+  /* 
+   * AIX manpage says the default is 0, but Solaris says the default
+   * is 6, and sprintf on AIX defaults to 6
+   */
+  if (max < 0)
+    max = 6;
+
+  ufvalue = abs_val (fvalue);
+
+  if (fvalue < 0)
+    signvalue = '-';
+  else
+    if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+      signvalue = '+';
+    else
+      if (flags & DP_F_SPACE)
+	signvalue = ' ';
+
+#if 0
+  if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+  intpart = ufvalue;
+
+  /* 
+   * Sorry, we only support 9 digits past the decimal because of our 
+   * conversion method
+   */
+  if (max > 9)
+    max = 9;
+
+  /* We "cheat" by converting the fractional part to integer by
+   * multiplying by a factor of 10
+   */
+  fracpart = round ((pow10 (max)) * (ufvalue - intpart));
+
+  if (fracpart >= pow10 (max))
+  {
+    intpart++;
+    fracpart -= pow10 (max);
+  }
+
+#ifdef DEBUG_SNPRINTF
+  dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
+#endif
+
+  /* Convert integer part */
+  do {
+    iconvert[iplace++] =
+      (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
+    intpart = (intpart / 10);
+  } while(intpart && (iplace < 20));
+  if (iplace == 20) iplace--;
+  iconvert[iplace] = 0;
+
+  /* Convert fractional part */
+  do {
+    fconvert[fplace++] =
+      (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
+    fracpart = (fracpart / 10);
+  } while(fracpart && (fplace < 20));
+  if (fplace == 20) fplace--;
+  fconvert[fplace] = 0;
+
+  /* -1 for decimal point, another -1 if we are printing a sign */
+  padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+  zpadlen = max - fplace;
+  if (zpadlen < 0)
+    zpadlen = 0;
+  if (padlen < 0) 
+    padlen = 0;
+  if (flags & DP_F_MINUS) 
+    padlen = -padlen; /* Left Justifty */
+
+  if ((flags & DP_F_ZERO) && (padlen > 0)) 
+  {
+    if (signvalue) 
+    {
+      dopr_outch (buffer, currlen, maxlen, signvalue);
+      --padlen;
+      signvalue = 0;
+    }
+    while (padlen > 0)
+    {
+      dopr_outch (buffer, currlen, maxlen, '0');
+      --padlen;
+    }
+  }
+  while (padlen > 0)
+  {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    --padlen;
+  }
+  if (signvalue) 
+    dopr_outch (buffer, currlen, maxlen, signvalue);
+
+  while (iplace > 0) 
+    dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+  /*
+   * Decimal point.  This should probably use locale to find the correct
+   * char to print out.
+   */
+  dopr_outch (buffer, currlen, maxlen, '.');
+
+  while (fplace > 0) 
+    dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+
+  while (zpadlen > 0)
+  {
+    dopr_outch (buffer, currlen, maxlen, '0');
+    --zpadlen;
+  }
+
+  while (padlen < 0) 
+  {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    ++padlen;
+  }
+}
+
+static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+  if (*currlen < maxlen)
+    buffer[(*currlen)++] = c;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#ifndef HAVE_VSNPRINTF
+int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+  str[0] = 0;
+  dopr(str, count, fmt, args);
+  return(strlen(str));
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+/* VARARGS3 */
+#ifdef HAVE_STDARGS
+int snprintf (char *str,size_t count,const char *fmt,...)
+#else
+int snprintf (va_alist) va_dcl
+#endif
+{
+#ifndef HAVE_STDARGS
+  char *str;
+  size_t count;
+  char *fmt;
+#endif
+  VA_LOCAL_DECL;
+    
+  VA_START (fmt);
+  VA_SHIFT (str, char *);
+  VA_SHIFT (count, size_t );
+  VA_SHIFT (fmt, char *);
+  (void) vsnprintf(str, count, fmt, ap);
+  VA_END;
+  return(strlen(str));
+}
+
+#ifdef TEST_SNPRINTF
+#ifndef LONG_STRING
+#define LONG_STRING 1024
+#endif
+int main (void)
+{
+  char buf1[LONG_STRING];
+  char buf2[LONG_STRING];
+  char *fp_fmt[] = {
+    "%-1.5f",
+    "%1.5f",
+    "%123.9f",
+    "%10.5f",
+    "% 10.5f",
+    "%+22.9f",
+    "%+4.9f",
+    "%01.3f",
+    "%4f",
+    "%3.1f",
+    "%3.2f",
+    NULL
+  };
+  double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, 
+    0.9996, 1.996, 4.136, 0};
+  char *int_fmt[] = {
+    "%-1.5d",
+    "%1.5d",
+    "%123.9d",
+    "%5.5d",
+    "%10.5d",
+    "% 10.5d",
+    "%+22.33d",
+    "%01.3d",
+    "%4d",
+    NULL
+  };
+  long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
+  int x, y;
+  int fail = 0;
+  int num = 0;
+
+  printf ("Testing snprintf format codes against system sprintf...\n");
+
+  for (x = 0; fp_fmt[x] != NULL ; x++)
+    for (y = 0; fp_nums[y] != 0 ; y++)
+    {
+      snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
+      sprintf (buf2, fp_fmt[x], fp_nums[y]);
+      if (strcmp (buf1, buf2))
+      {
+	printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n", 
+	    fp_fmt[x], buf1, buf2);
+	fail++;
+      }
+      num++;
+    }
+
+  for (x = 0; int_fmt[x] != NULL ; x++)
+    for (y = 0; int_nums[y] != 0 ; y++)
+    {
+      snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
+      sprintf (buf2, int_fmt[x], int_nums[y]);
+      if (strcmp (buf1, buf2))
+      {
+	printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n", 
+	    int_fmt[x], buf1, buf2);
+	fail++;
+      }
+      num++;
+    }
+  printf ("%d tests failed out of %d.\n", fail, num);
+}
+#endif /* SNPRINTF_TEST */
+
+#endif /* !HAVE_SNPRINTF */

+ 184 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/staticopen.h

@@ -0,0 +1,184 @@
+/* staticopen.h
+ * Rob Siemborski
+ * Howard Chu
+ * $Id: staticopen.h,v 1.9 2011/04/05 14:50:07 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+typedef enum {
+	UNKNOWN = 0, SERVER = 1, CLIENT = 2, AUXPROP = 3, CANONUSER = 4
+} _sasl_plug_type;
+
+typedef struct {
+	_sasl_plug_type type;
+	char *name;
+	sasl_client_plug_init_t *plug;
+} _sasl_plug_rec;
+
+/* For static linking */
+#define SPECIFIC_CLIENT_PLUG_INIT_PROTO( x ) \
+sasl_client_plug_init_t x##_client_plug_init
+
+#define SPECIFIC_SERVER_PLUG_INIT_PROTO( x ) \
+sasl_server_plug_init_t x##_server_plug_init
+
+#define SPECIFIC_AUXPROP_PLUG_INIT_PROTO( x ) \
+sasl_auxprop_init_t x##_auxprop_plug_init
+
+#define SPECIFIC_CANONUSER_PLUG_INIT_PROTO( x ) \
+sasl_canonuser_init_t x##_canonuser_plug_init
+
+/* Static Compillation Foo */
+#define SPECIFIC_CLIENT_PLUG_INIT( x, n )\
+	{ CLIENT, n, x##_client_plug_init }
+#define SPECIFIC_SERVER_PLUG_INIT( x, n )\
+	{ SERVER, n, (sasl_client_plug_init_t *)x##_server_plug_init }
+#define SPECIFIC_AUXPROP_PLUG_INIT( x, n )\
+	{ AUXPROP, n, (sasl_client_plug_init_t *)x##_auxprop_plug_init }
+#define SPECIFIC_CANONUSER_PLUG_INIT( x, n )\
+	{ CANONUSER, n, (sasl_client_plug_init_t *)x##_canonuser_plug_init }
+
+#ifdef STATIC_ANONYMOUS
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( anonymous );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( anonymous );
+#endif
+#ifdef STATIC_CRAMMD5
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( crammd5 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( crammd5 );
+#endif
+#ifdef STATIC_DIGESTMD5
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( digestmd5 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( digestmd5 );
+#endif
+#ifdef STATIC_SCRAM
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( scram );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( scram );
+#endif
+#ifdef STATIC_GSSAPIV2
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( gssapiv2 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( gssapiv2 );
+#endif
+#ifdef STATIC_KERBEROS4
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( kerberos4 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( kerberos4 );
+#endif
+#ifdef STATIC_LOGIN
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( login );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( login );
+#endif
+#ifdef STATIC_NTLM
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( ntlm );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( ntlm );
+#endif
+#ifdef STATIC_OTP
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( otp );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( otp );
+#endif
+#ifdef STATIC_PLAIN
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( plain );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( plain );
+#endif
+#ifdef STATIC_SRP
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( srp );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( srp );
+#endif
+#ifdef STATIC_SASLDB
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( sasldb );
+#endif
+#ifdef STATIC_SQL
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( sql );
+#endif
+#ifdef STATIC_LDAPDB
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( ldapdb );
+#endif
+
+_sasl_plug_rec _sasl_static_plugins[] = {
+#ifdef STATIC_ANONYMOUS
+	SPECIFIC_SERVER_PLUG_INIT( anonymous, "ANONYMOUS" ),
+	SPECIFIC_CLIENT_PLUG_INIT( anonymous, "ANONYMOUS" ),
+#endif
+#ifdef STATIC_CRAMMD5
+	SPECIFIC_SERVER_PLUG_INIT( crammd5, "CRAM-MD5" ),
+	SPECIFIC_CLIENT_PLUG_INIT( crammd5, "CRAM-MD5" ),
+#endif
+#ifdef STATIC_DIGESTMD5
+	SPECIFIC_SERVER_PLUG_INIT( digestmd5, "DIGEST-MD5" ),
+	SPECIFIC_CLIENT_PLUG_INIT( digestmd5, "DIGEST-MD5" ),
+#endif
+#ifdef STATIC_GSSAPIV2
+	SPECIFIC_SERVER_PLUG_INIT( gssapiv2, "GSSAPI" ),
+	SPECIFIC_CLIENT_PLUG_INIT( gssapiv2, "GSSAPI" ),
+#endif
+#ifdef STATIC_KERBEROS4
+	SPECIFIC_SERVER_PLUG_INIT( kerberos4, "KERBEROS_V4" ),
+	SPECIFIC_CLIENT_PLUG_INIT( kerberos4, "KERBEROS_V4" ),
+#endif
+#ifdef STATIC_LOGIN
+	SPECIFIC_SERVER_PLUG_INIT( login, "LOGIN" ),
+	SPECIFIC_CLIENT_PLUG_INIT( login, "LOGIN" ),
+#endif
+#ifdef STATIC_NTLM
+	SPECIFIC_SERVER_PLUG_INIT( ntlm, "NTLM" ),
+	SPECIFIC_CLIENT_PLUG_INIT( ntlm, "NTLM" ),
+#endif
+#ifdef STATIC_OTP
+	SPECIFIC_SERVER_PLUG_INIT( otp, "OTP" ),
+	SPECIFIC_CLIENT_PLUG_INIT( otp, "OTP" ),
+#endif
+#ifdef STATIC_PLAIN
+	SPECIFIC_SERVER_PLUG_INIT( plain, "PLAIN" ),
+	SPECIFIC_CLIENT_PLUG_INIT( plain, "PLAIN" ),
+#endif
+#ifdef STATIC_SRP
+	SPECIFIC_SERVER_PLUG_INIT( srp, "SRP" ),
+	SPECIFIC_CLIENT_PLUG_INIT( srp, "SRP" ),
+#endif
+#ifdef STATIC_SASLDB
+	SPECIFIC_AUXPROP_PLUG_INIT( sasldb, "SASLDB" ),
+#endif
+#ifdef STATIC_SQL
+	SPECIFIC_AUXPROP_PLUG_INIT( sql, "SQL" ),
+#endif
+#ifdef STATIC_LDAPDB
+    SPECIFIC_AUXPROP_PLUG_INIT( ldapdb, "LDAPDB" ),
+#endif
+	{ UNKNOWN, NULL, NULL }
+};

+ 330 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/lib/windlopen.c

@@ -0,0 +1,330 @@
+/* windlopen.c--Windows dynamic loader interface
+ * Ryan Troll
+ * $Id: windlopen.c,v 1.17 2009/01/25 20:20:57 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <io.h>
+#include <sys/stat.h>
+
+#include <config.h>
+#include <sasl.h>
+#include "saslint.h"
+
+#define DLL_SUFFIX	".dll"
+#define DLL_MASK	"*" DLL_SUFFIX
+#define DLL_MASK_LEN	5
+
+const int _is_sasl_server_static = 0;
+
+/* : inefficient representation, but works */
+typedef struct lib_list 
+{
+    struct lib_list *next;
+    HMODULE library;
+} lib_list_t;
+
+static lib_list_t *lib_list_head = NULL;
+
+int _sasl_locate_entry(void *library,
+		       const char *entryname,
+		       void **entry_point) 
+{
+    if(entryname == NULL) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "no entryname in _sasl_locate_entry");
+	return SASL_BADPARAM;
+    }
+
+    if(library == NULL) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "no library in _sasl_locate_entry");
+	return SASL_BADPARAM;
+    }
+
+    if(entry_point == NULL) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "no entrypoint output pointer in _sasl_locate_entry");
+	return SASL_BADPARAM;
+    }
+
+    *entry_point = GetProcAddress(library, entryname);
+
+    if (*entry_point == NULL) {
+#if 0 /* This message appears to confuse people */
+	_sasl_log(NULL, SASL_LOG_DEBUG,
+		  "unable to get entry point %s: %s", entryname,
+		  GetLastError());
+#endif
+	return SASL_FAIL;
+    }
+
+    return SASL_OK;
+}
+
+static int _sasl_plugin_load(char *plugin, void *library,
+			     const char *entryname,
+			     int (*add_plugin)(const char *, void *)) 
+{
+    void *entry_point;
+    int result;
+    
+    result = _sasl_locate_entry(library, entryname, &entry_point);
+    if(result == SASL_OK) {
+	result = add_plugin(plugin, entry_point);
+	if(result != SASL_OK)
+	    _sasl_log(NULL, SASL_LOG_DEBUG,
+		      "_sasl_plugin_load failed on %s for plugin: %s\n",
+		      entryname, plugin);
+    }
+
+    return result;
+}
+
+/* loads a plugin library */
+int _sasl_get_plugin(const char *file,
+		     const sasl_callback_t *verifyfile_cb,
+		     void **libraryptr)
+{
+    int r = 0;
+    HINSTANCE library;
+    lib_list_t *newhead;
+    
+    r = ((sasl_verifyfile_t *)(verifyfile_cb->proc))
+		    (verifyfile_cb->context, file, SASL_VRFY_PLUGIN);
+    if (r != SASL_OK) return r;
+
+    newhead = sasl_ALLOC(sizeof(lib_list_t));
+    if (!newhead) return SASL_NOMEM;
+
+    if (!(library = LoadLibrary (file))) {
+	_sasl_log(NULL, SASL_LOG_ERR,
+		  "unable to LoadLibrary %s: %s", file, GetLastError());
+	sasl_FREE(newhead);
+	return SASL_FAIL;
+    }
+
+    newhead->library = library;
+    newhead->next = lib_list_head;
+    lib_list_head = newhead;
+
+    *libraryptr = library;
+    return SASL_OK;
+}
+
+/* undoes actions done by _sasl_get_plugin */
+void _sasl_remove_last_plugin()
+{
+    lib_list_t *last_plugin = lib_list_head;
+    lib_list_head = lib_list_head->next;
+    if (last_plugin->library) {
+	FreeLibrary(last_plugin->library);
+    }
+    sasl_FREE(last_plugin);
+}
+
+/* gets the list of mechanisms */
+int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
+		       const sasl_callback_t *getpath_cb,
+		       const sasl_callback_t *verifyfile_cb)
+{
+    int result;
+    char cur_dir[PATH_MAX], full_name[PATH_MAX+2], prefix[PATH_MAX+2];
+				/* 1 for '\\' 1 for trailing '\0' */
+    char * pattern;
+    char c;
+    int pos;
+    const char *path=NULL;
+    int position;
+    const add_plugin_list_t *cur_ep;
+    struct stat statbuf;		/* filesystem entry information */
+    intptr_t fhandle;			/* file handle for _findnext function */
+    struct _finddata_t finddata;	/* data returned by _findnext() */
+    size_t prefix_len;
+
+    if (! entrypoints
+	|| ! getpath_cb
+	|| getpath_cb->id != SASL_CB_GETPATH
+	|| ! getpath_cb->proc
+	|| ! verifyfile_cb
+	|| verifyfile_cb->id != SASL_CB_VERIFYFILE
+	|| ! verifyfile_cb->proc)
+	return SASL_BADPARAM;
+
+    /* get the path to the plugins */
+    result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
+						    &path);
+    if (result != SASL_OK) return result;
+    if (! path) return SASL_FAIL;
+
+    if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
+	return SASL_FAIL;
+    }
+
+    position=0;
+    do {
+	pos=0;
+	do {
+	    c=path[position];
+	    position++;
+	    cur_dir[pos]=c;
+	    pos++;
+	} while ((c!=PATHS_DELIMITER) && (c!=0));
+	cur_dir[pos-1]='\0';
+
+
+/* : check to make sure that a valid directory name was passed in */
+	if (stat (cur_dir, &statbuf) < 0) {
+	    continue;
+	}
+	if ((statbuf.st_mode & S_IFDIR) == 0) {
+	    continue;
+	}
+
+	strcpy (prefix, cur_dir);
+	prefix_len = strlen (prefix);
+
+/* : Don't append trailing \ unless required */
+	if (prefix[prefix_len-1] != '\\') {
+	    strcat (prefix,"\\");
+	    prefix_len++;
+	}
+
+	pattern = prefix;
+
+/* : Check that we have enough space for "*.dll" */
+	if ((prefix_len + DLL_MASK_LEN) > (sizeof(prefix) - 1)) {
+	    _sasl_log(NULL, SASL_LOG_WARN, "plugin search mask is too big");
+            continue;
+	}
+
+	strcat (prefix + prefix_len, "*" DLL_SUFFIX);
+
+        fhandle = _findfirst (pattern, &finddata);
+        if (fhandle == -1) {	/* no matching files */
+            continue;
+        }
+
+/* : Truncate "*.dll" */
+	prefix[prefix_len] = '\0';
+
+	do {
+	    size_t length;
+	    void *library;
+	    char *c;
+	    char plugname[PATH_MAX];
+	    int entries;
+
+	    length = strlen(finddata.name);
+	    if (length < 5) { /* At least <Ch>.dll */
+		continue; /* can not possibly be what we're looking for */
+	    }
+
+/* : Check for overflow */
+	    if (length + prefix_len >= PATH_MAX) continue; /* too big */
+
+	    if (stricmp(finddata.name + (length - strlen(DLL_SUFFIX)), DLL_SUFFIX) != 0) {
+		continue;
+	    }
+
+/* : Check that it is not a directory */
+	    if ((finddata.attrib & _A_SUBDIR) == _A_SUBDIR) {
+		continue;
+	    }
+
+/* : Construct full name from prefix and name */
+
+	    strcpy (full_name, prefix);
+	    strcat (full_name, finddata.name);
+		
+/* cut off .dll suffix -- this only need be approximate */
+	    strcpy (plugname, finddata.name);
+	    c = strrchr(plugname, '.');
+	    if (c != NULL) *c = '\0';
+
+	    result = _sasl_get_plugin (full_name, verifyfile_cb, &library);
+
+	    if (result != SASL_OK) {
+		continue;
+	    }
+
+	    entries = 0;
+	    for (cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
+		result = _sasl_plugin_load(plugname,
+					   library,
+					   cur_ep->entryname,
+					   cur_ep->add_plugin);
+		if (result == SASL_OK) {
+		    ++entries;
+		}
+		/* If this fails, it's not the end of the world */
+	    }
+	    if (entries == 0) {
+		_sasl_remove_last_plugin();
+	    }
+
+	} while (_findnext (fhandle, &finddata) == 0);
+	
+	_findclose (fhandle);
+
+    } while ((c!='=') && (c!=0));
+
+    return SASL_OK;
+}
+
+int
+_sasl_done_with_plugins(void)
+{
+    lib_list_t *libptr, *libptr_next;
+    
+    for(libptr = lib_list_head; libptr; libptr = libptr_next) {
+	libptr_next = libptr->next;
+	if (libptr->library != NULL) {
+	    FreeLibrary(libptr->library);
+	}
+	sasl_FREE(libptr);
+    }
+
+    lib_list_head = NULL;
+
+    return SASL_OK;
+}

+ 93 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/meson.build

@@ -0,0 +1,93 @@
+project('cyrussasl', 'c',
+        version: '2.1.25',
+        license: 'CMU libsasl')
+
+openssl = dependency('openssl', fallback: ['openssl', 'dep'])
+
+src = [
+  'lib/auxprop.c',
+  'lib/canonusr.c',
+  'lib/checkpw.c',
+  'lib/client.c',
+  'lib/common.c',
+  'lib/config.c',
+  'lib/dlopen.c',
+  'lib/external.c',
+  'lib/getsubopt.c',
+  'lib/md5.c',
+  'lib/saslutil.c',
+  'lib/server.c',
+  'lib/seterror.c',
+  'lib/snprintf.c',
+  'plugins/anonymous.c',
+  'plugins/anonymous_init.c',
+  'plugins/cram.c',
+  'plugins/crammd5_init.c',
+  'plugins/digestmd5.c',
+  'plugins/digestmd5_init.c',
+  'plugins/login.c',
+  'plugins/login_init.c',
+  'plugins/ntlm.c',
+  'plugins/ntlm_init.c',
+  'plugins/otp.c',
+  'plugins/otp_init.c',
+  'plugins/passdss.c',
+  'plugins/passdss_init.c',
+  'plugins/plain.c',
+  'plugins/plain_init.c',
+  'plugins/plugin_common.c',
+  'plugins/scram.c',
+  'plugins/scram_init.c',
+  'plugins/srp.c',
+  'plugins/srp_init.c',
+]
+inc = include_directories(
+  'include',
+  'include/sasl',
+  'plugins',
+)
+
+# Silence warnings, we don't own this subproject
+cc = meson.get_compiler('c')
+ccargs = cc.get_supported_arguments(
+  [
+    '-Wno-discarded-qualifiers',
+    '-Wno-format',
+    '-Wno-incompatible-pointer-types',
+    '-Wno-nonnull-compare',
+    '-Wno-parentheses-equality',
+    '-Wno-pointer-sign',
+    '-Wno-sometimes-uninitialized',
+    '-Wno-tautological-compare',
+    '-Wno-unused-but-set-variable',
+    '-Wno-unused-const-variable',
+    '-Wno-unused-const-variable',
+    '-Wno-unused-function',
+    '-Wno-unused-variable',
+  ]
+)
+
+if get_option('static-pic-lib')
+  lib = static_library(
+    'sasl2', src,
+    c_args: ccargs,
+    pic: true,
+    include_directories: inc,
+    dependencies: [openssl],
+  )
+else
+  if get_option('default_library') != 'static'
+    error('Only --default-library=static is supported for now')
+  endif
+  lib = library(
+    'sasl2', src,
+    c_args: ccargs,
+    include_directories: inc,
+    dependencies: [openssl],
+  )
+endif
+
+dep = declare_dependency(
+  include_directories: include_directories('include'),
+  link_with: lib,
+)

+ 6 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/meson_options.txt

@@ -0,0 +1,6 @@
+option(
+  'static-pic-lib',
+  type: 'boolean',
+  value: false,
+  description: 'Build a static library with PIC support',
+)

+ 158 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/Makefile.am

@@ -0,0 +1,158 @@
+# Makefile.am for the SASL plugins
+# Rob Siemborski
+# Rob Earhart
+# $Id: Makefile.am,v 1.86 2011/09/05 14:18:10 murch Exp $
+#
+################################################################
+# Copyright (c) 2000 Carnegie Mellon University.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer. 
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# 3. The name "Carnegie Mellon University" must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission. For permission or any other legal
+#    details, please contact  
+#      Office of Technology Transfer
+#      Carnegie Mellon University
+#      5000 Forbes Avenue
+#      Pittsburgh, PA  15213-3890
+#      (412) 268-4387, fax: (412) 268-7395
+#      tech-transfer@andrew.cmu.edu
+#
+# 4. Redistributions of any form whatsoever must retain the following
+#    acknowledgment:
+#    "This product includes software developed by Computing Services
+#     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+#
+# CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+################################################################
+
+# Library version info - here at the top, for sanity
+# See <http://www.gnu.org/software/libtool/manual/libtool.html#Versioning>
+# CURRENT:REVISION:AGE
+plugin_version = 3:0:0
+
+INCLUDES=-I$(top_srcdir)/include -I$(top_srcdir)/lib -I$(top_srcdir)/sasldb -I$(top_builddir)/include
+AM_LDFLAGS = -module -export-dynamic -rpath $(plugindir) -version-info $(plugin_version)
+
+COMPAT_OBJS = @LTGETADDRINFOOBJS@ @LTGETNAMEINFOOBJS@ @LTSNPRINTFOBJS@
+
+EXTRA_DIST = makeinit.sh NTMakefile
+noinst_SCRIPTS = makeinit.sh
+
+LIB_MYSQL = @LIB_MYSQL@
+
+plugindir = @plugindir@
+
+common_sources = plugin_common.c plugin_common.h
+
+sasldir = $(prefix)/lib/sasl2
+sasl_LTLIBRARIES = @SASL_MECHS@
+EXTRA_LTLIBRARIES = libplain.la libanonymous.la libkerberos4.la libcrammd5.la \
+	libgs2.la libgssapiv2.la libdigestmd5.la liblogin.la libsrp.la libotp.la \
+	libscram.la libntlm.la libpassdss.la libsasldb.la libsql.la libldapdb.la
+
+libplain_la_SOURCES = plain.c plain_init.c $(common_sources)
+libplain_la_DEPENDENCIES = $(COMPAT_OBJS)
+libplain_la_LIBADD = $(PLAIN_LIBS) $(COMPAT_OBJS)
+
+libanonymous_la_SOURCES = anonymous.c anonymous_init.c $(common_sources)
+libanonymous_la_DEPENDENCIES = $(COMPAT_OBJS)
+libanonymous_la_LIBADD = $(COMPAT_OBJS)
+
+libkerberos4_la_SOURCES = kerberos4.c kerberos4_init.c $(common_sources)
+libkerberos4_la_DEPENDENCIES = $(COMPAT_OBJS)
+libkerberos4_la_LIBADD = $(SASL_KRB_LIB) $(LIB_SOCKET) $(COMPAT_OBJS)
+
+libgs2_la_SOURCES = gs2.c gs2_init.c gs2_token.c gs2_token.h $(common_sources)
+libgs2_la_DEPENDENCIES = $(COMPAT_OBJS)
+libgs2_la_LIBADD = $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET) $(COMPAT_OBJS)
+
+libgssapiv2_la_SOURCES = gssapi.c gssapiv2_init.c $(common_sources)
+libgssapiv2_la_DEPENDENCIES = $(COMPAT_OBJS)
+libgssapiv2_la_LIBADD = $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET) $(COMPAT_OBJS)
+
+libcrammd5_la_SOURCES = cram.c crammd5_init.c $(common_sources)
+libcrammd5_la_DEPENDENCIES = $(COMPAT_OBJS)
+libcrammd5_la_LIBADD = $(COMPAT_OBJS)
+
+libdigestmd5_la_SOURCES = digestmd5.c digestmd5_init.c $(common_sources)
+libdigestmd5_la_DEPENDENCIES = $(COMPAT_OBJS)
+libdigestmd5_la_LIBADD = $(LIB_DES) $(LIB_SOCKET) $(COMPAT_OBJS)
+
+libscram_la_SOURCES = scram.c scram_init.c $(common_sources)
+libscram_la_DEPENDENCIES = $(COMPAT_OBJS)
+libscram_la_LIBADD = $(SCRAM_LIBS) $(COMPAT_OBJS)
+
+liblogin_la_SOURCES = login.c login_init.c $(common_sources)
+liblogin_la_DEPENDENCIES = $(COMPAT_OBJS)
+liblogin_la_LIBADD = $(PLAIN_LIBS) $(COMPAT_OBJS)
+
+libsrp_la_SOURCES = srp.c srp_init.c $(common_sources)
+libsrp_la_DEPENDENCIES = $(COMPAT_OBJS)
+libsrp_la_LIBADD = $(SRP_LIBS) $(COMPAT_OBJS)
+
+libotp_la_SOURCES = otp.c otp_init.c otp.h $(common_sources)
+libotp_la_DEPENDENCIES = $(COMPAT_OBJS)
+libotp_la_LIBADD = $(OTP_LIBS) $(COMPAT_OBJS)
+
+libntlm_la_SOURCES = ntlm.c ntlm_init.c $(common_sources)
+libntlm_la_DEPENDENCIES = $(COMPAT_OBJS)
+libntlm_la_LIBADD = $(NTLM_LIBS) $(COMPAT_OBJS)
+
+libpassdss_la_SOURCES = passdss.c passdss_init.c $(common_sources)
+libpassdss_la_DEPENDENCIES = $(COMPAT_OBJS)
+libpassdss_la_LIBADD = $(PASSDSS_LIBS) $(COMPAT_OBJS)
+
+# Auxprop Plugins
+libsasldb_la_SOURCES = sasldb.c sasldb_init.c $(common_sources)
+libsasldb_la_DEPENDENCIES = $(COMPAT_OBJS)
+libsasldb_la_LIBADD = ../sasldb/libsasldb.la $(SASL_DB_LIB) $(COMPAT_OBJS)
+
+libldapdb_la_SOURCES = ldapdb.c ldapdb_init.c $(common_sources)
+libldapdb_la_DEPENDENCIES = $(COMPAT_OBJS)
+libldapdb_la_LIBADD = $(LIB_LDAP) $(COMPAT_OBJS)
+
+libsql_la_SOURCES = sql.c sql_init.c $(common_sources)
+libsql_la_LDFLAGS = $(LIB_MYSQL) $(LIB_PGSQL) $(LIB_SQLITE) $(LIB_SQLITE3) \
+	$(AM_LDFLAGS)
+libsql_la_DEPENDENCIES = $(COMPAT_OBJS)
+libsql_la_LIBADD = $(COMPAT_OBJS)
+
+
+# Instructions for making the _init files
+
+init_src=anonymous_init.c crammd5_init.c digestmd5_init.c scram_init.c gs2_init.c gssapiv2_init.c \
+kerberos4_init.c login_init.c plain_init.c srp_init.c otp_init.c ntlm_init.c \
+passdss_init.c sasldb_init.c sql_init.c ldapdb_init.c
+
+
+CLEANFILES=$(init_src)
+
+${init_src}: $(srcdir)/makeinit.sh
+	$(SHELL) $(srcdir)/makeinit.sh
+
+# Compatibility function build rules (they build in lib/)
+$(COMPAT_OBJS):
+	rm -f $(COMPAT_OBJS)
+	cd ../lib; $(MAKE) $(COMPAT_OBJS)
+	for file in $(COMPAT_OBJS); do ln -s ../lib/$$file .; done
+
+

+ 325 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/NTMakefile

@@ -0,0 +1,325 @@
+!INCLUDE ..\win32\common.mak
+
+SCRAM=1
+
+!IF "$(NTLM)" == "1"
+PLUGINS_EXT=saslNTLM.dll
+!ELSE 
+PLUGINS_EXT=
+!ENDIF 
+
+!IF "$(GSSAPI)" == "CyberSafe"
+PLUGINS_EXT=$(PLUGINS_EXT) saslGSSAPI.dll
+!ENDIF 
+
+!IF "$(SRP)" == "1"
+PLUGINS_EXT=$(PLUGINS_EXT) saslSRP.dll
+!IF "$(DO_SRP_SETPASS)" == "1"
+SRP_FLAGS=/DDO_SRP_SETPASS=1
+!ENDIF 
+!ENDIF 
+
+!IF "$(OTP)" == "1"
+PLUGINS_EXT=$(PLUGINS_EXT) saslOTP.dll
+!ENDIF
+
+!IF "$(LDAP)" == "1"
+PLUGINS_EXT=$(PLUGINS_EXT) saslLDAPDB.dll
+
+# NB: linking to libsasl itself!!!
+LDAP_FLAGS = /I $(LDAP_INCLUDE)
+LDAP_LIBS = $(LDAP_LIB_BASE)\olber32.lib $(LDAP_LIB_BASE)\oldap32.lib ..\lib\libsasl.lib
+!ENDIF 
+
+!IF "$(SQL)" == "SQLITE"
+PLUGINS_EXT=$(PLUGINS_EXT) saslSQLITE.dll
+SQL_FLAGS= $(SQLITE_INCLUDES) /DHAVE_SQLITE=1
+SQLITE_LIBS = /libpath:$(SQLITE_LIBPATH) libsqlite.lib
+!ENDIF
+!IF "$(SQL)" == "SQLITE3"
+PLUGINS_EXT=$(PLUGINS_EXT) saslSQLITE.dll
+SQL_FLAGS= $(SQLITE_INCLUDES3) /DHAVE_SQLITE3=1
+SQLITE_LIBS = /libpath:$(SQLITE_LIBPATH3) libsqlite3.lib
+!ENDIF
+
+PLUGINS=saslANONYMOUS.dll \
+	saslPLAIN.dll \
+	saslCRAMMD5.dll \
+	saslDIGESTMD5.dll \
+	saslLOGIN.dll \
+	saslSCRAM.dll \
+	$(PLUGINS_EXT) \
+	saslSASLDB.dll
+
+generated_rc=saslANONYMOUS.rc saslPLAIN.rc saslCRAMMD5.rc saslDIGESTMD5.rc saslLOGIN.rc saslNTLM.rc saslSCRAM.rc saslGSSAPI.rc saslSRP.rc saslOTP.rc saslSASLDB.rc saslSQLITE.rc saslLDAPDB.rc
+
+# WS2tcpip.h included in Visual Studio 7 provides getaddrinfo, ...
+# emulation on Windows, so there is no need to build getaddrinfo.c
+
+!IF "$(VCVER)" == "6"
+compat_sources = getaddrinfo.c getnameinfo.c
+compat_objs = getaddrinfo.obj getnameinfo.obj
+!ENDIF
+
+common_sources = plugin_common.c plugin_common.h
+common_objs = plugin_common.obj $(compat_objs)
+
+saslANONYMOUS_sources = anonymous.c anonymous_init.c $(common_sources)
+saslANONYMOUS_objs = anonymous.obj anonymous_init.obj $(common_objs)
+saslANONYMOUS_out = saslANONYMOUS.dll saslANONYMOUS.exp saslANONYMOUS.lib
+
+saslPLAIN_sources = plain.c plain_init.c $(common_sources)
+saslPLAIN_objs = plain.obj plain_init.obj $(common_objs)
+saslPLAIN_out = saslPLAIN.dll saslPLAIN.exp saslPLAIN.lib
+
+saslCRAMMD5_sources = cram.c crammd5_init.c $(common_sources)
+saslCRAMMD5_objs = cram.obj crammd5_init.obj $(common_objs)
+saslCRAMMD5_out = saslCRAMMD5.dll saslCRAMMD5.exp saslCRAMMD5.lib
+
+saslDIGESTMD5_sources = digestmd5.c digestmd5_init.c $(common_sources)
+saslDIGESTMD5_objs = digestmd5.obj digestmd5_init.obj $(common_objs)
+saslDIGESTMD5_out = saslDIGESTMD5.dll saslDIGESTMD5.exp saslDIGESTMD5.lib
+
+saslLOGIN_sources = login.c login_init.c $(common_sources)
+saslLOGIN_objs = login.obj login_init.obj $(common_objs)
+saslLOGIN_out = saslLOGIN.dll saslLOGIN.exp saslLOGIN.lib
+
+saslSCRAM_sources = scram.c scram_init.c $(common_sources)
+saslSCRAM_objs = scram.obj scram_init.obj $(common_objs)
+saslSCRAM_out = saslSCRAM.dll saslSCRAM.exp saslSCRAM.lib
+
+saslNTLM_sources = ntlm.c ntlm_init.c $(common_sources)
+saslNTLM_objs = ntlm.obj ntlm_init.obj $(common_objs)
+saslNTLM_out = saslNTLM.dll saslNTLM.exp saslNTLM.lib
+
+saslGSSAPI_sources = gssapi.c gssapiv2_init.c $(common_sources)
+saslGSSAPI_objs = gssapi.obj gssapiv2_init.obj $(common_objs)
+saslGSSAPI_out = saslGSSAPI.dll saslGSSAPI.exp saslGSSAPI.lib
+
+saslSRP_sources = srp.c srp_init.c $(common_sources)
+saslSRP_objs = srp.obj srp_init.obj $(common_objs)
+saslSRP_out = saslSRP.dll saslSRP.exp saslSRP.lib
+
+saslOTP_sources = otp.c otp_init.c $(common_sources)
+saslOTP_objs = otp.obj otp_init.obj $(common_objs)
+saslOTP_out = saslOTP.dll saslOTP.exp saslOTP.lib
+
+saslSQL_sources = sql.c sql_init.c $(common_sources)
+saslSQL_objs = sql.obj sql_init.obj $(common_objs)
+# saslSQL_out is an agregation of all generated files for all SQL plugins
+saslSQL_out = saslSQLITE.dll saslSQLITE.exp saslSQLITE.lib
+
+saslLDAPDB_sources = ldapdb.c $(common_sources)
+saslLDAPDB_objs = ldapdb.obj $(common_objs)
+saslLDAPDB_out = saslLDAPDB.dll saslLDAPDB.exp saslLDAPDB.lib
+
+!IF "$(NTLM)" == "1" || "$(SRP)" == "1" || "$(OTP)" == "1" || "$(SCRAM)" == "1"
+OPENSSL_FLAGS= /I $(OPENSSL_INCLUDE)
+!ELSE 
+OPENSSL_FLAGS=
+!ENDIF 
+
+!IF "$(GSSAPI)" == "CyberSafe"
+GSS_FLAGS= /I $(GSSAPI_INCLUDE) /D "HAVE_GSS_C_NT_HOSTBASED_SERVICE" /D "HAVE_GSS_C_NT_USER_NAME"
+GSS_LIBS=/libpath:$(GSSAPI_LIBPATH) gssapi32.lib
+!ELSE 
+GSS_FLAGS=
+GSS_LIBS=
+!ENDIF 
+
+CRAM_FLAGS=/DOBSOLETE_CRAM_ATTR=1
+
+DIGEST_FLAGS=/D "WITH_RC4"
+
+# Auxprop Plugin
+libsasldb_sources = allockey.c db_berkeley.c
+libsasldb_objs = allockey.obj db_berkeley.obj
+
+saslSASLDB_sources = sasldb.c sasldb_init.c $(libsasldb_sources) $(common_sources)
+saslSASLDB_objs = sasldb.obj sasldb_init.obj $(libsasldb_objs) $(common_objs)
+saslSASLDB_out = saslSASLDB.dll saslSASLDB.exp saslSASLDB.lib
+
+all_objs = $(saslANONYMOUS_objs) $(saslPLAIN_objs) $(saslCRAMMD5_objs) $(saslDIGESTMD5_objs) $(saslLOGIN_objs) $(saslSCRAM_objs) $(saslNTLM_objs) $(saslGSSAPI_objs) $(saslSRP_objs) $(saslOTP_objs) $(saslSASLDB_objs) $(saslSQL_objs) $(saslLDAPDB_objs)
+all_out = $(saslANONYMOUS_out) $(saslPLAIN_out) $(saslCRAMMD5_out) $(saslDIGESTMD5_out) $(saslLOGIN_out) $(saslSCRAM_out) $(saslNTLM_out) $(saslGSSAPI_out) $(saslSRP_out) $(saslOTP_out) $(saslSASLDB_out) $(saslSQL_out) $(saslLDAPDB_out)
+
+# LIBSASL_EXPORTS is required to export additional DB routines from sasldb
+DB_FLAGS = /I $(DB_INCLUDE) /I "..\sasldb" /D "LIBSASL_EXPORTS" /D "KEEP_DB_OPEN"
+
+!IF $(TARGET_WIN_SYSTEM) >= 51
+EXTRA_FLAGS = /D TARGET_WIN_SYSTEM=$(TARGET_WIN_SYSTEM) $(EXTRA_FLAGS)
+!ENDIF
+
+EXTRA_FLAGS=$(EXTRA_FLAGS) $(DB_FLAGS) $(OPENSSL_FLAGS) $(GSS_FLAGS) $(SRP_FLAGS) $(SQL_FLAGS) $(DIGEST_FLAGS) $(CRAM_FLAGS) $(LDAP_FLAGS)
+CPPFLAGS = /I "..\win32\include" /I "." /I "..\include" $(EXTRA_FLAGS) /D "WIN32" /D "_WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL"
+
+DB_LIBS=/libpath:$(DB_LIBPATH) $(DB_LIB)
+OPENSSL_LIBS=/libpath:$(OPENSSL_LIBPATH) libeay32.lib ssleay32.lib
+
+# Where to install files from this directory
+libdir = $(prefix)\lib
+bindir = $(prefix)\bin\sasl2
+
+all : all-recursive
+
+#
+# /I flag to xcopy tells to treat the last parameter as directory and create all missing levels
+#
+# In order to force xcopy not to confirm if the second parameter is file or directory,
+# the first parameter has to contain a wildcard character. For example, we use libsasl.l*,
+# instead of libsasl.lib. Ugly, but works!
+#
+# Note, that we will copy all dlls here, not just $(PLUGINS). This is a bug, but it allows
+# us to copy GSSAPI plugin, which might not be in $(PLUGINS).
+#
+install: $(PLUGINS)
+	@xcopy *.dll $(bindir) /I /F /Y
+
+all-recursive : $(PLUGINS)
+
+getaddrinfo.c: ..\lib\getaddrinfo.c
+	xcopy /D /Y ..\lib\getaddrinfo.c .
+
+getnameinfo.c: ..\lib\getnameinfo.c
+	xcopy /D /Y ..\lib\getnameinfo.c .
+
+allockey.c: ..\sasldb\allockey.c
+	xcopy /D /Y ..\sasldb\allockey.c .
+
+db_berkeley.c: ..\sasldb\db_berkeley.c
+	xcopy /D /Y ..\sasldb\db_berkeley.c .
+
+#Add /pdb: option?
+
+saslANONYMOUS.dll: $(saslANONYMOUS_objs) saslANONYMOUS.res
+	$(LINK32DLL) @<< $(LINK32DLL_FLAGS) /out:"saslANONYMOUS.dll" /implib:"saslANONYMOUS.lib" $(saslANONYMOUS_objs) saslANONYMOUS.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslPLAIN.dll: $(saslPLAIN_objs) saslPLAIN.res
+	$(LINK32DLL) @<< $(LINK32DLL_FLAGS) /out:"saslPLAIN.dll" /implib:"saslPLAIN.lib" $(saslPLAIN_objs) saslPLAIN.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslCRAMMD5.dll: $(saslCRAMMD5_objs) saslCRAMMD5.res
+	$(LINK32DLL) @<< $(LINK32DLL_FLAGS) /out:"saslCRAMMD5.dll" /implib:"saslCRAMMD5.lib" $(saslCRAMMD5_objs) saslCRAMMD5.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslDIGESTMD5.dll: $(saslDIGESTMD5_objs) saslDIGESTMD5.res
+	$(LINK32DLL) @<< $(LINK32DLL_FLAGS) /out:"saslDIGESTMD5.dll" /implib:"saslDIGESTMD5.lib" $(saslDIGESTMD5_objs) saslDIGESTMD5.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslLOGIN.dll: $(saslLOGIN_objs) saslLOGIN.res
+	$(LINK32DLL) @<< $(LINK32DLL_FLAGS) /out:"saslLOGIN.dll" /implib:"saslLOGIN.lib" $(saslLOGIN_objs) saslLOGIN.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslSCRAM.dll: $(saslSCRAM_objs) saslSCRAM.res
+	$(LINK32DLL) @<< $(OPENSSL_LIBS) $(LINK32DLL_FLAGS) /out:"saslSCRAM.dll" /implib:"saslSCRAM.lib" $(saslSCRAM_objs) saslSCRAM.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslNTLM.dll: $(saslNTLM_objs) saslNTLM.res
+	$(LINK32DLL) @<< $(OPENSSL_LIBS) $(LINK32DLL_FLAGS) /out:"saslNTLM.dll" /implib:"saslNTLM.lib" $(saslNTLM_objs) saslNTLM.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslGSSAPI.dll: $(saslGSSAPI_objs) saslGSSAPI.res
+	$(LINK32DLL) @<< $(GSS_LIBS) $(LINK32DLL_FLAGS) /out:"saslGSSAPI.dll" /implib:"saslGSSAPI.lib" $(saslGSSAPI_objs) saslGSSAPI.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslSRP.dll: $(saslSRP_objs) saslSRP.res
+	$(LINK32DLL) @<< $(OPENSSL_LIBS) $(LINK32DLL_FLAGS) /out:"saslSRP.dll" /implib:"saslSRP.lib" $(saslSRP_objs) saslSRP.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslOTP.dll: $(saslOTP_objs) saslOTP.res
+	$(LINK32DLL) @<< $(OPENSSL_LIBS) $(LINK32DLL_FLAGS) /out:"saslOTP.dll" /implib:"saslOTP.lib" $(saslOTP_objs) saslOTP.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslSASLDB.dll: $(saslSASLDB_objs) saslSASLDB.res
+	$(LINK32DLL) @<< $(DB_LIBS) $(LINK32DLL_FLAGS) /out:"saslSASLDB.dll" /implib:"saslSASLDB.lib" $(saslSASLDB_objs) saslSASLDB.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslSQLITE.dll: $(saslSQL_objs) saslSQLITE.res
+	$(LINK32DLL) @<< $(SQLITE_LIBS) $(LINK32DLL_FLAGS) /out:"saslSQLITE.dll" /implib:"saslSQLITE.lib" $(saslSQL_objs) saslSQLITE.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+saslLDAPDB.dll: $(saslLDAPDB_objs) saslLDAPDB.res
+	$(LINK32DLL) @<< $(LDAP_LIBS) $(OPENSSL_LIBS) $(LINK32DLL_FLAGS) /out:"saslLDAPDB.dll" /implib:"saslLDAPDB.lib" $(saslLDAPDB_objs) saslLDAPDB.res
+<<
+	IF EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;2
+
+CLEAN :
+	-@erase $(all_objs)
+	-@erase "*.idb"
+	-@erase "*.pdb"
+	-@erase "*.manifest"
+	-@erase getaddrinfo.c
+	-@erase allockey.c
+	-@erase db_berkeley.c
+	-@erase getnameinfo.c
+	-@erase $(generated_rc)
+	-@erase "*.res"
+	-@erase $(all_out)
+
+.c.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.rc.res:
+	rc $<
+
+$(generated_rc):
+	copy <<temp.rc $@
+#include "windows.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION $(SASL_VERSION_MAJOR),$(SASL_VERSION_MINOR),$(SASL_VERSION_STEP),0
+ PRODUCTVERSION $(SASL_VERSION_MAJOR),$(SASL_VERSION_MINOR),$(SASL_VERSION_STEP),0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Carnegie Mellon University\0"
+            VALUE "FileDescription", "CMU SASL $(@B) plugin\0"
+            VALUE "FileVersion", "$(SASL_VERSION_MAJOR).$(SASL_VERSION_MINOR).$(SASL_VERSION_STEP).0\0"
+            VALUE "InternalName", "$(@B)\0"
+            VALUE "LegalCopyright", "Copyright (c) Carnegie Mellon University 2002-2012\0"
+            VALUE "OriginalFilename", "$(@B).dll\0"
+            VALUE "ProductName", "Carnegie Mellon University SASL\0"
+            VALUE "ProductVersion", "$(SASL_VERSION_MAJOR).$(SASL_VERSION_MINOR).$(SASL_VERSION_STEP)-0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+<<

+ 390 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/anonymous.c

@@ -0,0 +1,390 @@
+/* Anonymous SASL plugin
+ * Rob Siemborski
+ * Tim Martin 
+ * $Id: anonymous.c,v 1.53 2009/02/13 14:46:47 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h> 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh 
+#include <sasl_anonymous_plugin_decl.h> 
+#endif 
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: anonymous.c,v 1.53 2009/02/13 14:46:47 mel Exp $";
+
+static const char anonymous_id[] = "anonymous";
+
+/*****************************  Server Section  *****************************/
+
+static int
+anonymous_server_mech_new(void *glob_context __attribute__((unused)),
+			  sasl_server_params_t *sparams,
+			  const char *challenge __attribute__((unused)),
+			  unsigned challen __attribute__((unused)),
+			  void **conn_context)
+{
+    /* holds state are in */
+    if (!conn_context) {
+	PARAMERROR( sparams->utils );
+	return SASL_BADPARAM;
+    }
+    
+    *conn_context = NULL;
+    
+    return SASL_OK;
+}
+
+static int
+anonymous_server_mech_step(void *conn_context __attribute__((unused)),
+			   sasl_server_params_t *sparams,
+			   const char *clientin,
+			   unsigned clientinlen,
+			   const char **serverout,
+			   unsigned *serveroutlen,
+			   sasl_out_params_t *oparams)
+{
+    char *clientdata;
+    int result;
+    
+    if (!sparams
+	|| !serverout
+	|| !serveroutlen
+	|| !oparams) {
+	PARAMERROR( sparams->utils );
+	return SASL_BADPARAM;
+    }
+    
+    *serverout = NULL;
+    *serveroutlen = 0;
+    
+    if (!clientin) {
+	return SASL_CONTINUE;
+    }
+    
+    /* We force a truncation 255 characters (specified by RFC 2245) */
+    if (clientinlen > 255) clientinlen = 255;
+    
+    /* NULL-terminate the clientin... */
+    clientdata = sparams->utils->malloc(clientinlen + 1);
+    if (!clientdata) {
+	MEMERROR(sparams->utils);
+	return SASL_NOMEM;
+    }
+    
+    strncpy(clientdata, clientin, clientinlen);
+    clientdata[clientinlen] = '\0';
+    
+    sparams->utils->log(sparams->utils->conn,
+			SASL_LOG_NOTE,
+			"ANONYMOUS login: \"%s\"",
+			clientdata);
+    
+    if (clientdata != clientin) 
+	sparams->utils->free(clientdata);
+    
+    result = sparams->canon_user(sparams->utils->conn,
+				 anonymous_id, 0,
+				 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+
+    if (result != SASL_OK) return result;
+    
+    /* set oparams */
+    oparams->doneflag = 1;
+    oparams->mech_ssf = 0;
+    oparams->maxoutbuf = 0;
+    oparams->encode_context = NULL;
+    oparams->encode = NULL;
+    oparams->decode_context = NULL;
+    oparams->decode = NULL;
+    oparams->param_version = 0;
+    
+    return SASL_OK;
+}
+
+static sasl_server_plug_t anonymous_server_plugins[] = 
+{
+    {
+	"ANONYMOUS",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOPLAINTEXT,		/* security_flags */
+	SASL_FEAT_WANT_CLIENT_FIRST
+	| SASL_FEAT_DONTUSE_USERPASSWD,	/* features */
+	NULL,				/* glob_context */
+	&anonymous_server_mech_new,	/* mech_new */
+	&anonymous_server_mech_step,	/* mech_step */
+	NULL,				/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	NULL,				/* mech_avail */
+	NULL                        	/* spare */
+    }
+};
+
+int anonymous_server_plug_init(const sasl_utils_t *utils,
+			       int maxversion,
+			       int *out_version,
+			       sasl_server_plug_t **pluglist,
+			       int *plugcount)
+{
+    if (maxversion < SASL_SERVER_PLUG_VERSION) {
+	SETERROR( utils, "ANONYMOUS version mismatch" );
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = anonymous_server_plugins;
+    *plugcount = 1;  
+    
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+typedef struct client_context {
+    char *out_buf;
+    unsigned out_buf_len;
+} client_context_t;
+
+static int
+anonymous_client_mech_new(void *glob_context __attribute__((unused)),
+			  sasl_client_params_t *cparams,
+			  void **conn_context)
+{
+    client_context_t *text;
+    
+    if (!conn_context) {
+	PARAMERROR(cparams->utils);
+	return SASL_BADPARAM;
+    }
+    
+    /* holds state are in */
+    text = cparams->utils->malloc(sizeof(client_context_t));
+    if (text == NULL) {
+	MEMERROR(cparams->utils);
+	return SASL_NOMEM;
+    }
+    
+    memset(text, 0, sizeof(client_context_t));
+    
+    *conn_context = text;
+    
+    return SASL_OK;
+}
+
+static int
+anonymous_client_mech_step(void *conn_context,
+			   sasl_client_params_t *cparams,
+			   const char *serverin __attribute__((unused)),
+			   unsigned serverinlen,
+			   sasl_interact_t **prompt_need,
+			   const char **clientout,
+			   unsigned *clientoutlen,
+			   sasl_out_params_t *oparams)
+{
+    client_context_t *text = (client_context_t *) conn_context;
+    size_t userlen;
+    char hostname[256];
+    const char *user = NULL;
+    int user_result = SASL_OK;
+    int result;
+    
+    if (!cparams
+	|| !clientout
+	|| !clientoutlen
+	|| !oparams) {
+	PARAMERROR( cparams->utils );
+	return SASL_BADPARAM;
+    }
+    
+    *clientout = NULL;
+    *clientoutlen = 0;
+    
+    if (serverinlen != 0) {
+	SETERROR( cparams->utils,
+		  "Nonzero serverinlen in ANONYMOUS continue_step" );
+	return SASL_BADPROT;
+    }
+    
+    /* check if sec layer strong enough */
+    if (cparams->props.min_ssf > cparams->external_ssf) {
+	SETERROR( cparams->utils, "SSF requested of ANONYMOUS plugin");
+	return SASL_TOOWEAK;
+    }
+    
+    /* try to get the trace info */
+    if (user == NULL) {
+	user_result = _plug_get_userid(cparams->utils, &user, prompt_need);
+	
+	if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+	    return user_result;
+	}
+    }
+    
+    /* free prompts we got */
+    if (prompt_need && *prompt_need) {
+	cparams->utils->free(*prompt_need);
+	*prompt_need = NULL;
+    }
+    
+    /* if there are prompts not filled in */
+    if (user_result == SASL_INTERACT) {
+	/* make the prompt list */
+	result =
+	    _plug_make_prompts(cparams->utils, prompt_need,
+			       user_result == SASL_INTERACT ?
+			       "Please enter anonymous identification" : NULL,
+			       "",
+			       NULL, NULL,
+			       NULL, NULL,
+			       NULL, NULL, NULL,
+			       NULL, NULL, NULL);
+	if (result != SASL_OK) return result;
+	
+	return SASL_INTERACT;
+    }
+    
+    if (!user || !*user) {
+	user = anonymous_id;
+    }
+    userlen = strlen(user);
+    
+    result = cparams->canon_user(cparams->utils->conn,
+				 anonymous_id, 0,
+				 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+    if (result != SASL_OK) return result;
+    
+    memset(hostname, 0, sizeof(hostname));
+    gethostname(hostname, sizeof(hostname));
+    hostname[sizeof(hostname)-1] = '\0';
+    
+    *clientoutlen = (unsigned) (userlen + strlen(hostname) + 1);
+    
+    result = _plug_buf_alloc(cparams->utils, &text->out_buf,
+			     &text->out_buf_len, *clientoutlen);
+    
+    if (result != SASL_OK) return result;
+    
+    strcpy(text->out_buf, user);
+    text->out_buf[userlen] = '@';
+    /* use memcpy() instead of strcpy() so we don't add the NUL */
+    memcpy(text->out_buf + userlen + 1, hostname, strlen(hostname));
+    
+    *clientout = text->out_buf;
+    
+    /* set oparams */
+    oparams->doneflag = 1;
+    oparams->mech_ssf = 0;
+    oparams->maxoutbuf = 0;
+    oparams->encode_context = NULL;
+    oparams->encode = NULL;
+    oparams->decode_context = NULL;
+    oparams->decode = NULL;
+    oparams->param_version = 0;
+    
+    return SASL_OK;
+}
+
+static void anonymous_client_dispose(void *conn_context,
+				     const sasl_utils_t *utils)
+{
+    client_context_t *text = (client_context_t *) conn_context;
+    
+    if(!text) return;
+    
+    if (text->out_buf) utils->free(text->out_buf);
+    
+    utils->free(text);
+}
+
+static const unsigned long anonymous_required_prompts[] = {
+    SASL_CB_LIST_END
+};
+
+static sasl_client_plug_t anonymous_client_plugins[] = 
+{
+    {
+	"ANONYMOUS",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOPLAINTEXT,		/* security_flags */
+	SASL_FEAT_WANT_CLIENT_FIRST,	/* features */
+	anonymous_required_prompts,	/* required_prompts */
+	NULL,				/* glob_context */
+	&anonymous_client_mech_new, 	/* mech_new */
+	&anonymous_client_mech_step,	/* mech_step */
+	&anonymous_client_dispose,	/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL                        	/* spare */
+    }
+};
+
+int anonymous_client_plug_init(const sasl_utils_t *utils,
+			       int maxversion,
+			       int *out_version,
+			       sasl_client_plug_t **pluglist,
+			       int *plugcount)
+{
+    if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+	SETERROR( utils, "ANONYMOUS version mismatch" );
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = anonymous_client_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+}

+ 43 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/anonymous_init.c

@@ -0,0 +1,43 @@
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_anonymous_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+					 )
+{
+    switch (ul_reason_for_call)
+	{
+		case DLL_PROCESS_ATTACH:
+		case DLL_THREAD_ATTACH:
+		case DLL_THREAD_DETACH:
+		case DLL_PROCESS_DETACH:
+			break;
+    }
+    return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( anonymous )
+SASL_SERVER_PLUG_INIT( anonymous )
+

+ 689 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/cram.c

@@ -0,0 +1,689 @@
+/* CRAM-MD5 SASL plugin
+ * Rob Siemborski
+ * Tim Martin 
+ * $Id: cram.c,v 1.87 2011/09/07 13:19:44 murch Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_cram_plugin_decl.h>
+#endif
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: cram.c,v 1.87 2011/09/07 13:19:44 murch Exp $";
+
+/* convert a string of 8bit chars to it's representation in hex
+ * using lowercase letters
+ */
+static char *convert16(unsigned char *in, int inlen, const sasl_utils_t *utils)
+{
+    static char hex[]="0123456789abcdef";
+    int lup;
+    char *out;
+
+    out = utils->malloc(inlen*2+1);
+    if (out == NULL) return NULL;
+    
+    for (lup=0; lup < inlen; lup++) {
+	out[lup*2] = hex[in[lup] >> 4];
+	out[lup*2+1] = hex[in[lup] & 15];
+    }
+
+    out[lup*2] = 0;
+    return out;
+}
+
+
+/*****************************  Server Section  *****************************/
+
+typedef struct server_context {
+    int state;
+
+    char *challenge;
+} server_context_t;
+
+static int
+crammd5_server_mech_new(void *glob_context __attribute__((unused)),
+			sasl_server_params_t *sparams,
+			const char *challenge __attribute__((unused)),
+			unsigned challen __attribute__((unused)),
+			void **conn_context)
+{
+    server_context_t *text;
+    
+    /* holds state are in */
+    text = sparams->utils->malloc(sizeof(server_context_t));
+    if (text == NULL) {
+	MEMERROR( sparams->utils );
+	return SASL_NOMEM;
+    }
+    
+    memset(text, 0, sizeof(server_context_t));
+    
+    text->state = 1;
+    
+    *conn_context = text;
+    
+    return SASL_OK;
+}
+
+/*
+ * Returns the current time (or part of it) in string form
+ *  maximum length=15
+ */
+static char *gettime(sasl_server_params_t *sparams)
+{
+    char *ret;
+    time_t t;
+    
+    t=time(NULL);
+    ret= sparams->utils->malloc(15);
+    if (ret==NULL) return NULL;
+    
+    /* the bottom bits are really the only random ones so if
+       we overflow we don't want to loose them */
+    snprintf(ret,15,"%lu",t%(0xFFFFFF));
+    
+    return ret;
+}
+
+static char *randomdigits(sasl_server_params_t *sparams)
+{
+    unsigned int num;
+    char *ret;
+    unsigned char temp[5]; /* random 32-bit number */
+    
+    sparams->utils->rand(sparams->utils->rpool,(char *) temp,4);
+    num=(temp[0] * 256 * 256 * 256) +
+	(temp[1] * 256 * 256) +
+	(temp[2] * 256) +
+	(temp[3] );
+    
+    ret = sparams->utils->malloc(15); /* there's no way an unsigned can be longer than this right? */
+    if (ret == NULL) return NULL;
+    sprintf(ret, "%u", num);
+    
+    return ret;
+}
+
+static int
+crammd5_server_mech_step1(server_context_t *text,
+			  sasl_server_params_t *sparams,
+			  const char *clientin __attribute__((unused)),
+			  unsigned clientinlen,
+			  const char **serverout,
+			  unsigned *serveroutlen,
+			  sasl_out_params_t *oparams __attribute__((unused)))
+{
+    char *time, *randdigits;
+	    
+    /* we shouldn't have received anything */
+    if (clientinlen != 0) {
+	SETERROR(sparams->utils, "CRAM-MD5 does not accept inital data");
+	return SASL_BADPROT;
+    }
+    
+    /* get time and a random number for the nonce */
+    time = gettime(sparams);
+    randdigits = randomdigits(sparams);
+    if ((time == NULL) || (randdigits == NULL)) {
+	MEMERROR( sparams->utils );
+	return SASL_NOMEM;
+    }
+    
+    /* allocate some space for the challenge */
+    text->challenge = sparams->utils->malloc(200 + 1);
+    if (text->challenge == NULL) {
+	MEMERROR(sparams->utils);
+	return SASL_NOMEM;
+    }
+    
+    /* create the challenge */
+    snprintf(text->challenge, 200, "<%s.%s@%s>", randdigits, time,
+	     sparams->serverFQDN);
+    
+    *serverout = text->challenge;
+    *serveroutlen = (unsigned) strlen(text->challenge);
+    
+    /* free stuff */
+    sparams->utils->free(time);    
+    sparams->utils->free(randdigits);    
+    
+    text->state = 2;
+    
+    return SASL_CONTINUE;
+}
+    
+static int
+crammd5_server_mech_step2(server_context_t *text,
+			  sasl_server_params_t *sparams,
+			  const char *clientin,
+			  unsigned clientinlen,
+			  const char **serverout __attribute__((unused)),
+			  unsigned *serveroutlen __attribute__((unused)),
+			  sasl_out_params_t *oparams)
+{
+    char *userid = NULL;
+    sasl_secret_t *sec = NULL;
+    int pos;
+    size_t len;
+    int result = SASL_FAIL;
+    const char *password_request[] = { SASL_AUX_PASSWORD,
+#if defined(OBSOLETE_CRAM_ATTR)
+				       "*cmusaslsecretCRAM-MD5",
+#endif
+				       NULL };
+    struct propval auxprop_values[3];
+    HMAC_MD5_CTX tmphmac;
+    HMAC_MD5_STATE md5state;
+    int clear_md5state = 0;
+    char *digest_str = NULL;
+    UINT4 digest[4];
+    
+    /* extract userid; everything before last space */
+    pos = clientinlen-1;
+    while ((pos > 0) && (clientin[pos] != ' ')) pos--;
+    
+    if (pos <= 0) {
+	SETERROR( sparams->utils,"need authentication name");
+	return SASL_BADPROT;
+    }
+    
+    userid = (char *) sparams->utils->malloc(pos+1);
+    if (userid == NULL) {
+	MEMERROR( sparams->utils);
+	return SASL_NOMEM;
+    }
+    
+    /* copy authstr out */
+    memcpy(userid, clientin, pos);
+    userid[pos] = '\0';
+    
+    result = sparams->utils->prop_request(sparams->propctx, password_request);
+    if (result != SASL_OK) goto done;
+    
+    /* this will trigger the getting of the aux properties */
+    result = sparams->canon_user(sparams->utils->conn,
+				 userid, 0, SASL_CU_AUTHID | SASL_CU_AUTHZID,
+				 oparams);
+    if (result != SASL_OK) goto done;
+    
+    result = sparams->utils->prop_getnames(sparams->propctx,
+					   password_request,
+					   auxprop_values);
+    if (result < 0 ||
+	((!auxprop_values[0].name || !auxprop_values[0].values)
+#if defined(OBSOLETE_CRAM_ATTR)
+	  && (!auxprop_values[1].name || !auxprop_values[1].values)
+#endif
+	)) {
+	/* We didn't find this username */
+	sparams->utils->seterror(sparams->utils->conn,0,
+				 "no secret in database");
+	result = sparams->transition ? SASL_TRANS : SASL_NOUSER;
+	goto done;
+    }
+    
+    if (auxprop_values[0].name && auxprop_values[0].values) {
+	len = strlen(auxprop_values[0].values[0]);
+	if (len == 0) {
+	    sparams->utils->seterror(sparams->utils->conn,0,
+				     "empty secret");
+	    result = SASL_FAIL;
+	    goto done;
+	}
+	
+	sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
+	if (!sec) goto done;
+	
+	sec->len = (unsigned) len;
+	strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);   
+	
+	clear_md5state = 1;
+	/* Do precalculation on plaintext secret */
+	sparams->utils->hmac_md5_precalc(&md5state, /* OUT */
+					 sec->data,
+					 sec->len);
+#if defined(OBSOLETE_CRAM_ATTR)
+    } else if (auxprop_values[1].name && auxprop_values[1].values) {
+	/* We have a precomputed secret */
+	memcpy(&md5state, auxprop_values[1].values[0],
+	       sizeof(HMAC_MD5_STATE));
+#endif
+    } else {
+	sparams->utils->seterror(sparams->utils->conn, 0,
+				 "Have neither type of secret");
+	return SASL_FAIL;
+    }
+    
+    /* erase the plaintext password */
+    sparams->utils->prop_erase(sparams->propctx, password_request[0]);
+
+    /* ok this is annoying:
+       so we have this half-way hmac transform instead of the plaintext
+       that means we half to:
+       -import it back into a md5 context
+       -do an md5update with the nonce 
+       -finalize it
+    */
+    sparams->utils->hmac_md5_import(&tmphmac, (HMAC_MD5_STATE *) &md5state);
+    sparams->utils->MD5Update(&(tmphmac.ictx),
+			      (const unsigned char *) text->challenge,
+			      (unsigned) strlen(text->challenge));
+    sparams->utils->hmac_md5_final((unsigned char *) &digest, &tmphmac);
+    
+    /* convert to base 16 with lower case letters */
+    digest_str = convert16((unsigned char *) digest, 16, sparams->utils);
+    
+    /* if same then verified 
+     *  - we know digest_str is null terminated but clientin might not be
+     *  - verify the length of clientin anyway!
+     */
+    len = strlen(digest_str);
+    if (clientinlen-pos-1 < len ||
+	strncmp(digest_str, clientin+pos+1, len) != 0) {
+	sparams->utils->seterror(sparams->utils->conn, 0,
+				 "incorrect digest response");
+	result = SASL_BADAUTH;
+	goto done;
+    }
+    
+    /* set oparams */
+    oparams->doneflag = 1;
+    oparams->mech_ssf = 0;
+    oparams->maxoutbuf = 0;
+    oparams->encode_context = NULL;
+    oparams->encode = NULL;
+    oparams->decode_context = NULL;
+    oparams->decode = NULL;
+    oparams->param_version = 0;
+    
+    result = SASL_OK;
+    
+  done:
+    if (userid) sparams->utils->free(userid);
+    if (sec) _plug_free_secret(sparams->utils, &sec);
+
+    if (digest_str) sparams->utils->free(digest_str);
+    if (clear_md5state) memset(&md5state, 0, sizeof(md5state));
+    
+    return result;
+}
+
+static int crammd5_server_mech_step(void *conn_context,
+				    sasl_server_params_t *sparams,
+				    const char *clientin,
+				    unsigned clientinlen,
+				    const char **serverout,
+				    unsigned *serveroutlen,
+				    sasl_out_params_t *oparams)
+{
+    server_context_t *text = (server_context_t *) conn_context;
+    
+    *serverout = NULL;
+    *serveroutlen = 0;
+
+    if (text == NULL) {
+	return SASL_BADPROT;
+    }
+
+    /* this should be well more than is ever needed */
+    if (clientinlen > 1024) {
+	SETERROR(sparams->utils, "CRAM-MD5 input longer than 1024 bytes");
+	return SASL_BADPROT;
+    }
+    
+    switch (text->state) {
+
+    case 1:
+	return crammd5_server_mech_step1(text, sparams,
+					 clientin, clientinlen,
+					 serverout, serveroutlen,
+					 oparams);
+
+    case 2:
+	return crammd5_server_mech_step2(text, sparams,
+					 clientin, clientinlen,
+					 serverout, serveroutlen,
+					 oparams);
+
+    default: /* should never get here */
+	sparams->utils->log(NULL, SASL_LOG_ERR,
+			   "Invalid CRAM-MD5 server step %d\n", text->state);
+	return SASL_FAIL;
+    }
+    
+    return SASL_FAIL; /* should never get here */
+}
+
+static void crammd5_server_mech_dispose(void *conn_context,
+					const sasl_utils_t *utils)
+{
+    server_context_t *text = (server_context_t *) conn_context;
+    
+    if (!text) return;
+    
+    if (text->challenge) _plug_free_string(utils,&(text->challenge));
+    
+    utils->free(text);
+}
+
+static sasl_server_plug_t crammd5_server_plugins[] = 
+{
+    {
+	"CRAM-MD5",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOANONYMOUS,		/* security_flags */
+	SASL_FEAT_SERVER_FIRST,		/* features */
+	NULL,				/* glob_context */
+	&crammd5_server_mech_new,	/* mech_new */
+	&crammd5_server_mech_step,	/* mech_step */
+	&crammd5_server_mech_dispose,	/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	NULL,				/* mech avail */
+	NULL				/* spare */
+    }
+};
+
+int crammd5_server_plug_init(const sasl_utils_t *utils,
+			     int maxversion,
+			     int *out_version,
+			     sasl_server_plug_t **pluglist,
+			     int *plugcount)
+{
+    if (maxversion < SASL_SERVER_PLUG_VERSION) {
+	SETERROR( utils, "CRAM version mismatch");
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = crammd5_server_plugins;
+    *plugcount = 1;  
+    
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+typedef struct client_context {
+    char *out_buf;
+    unsigned out_buf_len;
+} client_context_t;
+
+static int crammd5_client_mech_new(void *glob_context __attribute__((unused)), 
+				   sasl_client_params_t *params,
+				   void **conn_context)
+{
+    client_context_t *text;
+    
+    /* holds state are in */
+    text = params->utils->malloc(sizeof(client_context_t));
+    if (text == NULL) {
+	MEMERROR(params->utils);
+	return SASL_NOMEM;
+    }
+    
+    memset(text, 0, sizeof(client_context_t));
+
+    *conn_context = text;
+    
+    return SASL_OK;
+}
+
+static char *make_hashed(sasl_secret_t *sec, char *nonce, int noncelen, 
+			 const sasl_utils_t *utils)
+{
+    unsigned char digest[24];  
+    char *in16;
+    
+    if (sec == NULL) return NULL;
+    
+    /* do the hmac md5 hash output 128 bits */
+    utils->hmac_md5((unsigned char *) nonce, noncelen,
+		    sec->data, sec->len, digest);
+    
+    /* convert that to hex form */
+    in16 = convert16(digest, 16, utils);
+    if (in16 == NULL) return NULL;
+    
+    return in16;
+}
+
+static int crammd5_client_mech_step(void *conn_context,
+				    sasl_client_params_t *params,
+				    const char *serverin,
+				    unsigned serverinlen,
+				    sasl_interact_t **prompt_need,
+				    const char **clientout,
+				    unsigned *clientoutlen,
+				    sasl_out_params_t *oparams)
+{
+    client_context_t *text = (client_context_t *) conn_context;
+    const char *authid = NULL;
+    sasl_secret_t *password = NULL;
+    unsigned int free_password = 0; /* set if we need to free password */
+    int auth_result = SASL_OK;
+    int pass_result = SASL_OK;
+    int result;
+    size_t maxsize;
+    char *in16 = NULL;
+
+    *clientout = NULL;
+    *clientoutlen = 0;
+    
+    /* First check for absurd lengths */
+    if (serverinlen > 1024) {
+	params->utils->seterror(params->utils->conn, 0,
+				"CRAM-MD5 input longer than 1024 bytes");
+	return SASL_BADPROT;
+    }
+    
+    /* check if sec layer strong enough */
+    if (params->props.min_ssf > params->external_ssf) {
+	SETERROR( params->utils, "SSF requested of CRAM-MD5 plugin");
+	return SASL_TOOWEAK;
+    }
+    
+    /* try to get the userid */
+    if (oparams->authid == NULL) {
+	auth_result=_plug_get_authid(params->utils, &authid, prompt_need);
+	
+	if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
+	    return auth_result;
+    }
+    
+    /* try to get the password */
+    if (password == NULL) {
+	pass_result=_plug_get_password(params->utils, &password,
+				       &free_password, prompt_need);
+	
+	if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
+	    return pass_result;
+    }
+    
+    /* free prompts we got */
+    if (prompt_need && *prompt_need) {
+	params->utils->free(*prompt_need);
+	*prompt_need = NULL;
+    }
+    
+    /* if there are prompts not filled in */
+    if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) {
+	/* make the prompt list */
+	result =
+	    _plug_make_prompts(params->utils, prompt_need,
+			       NULL, NULL,
+			       auth_result == SASL_INTERACT ?
+			       "Please enter your authentication name" : NULL,
+			       NULL,
+			       pass_result == SASL_INTERACT ?
+			       "Please enter your password" : NULL, NULL,
+			       NULL, NULL, NULL,
+			       NULL, NULL, NULL);
+	if (result != SASL_OK) goto cleanup;
+	
+	return SASL_INTERACT;
+    }
+    
+    if (!password) {
+	PARAMERROR(params->utils);
+	return SASL_BADPARAM;
+    }
+    
+    result = params->canon_user(params->utils->conn, authid, 0,
+				SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+    if (result != SASL_OK) goto cleanup;
+    
+    /*
+     * username SP digest (keyed md5 where key is passwd)
+     */
+    
+    in16 = make_hashed(password, (char *) serverin, serverinlen,
+		       params->utils);
+    
+    if (in16 == NULL) {
+	SETERROR(params->utils, "whoops, make_hashed failed us this time");
+	result = SASL_FAIL;
+	goto cleanup;
+    }
+    
+    maxsize = 32+1+strlen(oparams->authid)+30;
+    result = _plug_buf_alloc(params->utils, &(text->out_buf),
+			     &(text->out_buf_len), (unsigned) maxsize);
+    if (result != SASL_OK) goto cleanup;
+    
+    snprintf(text->out_buf, maxsize, "%s %s", oparams->authid, in16);
+    
+    *clientout = text->out_buf;
+    *clientoutlen = (unsigned) strlen(*clientout);
+    
+    /* set oparams */
+    oparams->doneflag = 1;
+    oparams->mech_ssf = 0;
+    oparams->maxoutbuf = 0;
+    oparams->encode_context = NULL;
+    oparams->encode = NULL;
+    oparams->decode_context = NULL;
+    oparams->decode = NULL;
+    oparams->param_version = 0;
+    
+    result = SASL_OK;
+
+  cleanup:
+    /* get rid of private information */
+    if (in16) _plug_free_string(params->utils, &in16);
+    
+    /* get rid of all sensitive info */
+    if (free_password) _plug_free_secret(params-> utils, &password);
+
+    return result;
+}
+
+static void crammd5_client_mech_dispose(void *conn_context,
+					const sasl_utils_t *utils)
+{
+    client_context_t *text = (client_context_t *) conn_context;
+    
+    if (!text) return;
+    
+    if (text->out_buf) utils->free(text->out_buf);
+    
+    utils->free(text);
+}
+
+static sasl_client_plug_t crammd5_client_plugins[] = 
+{
+    {
+	"CRAM-MD5",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOANONYMOUS,		/* security_flags */
+	SASL_FEAT_SERVER_FIRST,		/* features */
+	NULL,				/* required_prompts */
+	NULL,				/* glob_context */
+	&crammd5_client_mech_new,	/* mech_new */
+	&crammd5_client_mech_step,	/* mech_step */
+	&crammd5_client_mech_dispose,	/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL				/* spare */
+    }
+};
+
+int crammd5_client_plug_init(const sasl_utils_t *utils,
+			     int maxversion,
+			     int *out_version,
+			     sasl_client_plug_t **pluglist,
+			     int *plugcount)
+{
+    if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+	SETERROR( utils, "CRAM version mismatch");
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = crammd5_client_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+}

+ 43 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/crammd5_init.c

@@ -0,0 +1,43 @@
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_crammd5_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+					 )
+{
+    switch (ul_reason_for_call)
+	{
+		case DLL_PROCESS_ATTACH:
+		case DLL_THREAD_ATTACH:
+		case DLL_THREAD_DETACH:
+		case DLL_PROCESS_DETACH:
+			break;
+    }
+    return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( crammd5 )
+SASL_SERVER_PLUG_INIT( crammd5 )
+

+ 4655 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/digestmd5.c

@@ -0,0 +1,4655 @@
+/* DIGEST-MD5 SASL plugin
+ * Ken Murchison
+ * Rob Siemborski
+ * Tim Martin
+ * Alexey Melnikov 
+ * $Id: digestmd5.c,v 1.205 2011/05/13 19:18:37 murch Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef macintosh
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <ctype.h>
+
+/* DES support */
+#ifdef WITH_DES
+# ifdef WITH_SSL_DES
+#  include <openssl/des.h>
+#  include <openssl/opensslv.h>
+#  if (OPENSSL_VERSION_NUMBER >= 0x0090700f) && \
+      !defined(OPENSSL_ENABLE_OLD_DES_SUPPORT)
+#   define des_cblock DES_cblock
+#   define des_key_schedule DES_key_schedule
+#   define des_key_sched(k,ks) \
+           DES_key_sched((k),&(ks))
+#   define des_cbc_encrypt(i,o,l,k,iv,e) \
+           DES_cbc_encrypt((i),(o),(l),&(k),(iv),(e))
+#   define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
+           DES_ede2_cbc_encrypt((i),(o),(l),&(k1),&(k2),(iv),(e))
+#  endif /* OpenSSL 0.9.7+ w/o old DES support */
+# else /* system DES library */
+#ifdef HAVE_DES_H
+#  include <des.h>
+#endif
+# endif
+#endif /* WITH_DES */
+
+#ifdef WIN32
+# include <winsock2.h>
+#else /* Unix */
+# include <netinet/in.h>
+#endif /* WIN32 */
+
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifndef WIN32
+extern int strcasecmp(const char *s1, const char *s2);
+#endif /* end WIN32 */
+
+#ifdef macintosh
+#include <sasl_md5_plugin_decl.h>
+#endif
+
+/* external definitions */
+
+#ifdef sun
+/* gotta define gethostname ourselves on suns */
+extern int      gethostname(char *, int);
+#endif
+
+#define bool int
+
+#ifndef TRUE
+#define TRUE  (1)
+#define FALSE (0)
+#endif
+
+/* MAX_UIN32_DIV_10 * 10 + MAX_UIN32_MOD_10 == 2^32-1 == 4294967295 */
+#define MAX_UIN32_DIV_10    429496729
+#define MAX_UIN32_MOD_10    5
+
+#define DEFAULT_BUFSIZE	    0xFFFF
+#define MAX_SASL_BUFSIZE    0xFFFFFF
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: digestmd5.c,v 1.205 2011/05/13 19:18:37 murch Exp $";
+
+/* Definitions */
+#define NONCE_SIZE (32)		/* arbitrary */
+
+/* Layer Flags */
+#define DIGEST_NOLAYER    (1)
+#define DIGEST_INTEGRITY  (2)
+#define DIGEST_PRIVACY    (4)
+
+/* defines */
+#define HASHLEN 16
+typedef unsigned char HASH[HASHLEN + 1];
+#define HASHHEXLEN 32
+typedef unsigned char HASHHEX[HASHHEXLEN + 1];
+
+#define MAC_SIZE 10
+#define MAC_OFFS 2
+
+const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
+const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
+
+const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
+const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
+
+#define HT	(9)
+#define CR	(13)
+#define LF	(10)
+#define SP	(32)
+#define DEL	(127)
+
+#define NEED_ESCAPING	"\"\\"
+
+#define REALM_CHAL_PREFIX	"Available realms:"
+
+static char *quote (char *str);
+
+struct context;
+
+/* function definitions for cipher encode/decode */
+typedef int cipher_function_t(struct context *,
+			      const char *,
+			      unsigned,
+			      unsigned char[],
+			      char *,
+			      unsigned *);
+
+typedef int cipher_init_t(struct context *, unsigned char [16], 
+                                            unsigned char [16]);
+typedef void cipher_free_t(struct context *);
+
+enum Context_type { SERVER = 0, CLIENT = 1 };
+
+typedef struct cipher_context cipher_context_t;
+
+/* cached auth info used for fast reauth */
+typedef struct reauth_entry {
+    char *authid;
+    char *realm;
+    unsigned char *nonce;
+    unsigned int nonce_count;
+    unsigned char *cnonce;
+
+    union {
+	struct {
+	    time_t timestamp;
+	} s; /* server stuff */
+
+	struct {
+	    char *serverFQDN;
+	    int protection;
+	    struct digest_cipher *cipher;
+	    unsigned long server_maxbuf;
+
+	    /* for HTTP mode (RFC 2617) only */
+	    char *algorithm;
+	    unsigned char *opaque;
+	} c; /* client stuff */
+    } u;
+} reauth_entry_t;
+
+typedef struct reauth_cache {
+    /* static stuff */
+    enum Context_type i_am;	/* are we the client or server? */
+    time_t timeout;
+    void *mutex;
+    unsigned size;
+
+    reauth_entry_t *e;		/* fixed-size hash table of entries */
+} reauth_cache_t;
+
+/* global context for reauth use */
+typedef struct digest_glob_context { 
+   reauth_cache_t *reauth; 
+} digest_glob_context_t;
+
+/* context that stores info */
+typedef struct context {
+    int state;			/* state in the authentication we are in */
+    enum Context_type i_am;	/* are we the client or server? */
+    int http_mode;    		/* use RFC 2617 compatible protocol? */
+    
+    reauth_cache_t *reauth;
+
+    char *authid;
+    char *realm;
+    unsigned char *nonce;
+    unsigned int nonce_count;
+    unsigned char *cnonce;
+
+    /* only used by the client */
+    char ** realms;
+    int realm_cnt;
+
+    char *response_value;
+    
+    unsigned int seqnum;
+    unsigned int rec_seqnum;	/* for checking integrity */
+    
+    HASH Ki_send;
+    HASH Ki_receive;
+    
+    HASH HA1;			/* Kcc or Kcs */
+    
+    /* copy of utils from the params structures */
+    const sasl_utils_t *utils;
+    
+    /* For general use */
+    char *out_buf;
+    unsigned out_buf_len;
+    
+    /* for encoding/decoding */
+    buffer_info_t *enc_in_buf;
+    char *encode_buf, *decode_buf, *decode_packet_buf;
+    unsigned encode_buf_len, decode_buf_len, decode_packet_buf_len;
+
+    decode_context_t decode_context;
+
+    /* if privacy mode is used use these functions for encode and decode */
+    cipher_function_t *cipher_enc;
+    cipher_function_t *cipher_dec;
+    cipher_init_t *cipher_init;
+    cipher_free_t *cipher_free;
+    struct cipher_context *cipher_enc_context;
+    struct cipher_context *cipher_dec_context;
+} context_t;
+
+struct digest_cipher {
+    char *name;
+    sasl_ssf_t ssf;
+    int n; /* bits to make privacy key */
+    int flag; /* a bitmask to make things easier for us */
+    
+    cipher_function_t *cipher_enc;
+    cipher_function_t *cipher_dec;
+    cipher_init_t *cipher_init;
+    cipher_free_t *cipher_free;
+};
+#if 0
+static const unsigned char *COLON = ":";
+#else
+static const unsigned char COLON[] = { ':', '\0' };
+#endif
+/* Hashes a string to produce an unsigned short */
+static unsigned hash(const char *str)
+{
+    unsigned val = 0;
+    int i;
+
+    while (str && *str) {
+	i = (int) *str;
+	val ^= i;
+	val <<= 1;
+	str++;
+    }
+
+    return val;
+}
+
+static void CvtHex(HASH Bin, HASHHEX Hex)
+{
+    unsigned short  i;
+    unsigned char   j;
+    
+    for (i = 0; i < HASHLEN; i++) {
+	j = (Bin[i] >> 4) & 0xf;
+	if (j <= 9)
+	    Hex[i * 2] = (j + '0');
+	else
+	    Hex[i * 2] = (j + 'a' - 10);
+	j = Bin[i] & 0xf;
+	if (j <= 9)
+	    Hex[i * 2 + 1] = (j + '0');
+	else
+	    Hex[i * 2 + 1] = (j + 'a' - 10);
+    }
+    Hex[HASHHEXLEN] = '\0';
+}
+
+/*
+ * calculate request-digest/response-digest as per HTTP Digest spec
+ */
+void
+DigestCalcResponse(const sasl_utils_t * utils,
+		   HASHHEX HA1,	/* HEX(H(A1)) */
+		   unsigned char *pszNonce,	/* nonce from server */
+		   unsigned int pszNonceCount,	/* 8 hex digits */
+		   unsigned char *pszCNonce,	/* client nonce */
+		   unsigned char *pszQop,	/* qop-value: "", "auth",
+						 * "auth-int" */
+		   unsigned char *pszDigestUri,	/* requested URL */
+		   unsigned char *pszMethod,
+		   HASHHEX HEntity,	/* H(entity body) if qop="auth-int" */
+		   HASHHEX Response	/* request-digest or response-digest */
+    )
+{
+    MD5_CTX         Md5Ctx;
+    HASH            HA2;
+    HASH            RespHash;
+    HASHHEX         HA2Hex;
+    unsigned char ncvalue[10];
+    
+    /* calculate H(A2) */
+    utils->MD5Init(&Md5Ctx);
+    
+    if (pszMethod != NULL) {
+	utils->MD5Update(&Md5Ctx, pszMethod, (unsigned) strlen((char *) pszMethod));
+    }
+    utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
+    
+    /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
+    utils->MD5Update(&Md5Ctx, pszDigestUri, (unsigned) strlen((char *) pszDigestUri));
+    if (strcasecmp((char *) pszQop, "auth") != 0) {
+	/* append ":00000000000000000000000000000000" */
+	utils->MD5Update(&Md5Ctx, COLON, 1);
+	utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
+    }
+    utils->MD5Final(HA2, &Md5Ctx);
+    CvtHex(HA2, HA2Hex);
+    
+    /* calculate response */
+    utils->MD5Init(&Md5Ctx);
+    utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
+    utils->MD5Update(&Md5Ctx, COLON, 1);
+    utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
+    utils->MD5Update(&Md5Ctx, COLON, 1);
+    if (*pszQop) {
+	sprintf((char *)ncvalue, "%08x", pszNonceCount);
+	utils->MD5Update(&Md5Ctx, ncvalue, (unsigned) strlen((char *)ncvalue));
+	utils->MD5Update(&Md5Ctx, COLON, 1);
+	utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
+	utils->MD5Update(&Md5Ctx, COLON, 1);
+	utils->MD5Update(&Md5Ctx, pszQop, (unsigned) strlen((char *) pszQop));
+	utils->MD5Update(&Md5Ctx, COLON, 1);
+    }
+    utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
+    utils->MD5Final(RespHash, &Md5Ctx);
+    CvtHex(RespHash, Response);
+}
+
+static bool UTF8_In_8859_1(const unsigned char *base, size_t len)
+{
+    const unsigned char *scan, *end;
+    
+    end = base + len;
+    for (scan = base; scan < end; ++scan) {
+	if (*scan > 0xC3)
+	    break;			/* abort if outside 8859-1 */
+	if (*scan >= 0xC0 && *scan <= 0xC3) {
+	    if (++scan == end || *scan < 0x80 || *scan > 0xBF)
+		break;
+	}
+    }
+    
+    /* if scan >= end, then this is a 8859-1 string. */
+    return (scan >= end);
+}
+
+/*
+ * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
+ * 8859-1 prior to MD5
+ */
+static void MD5_UTF8_8859_1(const sasl_utils_t * utils,
+			    MD5_CTX * ctx,
+			    bool In_ISO_8859_1,
+			    const unsigned char *base,
+			    int len)
+{
+    const unsigned char *scan, *end;
+    unsigned char   cbuf;
+    
+    end = base + len;
+    
+    /* if we found a character outside 8859-1, don't alter string */
+    if (!In_ISO_8859_1) {
+	utils->MD5Update(ctx, base, len);
+	return;
+    }
+    /* convert to 8859-1 prior to applying hash */
+    do {
+	for (scan = base; scan < end && *scan < 0xC0; ++scan);
+	if (scan != base)
+	    utils->MD5Update(ctx, base, (unsigned) (scan - base));
+	if (scan + 1 >= end)
+	    break;
+	cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
+	utils->MD5Update(ctx, &cbuf, 1);
+	base = scan + 2;
+    }
+    while (base < end);
+}
+
+/**
+ * Returns true if it mangled the username.
+ */
+static bool DigestCalcSecret(const sasl_utils_t * utils,
+		            unsigned char *pszUserName,
+		            unsigned char *pszRealm,
+		            unsigned char *Password,
+		            int PasswordLen,
+		            bool Ignore_8859,
+		            HASH HA1)
+{
+    bool            In_8859_1;
+    bool            Any_8859_1 = FALSE;
+    MD5_CTX         Md5Ctx;
+    
+    /* Chris Newman clarified that the following text in DIGEST-MD5 spec
+       is bogus: "if name and password are both in ISO 8859-1 charset"
+       We shoud use code example instead */
+    
+    utils->MD5Init(&Md5Ctx);
+    
+    /* We have to convert UTF-8 to ISO-8859-1 if possible */
+    if (Ignore_8859 == FALSE) {
+	In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
+	MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+			pszUserName, (unsigned) strlen((char *) pszUserName));
+	Any_8859_1 |= In_8859_1;
+    } else {
+	utils->MD5Update(&Md5Ctx, pszUserName, (unsigned) strlen((char *) pszUserName));
+    }
+    
+    utils->MD5Update(&Md5Ctx, COLON, 1);
+    
+    /* a NULL realm is equivalent to the empty string */
+    if (pszRealm != NULL && pszRealm[0] != '\0') {
+	if (Ignore_8859 == FALSE) {
+	    /* We have to convert UTF-8 to ISO-8859-1 if possible */
+	    In_8859_1 = UTF8_In_8859_1(pszRealm, strlen((char *) pszRealm));
+	    MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+			    pszRealm, (unsigned) strlen((char *) pszRealm));
+	    Any_8859_1 |= In_8859_1;
+	} else {
+	   utils->MD5Update(&Md5Ctx, pszRealm, (unsigned) strlen((char *) pszRealm));
+	}
+    }  
+    
+    utils->MD5Update(&Md5Ctx, COLON, 1);
+
+    if (Ignore_8859 == FALSE) {
+	/* We have to convert UTF-8 to ISO-8859-1 if possible */
+	In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
+	MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+			Password, PasswordLen);
+	Any_8859_1 |= In_8859_1;
+    } else {
+	utils->MD5Update(&Md5Ctx, Password, PasswordLen);
+    }
+    utils->MD5Final(HA1, &Md5Ctx);
+
+    return Any_8859_1;
+}
+
+static unsigned char *create_nonce(const sasl_utils_t * utils)
+{
+    unsigned char  *base64buf;
+    int             base64len;
+    
+    char           *ret = (char *) utils->malloc(NONCE_SIZE);
+    if (ret == NULL)
+	return NULL;
+    
+    utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
+    
+    /* base 64 encode it so it has valid chars */
+    base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
+    
+    base64buf = (unsigned char *) utils->malloc(base64len + 1);
+    if (base64buf == NULL) {
+	utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
+	return NULL;
+    }
+    
+    /*
+     * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+     */
+    if (utils->encode64(ret, NONCE_SIZE,
+			(char *) base64buf, base64len, NULL) != SASL_OK) {
+	utils->free(ret);
+	return NULL;
+    }
+    utils->free(ret);
+    
+    return base64buf;
+}
+
+static int add_to_challenge(const sasl_utils_t *utils,
+			    char **str, unsigned *buflen, unsigned *curlen,
+			    char *name,
+			    unsigned char *value,
+			    bool need_quotes)
+{
+    size_t          namesize = strlen(name);
+    size_t          valuesize = strlen((char *) value);
+    unsigned        newlen;
+    int             ret;
+    
+    newlen = (unsigned) (*curlen + 1 + namesize + 2 + valuesize + 2);
+    ret = _plug_buf_alloc(utils, str, buflen, newlen);
+    if(ret != SASL_OK) return ret;
+
+    if (*curlen > 0) {
+	strcat(*str, ",");
+	strcat(*str, name);
+    } else {
+	strcpy(*str, name);
+    }
+    
+    if (need_quotes) {
+	strcat(*str, "=\"");
+
+	/* Check if the value needs quoting */
+	if (strpbrk ((char *)value, NEED_ESCAPING) != NULL) {
+	    char * quoted = quote ((char *) value);
+	    valuesize = strlen(quoted);
+	    /* As the quoted string is bigger, make sure we have enough
+	       space now */
+	    ret = _plug_buf_alloc(utils, str, buflen, newlen);
+	    if (ret == SASL_OK) {
+		strcat(*str, quoted);
+		free (quoted);
+	    } else {
+		free (quoted);
+		return ret;
+	    }
+	} else {
+	    strcat(*str, (char *) value);
+	}
+	strcat(*str, "\"");
+    } else {
+	strcat(*str, "=");
+	strcat(*str, (char *) value);
+    }
+    
+    *curlen = newlen;
+    return SASL_OK;
+}
+
+static int is_lws_char (char c)
+{
+    return (c == ' ' || c == HT || c == CR || c == LF);
+}
+
+static char *skip_lws (char *s)
+{
+    if (!s) return NULL;
+    
+    /* skipping spaces: */
+    while (is_lws_char(s[0])) {
+	if (s[0] == '\0') break;
+	s++;
+    }  
+    
+    return s;
+}
+
+/* Same as skip_lws, but do this right to left */
+/* skip LWSP at the end of the value (if any), skip_r_lws returns pointer to
+   the first LWSP character, NUL (if there were none) or NULL if the value
+   is entirely from LWSP characters */
+static char *skip_r_lws (char *s)
+{
+    char *end;
+    size_t len;
+
+    if (!s) return NULL;
+    
+    len = strlen(s);
+    if (len == 0) return NULL;
+
+    /* the last character before terminating NUL */
+    end = s + len - 1;
+
+    /* skipping spaces: */
+    while (end > s && (end[0] == ' ' || end[0] == HT || end[0] == CR || end[0] == LF)) {
+	end--;
+    }  
+
+    /* If all string from spaces, return NULL */
+    if (end == s && (end[0] == ' ' || end[0] == HT || end[0] == CR || end[0] == LF)) {
+	return NULL;
+    } else {
+	return (end + 1);
+    }
+}
+
+static char *skip_token (char *s, int caseinsensitive)
+{
+    if(!s) return NULL;
+    
+    while (s[0]>SP) {
+	if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
+	    s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
+	    s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
+	    s[0]=='=' || s[0]== '{' || s[0]== '}') {
+	    if (caseinsensitive == 1) {
+		if (!isupper((unsigned char) s[0]))
+		    break;
+	    } else {
+		break;
+	    }
+	}
+	s++;
+    }  
+    return s;
+}
+
+/* Convert a string to 32 bit unsigned integer.
+   Any number of trailing spaces is allowed, but not a string
+   entirely comprised of spaces */
+static bool str2ul32 (char *str, unsigned long * value)
+{
+    unsigned int n;
+    char c;
+
+    if (str == NULL) {
+	return (FALSE);
+    }
+    
+    *value = 0;
+
+    str = skip_lws (str);
+    if (str[0] == '\0') {
+	return (FALSE);
+    }
+
+    n = 0;
+    while (str[0] != '\0') {
+	c = str[0];
+	if (!isdigit((int)c)) {
+	    return (FALSE);
+	}
+
+/* Will overflow after adding additional digit */
+	if (n > MAX_UIN32_DIV_10) {
+	    return (FALSE);
+	} else if (n == MAX_UIN32_DIV_10 && ((unsigned) (c - '0') > MAX_UIN32_MOD_10)) {
+	    return (FALSE);
+	}
+
+	n = n * 10 + (unsigned) (c - '0');
+	str++;
+    }
+
+    *value = n;
+    return (TRUE);
+}
+
+/* NULL - error (unbalanced quotes), 
+   otherwise pointer to the first character after the value.
+   The function performs work in place. */
+static char *unquote (char *qstr)
+{
+    char *endvalue;
+    int   escaped = 0;
+    char *outptr;
+    
+    if(!qstr) return NULL;
+    
+    if (qstr[0] == '"') {
+	qstr++;
+	outptr = qstr;
+	
+	for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
+	    if (escaped) {
+		outptr[0] = endvalue[0];
+		escaped = 0;
+	    }
+	    else if (endvalue[0] == '\\') {
+		escaped = 1;
+		outptr--; /* Will be incremented at the end of the loop */
+	    }
+	    else if (endvalue[0] == '"') {
+		break;
+	    }      
+	    else {
+		outptr[0] = endvalue[0];      
+	    }
+	}
+	
+	if (endvalue[0] != '"') {
+	    return NULL;
+	}
+	
+	while (outptr <= endvalue) {
+	    outptr[0] = '\0';
+	    outptr++;
+	}
+	endvalue++;
+    }
+    else { /* not qouted value (token) */
+	/* qstr already contains output */
+	endvalue = skip_token(qstr,0);
+    };
+    
+    return endvalue;  
+}
+
+/* Unlike unquote, this function returns an allocated quoted copy */
+static char *quote (char *str)
+{
+    char *p;
+    char *outp;
+    char *result;
+    int num_to_escape;		/* How many characters need escaping */
+    
+    if (!str) return NULL;
+
+    num_to_escape = 0;
+    p = strpbrk (str, NEED_ESCAPING);
+    while (p != NULL) {
+	num_to_escape++;
+	p = strpbrk (p + 1, NEED_ESCAPING);
+    }
+
+    if (num_to_escape == 0) {
+	return (strdup (str));
+    }
+
+    result = malloc (strlen(str) + num_to_escape + 1);
+    for (p = str, outp = result; *p; p++) {
+	if (*p == '"' || *p == '\\') {
+	    *outp = '\\';
+	    outp++;
+	}
+	*outp = *p;
+	outp++;
+    }
+
+    *outp = '\0';
+    
+    return (result);
+}
+
+static void get_pair(char **in, char **name, char **value)
+{
+    char  *endpair;
+    char  *curp = *in;
+    *name = NULL;
+    *value = NULL;
+    
+    if (curp == NULL) return;
+
+    while (curp[0] != '\0') {
+	/* skipping spaces: */
+	curp = skip_lws(curp);
+        
+	/* 'LWS "," LWS "," ...' is allowed by the DIGEST-MD5 ABNF */
+	if (curp[0] == ',') {
+	    curp++;
+	} else {
+	    break;
+	}
+    }
+
+    if (curp[0] == '\0') {
+	/* End of the string is not an error */
+	*name = "";
+	return;
+    }
+
+    *name = curp;
+    
+    curp = skip_token(curp,1);
+    
+    /* strip wierd chars */
+    if (curp[0] != '=' && curp[0] != '\0') {
+	*curp++ = '\0';
+    };
+    
+    curp = skip_lws(curp);
+    
+    if (curp[0] != '=') { /* No '=' sign */ 
+	*name = NULL;
+	return;
+    }
+    
+    curp[0] = '\0';
+    curp++;
+    
+    curp = skip_lws(curp);  
+    
+    *value = (curp[0] == '"') ? curp+1 : curp;
+    
+    endpair = unquote (curp);
+    if (endpair == NULL) { /* Unbalanced quotes */ 
+	*name = NULL;
+	*value = NULL;
+	return;
+    }
+
+    /* An optional LWS is allowed after the value. Skip it. */
+    if (is_lws_char (endpair[0])) {
+	/* Remove the trailing LWS from the value */
+	*endpair++ = '\0'; 
+	endpair = skip_lws(endpair);
+    }
+
+    /* syntax check: MUST be '\0' or ',' */  
+    if (endpair[0] == ',') {
+	endpair[0] = '\0';
+	endpair++; /* skipping <,> */
+    } else if (endpair[0] != '\0') { 
+	*name = NULL;
+	*value = NULL;
+	return;
+    }
+    
+    *in = endpair;
+}
+
+#ifdef WITH_DES
+struct des_context_s {
+    des_key_schedule keysched;  /* key schedule for des initialization */
+    des_cblock ivec;            /* initial vector for encoding */
+    des_key_schedule keysched2; /* key schedule for 3des initialization */
+};
+
+typedef struct des_context_s des_context_t;
+
+/* slide the first 7 bytes of 'inbuf' into the high seven bits of the
+   first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
+static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
+{
+    keybuf[0] = inbuf[0];
+    keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
+    keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
+    keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
+    keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
+    keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
+    keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
+    keybuf[7] = (inbuf[6]<<1);
+}
+
+/******************************
+ *
+ * 3DES functions
+ *
+ *****************************/
+
+static int dec_3des(context_t *text,
+		    const char *input,
+		    unsigned inputlen,
+		    unsigned char digest[16] __attribute__((unused)),
+		    char *output,
+		    unsigned *outputlen)
+{
+    des_context_t *c = (des_context_t *) text->cipher_dec_context;
+    int padding, p;
+    
+    des_ede2_cbc_encrypt((void *) input,
+			 (void *) output,
+			 inputlen,
+			 c->keysched,
+			 c->keysched2,
+			 &c->ivec,
+			 DES_DECRYPT);
+    
+    /* now chop off the padding */
+    padding = output[inputlen - 11];
+    if (padding < 1 || padding > 8) {
+	/* invalid padding length */
+	return SASL_FAIL;
+    }
+    /* verify all padding is correct */
+    for (p = 1; p <= padding; p++) {
+	if (output[inputlen - 10 - p] != padding) {
+	    return SASL_FAIL;
+	}
+    }
+    
+    /* chop off the padding */
+    *outputlen = inputlen - padding - 10;
+
+    return SASL_OK;
+}
+
+static int enc_3des(context_t *text,
+		    const char *input,
+		    unsigned inputlen,
+		    unsigned char digest[16],
+		    char *output,
+		    unsigned *outputlen)
+{
+    des_context_t *c = (des_context_t *) text->cipher_enc_context;
+    int len;
+    int paddinglen;
+    
+    /* determine padding length */
+    paddinglen = 8 - ((inputlen + 10) % 8);
+    
+    /* now construct the full stuff to be ciphered */
+    memcpy(output, input, inputlen);                /* text */
+    memset(output+inputlen, paddinglen, paddinglen);/* pad  */
+    memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
+    
+    len=inputlen+paddinglen+10;
+    
+    des_ede2_cbc_encrypt((void *) output,
+			 (void *) output,
+			 len,
+			 c->keysched,
+			 c->keysched2,
+			 &c->ivec,
+			 DES_ENCRYPT);
+    
+    *outputlen=len;
+    
+    return SASL_OK;
+}
+
+static int init_3des(context_t *text, 
+		     unsigned char enckey[16],
+		     unsigned char deckey[16])
+{
+    des_context_t *c;
+    unsigned char keybuf[8];
+
+    /* allocate enc & dec context */
+    c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
+    if (c == NULL) return SASL_NOMEM;
+
+    /* setup enc context */
+    slidebits(keybuf, enckey);
+    if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
+	return SASL_FAIL;
+
+    slidebits(keybuf, enckey + 7);
+    if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
+	return SASL_FAIL;
+    memcpy(c->ivec, ((char *) enckey) + 8, 8);
+
+    text->cipher_enc_context = (cipher_context_t *) c;
+
+    /* setup dec context */
+    c++;
+    slidebits(keybuf, deckey);
+    if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
+	return SASL_FAIL;
+    
+    slidebits(keybuf, deckey + 7);
+    if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
+	return SASL_FAIL;
+    
+    memcpy(c->ivec, ((char *) deckey) + 8, 8);
+
+    text->cipher_dec_context = (cipher_context_t *) c;
+    
+    return SASL_OK;
+}
+
+
+/******************************
+ *
+ * DES functions
+ *
+ *****************************/
+
+static int dec_des(context_t *text, 
+		   const char *input,
+		   unsigned inputlen,
+		   unsigned char digest[16] __attribute__((unused)),
+		   char *output,
+		   unsigned *outputlen)
+{
+    des_context_t *c = (des_context_t *) text->cipher_dec_context;
+    int p, padding = 0;
+    
+    des_cbc_encrypt((void *) input,
+		    (void *) output,
+		    inputlen,
+		    c->keysched,
+		    &c->ivec,
+		    DES_DECRYPT);
+
+    /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
+       this way) */
+    memcpy(c->ivec, input + (inputlen - 8), 8);
+    
+    /* now chop off the padding */
+    padding = output[inputlen - 11];
+    if (padding < 1 || padding > 8) {
+	/* invalid padding length */
+	return SASL_FAIL;
+    }
+    /* verify all padding is correct */
+    for (p = 1; p <= padding; p++) {
+	if (output[inputlen - 10 - p] != padding) {
+	    return SASL_FAIL;
+	}
+    }
+    
+    /* chop off the padding */
+    *outputlen = inputlen - padding - 10;
+
+    return SASL_OK;
+}
+
+static int enc_des(context_t *text,
+		   const char *input,
+		   unsigned inputlen,
+		   unsigned char digest[16],
+		   char *output,
+		   unsigned *outputlen)
+{
+    des_context_t *c = (des_context_t *) text->cipher_enc_context;
+    int len;
+    int paddinglen;
+  
+    /* determine padding length */
+    paddinglen = 8 - ((inputlen+10) % 8);
+
+    /* now construct the full stuff to be ciphered */
+    memcpy(output, input, inputlen);                /* text */
+    memset(output+inputlen, paddinglen, paddinglen);/* pad  */
+    memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
+    
+    len = inputlen + paddinglen + 10;
+    
+    des_cbc_encrypt((void *) output,
+                    (void *) output,
+                    len,
+                    c->keysched,
+                    &c->ivec,
+                    DES_ENCRYPT);
+    
+    /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
+       this way) */
+    memcpy(c->ivec, output + (len - 8), 8);
+    
+    *outputlen = len;
+    
+    return SASL_OK;
+}
+
+static int init_des(context_t *text,
+		    unsigned char enckey[16],
+		    unsigned char deckey[16])
+{
+    des_context_t *c;
+    unsigned char keybuf[8];
+
+    /* allocate enc context */
+    c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
+    if (c == NULL) return SASL_NOMEM;
+    
+    /* setup enc context */
+    slidebits(keybuf, enckey);
+    des_key_sched((des_cblock *) keybuf, c->keysched);
+
+    memcpy(c->ivec, ((char *) enckey) + 8, 8);
+    
+    text->cipher_enc_context = (cipher_context_t *) c;
+
+    /* setup dec context */
+    c++;
+    slidebits(keybuf, deckey);
+    des_key_sched((des_cblock *) keybuf, c->keysched);
+
+    memcpy(c->ivec, ((char *) deckey) + 8, 8);
+    
+    text->cipher_dec_context = (cipher_context_t *) c;
+
+    return SASL_OK;
+}
+
+static void free_des(context_t *text)
+{
+    /* free des contextss. only cipher_enc_context needs to be free'd,
+       since cipher_dec_context was allocated at the same time. */
+    if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
+}
+
+#endif /* WITH_DES */
+
+#ifdef WITH_RC4
+/* quick generic implementation of RC4 */
+struct rc4_context_s {
+    unsigned char sbox[256];
+    int i, j;
+};
+
+typedef struct rc4_context_s rc4_context_t;
+
+static void rc4_init(rc4_context_t *text,
+		     const unsigned char *key,
+		     unsigned keylen)
+{
+    int i, j;
+    
+    /* fill in linearly s0=0 s1=1... */
+    for (i=0;i<256;i++)
+	text->sbox[i]=i;
+    
+    j=0;
+    for (i = 0; i < 256; i++) {
+	unsigned char tmp;
+	/* j = (j + Si + Ki) mod 256 */
+	j = (j + text->sbox[i] + key[i % keylen]) % 256;
+	
+	/* swap Si and Sj */
+	tmp = text->sbox[i];
+	text->sbox[i] = text->sbox[j];
+	text->sbox[j] = tmp;
+    }
+    
+    /* counters initialized to 0 */
+    text->i = 0;
+    text->j = 0;
+}
+
+static void rc4_encrypt(rc4_context_t *text,
+			const char *input,
+			char *output,
+			unsigned len)
+{
+    int tmp;
+    int i = text->i;
+    int j = text->j;
+    int t;
+    int K;
+    const char *input_end = input + len;
+    
+    while (input < input_end) {
+	i = (i + 1) % 256;
+	
+	j = (j + text->sbox[i]) % 256;
+	
+	/* swap Si and Sj */
+	tmp = text->sbox[i];
+	text->sbox[i] = text->sbox[j];
+	text->sbox[j] = tmp;
+	
+	t = (text->sbox[i] + text->sbox[j]) % 256;
+	
+	K = text->sbox[t];
+	
+	/* byte K is Xor'ed with plaintext */
+	*output++ = *input++ ^ K;
+    }
+    
+    text->i = i;
+    text->j = j;
+}
+
+static void rc4_decrypt(rc4_context_t *text,
+			const char *input,
+			char *output,
+			unsigned len)
+{
+    int tmp;
+    int i = text->i;
+    int j = text->j;
+    int t;
+    int K;
+    const char *input_end = input + len;
+    
+    while (input < input_end) {
+	i = (i + 1) % 256;
+	
+	j = (j + text->sbox[i]) % 256;
+	
+	/* swap Si and Sj */
+	tmp = text->sbox[i];
+	text->sbox[i] = text->sbox[j];
+	text->sbox[j] = tmp;
+	
+	t = (text->sbox[i] + text->sbox[j]) % 256;
+	
+	K = text->sbox[t];
+	
+	/* byte K is Xor'ed with plaintext */
+	*output++ = *input++ ^ K;
+    }
+    
+    text->i = i;
+    text->j = j;
+}
+
+static void free_rc4(context_t *text)
+{
+    /* free rc4 context structures */
+
+    if(text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
+    if(text->cipher_dec_context) text->utils->free(text->cipher_dec_context);
+}
+
+static int init_rc4(context_t *text, 
+		    unsigned char enckey[16],
+		    unsigned char deckey[16])
+{
+    /* allocate rc4 context structures */
+    text->cipher_enc_context=
+	(cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
+    if (text->cipher_enc_context == NULL) return SASL_NOMEM;
+    
+    text->cipher_dec_context=
+	(cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
+    if (text->cipher_dec_context == NULL) return SASL_NOMEM;
+    
+    /* initialize them */
+    rc4_init((rc4_context_t *) text->cipher_enc_context,
+             (const unsigned char *) enckey, 16);
+    rc4_init((rc4_context_t *) text->cipher_dec_context,
+             (const unsigned char *) deckey, 16);
+    
+    return SASL_OK;
+}
+
+static int dec_rc4(context_t *text,
+		   const char *input,
+		   unsigned inputlen,
+		   unsigned char digest[16] __attribute__((unused)),
+		   char *output,
+		   unsigned *outputlen)
+{
+    /* decrypt the text part & HMAC */
+    rc4_decrypt((rc4_context_t *) text->cipher_dec_context, 
+                input, output, inputlen);
+
+    /* no padding so we just subtract the HMAC to get the text length */
+    *outputlen = inputlen - 10;
+    
+    return SASL_OK;
+}
+
+static int enc_rc4(context_t *text,
+		   const char *input,
+		   unsigned inputlen,
+		   unsigned char digest[16],
+		   char *output,
+		   unsigned *outputlen)
+{
+    /* pad is zero */
+    *outputlen = inputlen+10;
+    
+    /* encrypt the text part */
+    rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
+                input,
+                output,
+                inputlen);
+    
+    /* encrypt the HMAC part */
+    rc4_encrypt((rc4_context_t *) text->cipher_enc_context, 
+                (const char *) digest, 
+		(output)+inputlen, 10);
+    
+    return SASL_OK;
+}
+
+#endif /* WITH_RC4 */
+
+struct digest_cipher available_ciphers[] =
+{
+#ifdef WITH_RC4
+    { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+    { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+    { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+#endif
+#ifdef WITH_DES
+    { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
+    { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
+#endif
+    { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+static int create_layer_keys(context_t *text,
+			     const sasl_utils_t *utils,
+			     HASH key, int keylen,
+			     unsigned char enckey[16],
+			     unsigned char deckey[16])
+{
+    MD5_CTX Md5Ctx;
+    
+    utils->log(utils->conn, SASL_LOG_DEBUG,
+	       "DIGEST-MD5 create_layer_keys()");
+
+    utils->MD5Init(&Md5Ctx);
+    utils->MD5Update(&Md5Ctx, key, keylen);
+    if (text->i_am == SERVER) {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT, 
+			 (unsigned) strlen(SEALING_SERVER_CLIENT));
+    } else {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
+			 (unsigned) strlen(SEALING_CLIENT_SERVER));
+    }
+    utils->MD5Final(enckey, &Md5Ctx);
+    
+    utils->MD5Init(&Md5Ctx);
+    utils->MD5Update(&Md5Ctx, key, keylen);
+    if (text->i_am != SERVER) {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT, 
+			 (unsigned) strlen(SEALING_SERVER_CLIENT));
+    } else {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
+			 (unsigned) strlen(SEALING_CLIENT_SERVER));
+    }
+    utils->MD5Final(deckey, &Md5Ctx);
+    
+    /* create integrity keys */
+    /* sending */
+    utils->MD5Init(&Md5Ctx);
+    utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
+    if (text->i_am == SERVER) {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT, 
+			 (unsigned) strlen(SIGNING_SERVER_CLIENT));
+    } else {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
+			 (unsigned) strlen(SIGNING_CLIENT_SERVER));
+    }
+    utils->MD5Final(text->Ki_send, &Md5Ctx);
+    
+    /* receiving */
+    utils->MD5Init(&Md5Ctx);
+    utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
+    if (text->i_am != SERVER) {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT, 
+			 (unsigned) strlen(SIGNING_SERVER_CLIENT));
+    } else {
+	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
+			 (unsigned) strlen(SIGNING_CLIENT_SERVER));
+    }
+    utils->MD5Final(text->Ki_receive, &Md5Ctx);
+    
+    return SASL_OK;
+}
+
+static const unsigned short version = 1;
+
+/*
+ * privacy:
+ * len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum
+ *
+ * integrity:
+ * len, HMAC(ki, {SeqNum, msg})[0..9], x0001, SeqNum
+ */
+static int digestmd5_encode(void *context,
+			    const struct iovec *invec,
+			    unsigned numiov,
+			    const char **output,
+			    unsigned *outputlen)
+{
+    context_t *text = (context_t *) context;
+    int tmp;
+    unsigned int tmpnum;
+    unsigned short int tmpshort;
+    int ret;
+    char *out;
+    struct buffer_info *inblob, bufinfo;
+    
+    if(!context || !invec || !numiov || !output || !outputlen) {
+	PARAMERROR(text->utils);
+	return SASL_BADPARAM;
+    }
+    
+    if (numiov > 1) {
+	ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
+	if (ret != SASL_OK) return ret;
+	inblob = text->enc_in_buf;
+    } else {
+	/* avoid the data copy */
+	bufinfo.data = invec[0].iov_base;
+	bufinfo.curlen = invec[0].iov_len;
+	inblob = &bufinfo;
+    }
+    
+    /* make sure the output buffer is big enough for this blob */
+    ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
+			  &(text->encode_buf_len),
+			  (4 +			/* for length */
+			   inblob->curlen +	/* for content */
+			   10 +			/* for MAC */
+			   8 +			/* maximum pad */
+			   6));			/* for ver and seqnum */
+    if(ret != SASL_OK) return ret;
+    
+    /* skip by the length for now */
+    out = (text->encode_buf)+4;
+    
+    /* construct (seqnum, msg)
+     *
+     * Use the output buffer so that the message text is already in place
+     * for an integrity-only layer.
+     */
+    tmpnum = htonl(text->seqnum);
+    memcpy(text->encode_buf, &tmpnum, 4);
+    memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
+    
+    if (text->cipher_enc) {
+	unsigned char digest[16];
+
+	/* HMAC(ki, (seqnum, msg) ) */
+	text->utils->hmac_md5((const unsigned char *) text->encode_buf,
+			      inblob->curlen + 4, 
+			      text->Ki_send, HASHLEN, digest);
+
+	/* calculate the encrypted part */
+	text->cipher_enc(text, inblob->data, inblob->curlen,
+			 digest, out, outputlen);
+	out+=(*outputlen);
+    }
+    else {
+	/* HMAC(ki, (seqnum, msg) ) -- put directly into output buffer */
+	text->utils->hmac_md5((const unsigned char *) text->encode_buf,
+			      inblob->curlen + 4, 
+			      text->Ki_send, HASHLEN,
+			      (unsigned char *) text->encode_buf +
+						inblob->curlen + 4);
+
+	*outputlen = inblob->curlen + 10; /* for message + CMAC */
+	out+=inblob->curlen + 10;
+    }
+    
+    /* copy in version */
+    tmpshort = htons(version);
+    memcpy(out, &tmpshort, 2);	/* 2 bytes = version */
+    
+    out+=2;
+    (*outputlen)+=2; /* for version */
+    
+    /* put in seqnum */
+    tmpnum = htonl(text->seqnum);
+    memcpy(out, &tmpnum, 4);	/* 4 bytes = seq # */  
+    
+    (*outputlen)+=4; /* for seqnum */
+    
+    /* put the 1st 4 bytes in */
+    tmp=htonl(*outputlen);  
+    memcpy(text->encode_buf, &tmp, 4);
+    
+    (*outputlen)+=4;
+    
+    *output = text->encode_buf;
+    text->seqnum++;
+    
+    return SASL_OK;
+}
+
+static int digestmd5_decode_packet(void *context,
+					   const char *input,
+					   unsigned inputlen,
+					   char **output,
+					   unsigned *outputlen)
+{
+    context_t *text = (context_t *) context;
+    int result;
+    unsigned char *digest;
+    int tmpnum;
+    int lup;
+    unsigned short ver;
+    unsigned int seqnum;
+    unsigned char checkdigest[16];
+	
+    if (inputlen < 16) {
+	text->utils->seterror(text->utils->conn, 0, "DIGEST-MD5 SASL packets must be at least 16 bytes long");
+	return SASL_FAIL;
+    }
+
+    /* check the version number */
+    memcpy(&ver, input+inputlen-6, 2);
+    ver = ntohs(ver);
+    if (ver != version) {
+	text->utils->seterror(text->utils->conn, 0, "Wrong Version");
+	return SASL_FAIL;
+    }
+	
+    /* check the sequence number */
+    memcpy(&seqnum, input+inputlen-4, 4);
+    seqnum = ntohl(seqnum);
+	
+    if (seqnum != text->rec_seqnum) {
+	text->utils->seterror(text->utils->conn, 0,
+	    "Incorrect Sequence Number: received %u, expected %u",
+	    seqnum,
+	    text->rec_seqnum);
+	return SASL_FAIL;
+    }
+
+    /* allocate a buffer large enough for the output */
+    result = _plug_buf_alloc(text->utils, &text->decode_packet_buf,
+			     &text->decode_packet_buf_len,
+			     inputlen	/* length of message */
+			     - 6	/* skip ver and seqnum */
+			     + 4);	/* prepend seqnum */
+    if (result != SASL_OK) return result;
+	
+    /* construct (seqnum, msg) */
+    tmpnum = htonl(text->rec_seqnum);
+    memcpy(text->decode_packet_buf, &tmpnum, 4);
+
+    text->rec_seqnum++; /* now increment it */
+
+    *output = text->decode_packet_buf + 4; /* skip seqnum */
+
+    if (text->cipher_dec) {
+	/* decrypt message & HMAC into output buffer */
+	result = text->cipher_dec(text, input, inputlen-6, NULL,
+				  *output, outputlen);
+	if (result != SASL_OK) return result;
+    }
+    else {
+	/* copy message & HMAC into output buffer */
+	memcpy(*output, input, inputlen - 6);
+	*outputlen = inputlen - 16; /* -16 to skip HMAC, ver and seqnum */
+    }
+    digest = (unsigned char *) *output + (inputlen - 16);
+
+    /* check the CMAC */
+
+    /* HMAC(ki, (seqnum, msg) ) */
+    text->utils->hmac_md5((const unsigned char *) text->decode_packet_buf,
+			  (*outputlen) + 4, 
+			  text->Ki_receive, HASHLEN, checkdigest);
+	
+    /* now check it */
+    for (lup = 0; lup < 10; lup++)
+	if (checkdigest[lup] != digest[lup]) {
+	    text->utils->seterror(text->utils->conn, 0,
+				  "CMAC doesn't match at byte %d!", lup);
+	    return SASL_FAIL;
+	}
+	
+    return SASL_OK;
+}
+
+static int digestmd5_decode(void *context,
+				    const char *input, unsigned inputlen,
+				    const char **output, unsigned *outputlen)
+{
+    context_t *text = (context_t *) context;
+    int ret;
+    
+    ret = _plug_decode(&text->decode_context, input, inputlen,
+		       &text->decode_buf, &text->decode_buf_len, outputlen,
+		       digestmd5_decode_packet, text);
+    
+    *output = text->decode_buf;
+    
+    return ret;
+}
+
+static void digestmd5_common_mech_dispose(void *conn_context,
+					  const sasl_utils_t *utils)
+{
+    context_t *text = (context_t *) conn_context;
+    int lup;
+    
+    if (!text || !utils) return;
+    
+    utils->log(utils->conn, SASL_LOG_DEBUG,
+	       "DIGEST-MD5 common mech dispose");
+
+    if (text->authid) utils->free(text->authid);
+    if (text->realm) utils->free(text->realm);
+
+    if (text->realms) {
+	/* need to free all the realms */
+	for (lup = 0; lup < text->realm_cnt; lup++)
+	    utils->free (text->realms[lup]);
+	
+	utils->free(text->realms);
+    }
+
+    if (text->nonce) utils->free(text->nonce);
+    if (text->cnonce) utils->free(text->cnonce);
+
+    if (text->cipher_free) text->cipher_free(text);
+    
+    /* free the stuff in the context */
+    if (text->response_value) utils->free(text->response_value);
+    
+    _plug_decode_free(&text->decode_context);
+    if (text->encode_buf) utils->free(text->encode_buf);
+    if (text->decode_buf) utils->free(text->decode_buf);
+    if (text->decode_packet_buf) utils->free(text->decode_packet_buf);
+    if (text->out_buf) utils->free(text->out_buf);
+    
+    if (text->enc_in_buf) {
+	if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
+	utils->free(text->enc_in_buf);
+    }
+    
+    utils->free(conn_context);
+}
+
+static void clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
+			       const sasl_utils_t *utils)
+{
+    if (!reauth) return;
+
+    if (reauth->authid) utils->free(reauth->authid);
+    if (reauth->realm) utils->free(reauth->realm);
+    if (reauth->nonce) utils->free(reauth->nonce);
+    if (reauth->cnonce) utils->free(reauth->cnonce);
+
+    if (type == CLIENT) {
+	if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
+    }
+
+    memset(reauth, 0, sizeof(reauth_entry_t));
+}
+
+static void digestmd5_common_mech_free(void *glob_context,
+				       const sasl_utils_t *utils)
+{
+    digest_glob_context_t *my_glob_context =
+	(digest_glob_context_t *) glob_context;
+    reauth_cache_t *reauth_cache = my_glob_context->reauth;
+    size_t n;
+
+    utils->log(utils->conn, SASL_LOG_DEBUG,
+	       "DIGEST-MD5 common mech free");
+ 
+    /* Prevent anybody else from freeing this as well */
+    my_glob_context->reauth = NULL;
+
+    if (!reauth_cache) return;
+
+    for (n = 0; n < reauth_cache->size; n++) {
+	clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
+    }
+    if (reauth_cache->e) utils->free(reauth_cache->e);
+
+    if (reauth_cache->mutex) {
+	utils->mutex_free(reauth_cache->mutex);
+	reauth_cache->mutex = NULL;
+    }
+
+    utils->free(reauth_cache);
+}
+
+/*****************************  Server Section  *****************************/
+
+typedef struct server_context {
+    context_t common;
+
+    time_t timestamp;
+    int stale;				/* last nonce is stale */
+    sasl_ssf_t limitssf, requiressf;	/* application defined bounds */
+} server_context_t;
+
+static digest_glob_context_t server_glob_context;
+
+static void DigestCalcHA1FromSecret(context_t * text,
+				    const sasl_utils_t * utils,
+				    HASH HA1,
+				    unsigned char *authorization_id,
+				    unsigned char *pszNonce,
+				    unsigned char *pszCNonce,
+				    HASHHEX SessionKey)
+{
+    MD5_CTX Md5Ctx;
+    
+    /* calculate session key */
+    utils->MD5Init(&Md5Ctx);
+    if (text->http_mode) {
+	/* per RFC 2617 Errata ID 1649 */
+	HASHHEX HA1Hex;
+    
+	CvtHex(HA1, HA1Hex);
+	utils->MD5Update(&Md5Ctx, HA1Hex, HASHHEXLEN);
+    }
+    else {
+	/* per RFC 2831 */
+	utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
+    }
+    utils->MD5Update(&Md5Ctx, COLON, 1);
+    utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
+    utils->MD5Update(&Md5Ctx, COLON, 1);
+    utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
+    if (authorization_id != NULL) {
+	utils->MD5Update(&Md5Ctx, COLON, 1);
+	utils->MD5Update(&Md5Ctx, authorization_id,
+			(unsigned) strlen((char *) authorization_id));
+    }
+    utils->MD5Final(HA1, &Md5Ctx);
+    
+    CvtHex(HA1, SessionKey);
+    
+    
+    /* save HA1 because we need it to make the privacy and integrity keys */
+    memcpy(text->HA1, HA1, sizeof(HASH));
+}
+
+static char *create_response(context_t * text,
+			     const sasl_utils_t * utils,
+			     unsigned char *nonce,
+			     unsigned int ncvalue,
+			     unsigned char *cnonce,
+			     char *qop,
+			     const sasl_http_request_t *request,
+			     HASH Secret,
+			     char *authorization_id,
+			     char **response_value)
+{
+    HASHHEX         SessionKey;
+    HASH            EntityHash;
+    HASHHEX         HEntity;
+    HASHHEX         Response;
+    char           *result;
+    
+    if (qop == NULL) qop = "auth";
+    
+    DigestCalcHA1FromSecret(text,
+			    utils,
+			    Secret,
+			    (unsigned char *) authorization_id,
+			    nonce,
+			    cnonce,
+			    SessionKey);
+
+    if (text->http_mode) {
+	/* per RFC 2617 */
+	MD5_CTX Md5Ctx;
+
+	utils->MD5Init(&Md5Ctx);
+	utils->MD5Update(&Md5Ctx, request->entity, request->elen);
+	utils->MD5Final(EntityHash, &Md5Ctx);
+    }
+    else {
+	/* per RFC 2831 */
+	memset(EntityHash, 0, HASHLEN);
+    }
+    CvtHex(EntityHash, HEntity);
+
+    /* Calculate response for comparison with client's response */
+    DigestCalcResponse(utils,
+		       SessionKey,/* HEX(H(A1)) */
+		       nonce,	/* nonce from server */
+		       ncvalue,	/* 8 hex digits */
+		       cnonce,	/* client nonce */
+		       (unsigned char *) qop,	/* qop-value: "", "auth",
+						 * "auth-int" */
+		       (unsigned char *) request->uri,	/* requested URL */
+		       (unsigned char *) request->method,
+		       HEntity,	/* H(entity body) if qop="auth-int" */
+		       Response	/* request-digest or response-digest */
+	);
+    
+    result = utils->malloc(HASHHEXLEN + 1);
+    memcpy(result, Response, HASHHEXLEN);
+    result[HASHHEXLEN] = 0;
+    
+    /* Calculate response value for mutual auth with the client (NO Method) */
+    if (response_value != NULL) {
+	char * new_response_value;
+
+	DigestCalcResponse(utils,
+			   SessionKey,	/* HEX(H(A1)) */
+			   nonce,	/* nonce from server */
+			   ncvalue,	/* 8 hex digits */
+			   cnonce,	/* client nonce */
+			   (unsigned char *) qop,	/* qop-value: "", "auth",
+							 * "auth-int" */
+			   (unsigned char *) request->uri, /* requested URL */
+			   NULL,
+			   HEntity,	/* H(entity body) if qop="auth-int" */
+			   Response	/* request-digest or response-digest */
+	    );
+	
+	new_response_value = utils->realloc(*response_value, HASHHEXLEN + 1);
+	if (new_response_value == NULL) {
+	    free (*response_value);
+	    *response_value = NULL;
+	    return NULL;
+	}
+	*response_value = new_response_value;
+
+	memcpy(*response_value, Response, HASHHEXLEN);
+	(*response_value)[HASHHEXLEN] = 0;
+    }
+    return result;
+}
+
+static int get_server_realm(sasl_server_params_t * params, char **realm)
+{
+    /* look at user realm first */
+    if (params->user_realm != NULL) {
+	if(params->user_realm[0] != '\0') {
+	    *realm = (char *) params->user_realm;
+	} else {
+	    /* Catch improperly converted apps */
+	    params->utils->seterror(params->utils->conn, 0,
+				    "user_realm is an empty string!");
+	    return SASL_BADPARAM;
+	}
+    } else if (params->serverFQDN != NULL) {
+	*realm = (char *) params->serverFQDN;
+    } else {
+	params->utils->seterror(params->utils->conn, 0,
+				"no way to obtain DIGEST-MD5 realm");
+	return SASL_FAIL;
+    }
+    
+    return SASL_OK;
+}
+
+/*
+ * Convert hex string to int
+ */
+static int htoi(unsigned char *hexin, unsigned int *res)
+{
+    size_t             lup, inlen;
+    inlen = strlen((char *) hexin);
+    
+    *res = 0;
+    for (lup = 0; lup < inlen; lup++) {
+	switch (hexin[lup]) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	    *res = (*res << 4) + (hexin[lup] - '0');
+	    break;
+	    
+	case 'a':
+	case 'b':
+	case 'c':
+	case 'd':
+	case 'e':
+	case 'f':
+	    *res = (*res << 4) + (hexin[lup] - 'a' + 10);
+	    break;
+	    
+	case 'A':
+	case 'B':
+	case 'C':
+	case 'D':
+	case 'E':
+	case 'F':
+	    *res = (*res << 4) + (hexin[lup] - 'A' + 10);
+	    break;
+	    
+	default:
+	    return SASL_BADPARAM;
+	}
+	
+    }
+    
+    return SASL_OK;
+}
+
+static int digestmd5_server_mech_new(void *glob_context,
+				     sasl_server_params_t * sparams,
+				     const char *challenge __attribute__((unused)),
+				     unsigned challen __attribute__((unused)),
+				     void **conn_context)
+{
+    context_t *text;
+    
+    /* holds state are in -- allocate server size */
+    text = sparams->utils->malloc(sizeof(server_context_t));
+    if (text == NULL)
+	return SASL_NOMEM;
+    memset(text, 0, sizeof(server_context_t));
+    
+    text->state = 1;
+    text->i_am = SERVER;
+    text->http_mode = (sparams->flags & SASL_NEED_HTTP);
+    text->reauth = ((digest_glob_context_t *) glob_context)->reauth;
+    
+    *conn_context = text;
+    return SASL_OK;
+}
+
+static int
+digestmd5_server_mech_step1(server_context_t *stext,
+			    sasl_server_params_t *sparams,
+			    const char *clientin __attribute__((unused)),
+			    unsigned clientinlen __attribute__((unused)),
+			    const char **serverout,
+			    unsigned *serveroutlen,
+			    sasl_out_params_t * oparams __attribute__((unused)))
+{
+    context_t *text = (context_t *) stext;
+    int             result;
+    char           *realm;
+    unsigned char  *nonce;
+    char           *charset = "utf-8";
+    char qop[1024], cipheropts[1024];
+    struct digest_cipher *cipher;
+    unsigned       resplen;
+    int added_conf = 0;
+    char maxbufstr[64];
+    
+    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+			"DIGEST-MD5 server step 1");
+
+    /* get realm */
+    result = get_server_realm(sparams, &realm);
+    if(result != SASL_OK) return result;
+    
+    /* what options should we offer the client? */
+    qop[0] = '\0';
+    cipheropts[0] = '\0';
+    if (stext->requiressf == 0) {
+	if (*qop) strcat(qop, ",");
+	strcat(qop, "auth");
+    }
+    if (stext->requiressf <= 1 && stext->limitssf >= 1) {
+	if (*qop) strcat(qop, ",");
+	strcat(qop, "auth-int");
+    }
+    
+    cipher = available_ciphers;
+    while (cipher->name) {
+	/* do we allow this particular cipher? */
+	if (stext->requiressf <= cipher->ssf &&
+	    stext->limitssf >= cipher->ssf) {
+	    if (!added_conf) {
+		if (*qop) strcat(qop, ",");
+		strcat(qop, "auth-conf");
+		added_conf = 1;
+	    }
+	    if (*cipheropts) strcat(cipheropts, ",");
+	    strcat(cipheropts, cipher->name);
+	}
+	cipher++;
+    }
+    
+    if (*qop == '\0') {
+	/* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
+	   that's close enough */
+	return SASL_TOOWEAK;
+    }
+    
+    /*
+     * digest-challenge  = 1#( realm | nonce | qop-options | stale | maxbuf |
+     * charset | cipher-opts | auth-param )
+     */
+    
+    nonce = create_nonce(sparams->utils);
+    if (nonce == NULL) {
+	SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
+	return SASL_FAIL;
+    }
+    
+    resplen = 0;
+    text->out_buf = NULL;
+    text->out_buf_len = 0;
+    if (add_to_challenge(sparams->utils,
+				  &text->out_buf, &text->out_buf_len, &resplen,
+				  "nonce", (unsigned char *) nonce,
+				  TRUE) != SASL_OK) {
+	SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+	return SASL_FAIL;
+    }
+
+    /* add to challenge; if we chose not to specify a realm, we won't
+     * send one to the client */
+    if (realm && add_to_challenge(sparams->utils,
+				  &text->out_buf, &text->out_buf_len, &resplen,
+				  "realm", (unsigned char *) realm,
+				  TRUE) != SASL_OK) {
+	SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+	return SASL_FAIL;
+    }
+    /*
+     * qop-options A quoted string of one or more tokens indicating the
+     * "quality of protection" values supported by the server.  The value
+     * "auth" indicates authentication; the value "auth-int" indicates
+     * authentication with integrity protection; the value "auth-conf"
+     * indicates authentication with integrity protection and encryption.
+     */
+    
+    /* add qop to challenge */
+    if (add_to_challenge(sparams->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "qop", 
+			 (unsigned char *) qop, TRUE) != SASL_OK) {
+	SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
+	return SASL_FAIL;
+    }
+    
+    /*
+     *  Cipheropts - list of ciphers server supports
+     */
+    /* add cipher-opts to challenge; only add if there are some */
+    if (strcmp(cipheropts,"")!=0)
+	{
+	    if (add_to_challenge(sparams->utils,
+				 &text->out_buf, &text->out_buf_len, &resplen,
+				 "cipher", (unsigned char *) cipheropts, 
+				 TRUE) != SASL_OK) {
+		SETERROR(sparams->utils,
+			 "internal error: add_to_challenge 4 failed");
+		return SASL_FAIL;
+	    }
+	}
+    
+    /* "stale" is true if a reauth failed because of a nonce timeout */
+    if (stext->stale &&
+	add_to_challenge(sparams->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "stale", (unsigned char *) "true", FALSE) != SASL_OK) {
+	SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+	return SASL_FAIL;
+    }
+    
+    /*
+     * maxbuf A number indicating the size of the largest buffer the server
+     * is able to receive when using "auth-int". If this directive is
+     * missing, the default value is 65536. This directive may appear at most
+     * once; if multiple instances are present, the client should abort the
+     * authentication exchange.
+     */
+    if(sparams->props.maxbufsize) {
+	snprintf(maxbufstr, sizeof(maxbufstr), "%u",
+		 sparams->props.maxbufsize);
+	if (add_to_challenge(sparams->utils,
+			     &text->out_buf, &text->out_buf_len, &resplen,
+			     "maxbuf", 
+			     (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
+	    SETERROR(sparams->utils,
+		     "internal error: add_to_challenge 5 failed");
+	    return SASL_FAIL;
+	}
+    }
+    
+    if (add_to_challenge(sparams->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "charset", 
+			 (unsigned char *) charset, FALSE) != SASL_OK) {
+	SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
+	return SASL_FAIL;
+    }
+    
+    
+    /*
+     * algorithm 
+     *  This directive is required for backwards compatibility with HTTP 
+     *  Digest, which supports other algorithms. This directive is 
+     *  required and MUST appear exactly once; if not present, or if multiple 
+     *  instances are present, the client should abort the authentication 
+     *  exchange. 
+     *
+     * algorithm         = "algorithm" "=" "md5-sess" 
+     */
+    
+    if (add_to_challenge(sparams->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "algorithm",
+			 (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
+	SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
+	return SASL_FAIL;
+    }
+    
+    /*
+     * The size of a digest-challenge MUST be less than 2048 bytes!!!
+     */
+    if (*serveroutlen > 2048) {
+	SETERROR(sparams->utils,
+		 "internal error: challenge larger than 2048 bytes");
+	return SASL_FAIL;
+    }
+
+    text->authid = NULL;
+    if (_plug_strdup(sparams->utils, realm, &text->realm, NULL) != SASL_OK) {
+	SETERROR(sparams->utils,
+		 "internal error: out of memory when saving realm");
+	return SASL_FAIL;
+    }
+
+    if (text->http_mode &&
+	sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+
+	/* Create an initial cache entry for non-persistent HTTP connections */
+	unsigned val = hash((char *) nonce) % text->reauth->size;
+
+	clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+	text->reauth->e[val].authid = NULL;
+	text->reauth->e[val].realm = text->realm; text->realm = NULL;
+	text->reauth->e[val].nonce = nonce;
+	text->reauth->e[val].nonce_count = 1;
+	text->reauth->e[val].cnonce = NULL;
+	text->reauth->e[val].u.s.timestamp = time(0);
+
+	sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+    }
+    else {
+	text->nonce = nonce;
+	text->nonce_count = 1;
+	text->cnonce = NULL;
+	stext->timestamp = time(0);
+    }
+    
+    *serveroutlen = (unsigned) strlen(text->out_buf);
+    *serverout = text->out_buf;
+    
+    text->state = 2;
+    
+    return SASL_CONTINUE;
+}
+
+static int digestmd5_server_mech_step2(server_context_t *stext,
+				       sasl_server_params_t *sparams,
+				       const char *clientin,
+				       unsigned clientinlen,
+				       const char **serverout,
+				       unsigned *serveroutlen,
+				       sasl_out_params_t * oparams)
+{
+    context_t *text = (context_t *) stext;
+    /* verify digest */
+    sasl_secret_t  *sec = NULL;
+    int             result;
+    char           *serverresponse = NULL;
+    char           *username = NULL;
+    char           *authorization_id = NULL;
+    char           *realm = NULL;
+    unsigned char  *nonce = NULL, *cnonce = NULL;
+    unsigned int   noncecount = 0;
+    char           *qop = NULL;
+    char           *digesturi = NULL;
+    sasl_http_request_t rfc2831_request;
+    const sasl_http_request_t *request;
+    char           *response = NULL;
+    
+    /* setting the default value (65536) */
+    unsigned long  client_maxbuf = 65536;
+    int            maxbuf_count = 0;  /* How many maxbuf instances was found */
+    
+    char           *charset = NULL;
+    char           *cipher = NULL;
+    unsigned int   n = 0;
+    
+    HASH           Secret;
+    HASH           SecretBogus;
+    bool           Try_8859_1 = FALSE;
+    int            client_ignores_realm = 0;
+    char           *full_username = NULL;
+    char           *internal_username = NULL;
+    int            canon_flags;
+
+    /* password prop_request */
+    const char *password_request[] = { SASL_AUX_PASSWORD,
+				       "*cmusaslsecretDIGEST-MD5",
+				       NULL };
+    size_t len;
+    struct propval auxprop_values[2];
+    
+    /* can we mess with clientin? copy it to be safe */
+    char           *in_start = NULL;
+    char           *in = NULL;
+    cipher_free_t  *old_cipher_free = NULL;
+    
+    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+			"DIGEST-MD5 server step 2");
+
+    if (clientinlen == 0) {
+	SETERROR(sparams->utils, "input expected in DIGEST-MD5, step 2");
+	result = SASL_BADAUTH;
+	goto FreeAllMem;
+    }
+
+    if (text->http_mode) {
+	/* per RFC 2617 (HTTP Request as set by calling application) */
+	request = sparams->http_request;
+	if (!request) {
+	    SETERROR(sparams->utils,
+		     "missing HTTP request in DIGEST-MD5, step 2");
+	    result = SASL_BADPARAM;
+	    goto FreeAllMem;
+	}
+    }
+    else {
+	/* per RFC 2831 */
+	rfc2831_request.method = "AUTHENTICATE";
+	rfc2831_request.uri = NULL;  /* to be filled in below from response */
+	rfc2831_request.entity = NULL;
+	rfc2831_request.elen = 0;
+	rfc2831_request.non_persist = 0;
+	request = &rfc2831_request;
+    }
+    
+    in = sparams->utils->malloc(clientinlen + 1);
+    
+    memcpy(in, clientin, clientinlen);
+    in[clientinlen] = 0;
+    
+    in_start = in;
+    
+    
+    /* parse what we got */
+    while (in[0] != '\0') {
+	char           *name = NULL, *value = NULL;
+	get_pair(&in, &name, &value);
+	
+	if (name == NULL) {
+	    SETERROR(sparams->utils,
+		     "Parse error");
+	    result = SASL_BADAUTH;
+	    goto FreeAllMem;
+	}
+	
+	if (*name == '\0') {
+	    break;
+	}
+
+	/* Extracting parameters */
+	
+	/*
+	 * digest-response  = 1#( username | realm | nonce | cnonce |
+	 * nonce-count | qop | digest-uri | response | maxbuf | charset |
+	 * cipher | auth-param )
+	 */
+	
+	if (strcasecmp(name, "username") == 0) {
+	    _plug_strdup(sparams->utils, value, &username, NULL);
+	} else if (strcasecmp(name, "authzid") == 0) {
+	    _plug_strdup(sparams->utils, value, &authorization_id, NULL);
+	} else if (strcasecmp(name, "cnonce") == 0) {
+	    _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
+	} else if (strcasecmp(name, "nc") == 0) {
+	    if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
+		SETERROR(sparams->utils,
+			 "error converting hex to int");
+		result = SASL_BADAUTH;
+		goto FreeAllMem;
+	    }
+	} else if (strcasecmp(name, "realm") == 0) {
+	    if (realm) {
+		SETERROR(sparams->utils,
+			 "duplicate realm: authentication aborted");
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+	    _plug_strdup(sparams->utils, value, &realm, NULL);
+	} else if (strcasecmp(name, "nonce") == 0) {
+	    _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
+	} else if (strcasecmp(name, "qop") == 0) {
+	    if (qop) {
+		SETERROR(sparams->utils,
+			 "duplicate qop: authentication aborted");
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+	    _plug_strdup(sparams->utils, value, &qop, NULL);
+	} else if (strcasecmp(name, "digest-uri") == 0 ||  /* per RFC 2831 */
+		   (text->http_mode &&
+		    strcasecmp(name, "uri") == 0)) {	   /* per RFC 2617 */
+            size_t service_len;
+
+	    if (digesturi) {
+		SETERROR(sparams->utils,
+			 "duplicate digest-uri: authentication aborted");
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+
+	    _plug_strdup(sparams->utils, value, &digesturi, NULL);
+
+	    if (text->http_mode && request && request->uri) {
+		/* Verify digest-uri matches HTTP request (per RFC 2617) */
+		if (strcmp(digesturi, request->uri)) {
+		    result = SASL_BADAUTH;
+		    SETERROR(sparams->utils, 
+			     "bad digest-uri: doesn't match HTTP request");
+		    goto FreeAllMem;
+		}
+	    }
+	    else {
+		/* Verify digest-uri format (per RFC 2831):
+		 *
+		 * digest-uri-value  = serv-type "/" host [ "/" serv-name ]
+		 */
+
+		/* make sure it's the service that we're expecting */
+		service_len = strlen(sparams->service);
+		if (strncasecmp(digesturi, sparams->service, service_len) ||
+		    digesturi[service_len] != '/') {
+		    result = SASL_BADAUTH;
+		    SETERROR(sparams->utils, 
+			     "bad digest-uri: doesn't match service");
+		    goto FreeAllMem;
+		}
+
+		/* xxx we don't verify the hostname component */
+
+		rfc2831_request.uri = digesturi;
+	    }
+            
+	} else if (strcasecmp(name, "response") == 0) {
+	    _plug_strdup(sparams->utils, value, &response, NULL);
+	} else if (strcasecmp(name, "cipher") == 0) {
+	    _plug_strdup(sparams->utils, value, &cipher, NULL);
+	} else if (strcasecmp(name, "maxbuf") == 0) {
+	    maxbuf_count++;
+	    if (maxbuf_count != 1) {
+		result = SASL_BADAUTH;
+		SETERROR(sparams->utils,
+			 "duplicate maxbuf: authentication aborted");
+		goto FreeAllMem;
+	    } else if (str2ul32 (value, &client_maxbuf) == FALSE) {
+		result = SASL_BADAUTH;
+		SETERROR(sparams->utils, "invalid maxbuf parameter");
+		goto FreeAllMem;
+	    } else {
+		if (client_maxbuf <= 16) {
+		    result = SASL_BADAUTH;
+		    SETERROR(sparams->utils,
+			     "maxbuf parameter too small");
+		    goto FreeAllMem;
+		}
+
+		if (client_maxbuf > MAX_SASL_BUFSIZE) {
+		    result = SASL_BADAUTH;
+		    SETERROR(sparams->utils,
+			     "maxbuf parameter too big");
+		    goto FreeAllMem;
+		}
+	    }
+	} else if (strcasecmp(name, "charset") == 0) {
+	    if (strcasecmp(value, "utf-8") != 0) {
+		SETERROR(sparams->utils, "client doesn't support UTF-8");
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+	    _plug_strdup(sparams->utils, value, &charset, NULL);
+	} else if (strcasecmp(name,"algorithm") == 0) {
+	    /* per RFC 2831: algorithm MUST be ignored if received */
+	    if (text->http_mode && strcasecmp(value, "md5-sess") != 0) {
+		/* per RFC 2617: algorithm MUST match that sent in challenge */
+		SETERROR(sparams->utils, "'algorithm' isn't 'md5-sess'");
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+	} else {
+	    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+				"DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+				name, value);
+	}
+    }
+    
+    /*
+     * username         = "username" "=" <"> username-value <">
+     * username-value   = qdstr-val
+     * cnonce           = "cnonce" "=" <"> cnonce-value <"> 
+     * cnonce-value     = qdstr-val
+     * nonce-count      = "nc" "=" nc-value
+     * nc-value         = 8LHEX
+     * qop              = "qop" "=" qop-value
+     * digest-uri       = "digest-uri" "=" digest-uri-value
+     * digest-uri-value = serv-type "/" host [ "/" serv-name ]
+     * serv-type        = 1*ALPHA
+     * host             = 1*( ALPHA | DIGIT | "-" | "." )
+     * service          = host
+     * response         = "response" "=" <"> response-value <">
+     * response-value   = 32LHEX
+     * LHEX             = "0" | "1" | "2" | "3" | "4" | "5" |
+     * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f"
+     * cipher           = "cipher" "=" cipher-value
+     */
+    /* Verifing that all required parameters were received */
+    if ((username == NULL)) {
+	SETERROR(sparams->utils, "required parameters missing: username");
+	result = SASL_BADAUTH;
+	goto FreeAllMem;
+    }
+    if ((nonce == NULL)) {
+	SETERROR(sparams->utils, "required parameters missing: nonce");
+	result = SASL_BADAUTH;
+	goto FreeAllMem;
+    }
+    if ((noncecount == 0)) {
+	SETERROR(sparams->utils, "required parameters missing: noncecount");
+	result = SASL_BADAUTH;
+	goto FreeAllMem;
+    }
+    if ((cnonce == NULL)) {
+	SETERROR(sparams->utils, "required parameters missing: cnonce");
+	result = SASL_BADAUTH;
+	goto FreeAllMem;
+    }
+    if ((digesturi == NULL)) {
+	SETERROR(sparams->utils, "required parameters missing: digesturi");
+	result = SASL_BADAUTH;
+	goto FreeAllMem;
+    }
+    if ((response == NULL)) {
+	SETERROR(sparams->utils, "required parameters missing: response");
+	result = SASL_BADAUTH;
+	goto FreeAllMem;
+    }
+
+    if (realm == NULL) {
+        /* From 2831bis:
+           If the directive is missing, "realm-value" will set to
+           the empty string when computing A1. */
+	_plug_strdup(sparams->utils, "", &realm, NULL);
+	sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+			"The client didn't send a realm, assuming empty string.");
+#if 0
+        if (text->realm[0] != '\0') {
+            SETERROR(sparams->utils,
+		 "realm changed: authentication aborted");
+            result = SASL_BADAUTH;
+            goto FreeAllMem;
+        }
+#endif
+    }
+
+    if (!text->nonce) {
+	unsigned val = hash((char *) nonce) % text->reauth->size;
+
+	/* reauth attempt or continuation of HTTP Digest on a
+	   non-persistent connection, see if we have any info for this nonce */
+	if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+	    if (text->reauth->e[val].realm &&
+		!strcmp(realm, text->reauth->e[val].realm) &&
+		((text->reauth->e[val].nonce_count == 1) ||
+		 (text->reauth->e[val].authid &&
+		  !strcmp(username, text->reauth->e[val].authid)))) {
+
+		_plug_strdup(sparams->utils, text->reauth->e[val].realm,
+			     &text->realm, NULL);
+		_plug_strdup(sparams->utils, (char *) text->reauth->e[val].nonce,
+			     (char **) &text->nonce, NULL);
+		text->nonce_count = text->reauth->e[val].nonce_count;
+#if 0  /* XXX  Neither RFC 2617 nor RFC 2831 state that the cnonce
+	  needs to remain constant for subsequent authentication to work */
+		_plug_strdup(sparams->utils, (char *) text->reauth->e[val].cnonce,
+			     (char **) &text->cnonce, NULL);
+#endif
+		stext->timestamp = text->reauth->e[val].u.s.timestamp;
+	    }
+	    sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+	}
+
+	if (!text->nonce) {
+	    /* we don't have any reauth info */
+	    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+				"No reauth info for '%s' found", nonce);
+
+	    /* we will continue processing the response to determine
+	       if the client knows the password and return stale accordingly */
+	}
+    }
+
+    /* Sanity check the parameters */
+    if (text->nonce) {
+	/* CLAIM: realm is not NULL below */
+	if (text->realm == NULL) {
+	    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+				"The client specifies a realm when the server hasn't provided one. Using client's realm.");
+	    _plug_strdup(sparams->utils, realm, &text->realm, NULL);
+	} else if ((strcmp(realm, text->realm) != 0) &&
+		   /* XXX - Not sure why the check for text->realm not being empty is needed,
+		      as it should always be non-empty */
+		   (text->realm[0] != 0)) {
+
+	    client_ignores_realm = 1;
+	    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+				"The client tries to override server provided realm");
+	    if (text->realm) sparams->utils->free(text->realm);
+	    _plug_strdup(sparams->utils, realm, &text->realm, NULL);
+	}
+
+	if (strcmp((char *) nonce, (char *) text->nonce) != 0) {
+	    SETERROR(sparams->utils,
+		     "nonce changed: authentication aborted");
+	    result = SASL_BADAUTH;
+	    goto FreeAllMem;
+	}
+#if 0	/* XXX  Possible replay attack, but we will continue processing
+	 * the response to determine if the client knows the password and
+	 return stale accordingly */
+	if (noncecount != text->nonce_count) {
+	    SETERROR(sparams->utils,
+		     "incorrect nonce-count: authentication aborted");
+	    result = SASL_BADAUTH;
+	    goto FreeAllMem;
+	}
+#endif
+#if 0	/* XXX  Neither RFC 2617 nor RFC 2831 state that the cnonce
+	   needs to remain constant for subsequent authentication to work */
+	if (text->cnonce && strcmp((char *) cnonce, (char *) text->cnonce) != 0) {
+	    SETERROR(sparams->utils,
+		     "cnonce changed: authentication aborted");
+	    result = SASL_BADAUTH;
+	    goto FreeAllMem;
+	}
+#endif
+    }
+	    
+    result = sparams->utils->prop_request(sparams->propctx, password_request);
+    if(result != SASL_OK) {
+	SETERROR(sparams->utils, "unable to obtain user password");
+	goto FreeAllMem;
+    }
+    
+    /* this will trigger the getting of the aux properties */
+    /* Note that if we don't have an authorization id, we don't use it... */
+
+    if (client_ignores_realm) {
+	if (strlen(text->realm) == 0) {
+	    /* Don't put @ at the end of the username, if the realm is empty */
+	    _plug_strdup(sparams->utils, username, &full_username, NULL);
+	} else {
+	    full_username = (char *) sparams->utils->malloc(strlen(username) +
+					strlen(text->realm) + 2);
+	    full_username[0] = '\0';
+	    sprintf (full_username, "%s@%s", username, text->realm);
+	}
+	internal_username = full_username;
+    } else {
+	internal_username = username;
+    }
+
+    canon_flags = SASL_CU_AUTHID;
+    if (!authorization_id || !*authorization_id) {
+	canon_flags |= SASL_CU_AUTHZID;
+    }
+
+    result = sparams->canon_user(sparams->utils->conn,
+				 internal_username,
+				 0,
+				 canon_flags,
+				 oparams);
+    if (result != SASL_OK) {
+	SETERROR(sparams->utils, "unable to canonify user and get auxprops");
+	goto FreeAllMem;
+    }
+    
+    if (authorization_id != NULL && *authorization_id != '\0') {
+	result = sparams->canon_user(sparams->utils->conn,
+				     authorization_id, 0, SASL_CU_AUTHZID,
+				     oparams);
+    }
+    if (result != SASL_OK) {
+	SETERROR(sparams->utils, "unable to canonify authorization ID");
+	goto FreeAllMem;
+    }
+    
+    result = sparams->utils->prop_getnames(sparams->propctx, password_request,
+					   auxprop_values);
+    if (result < 0 ||
+       ((!auxprop_values[0].name || !auxprop_values[0].values) &&
+	(!auxprop_values[1].name || !auxprop_values[1].values))) {
+	/* We didn't find this username */
+	sparams->utils->seterror(sparams->utils->conn, 0,
+				 "no secret in database");
+	result = sparams->transition ? SASL_TRANS : SASL_NOUSER;
+	goto FreeAllMem;
+    }
+    
+    if (auxprop_values[0].name && auxprop_values[0].values) {
+	len = strlen(auxprop_values[0].values[0]);
+	if (len == 0) {
+	    sparams->utils->seterror(sparams->utils->conn,0,
+				     "empty secret");
+	    result = SASL_FAIL;
+	    goto FreeAllMem;
+	}
+	
+	sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
+	if (!sec) {
+	    SETERROR(sparams->utils, "unable to allocate secret");
+	    result = SASL_FAIL;
+	    goto FreeAllMem;
+	}
+	
+	sec->len = (unsigned) len;
+	strncpy((char *) sec->data, auxprop_values[0].values[0], len + 1); 
+	
+	/*
+	 * Verifying response obtained from client
+	 * 
+	 * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
+	 * contains H_URP
+	 */
+	
+	/* Calculate the secret from the plaintext password */
+	{
+	    /*
+	     * Secret = { H( { username-value, ":", realm-value, ":", passwd } ) }
+	     *
+	     * (used to build A1)
+	     */
+	    
+	    Try_8859_1 = DigestCalcSecret(sparams->utils,
+					  (unsigned char *) username,
+					  (unsigned char *) realm,
+					  sec->data,
+					  sec->len,
+					  FALSE,
+					  Secret);
+	    Secret[HASHLEN] = '\0';
+	}
+	if (Try_8859_1) {
+	    /*
+	     * Secret = { H( { username-value, ":", realm-value, ":", passwd } ) }
+	     *
+	     * (used to build A1)
+	     */
+	    
+	    DigestCalcSecret(sparams->utils,
+			     (unsigned char *) username,
+			     (unsigned char *) realm,
+			     sec->data,
+			     sec->len,
+			     TRUE,
+			     SecretBogus);
+	    SecretBogus[HASHLEN] = '\0';
+	}
+	
+	/* We're done with sec now. Let's get rid of it */
+	_plug_free_secret(sparams->utils, &sec);
+    } else if (auxprop_values[1].name && auxprop_values[1].values) {
+        /* NB: This will most likely fail for clients that
+	   choose to ignore server-advertised realm */
+	memcpy(Secret, auxprop_values[1].values[0], HASHLEN);
+	Secret[HASHLEN] = '\0';
+    } else {
+	sparams->utils->seterror(sparams->utils->conn, 0,
+				 "Have neither type of secret");
+	return SASL_FAIL;
+    } 
+    
+    /* erase the plaintext password */
+    sparams->utils->prop_erase(sparams->propctx, password_request[0]);
+
+    /* defaulting qop to "auth" if not specified */
+    if (qop == NULL) {
+	_plug_strdup(sparams->utils, "auth", &qop, NULL);      
+    }
+
+    if (oparams->mech_ssf > 1) {
+	/* Remember the old cipher free function (if any).
+	   It will be called later, once we are absolutely
+	   sure that authentication was successful. */
+	old_cipher_free = text->cipher_free;
+	/* free the old cipher context first */
+    }
+    
+    /* check which layer/cipher to use */
+    if ((!strcasecmp(qop, "auth-conf")) && (cipher != NULL)) {
+	/* see what cipher was requested */
+	struct digest_cipher *cptr;
+	
+	cptr = available_ciphers;
+	while (cptr->name) {
+	    /* find the cipher requested & make sure it's one we're happy
+	       with by policy */
+	    if (!strcasecmp(cipher, cptr->name) && 
+		stext->requiressf <= cptr->ssf &&
+		stext->limitssf >= cptr->ssf) {
+		/* found it! */
+		break;
+	    }
+	    cptr++;
+	}
+	
+	if (cptr->name) {
+	    text->cipher_enc = cptr->cipher_enc;
+	    text->cipher_dec = cptr->cipher_dec;
+	    text->cipher_init = cptr->cipher_init;
+	    text->cipher_free = cptr->cipher_free;
+	    oparams->mech_ssf = cptr->ssf;
+	    n = cptr->n;
+	} else {
+	    /* erg? client requested something we didn't advertise! */
+	    sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
+				"protocol violation: client requested invalid cipher");
+	    SETERROR(sparams->utils, "client requested invalid cipher");
+	    /* Mark that we attempted security layer negotiation */
+	    oparams->mech_ssf = 2;
+	    result = SASL_FAIL;
+	    goto FreeAllMem;
+	}
+	
+	oparams->encode=&digestmd5_encode;
+	oparams->decode=&digestmd5_decode;
+    } else if (!strcasecmp(qop, "auth-int") &&
+	       stext->requiressf <= 1 && stext->limitssf >= 1) {
+	oparams->encode = &digestmd5_encode;
+	oparams->decode = &digestmd5_decode;
+	oparams->mech_ssf = 1;
+    } else if (!strcasecmp(qop, "auth") && stext->requiressf == 0) {
+	oparams->encode = NULL;
+	oparams->decode = NULL;
+	oparams->mech_ssf = 0;
+    } else {
+	SETERROR(sparams->utils,
+		 "protocol violation: client requested invalid qop");
+	result = SASL_FAIL;
+	goto FreeAllMem;
+    }
+    
+    serverresponse = create_response(text,
+				     sparams->utils,
+				     nonce,
+				     noncecount,
+				     cnonce,
+				     qop,
+				     request,
+				     Secret,
+				     authorization_id,
+				     &text->response_value);
+    
+    if (serverresponse == NULL) {
+	SETERROR(sparams->utils, "internal error: unable to create response");
+	result = SASL_NOMEM;
+	goto FreeAllMem;
+    }
+    
+    /* if ok verified */
+    if (strcmp(serverresponse, response) != 0) {
+	if (Try_8859_1) {
+	    
+	    serverresponse = create_response(text,
+					     sparams->utils,
+					     nonce,
+					     noncecount,
+					     cnonce,
+					     qop,
+					     request,
+					     SecretBogus,
+					     authorization_id,
+					     &text->response_value);
+	    
+	    if (serverresponse == NULL) {
+		SETERROR(sparams->utils, "internal error: unable to create response");
+		result = SASL_NOMEM;
+		goto FreeAllMem;
+	    }
+	    
+	    /* if ok verified */
+	    if (strcmp(serverresponse, response) != 0) {
+		SETERROR(sparams->utils,
+			 "client response doesn't match what we generated (tried bogus)");
+		result = SASL_BADAUTH;
+		
+		goto FreeAllMem;
+	    }
+	    
+	} else {	    
+	    SETERROR(sparams->utils,
+		     "client response doesn't match what we generated");
+	    result = SASL_BADAUTH;
+	    
+	    goto FreeAllMem;
+	}
+    }
+
+    /* see if our nonce expired */
+    if (!text->nonce ||
+	(noncecount != text->nonce_count) ||
+	(text->reauth->timeout &&
+	 time(0) - stext->timestamp > text->reauth->timeout)) {
+	if (!text->nonce) SETERROR(sparams->utils, "no cached server nonce");
+	else if (noncecount != text->nonce_count)
+	    SETERROR(sparams->utils, "incorrect nonce-count");
+	else SETERROR(sparams->utils, "server nonce expired");
+	stext->stale = 1;
+	result = SASL_BADAUTH;
+
+	goto FreeAllMem;
+    }
+
+    /*
+     * nothing more to do; authenticated set oparams information
+     */
+    oparams->doneflag = 1;
+    oparams->maxoutbuf = client_maxbuf - 4;
+    if (oparams->mech_ssf > 1) {
+	/* MAC block (privacy) */
+	oparams->maxoutbuf -= 25;
+    } else if(oparams->mech_ssf == 1) {
+	/* MAC block (integrity) */
+	oparams->maxoutbuf -= 16;
+    }
+    
+    oparams->param_version = 0;
+    
+    text->seqnum = 0;		/* for integrity/privacy */
+    text->rec_seqnum = 0;	/* for integrity/privacy */
+    text->utils = sparams->utils;
+
+    /* Free the old security layer, if any */
+    if (old_cipher_free) old_cipher_free(text);
+
+    /* used by layers */
+    _plug_decode_init(&text->decode_context, text->utils,
+		      sparams->props.maxbufsize ? sparams->props.maxbufsize :
+		      DEFAULT_BUFSIZE);
+
+    if (oparams->mech_ssf > 0) {
+	unsigned char enckey[16];
+	unsigned char deckey[16];
+	
+	create_layer_keys(text, sparams->utils,text->HA1,n,enckey,deckey);
+	
+	/* initialize cipher if need be */
+	if (text->cipher_init) {
+	    if (text->cipher_init(text, enckey, deckey) != SASL_OK) {
+		sparams->utils->seterror(sparams->utils->conn, 0,
+					 "couldn't init cipher");
+	    }
+	}
+    }
+    
+    /*
+     * The server receives and validates the "digest-response". The server
+     * checks that the nonce-count is "00000001". If it supports subsequent
+     * authentication, it saves the value of the nonce and the nonce-count.
+     */
+    
+    /*
+     * The "username-value", "realm-value" and "passwd" are encoded according
+     * to the value of the "charset" directive. If "charset=UTF-8" is
+     * present, and all the characters of either "username-value" or "passwd"
+     * are in the ISO 8859-1 character set, then it must be converted to
+     * UTF-8 before being hashed. A sample implementation of this conversion
+     * is in section 8.
+     */
+    
+    /* add to challenge */
+    {
+	unsigned resplen = 0;
+
+	if (add_to_challenge(sparams->utils,
+			     &text->out_buf, &text->out_buf_len, &resplen,
+			     "rspauth", (unsigned char *) text->response_value,
+			     text->http_mode ? TRUE : FALSE) != SASL_OK) {
+	    SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+	    result = SASL_FAIL;
+	    goto FreeAllMem;
+	}
+
+	if (text->http_mode) {
+	    /* per RFC 2617 */
+	    char ncvalue[10];
+
+	    if (add_to_challenge(sparams->utils,
+				 &text->out_buf, &text->out_buf_len, &resplen,
+				 "cnonce", cnonce, TRUE) != SASL_OK) {
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+	    snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
+	    if (add_to_challenge(sparams->utils,
+				 &text->out_buf, &text->out_buf_len, &resplen,
+				 "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+	    if (add_to_challenge(sparams->utils,
+				 &text->out_buf, &text->out_buf_len, &resplen,
+				 "qop", (unsigned char *) qop, TRUE) != SASL_OK) {
+		result = SASL_FAIL;
+		goto FreeAllMem;
+	    }
+	}
+
+	/* self check */
+	if (strlen(text->out_buf) > 2048) {
+	    result = SASL_FAIL;
+	    goto FreeAllMem;
+	}
+    }
+    
+    *serveroutlen = (unsigned) strlen(text->out_buf);
+    *serverout = text->out_buf;
+	
+    result = SASL_OK;
+
+  FreeAllMem:
+    if (clientinlen > 0 &&
+	text->reauth->timeout &&
+	sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+
+	/* Look for an entry for the nonce value */
+	unsigned val = hash((char *) nonce) % text->reauth->size;
+
+	switch (result) {
+	case SASL_OK:
+	    /* successful auth, setup for future reauth */
+	    if (text->nonce_count == 1) {
+		/* successful initial auth, create new entry */
+		clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+		text->reauth->e[val].authid = username; username = NULL;
+		text->reauth->e[val].realm = text->realm; text->realm = NULL;
+		text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
+		text->reauth->e[val].cnonce = cnonce; cnonce = NULL;
+	    }
+	    if (text->nonce_count < text->reauth->e[val].nonce_count) {
+		/* paranoia.  prevent replay attacks */
+		clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+	    }
+	    else {
+		text->reauth->e[val].nonce_count = ++text->nonce_count;
+		text->reauth->e[val].u.s.timestamp = time(0);
+	    }
+	    break;
+	default:
+	    if (text->nonce_count > 1) {
+		/* failed reauth, clear entry */
+		clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+	    }
+	    else {
+		/* failed initial auth, leave existing cache */
+	    }
+	}
+	sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+    }
+
+    /* free everything */
+    if (in_start) sparams->utils->free (in_start);
+    
+    if (full_username != NULL) 
+	sparams->utils->free (full_username);
+    if (username != NULL)
+	sparams->utils->free (username);
+    if (authorization_id != NULL)
+	sparams->utils->free (authorization_id);
+    if (realm != NULL)
+	sparams->utils->free (realm);
+    if (nonce != NULL)
+	sparams->utils->free (nonce);
+    if (cnonce != NULL)
+	sparams->utils->free (cnonce);
+    if (response != NULL)
+	sparams->utils->free (response);
+    if (cipher != NULL)
+	sparams->utils->free (cipher);
+    if (serverresponse != NULL)
+	sparams->utils->free(serverresponse);
+    if (charset != NULL)
+	sparams->utils->free (charset);
+    if (digesturi != NULL)
+	sparams->utils->free (digesturi);
+    if (qop!=NULL)
+	sparams->utils->free (qop);  
+    if (sec)
+	_plug_free_secret(sparams->utils, &sec);
+    
+    return result;
+}
+
+static int digestmd5_server_mech_step(void *conn_context,
+				      sasl_server_params_t *sparams,
+				      const char *clientin,
+				      unsigned clientinlen,
+				      const char **serverout,
+				      unsigned *serveroutlen,
+				      sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) conn_context;
+    server_context_t *stext = (server_context_t *) conn_context;
+    
+    *serverout = NULL;
+    *serveroutlen = 0;
+    
+    if (clientinlen > 4096) return SASL_BADPROT;
+
+    if (text == NULL) {
+	return SASL_BADPROT;
+    }
+
+    switch (text->state) {
+	
+    case 1:
+	/* setup SSF limits */
+	if (!text->http_mode &&		/* HTTP Digest doesn't need buffer */
+	    !sparams->props.maxbufsize) {
+	    stext->limitssf = 0;
+	    stext->requiressf = 0;
+	} else {
+	    if (sparams->props.max_ssf < sparams->external_ssf) {
+		stext->limitssf = 0;
+	    } else {
+		stext->limitssf =
+		    sparams->props.max_ssf - sparams->external_ssf;
+	    }
+	    if (sparams->props.min_ssf < sparams->external_ssf) {
+		stext->requiressf = 0;
+	    } else {
+		stext->requiressf =
+		    sparams->props.min_ssf - sparams->external_ssf;
+	    }
+	}
+
+        if (clientin && text->reauth->timeout) {
+	    /* here's where we attempt fast reauth if possible */
+	    if (digestmd5_server_mech_step2(stext, sparams,
+					    clientin, clientinlen,
+					    serverout, serveroutlen,
+					    oparams) == SASL_OK) {
+		return SASL_OK;
+	    }
+
+	    sparams->utils->log(NULL, SASL_LOG_WARN,
+				"DIGEST-MD5 reauth failed\n");
+
+	    /* re-initialize everything for a fresh start */
+	    memset(oparams, 0, sizeof(sasl_out_params_t));
+	    if (text->nonce) sparams->utils->free(text->nonce);
+	    if (text->realm) sparams->utils->free(text->realm);
+	    text->nonce = text->realm = NULL;
+
+	    /* fall through and issue challenge */
+	}
+
+	return digestmd5_server_mech_step1(stext, sparams,
+					   clientin, clientinlen,
+					   serverout, serveroutlen, oparams);
+	
+    case 2:
+	return digestmd5_server_mech_step2(stext, sparams,
+					   clientin, clientinlen,
+					   serverout, serveroutlen, oparams);
+	
+    default:
+	sparams->utils->log(NULL, SASL_LOG_ERR,
+			    "Invalid DIGEST-MD5 server step %d\n", text->state);
+	return SASL_FAIL;
+    }
+    
+    return SASL_FAIL; /* should never get here */
+}
+
+static void digestmd5_server_mech_dispose(void *conn_context,
+					  const sasl_utils_t *utils)
+{
+    server_context_t *stext = (server_context_t *) conn_context;
+    
+    if (!stext || !utils) return;
+    
+    digestmd5_common_mech_dispose(conn_context, utils);
+}
+
+static sasl_server_plug_t digestmd5_server_plugins[] =
+{
+    {
+	"DIGEST-MD5",			/* mech_name */
+#ifdef WITH_RC4
+	128,				/* max_ssf */
+#elif defined(WITH_DES)
+	112,
+#else 
+	1,
+#endif
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
+	SASL_FEAT_ALLOWS_PROXY
+	| SASL_FEAT_SUPPORTS_HTTP,	/* features */
+	&server_glob_context,		/* glob_context */
+	&digestmd5_server_mech_new,	/* mech_new */
+	&digestmd5_server_mech_step,	/* mech_step */
+	&digestmd5_server_mech_dispose,	/* mech_dispose */
+	&digestmd5_common_mech_free,	/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	NULL,				/* mech avail */
+	NULL				/* spare */
+    }
+};
+
+int digestmd5_server_plug_init(sasl_utils_t *utils,
+			       int maxversion,
+			       int *out_version,
+			       sasl_server_plug_t **pluglist,
+			       int *plugcount) 
+{
+    reauth_cache_t *reauth_cache;
+    const char *timeout = NULL;
+    unsigned int len;
+
+    if (maxversion < SASL_SERVER_PLUG_VERSION) {
+	return SASL_BADVERS;
+    }
+
+    /* reauth cache */
+    reauth_cache = utils->malloc(sizeof(reauth_cache_t));
+    if (reauth_cache == NULL) {
+	return SASL_NOMEM;
+    }
+    memset(reauth_cache, 0, sizeof(reauth_cache_t));
+    reauth_cache->i_am = SERVER;
+
+    /* fetch and canonify the reauth_timeout */
+    utils->getopt(utils->getopt_context, "DIGEST-MD5", "reauth_timeout",
+		  &timeout, &len);
+    if (timeout) {
+	reauth_cache->timeout = (time_t) 60 * strtol(timeout, NULL, 10);
+    }
+    if (reauth_cache->timeout < 0) {
+	reauth_cache->timeout = 0;
+    }
+
+    if (reauth_cache->timeout) {
+	/* mutex */
+	reauth_cache->mutex = utils->mutex_alloc();
+	if (!reauth_cache->mutex) {
+	    utils->free(reauth_cache);
+	    return SASL_FAIL;
+	}
+
+	/* entries */
+	reauth_cache->size = 100;
+	reauth_cache->e = utils->malloc(reauth_cache->size *
+					sizeof(reauth_entry_t));
+	if (reauth_cache->e == NULL) {
+	    utils->mutex_free(reauth_cache->mutex);
+	    utils->free(reauth_cache);
+	    return SASL_NOMEM;
+	}
+	memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
+    }
+
+    ((digest_glob_context_t *) digestmd5_server_plugins[0].glob_context)->reauth = reauth_cache;
+
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = digestmd5_server_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+typedef struct client_context {
+    context_t common;
+
+    sasl_secret_t *password;	/* user password */
+    unsigned int free_password; /* set if we need to free password */
+
+    int protection;
+    struct digest_cipher *cipher;
+    unsigned long server_maxbuf;
+
+    /* for HTTP mode (RFC 2617) only */
+    char *algorithm;
+    unsigned char *opaque;
+} client_context_t;
+
+static digest_glob_context_t client_glob_context;
+
+/* calculate H(A1) as per spec */
+static void DigestCalcHA1(context_t * text,
+			  const sasl_utils_t * utils,
+			  char *pszAlg,
+			  unsigned char *pszUserName,
+			  unsigned char *pszRealm,
+			  sasl_secret_t * pszPassword,
+			  unsigned char *pszAuthorization_id,
+			  unsigned char *pszNonce,
+			  unsigned char *pszCNonce,
+			  HASHHEX SessionKey)
+{
+    MD5_CTX         Md5Ctx;
+    HASH            HA1;
+    
+    DigestCalcSecret(utils,
+		     pszUserName,
+		     pszRealm,
+		     (unsigned char *) pszPassword->data,
+		     pszPassword->len,
+		     FALSE,
+		     HA1);
+    
+    if (!text->http_mode ||				    /* per RFC 2831 */
+	(pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)) {  /* per RFC 2617 */
+	/* calculate the session key */
+	utils->MD5Init(&Md5Ctx);
+	if (text->http_mode) {
+	    /* per RFC 2617 Errata ID 1649 */
+	    HASHHEX HA1Hex;
+    
+	    CvtHex(HA1, HA1Hex);
+	    utils->MD5Update(&Md5Ctx, HA1Hex, HASHHEXLEN);
+	}
+	else {
+	    /* per RFC 2831 */
+	    utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
+	}
+	utils->MD5Update(&Md5Ctx, COLON, 1);
+	utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
+	utils->MD5Update(&Md5Ctx, COLON, 1);
+	utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
+	if (pszAuthorization_id != NULL) {
+	    utils->MD5Update(&Md5Ctx, COLON, 1);
+	    utils->MD5Update(&Md5Ctx, pszAuthorization_id, 
+			     (unsigned) strlen((char *) pszAuthorization_id));
+	}
+	utils->MD5Final(HA1, &Md5Ctx);
+    }
+    
+    CvtHex(HA1, SessionKey);
+    
+    /* xxx rc-* use different n */
+    
+    /* save HA1 because we'll need it for the privacy and integrity keys */
+    memcpy(text->HA1, HA1, sizeof(HASH));
+    
+}
+
+static char *calculate_response(context_t * text,
+				const sasl_utils_t * utils,
+				char *algorithm,
+				unsigned char *username,
+				unsigned char *realm,
+				unsigned char *nonce,
+				unsigned int ncvalue,
+				unsigned char *cnonce,
+				char *qop,
+				const sasl_http_request_t *request,
+				sasl_secret_t * passwd,
+				unsigned char *authorization_id,
+				char **response_value)
+{
+    HASHHEX         SessionKey;
+    HASH            EntityHash;
+    HASHHEX         HEntity;
+    HASHHEX         Response;
+    char           *result;
+    
+    /* Verifing that all parameters was defined */
+    if(!username || !cnonce || !nonce || !ncvalue || !request || !passwd) {
+	PARAMERROR( utils );
+	return NULL;
+    }
+    
+    if (realm == NULL) {
+	/* a NULL realm is equivalent to the empty string */
+	realm = (unsigned char *) "";
+    }
+    
+    if (qop == NULL) {
+	/* default to a qop of just authentication */
+	qop = "auth";
+    }
+    
+    DigestCalcHA1(text,
+		  utils,
+		  algorithm,
+		  username,
+		  realm,
+		  passwd,
+		  authorization_id,
+		  nonce,
+		  cnonce,
+		  SessionKey);
+    
+    if (text->http_mode) {
+	/* per RFC 2617 */
+	MD5_CTX Md5Ctx;
+
+	utils->MD5Init(&Md5Ctx);
+	utils->MD5Update(&Md5Ctx, request->entity, request->elen);
+	utils->MD5Final(EntityHash, &Md5Ctx);
+    }
+    else {
+	/* per RFC 2831 */
+	memset(EntityHash, 0, HASHLEN);
+    }
+    CvtHex(EntityHash, HEntity);
+
+    DigestCalcResponse(utils,
+		       SessionKey,/* HEX(H(A1)) */
+		       nonce,	/* nonce from server */
+		       ncvalue,	/* 8 hex digits */
+		       cnonce,	/* client nonce */
+		       (unsigned char *) qop,	/* qop-value: "", "auth",
+						 * "auth-int" */
+		       (unsigned char *) request->uri,	/* requested URL */
+		       (unsigned char *) request->method,
+		       HEntity,	/* H(entity body) if qop="auth-int" */
+		       Response	/* request-digest or response-digest */
+	);
+    
+    result = utils->malloc(HASHHEXLEN + 1);
+    memcpy(result, Response, HASHHEXLEN);
+    result[HASHHEXLEN] = 0;
+    
+    if (response_value != NULL) {
+	char * new_response_value;
+
+	DigestCalcResponse(utils,
+			   SessionKey,	/* HEX(H(A1)) */
+			   nonce,	/* nonce from server */
+			   ncvalue,	/* 8 hex digits */
+			   cnonce,	/* client nonce */
+			   (unsigned char *) qop,	/* qop-value: "", "auth",
+							 * "auth-int" */
+			   (unsigned char *) request->uri,	/* requested URL */
+			   NULL,
+			   HEntity,	/* H(entity body) if qop="auth-int" */
+			   Response	/* request-digest or response-digest */
+	    );
+	
+	new_response_value = utils->realloc(*response_value, HASHHEXLEN + 1);
+	if (new_response_value == NULL) {
+	    free (*response_value);
+	    *response_value = NULL;
+	    return NULL;
+	}
+	*response_value = new_response_value;
+	
+	memcpy(*response_value, Response, HASHHEXLEN);
+	(*response_value)[HASHHEXLEN] = 0;
+	
+    }
+    
+    return result;
+}
+
+static int make_client_response(context_t *text,
+				sasl_client_params_t *params,
+				sasl_out_params_t *oparams)
+{
+    client_context_t *ctext = (client_context_t *) text;
+    char *qop = NULL;
+    unsigned nbits = 0;
+    char  *digesturi = NULL;
+    bool            IsUTF8 = FALSE;
+    char           ncvalue[10];
+    char           maxbufstr[64];
+    char           *response = NULL;
+    unsigned        resplen = 0;
+    int result = SASL_OK;
+    cipher_free_t  *old_cipher_free = NULL;
+    sasl_http_request_t rfc2831_request;
+    const sasl_http_request_t *request;
+
+    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+		       "DIGEST-MD5 make_client_response()");
+
+    if (oparams->mech_ssf > 1) {
+	/* Remember the old cipher free function (if any).
+	   It will be called later, once we are absolutely
+	   sure that authentication was successful. */
+	old_cipher_free = text->cipher_free;
+	/* free the old cipher context first */
+    }
+
+    switch (ctext->protection) {
+    case DIGEST_PRIVACY:
+	qop = "auth-conf";
+	oparams->encode = &digestmd5_encode; 
+	oparams->decode = &digestmd5_decode;
+	oparams->mech_ssf = ctext->cipher->ssf;
+
+	nbits = ctext->cipher->n;
+	text->cipher_enc = ctext->cipher->cipher_enc;
+	text->cipher_dec = ctext->cipher->cipher_dec;
+	text->cipher_free = ctext->cipher->cipher_free;
+	text->cipher_init = ctext->cipher->cipher_init;
+	break;
+    case DIGEST_INTEGRITY:
+	qop = "auth-int";
+	oparams->encode = &digestmd5_encode;
+	oparams->decode = &digestmd5_decode;
+	oparams->mech_ssf = 1;
+	break;
+    case DIGEST_NOLAYER:
+    default:
+	qop = "auth";
+	oparams->encode = NULL;
+	oparams->decode = NULL;
+	oparams->mech_ssf = 0;
+    }
+
+    if (text->http_mode) {
+	/* per RFC 2617 (HTTP Request as set by calling application) */
+	request = params->http_request;
+    }
+    else {
+	/* per RFC 2831 */
+	digesturi = params->utils->malloc(strlen(params->service) + 1 +
+					  strlen(params->serverFQDN) + 1 +
+					  1);
+	if (digesturi == NULL) {
+	    result = SASL_NOMEM;
+	    goto FreeAllocatedMem;
+	}
+
+	/* allocated exactly this. safe */
+	strcpy(digesturi, params->service);
+	strcat(digesturi, "/");
+	strcat(digesturi, params->serverFQDN);
+	/*
+	 * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
+	 */
+
+	rfc2831_request.method = "AUTHENTICATE";
+	rfc2831_request.uri = digesturi;
+	rfc2831_request.entity = NULL;
+	rfc2831_request.elen = 0;
+	rfc2831_request.non_persist = 0;
+	request = &rfc2831_request;
+    }
+
+    /* response */
+    response =
+	calculate_response(text,
+			   params->utils,
+			   ctext->algorithm,
+			   (unsigned char *) oparams->authid,
+			   (unsigned char *) text->realm,
+			   text->nonce,
+			   text->nonce_count,
+			   text->cnonce,
+			   qop,
+			   request,
+			   ctext->password,
+			   strcmp(oparams->user, oparams->authid) ?
+			   (unsigned char *) oparams->user : NULL,
+			   &text->response_value);
+    
+    
+    resplen = 0;
+    if (text->out_buf) params->utils->free(text->out_buf);
+    text->out_buf = NULL;
+    text->out_buf_len = 0;
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "username", (unsigned char *) oparams->authid,
+			 TRUE) != SASL_OK) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "realm", (unsigned char *) text->realm,
+			 TRUE) != SASL_OK) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+    if (strcmp(oparams->user, oparams->authid)) {
+	if (add_to_challenge(params->utils,
+			     &text->out_buf, &text->out_buf_len, &resplen,
+			     "authzid", (unsigned char *) oparams->user, TRUE) != SASL_OK) {
+	    result = SASL_FAIL;
+	    goto FreeAllocatedMem;
+	}
+    }
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "nonce", text->nonce, TRUE) != SASL_OK) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "cnonce", text->cnonce, TRUE) != SASL_OK) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+    snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "qop", (unsigned char *) qop, FALSE) != SASL_OK) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+    if (ctext->cipher != NULL) {
+	if (add_to_challenge(params->utils,
+			     &text->out_buf, &text->out_buf_len, &resplen,
+			     "cipher", 
+			     (unsigned char *) ctext->cipher->name,
+			     FALSE) != SASL_OK) {
+	    result = SASL_FAIL;
+	    goto FreeAllocatedMem;
+	}
+    }
+
+    if (params->props.maxbufsize) {
+	snprintf(maxbufstr, sizeof(maxbufstr), "%d", params->props.maxbufsize);
+	if (add_to_challenge(params->utils,
+			     &text->out_buf, &text->out_buf_len, &resplen,
+			     "maxbuf", (unsigned char *) maxbufstr, 
+			     FALSE) != SASL_OK) {
+	    SETERROR(params->utils,
+		     "internal error: add_to_challenge maxbuf failed");
+	    goto FreeAllocatedMem;
+	}
+    }
+    
+    if (IsUTF8) {
+	if (add_to_challenge(params->utils,
+			     &text->out_buf, &text->out_buf_len, &resplen,
+			     "charset", (unsigned char *) "utf-8",
+			     FALSE) != SASL_OK) {
+	    result = SASL_FAIL;
+	    goto FreeAllocatedMem;
+	}
+    }
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 text->http_mode ? "uri"	     /* per RFC 2617 */
+			 : "digest-uri",   		     /* per RFC 2831 */
+			 (unsigned char *) request->uri,
+			 TRUE) != SASL_OK) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+    if (text->http_mode) {
+	/* per RFC 2617: algorithm & opaque MUST be sent back to server */
+	if (add_to_challenge(params->utils,
+			     &text->out_buf, &text->out_buf_len, &resplen,
+			     "algorithm", (unsigned char *) ctext->algorithm,
+			     FALSE) != SASL_OK) {
+	    result = SASL_FAIL;
+	    goto FreeAllocatedMem;
+	}
+	if (ctext->opaque) {
+	    if (add_to_challenge(params->utils,
+				 &text->out_buf, &text->out_buf_len, &resplen,
+				 "opaque", ctext->opaque, TRUE) != SASL_OK) {
+		result = SASL_FAIL;
+		goto FreeAllocatedMem;
+	    }
+	}
+    }
+    if (add_to_challenge(params->utils,
+			 &text->out_buf, &text->out_buf_len, &resplen,
+			 "response", (unsigned char *) response,
+			 FALSE) != SASL_OK) {
+	
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+    
+    /* self check */
+    if (strlen(text->out_buf) > 2048) {
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+
+    /* set oparams */
+    oparams->maxoutbuf = ctext->server_maxbuf;
+    if(oparams->mech_ssf > 1) {
+	/* MAC block (privacy) */
+	oparams->maxoutbuf -= 25;
+    } else if(oparams->mech_ssf == 1) {
+	/* MAC block (integrity) */
+	oparams->maxoutbuf -= 16;
+    }
+    
+    text->seqnum = 0;	/* for integrity/privacy */
+    text->rec_seqnum = 0;	/* for integrity/privacy */
+    text->utils = params->utils;
+
+    /* Free the old security layer, if any */
+    if (old_cipher_free) old_cipher_free(text);
+
+    /* used by layers */
+    _plug_decode_init(&text->decode_context, text->utils,
+		      params->props.maxbufsize ? params->props.maxbufsize :
+		      DEFAULT_BUFSIZE);
+    
+    if (oparams->mech_ssf > 0) {
+	unsigned char enckey[16];
+	unsigned char deckey[16];
+	
+	create_layer_keys(text, params->utils, text->HA1, nbits,
+			  enckey, deckey);
+	
+	/* initialize cipher if need be */
+	if (text->cipher_init) {
+	    text->cipher_init(text, enckey, deckey);
+	}
+    }
+    
+    result = SASL_OK;
+
+  FreeAllocatedMem:
+    if (digesturi) params->utils->free(digesturi);
+    if (response) params->utils->free(response);
+
+    return result;
+}
+
+static int parse_server_challenge(client_context_t *ctext,
+				  sasl_client_params_t *params,
+				  const char *serverin, unsigned serverinlen,
+				  char ***outrealms, int *noutrealm)
+{
+    context_t *text = (context_t *) ctext;
+    int result = SASL_OK;
+    char *in_start = NULL;
+    char *in = NULL;
+    char **realms = NULL;
+    int nrealm = 0;
+    sasl_ssf_t limit, musthave = 0;
+    sasl_ssf_t external;
+    int protection = 0;
+    int saw_qop = 0;
+    int ciphers = 0;
+    int maxbuf_count = 0;
+    bool IsUTF8 = FALSE;
+    int algorithm_count = 0;
+    int opaque_count = 0;
+
+    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+		       "DIGEST-MD5 parse_server_challenge()");
+
+    if (!serverin || !serverinlen) {
+	params->utils->seterror(params->utils->conn, 0,
+				"no server challenge");
+	return SASL_FAIL;
+    }
+
+    in_start = in = params->utils->malloc(serverinlen + 1);
+    if (in == NULL) return SASL_NOMEM;
+    
+    memcpy(in, serverin, serverinlen);
+    in[serverinlen] = 0;
+    
+    ctext->server_maxbuf = 65536; /* Default value for maxbuf */
+
+    /* create a new cnonce */
+    text->cnonce = create_nonce(params->utils);
+    if (text->cnonce == NULL) {
+	params->utils->seterror(params->utils->conn, 0,
+				"failed to create cnonce");
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+
+    /* parse the challenge */
+    while (in[0] != '\0') {
+	char *name, *value;
+	
+	get_pair(&in, &name, &value);
+	
+	/* if parse error */
+	if (name == NULL) {
+	    params->utils->seterror(params->utils->conn, 0, "Parse error");
+	    result = SASL_BADAUTH;
+	    goto FreeAllocatedMem;
+	}
+	
+	if (*name == '\0') {
+	    break;
+	}
+
+	if (strcasecmp(name, "realm") == 0) {
+	    nrealm++;
+	    
+	    if(!realms)
+		realms = params->utils->malloc(sizeof(char *) * (nrealm + 1));
+	    else
+		realms = params->utils->realloc(realms, 
+						sizeof(char *) * (nrealm + 1));
+	    
+	    if (realms == NULL) {
+		result = SASL_NOMEM;
+		goto FreeAllocatedMem;
+	    }
+	    
+	    _plug_strdup(params->utils, value, &realms[nrealm-1], NULL);
+	    realms[nrealm] = NULL;
+	} else if (strcasecmp(name, "nonce") == 0) {
+	    _plug_strdup(params->utils, value, (char **) &text->nonce,
+			 NULL);
+	    text->nonce_count = 1;
+	} else if (strcasecmp(name, "qop") == 0) {
+	    saw_qop = 1;
+	    while (value && *value) {
+		char *comma;
+		char *end_val;
+
+SKIP_SPACES_IN_QOP:
+		/* skipping spaces: */
+		value = skip_lws(value);
+		if (*value == '\0') {
+		    break;
+		}
+
+		/* check for an extreme case when there is no data: LWSP ',' */
+		if (*value == ',') {
+		    value++;
+		    goto SKIP_SPACES_IN_QOP;
+		}
+
+		comma = strchr(value, ',');
+
+		if (comma != NULL) {
+		    *comma++ = '\0';
+		}
+
+		/* skip LWSP at the end of the value (if any), skip_r_lws returns pointer to
+		   the first LWSP character, NUL (if there were none) or NULL if the value
+		   is entirely from LWSP characters */
+		end_val = skip_r_lws (value);
+		if (end_val == NULL) {
+		    value = comma;
+		    continue;
+		} else {
+		    /* strip LWSP */
+		    *end_val = '\0';
+		}
+
+		if (strcasecmp(value, "auth-conf") == 0) {
+		    protection |= DIGEST_PRIVACY;
+		} else if (strcasecmp(value, "auth-int") == 0) {
+		    protection |= DIGEST_INTEGRITY;
+		} else if (strcasecmp(value, "auth") == 0) {
+		    protection |= DIGEST_NOLAYER;
+		} else {
+		    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+				       "Server supports unknown layer: %s\n",
+				       value);
+		}
+		
+		value = comma;
+	    }
+	} else if (strcasecmp(name, "cipher") == 0) {
+	    while (value && *value) {
+		struct digest_cipher *cipher = available_ciphers;
+		char *comma;
+		char *end_val;
+
+SKIP_SPACES_IN_CIPHER:
+		/* skipping spaces: */
+		value = skip_lws(value);
+		if (*value == '\0') {
+		    break;
+		}
+
+		/* check for an extreme case when there is no data: LWSP ',' */
+		if (*value == ',') {
+		    value++;
+		    goto SKIP_SPACES_IN_CIPHER;
+		}
+
+		comma = strchr(value, ',');
+
+		if (comma != NULL) {
+		    *comma++ = '\0';
+		}
+
+		/* skip LWSP at the end of the value, skip_r_lws returns pointer to
+		   the first LWSP character or NULL */
+		end_val = skip_r_lws (value);
+		if (end_val == NULL) {
+		    value = comma;
+		    continue;
+		} else {
+		    /* strip LWSP */
+		    *end_val = '\0';
+		}
+
+		/* do we support this cipher? */
+		while (cipher->name) {
+		    if (!strcasecmp(value, cipher->name)) break;
+		    cipher++;
+		}
+		if (cipher->name) {
+		    ciphers |= cipher->flag;
+		} else {
+		    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+				       "Server supports unknown cipher: %s\n",
+				       value);
+		}
+		
+		value = comma;
+	    }
+	} else if (strcasecmp(name, "stale") == 0 && ctext->password) {
+	    /* clear any cached password */
+	    if (ctext->free_password)
+		_plug_free_secret(params->utils, &ctext->password);
+	    ctext->password = NULL;
+	} else if (strcasecmp(name, "maxbuf") == 0) {
+	    /* maxbuf A number indicating the size of the largest
+	     * buffer the server is able to receive when using
+	     * "auth-int". If this directive is missing, the default
+	     * value is 65536. This directive may appear at most once;
+	     * if multiple instances are present, the client should
+	     * abort the authentication exchange.  
+	     */
+	    maxbuf_count++;
+	    
+	    if (maxbuf_count != 1) {
+		result = SASL_BADAUTH;
+		params->utils->seterror(params->utils->conn, 0,
+					"At least two maxbuf directives found. Authentication aborted");
+		goto FreeAllocatedMem;
+	    } 
+
+	    if (str2ul32 (value, &ctext->server_maxbuf) == FALSE) {
+		result = SASL_BADAUTH;
+		params->utils->seterror(params->utils->conn, 0,
+					"Invalid maxbuf parameter received from server (%s)", value);
+		goto FreeAllocatedMem;
+	    }
+	    
+	    if (ctext->server_maxbuf <= 16) {
+		result = SASL_BADAUTH;
+		params->utils->seterror(params->utils->conn, 0,
+					"Invalid maxbuf parameter received from server (too small: %s)", value);
+		goto FreeAllocatedMem;
+	    }
+
+	    if (ctext->server_maxbuf > MAX_SASL_BUFSIZE) {
+		result = SASL_BADAUTH;
+		params->utils->seterror(params->utils->conn, 0,
+					"Invalid maxbuf parameter received from server (too big: %s)", value);
+		goto FreeAllocatedMem;
+	    }
+	} else if (strcasecmp(name, "charset") == 0) {
+	    if (strcasecmp(value, "utf-8") != 0) {
+		result = SASL_BADAUTH;
+		params->utils->seterror(params->utils->conn, 0,
+					"Charset must be UTF-8");
+		goto FreeAllocatedMem;
+	    } else {
+		IsUTF8 = TRUE;
+	    }
+	} else if (strcasecmp(name,"algorithm")==0) {
+	    if (text->http_mode && strcasecmp(value, "md5") == 0) {
+		/* per RFC 2617: need to support both "md5" and "md5-sess" */
+	    }
+	    else if (strcasecmp(value, "md5-sess") != 0)
+		{
+		    params->utils->seterror(params->utils->conn, 0,
+					    "'algorithm' isn't 'md5-sess'");
+		    result = SASL_FAIL;
+		    goto FreeAllocatedMem;
+		}
+
+	    if (text->http_mode) {
+		/* per RFC 2617: algorithm MUST be saved */
+		_plug_strdup(params->utils, value, (char **) &ctext->algorithm,
+			     NULL);
+	    }
+	    algorithm_count++;
+	    if (algorithm_count > 1)
+		{
+		    params->utils->seterror(params->utils->conn, 0,
+					    "Must see 'algorithm' only once");
+		    result = SASL_FAIL;
+		    goto FreeAllocatedMem;
+		}
+	} else if (strcasecmp(name,"opaque")==0) {
+	    /* per RFC 2831: opaque MUST be ignored if received */
+	    if (text->http_mode) {
+		/* per RFC 2617: opaque MUST be saved */
+		_plug_strdup(params->utils, value, (char **) &ctext->opaque,
+			     NULL);
+		opaque_count++;
+		if (opaque_count > 1)
+		    {
+			params->utils->seterror(params->utils->conn, 0,
+						"Must see 'opaque' only once");
+			result = SASL_FAIL;
+			goto FreeAllocatedMem;
+		    }
+	    }
+	} else {
+	    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+			       "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+			       name, value);
+	}
+    }
+    
+    if (protection == 0) {
+	/* From RFC 2831[bis]:
+	   This directive is optional; if not present it defaults to "auth". */
+	if (saw_qop == 0) {
+	    protection = DIGEST_NOLAYER;
+	} else {
+	    result = SASL_BADAUTH;
+	    params->utils->seterror(params->utils->conn, 0,
+				    "Server doesn't support any known qop level");
+	    goto FreeAllocatedMem;
+	}
+    }
+
+    if (algorithm_count != 1) {
+	params->utils->seterror(params->utils->conn, 0,
+				"Must see 'algorithm' once. Didn't see at all");
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+
+    /* make sure we have everything we require */
+    if (text->nonce == NULL) {
+	params->utils->seterror(params->utils->conn, 0,
+				"Don't have nonce.");
+	result = SASL_FAIL;
+	goto FreeAllocatedMem;
+    }
+
+    /* get requested ssf */
+    external = params->external_ssf;
+    
+    /* what do we _need_?  how much is too much? */
+    if (!text->http_mode &&    	       	   /* HTTP Digest doesn't need buffer */
+	params->props.maxbufsize == 0) {
+	musthave = 0;
+	limit = 0;
+    } else {
+	if (params->props.max_ssf > external) {
+	    limit = params->props.max_ssf - external;
+	} else {
+	    limit = 0;
+	}
+	if (params->props.min_ssf > external) {
+	    musthave = params->props.min_ssf - external;
+	} else {
+	    musthave = 0;
+	}
+    }
+    
+    /* we now go searching for an option that gives us at least "musthave"
+       and at most "limit" bits of ssf. */
+    if ((limit > 1) && (protection & DIGEST_PRIVACY)) {
+	struct digest_cipher *cipher;
+	
+	/* let's find an encryption scheme that we like */
+	cipher = available_ciphers;
+	while (cipher->name) {
+	    /* examine each cipher we support, see if it meets our security
+	       requirements, and see if the server supports it.
+	       choose the best one of these */
+	    if ((limit >= cipher->ssf) && (musthave <= cipher->ssf) &&
+		(ciphers & cipher->flag) &&
+		(!ctext->cipher || (cipher->ssf > ctext->cipher->ssf))) {
+		ctext->cipher = cipher;
+	    }
+	    cipher++;
+	}
+	
+	if (ctext->cipher) {
+	    /* we found a cipher we like */
+	    ctext->protection = DIGEST_PRIVACY;
+	} else {
+	    /* we didn't find any ciphers we like */
+	    params->utils->seterror(params->utils->conn, 0,
+				    "No good privacy layers");
+	}
+    }
+    
+    if (ctext->cipher == NULL) {
+	/* we failed to find an encryption layer we liked;
+	   can we use integrity or nothing? */
+	
+	if ((limit >= 1) && (musthave <= 1) 
+	    && (protection & DIGEST_INTEGRITY)) {
+	    /* integrity */
+	    ctext->protection = DIGEST_INTEGRITY;
+	} else if (musthave <= 0) {
+	    /* no layer */
+	    ctext->protection = DIGEST_NOLAYER;
+
+	    /* See if server supports not having a layer */
+	    if ((protection & DIGEST_NOLAYER) != DIGEST_NOLAYER) {
+		params->utils->seterror(params->utils->conn, 0, 
+					"Server doesn't support \"no layer\"");
+		result = SASL_FAIL;
+		goto FreeAllocatedMem;
+	    }
+	} else {
+	    params->utils->seterror(params->utils->conn, 0,
+				    "Can't find an acceptable layer");
+	    result = SASL_TOOWEAK;
+	    goto FreeAllocatedMem;
+	}
+    }
+
+    *outrealms = realms;
+    *noutrealm = nrealm;
+
+  FreeAllocatedMem:
+    if (in_start) params->utils->free(in_start);
+
+    if (result != SASL_OK && realms) {
+	int lup;
+	
+	/* need to free all the realms */
+	for (lup = 0;lup < nrealm; lup++)
+	    params->utils->free(realms[lup]);
+	
+	params->utils->free(realms);
+    }
+
+    return result;
+}
+
+static int ask_user_info(client_context_t *ctext,
+			 sasl_client_params_t *params,
+			 char **realms, int nrealm,
+			 sasl_interact_t **prompt_need,
+			 sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) ctext;
+    int result = SASL_OK;
+    const char *authid = NULL, *userid = NULL, *realm = NULL;
+    char *realm_chal = NULL;
+    int user_result = SASL_OK;
+    int auth_result = SASL_OK;
+    int pass_result = SASL_OK;
+    int realm_result = SASL_FAIL;
+    int i;
+    size_t len;
+
+    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+		       "DIGEST-MD5 ask_user_info()");
+
+    /* try to get the authid */
+    if (oparams->authid == NULL) {
+	auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
+	
+	if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) {
+	    return auth_result;
+	}
+    }
+    
+    /* try to get the userid */
+    if (oparams->user == NULL) {
+	user_result = _plug_get_userid(params->utils, &userid, prompt_need);
+	
+	if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+	    return user_result;
+	}
+    }
+    
+    /* try to get the password */
+    if (ctext->password == NULL) {
+	pass_result = _plug_get_password(params->utils, &ctext->password,
+					 &ctext->free_password, prompt_need);
+	if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
+	    return pass_result;
+	}
+    }
+
+    /* try to get the realm */
+    if (text->realm == NULL) {
+	if (realms) {
+	    if(nrealm == 1) {
+		/* only one choice */
+		realm = realms[0];
+		realm_result = SASL_OK;
+	    } else {
+		/* ask the user */
+		realm_result = _plug_get_realm(params->utils,
+					       (const char **) realms,
+					       (const char **) &realm,
+					       prompt_need);
+	    }
+	}
+
+	/* fake the realm if we must */
+	if ((realm_result != SASL_OK) && (realm_result != SASL_INTERACT)) {
+	    if (params->serverFQDN) {
+		realm = params->serverFQDN;
+	    } else {
+		return realm_result;
+	    }
+	}    
+    }
+    
+    /* free prompts we got */
+    if (prompt_need && *prompt_need) {
+	params->utils->free(*prompt_need);
+	*prompt_need = NULL;
+    }
+    
+    /* if there are prompts not filled in */
+    if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
+	(pass_result == SASL_INTERACT) || (realm_result == SASL_INTERACT)) {
+
+	/* make our default realm */
+	if (realm_result == SASL_INTERACT) {
+	    if (realms) {
+		len = strlen(REALM_CHAL_PREFIX);
+		for (i = 0; i < nrealm; i++) {
+		    len += strlen(realms[i]) + 4 /* " {}," */;
+		}
+		realm_chal = params->utils->malloc(len + 1);
+		strcpy (realm_chal, REALM_CHAL_PREFIX);
+		for (i = 0; i < nrealm; i++) {
+		    strcat (realm_chal, " {");
+		    strcat (realm_chal, realms[i]);
+		    strcat (realm_chal, "},");
+		}
+		/* Replace the terminating comma with dot */
+		realm_chal[len-1] = '.';
+
+	    } else if (params->serverFQDN) {
+		realm_chal = params->utils->malloc(3+strlen(params->serverFQDN));
+		if (realm_chal) {
+		    sprintf(realm_chal, "{%s}", params->serverFQDN);
+		} else {
+		    return SASL_NOMEM;
+		}
+	    }
+	}
+
+	/* make the prompt list */
+	result =
+	    _plug_make_prompts(params->utils, prompt_need,
+			       user_result == SASL_INTERACT ?
+			       "Please enter your authorization name" : NULL,
+			       NULL,
+			       auth_result == SASL_INTERACT ?
+			       "Please enter your authentication name" : NULL,
+			       NULL,
+			       pass_result == SASL_INTERACT ?
+			       "Please enter your password" : NULL, NULL,
+			       NULL, NULL, NULL,
+			       realm_chal ? realm_chal : "{}",
+			       realm_result == SASL_INTERACT ?
+			       "Please enter your realm" : NULL,
+			       params->serverFQDN ? params->serverFQDN : NULL);
+	
+	if (result == SASL_OK) return SASL_INTERACT;
+
+	return result;
+    }
+    
+    if (oparams->authid == NULL) {
+	if (!userid || !*userid) {
+	    result = params->canon_user(params->utils->conn, authid, 0,
+					SASL_CU_AUTHID | SASL_CU_AUTHZID,
+					oparams);
+	}
+	else {
+	    result = params->canon_user(params->utils->conn,
+					authid, 0, SASL_CU_AUTHID, oparams);
+	    if (result != SASL_OK) return result;
+
+	    result = params->canon_user(params->utils->conn,
+					userid, 0, SASL_CU_AUTHZID, oparams);
+	}
+	if (result != SASL_OK) return result;
+    }
+
+    /* Get an allocated version of the realm into the structure */
+    if (realm && text->realm == NULL) {
+	_plug_strdup(params->utils, realm, (char **) &text->realm, NULL);
+    }
+
+    return result;
+}
+
+static int digestmd5_client_mech_new(void *glob_context,
+				     sasl_client_params_t * params,
+				     void **conn_context)
+{
+    context_t *text;
+    
+    if ((params->flags & SASL_NEED_HTTP) && !params->http_request) {
+	SETERROR(params->utils,
+		 "DIGEST-MD5 unavailable due to lack of HTTP request");
+	return SASL_BADPARAM;
+    }
+
+    /* holds state are in -- allocate client size */
+    text = params->utils->malloc(sizeof(client_context_t));
+    if (text == NULL)
+	return SASL_NOMEM;
+    memset(text, 0, sizeof(client_context_t));
+    
+    text->state = 1;
+    text->i_am = CLIENT;
+    text->http_mode = (params->flags & SASL_NEED_HTTP);
+    text->reauth = ((digest_glob_context_t *) glob_context)->reauth;
+    
+    *conn_context = text;
+
+    return SASL_OK;
+}
+
+static int
+digestmd5_client_mech_step1(client_context_t *ctext,
+			    sasl_client_params_t *params,
+			    const char *serverin __attribute__((unused)), 
+			    unsigned serverinlen __attribute__((unused)), 
+			    sasl_interact_t **prompt_need,
+			    const char **clientout,
+			    unsigned *clientoutlen,
+			    sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) ctext;
+    int result = SASL_FAIL;
+    unsigned val;
+
+    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+		       "DIGEST-MD5 client step 1");
+
+    result = ask_user_info(ctext, params, NULL, 0, prompt_need, oparams);
+    if (result != SASL_OK) return result;
+
+    /* check if we have cached info for this user on this server */
+    val = hash(params->serverFQDN) % text->reauth->size;
+    if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+	if (text->reauth->e[val].u.c.serverFQDN &&
+	    !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
+			params->serverFQDN) &&
+	    !strcmp(text->reauth->e[val].authid, oparams->authid)) {
+
+	    /* we have info, so use it */
+	    if (text->realm) params->utils->free(text->realm);
+	    _plug_strdup(params->utils, text->reauth->e[val].realm,
+			 &text->realm, NULL);
+	    _plug_strdup(params->utils, (char *) text->reauth->e[val].nonce,
+			 (char **) &text->nonce, NULL);
+	    text->nonce_count = ++text->reauth->e[val].nonce_count;
+	    _plug_strdup(params->utils, (char *) text->reauth->e[val].cnonce,
+			 (char **) &text->cnonce, NULL);
+	    if (text->http_mode) {
+		/* per RFC 2617: algorithm & opaque MUST be sent back to server */
+		_plug_strdup(params->utils,
+			     (char *) text->reauth->e[val].u.c.algorithm,
+			     (char **) &ctext->algorithm, NULL);
+		if (text->reauth->e[val].u.c.opaque) {
+		    _plug_strdup(params->utils,
+				 (char *) text->reauth->e[val].u.c.opaque,
+				 (char **) &ctext->opaque, NULL);
+		}
+	    }
+	    ctext->protection = text->reauth->e[val].u.c.protection;
+	    ctext->cipher = text->reauth->e[val].u.c.cipher;
+	    ctext->server_maxbuf = text->reauth->e[val].u.c.server_maxbuf;
+	}
+	params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+    }
+
+    if (!text->nonce) {
+	/* we don't have any reauth info, so just return
+	 * that there is no initial client send */
+	text->state = 2;
+	return SASL_CONTINUE;
+    }
+
+    /*
+     * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
+     * response | maxbuf | charset | auth-param )
+     */
+    
+    result = make_client_response(text, params, oparams);
+    if (result != SASL_OK) return result;
+
+    *clientoutlen = (unsigned) strlen(text->out_buf);
+    *clientout = text->out_buf;
+
+    text->state = 3;
+    return SASL_CONTINUE;
+}
+
+static int digestmd5_client_mech_step2(client_context_t *ctext,
+				       sasl_client_params_t *params,
+				       const char *serverin,
+				       unsigned serverinlen,
+				       sasl_interact_t **prompt_need,
+				       const char **clientout,
+				       unsigned *clientoutlen,
+				       sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) ctext;
+    int result = SASL_FAIL;
+    char **realms = NULL;
+    int nrealm = 0;
+
+    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+		       "DIGEST-MD5 client step 2");
+
+    if (params->props.min_ssf > params->props.max_ssf) {
+	return SASL_BADPARAM;
+    }
+
+    /* don't bother parsing the challenge more than once */
+    if (text->nonce == NULL) {
+	result = parse_server_challenge(ctext, params, serverin, serverinlen,
+					&realms, &nrealm);
+	if (result != SASL_OK) goto FreeAllocatedMem;
+    
+	if (nrealm == 1) {
+	    /* only one choice! */
+	    text->realm = realms[0];
+
+	    /* free realms */
+	    params->utils->free(realms);
+	    realms = NULL;
+	} else {
+	    /* Save realms for later use */
+	    text->realms = realms;
+	    text->realm_cnt = nrealm;
+	}
+    } else {
+	/* Restore the list of realms */
+	realms = text->realms;
+	nrealm = text->realm_cnt;
+    }
+
+    result = ask_user_info(ctext, params, realms, nrealm,
+			   prompt_need, oparams);
+    if (result != SASL_OK) goto FreeAllocatedMem;
+
+    /*
+     * (username | realm | nonce | cnonce | nonce-count | qop | digest-uri |
+     *  response | maxbuf | charset | auth-param )
+     */
+    
+    result = make_client_response(text, params, oparams);
+    if (result != SASL_OK) goto FreeAllocatedMem;
+
+    *clientoutlen = (unsigned) strlen(text->out_buf);
+    *clientout = text->out_buf;
+
+    text->state = 3;
+    
+    result = SASL_CONTINUE;
+    
+  FreeAllocatedMem:
+    return result;
+}
+
+static int
+digestmd5_client_mech_step3(client_context_t *ctext,
+			    sasl_client_params_t *params,
+			    const char *serverin,
+			    unsigned serverinlen,
+			    sasl_interact_t **prompt_need __attribute__((unused)),
+			    const char **clientout __attribute__((unused)),
+			    unsigned *clientoutlen __attribute__((unused)),
+			    sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) ctext;
+    char           *in = NULL;
+    char           *in_start;
+    int result = SASL_FAIL;
+    
+    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+		       "DIGEST-MD5 client step 3");
+
+    /* Verify that server is really what he claims to be */
+    in_start = in = params->utils->malloc(serverinlen + 1);
+    if (in == NULL) return SASL_NOMEM;
+
+    memcpy(in, serverin, serverinlen);
+    in[serverinlen] = 0;
+    
+    /* parse the response */
+    while (in[0] != '\0') {
+	char *name, *value;
+	get_pair(&in, &name, &value);
+	
+	if (name == NULL) {
+	    params->utils->seterror(params->utils->conn, 0,
+				    "DIGEST-MD5 Received Garbage");
+	    result = SASL_BADAUTH;
+	    break;
+	}
+	
+	if (*name == '\0') {
+	    break;
+	}
+
+	if (strcasecmp(name, "rspauth") == 0) {
+	    
+	    if (strcmp(text->response_value, value) != 0) {
+		params->utils->seterror(params->utils->conn, 0,
+					"DIGEST-MD5: This server wants us to believe that he knows shared secret");
+		result = SASL_BADSERV;
+	    } else {
+		oparams->doneflag = 1;
+		oparams->param_version = 0;
+		
+		result = SASL_OK;
+	    }
+	    break;
+	} else {
+	    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+			       "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+			       name, value);
+	}
+    }
+    
+    params->utils->free(in_start);
+
+    if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+	unsigned val = hash(params->serverFQDN) % text->reauth->size;
+	switch (result) {
+	case SASL_OK:
+	    if (text->nonce_count == 1) {
+		/* successful initial auth, setup for future reauth */
+		clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+		_plug_strdup(params->utils, oparams->authid,
+			     &text->reauth->e[val].authid, NULL);
+		text->reauth->e[val].realm = text->realm; text->realm = NULL;
+		text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
+		text->reauth->e[val].nonce_count = text->nonce_count;
+		text->reauth->e[val].cnonce = text->cnonce; text->cnonce = NULL;
+		_plug_strdup(params->utils, params->serverFQDN,
+			     &text->reauth->e[val].u.c.serverFQDN, NULL);
+		if (text->http_mode) {
+		    /* per RFC 2617: algorithm & opaque MUST be saved */
+		    text->reauth->e[val].u.c.algorithm = ctext->algorithm;
+		    ctext->algorithm = NULL;
+		    text->reauth->e[val].u.c.opaque = ctext->opaque;
+		    ctext->opaque = NULL;
+		}
+		text->reauth->e[val].u.c.protection = ctext->protection;
+		text->reauth->e[val].u.c.cipher = ctext->cipher;
+		text->reauth->e[val].u.c.server_maxbuf = ctext->server_maxbuf;
+	    }
+	    else {
+		/* reauth, we already incremented nonce_count */
+	    }
+	    break;
+	default:
+	    if (text->nonce_count > 1) {
+		/* failed reauth, clear cache */
+		clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+	    }
+	    else {
+		/* failed initial auth, leave existing cache */
+	    }
+	}
+	params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+    }
+
+    return result;
+}
+
+static int digestmd5_client_mech_step(void *conn_context,
+				      sasl_client_params_t *params,
+				      const char *serverin,
+				      unsigned serverinlen,
+				      sasl_interact_t **prompt_need,
+				      const char **clientout,
+				      unsigned *clientoutlen,
+				      sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) conn_context;
+    client_context_t *ctext = (client_context_t *) conn_context;
+    unsigned val = hash(params->serverFQDN) % text->reauth->size;
+    
+    if (serverinlen > 2048) return SASL_BADPROT;
+    
+    *clientout = NULL;
+    *clientoutlen = 0;
+
+    switch (text->state) {
+
+    case 1:
+	if (!serverin) {
+	    /* here's where we attempt fast reauth if possible */
+	    int reauth = 0;
+
+	    /* check if we have saved info for this server */
+	    if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+		reauth = text->reauth->e[val].u.c.serverFQDN &&
+		    !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
+				params->serverFQDN);
+		params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+	    }
+	    if (reauth) {
+		return digestmd5_client_mech_step1(ctext, params,
+						   serverin, serverinlen,
+						   prompt_need,
+						   clientout, clientoutlen,
+						   oparams);
+	    }
+	    else {
+		/* we don't have any reauth info, so just return
+		 * that there is no initial client send */
+		text->state = 2;
+		return SASL_CONTINUE;
+	    }
+	}
+	
+	/* fall through and respond to challenge */
+	
+    case 3:
+	if (serverin && !strncasecmp(serverin, "rspauth=", 8)) {
+	    return digestmd5_client_mech_step3(ctext, params,
+					       serverin, serverinlen,
+					       prompt_need,
+					       clientout, clientoutlen,
+					       oparams);
+	}
+
+	/* fall through and respond to challenge */
+	text->state = 2;
+
+	/* cleanup after a failed reauth attempt */
+	if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+	    clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+
+	    params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+	}
+
+	if (text->realm) params->utils->free(text->realm);
+	if (text->nonce) params->utils->free(text->nonce);
+	if (text->cnonce) params->utils->free(text->cnonce);
+	text->realm = NULL;
+	text->nonce = text->cnonce = NULL;
+	ctext->cipher = NULL;
+    
+    case 2:
+	return digestmd5_client_mech_step2(ctext, params,
+					   serverin, serverinlen,
+					   prompt_need,
+					   clientout, clientoutlen,
+					   oparams);
+
+    default:
+	params->utils->log(NULL, SASL_LOG_ERR,
+			   "Invalid DIGEST-MD5 client step %d\n", text->state);
+	return SASL_FAIL;
+    }
+    
+    return SASL_FAIL; /* should never get here */
+}
+
+static void digestmd5_client_mech_dispose(void *conn_context,
+					  const sasl_utils_t *utils)
+{
+    client_context_t *ctext = (client_context_t *) conn_context;
+    
+    if (!ctext || !utils) return;
+    
+    utils->log(utils->conn, SASL_LOG_DEBUG,
+	       "DIGEST-MD5 client mech dispose");
+
+    if (ctext->free_password) _plug_free_secret(utils, &ctext->password);
+
+    digestmd5_common_mech_dispose(conn_context, utils);
+}
+
+static sasl_client_plug_t digestmd5_client_plugins[] =
+{
+    {
+	"DIGEST-MD5",
+#ifdef WITH_RC4				/* mech_name */
+	128,				/* max ssf */
+#elif defined(WITH_DES)
+	112,
+#else
+	1,
+#endif
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
+	SASL_FEAT_NEEDSERVERFQDN
+	| SASL_FEAT_ALLOWS_PROXY
+	| SASL_FEAT_SUPPORTS_HTTP,	/* features */
+	NULL,				/* required_prompts */
+	&client_glob_context,		/* glob_context */
+	&digestmd5_client_mech_new,	/* mech_new */
+	&digestmd5_client_mech_step,	/* mech_step */
+	&digestmd5_client_mech_dispose,	/* mech_dispose */
+	&digestmd5_common_mech_free,	/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare1 */
+	NULL				/* spare2 */
+    }
+};
+
+int digestmd5_client_plug_init(sasl_utils_t *utils,
+			       int maxversion,
+			       int *out_version,
+			       sasl_client_plug_t **pluglist,
+			       int *plugcount)
+{
+    reauth_cache_t *reauth_cache;
+
+    if (maxversion < SASL_CLIENT_PLUG_VERSION)
+	return SASL_BADVERS;
+    
+    /* reauth cache */
+    reauth_cache = utils->malloc(sizeof(reauth_cache_t));
+    if (reauth_cache == NULL)
+	return SASL_NOMEM;
+    memset(reauth_cache, 0, sizeof(reauth_cache_t));
+    reauth_cache->i_am = CLIENT;
+    
+    /* mutex */
+    reauth_cache->mutex = utils->mutex_alloc();
+    if (!reauth_cache->mutex)
+	return SASL_FAIL;
+
+    /* entries */
+    reauth_cache->size = 10;
+    reauth_cache->e = utils->malloc(reauth_cache->size *
+				    sizeof(reauth_entry_t));
+    if (reauth_cache->e == NULL)
+	return SASL_NOMEM;
+    memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
+
+    ((digest_glob_context_t *) digestmd5_client_plugins[0].glob_context)->reauth = reauth_cache;
+
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = digestmd5_client_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+}

+ 43 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/digestmd5_init.c

@@ -0,0 +1,43 @@
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_digestmd5_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+					 )
+{
+    switch (ul_reason_for_call)
+	{
+		case DLL_PROCESS_ATTACH:
+		case DLL_THREAD_ATTACH:
+		case DLL_THREAD_DETACH:
+		case DLL_PROCESS_DETACH:
+			break;
+    }
+    return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( digestmd5 )
+SASL_SERVER_PLUG_INIT( digestmd5 )
+

+ 1851 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2.c

@@ -0,0 +1,1851 @@
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1998-2003 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <gssapi/gssapi.h>
+
+#ifndef KRB5_HEIMDAL
+#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
+#include <gssapi/gssapi_ext.h>
+#endif
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include "gs2_token.h"
+
+#define GS2_CB_FLAG_MASK    0x0F
+#define GS2_CB_FLAG_N       0x00
+#define GS2_CB_FLAG_P       0x01
+#define GS2_CB_FLAG_Y       0x02
+#define GS2_NONSTD_FLAG     0x10
+
+typedef struct context {
+    gss_ctx_id_t gss_ctx;
+    gss_name_t client_name;
+    gss_name_t server_name;
+    gss_cred_id_t server_creds;
+    gss_cred_id_t client_creds;
+    char *out_buf;
+    unsigned out_buf_len;
+    const sasl_utils_t *utils;
+    char *authid;
+    char *authzid;
+    union {
+        sasl_client_plug_t *client;
+        sasl_server_plug_t *server;
+    } plug;
+    gss_OID mechanism;
+    int gs2_flags;
+    char *cbindingname;
+    struct gss_channel_bindings_struct gss_cbindings;
+    sasl_secret_t *password;
+    unsigned int free_password;
+    OM_uint32 lifetime;
+} context_t;
+
+static gss_OID_set gs2_mechs = GSS_C_NO_OID_SET;
+
+static int gs2_get_init_creds(context_t *context,
+                              sasl_client_params_t *params,
+                              sasl_interact_t **prompt_need,
+                              sasl_out_params_t *oparams);
+
+static int gs2_verify_initial_message(context_t *text,
+                                      sasl_server_params_t *sparams,
+                                      const char *in,
+                                      unsigned inlen,
+                                      gss_buffer_t token);
+
+static int gs2_make_header(context_t *text,
+                           sasl_client_params_t *cparams,
+                           const char *authzid,
+                           char **out,
+                           unsigned *outlen);
+
+static int gs2_make_message(context_t *text,
+                            sasl_client_params_t *cparams,
+                            int initialContextToken,
+                            gss_buffer_t token,
+                            char **out,
+                            unsigned *outlen);
+
+static int gs2_get_mech_attrs(const sasl_utils_t *utils,
+                              const gss_OID mech,
+                              unsigned int *security_flags,
+                              unsigned int *features,
+                              const unsigned long **prompts);
+
+static int gs2_indicate_mechs(const sasl_utils_t *utils);
+
+static int gs2_map_sasl_name(const sasl_utils_t *utils,
+                             const char *mech,
+                             gss_OID *oid);
+
+static int gs2_duplicate_buffer(const sasl_utils_t *utils,
+                                const gss_buffer_t src,
+                                gss_buffer_t dst);
+
+static int gs2_unescape_authzid(const sasl_utils_t *utils,
+                                char **in,
+                                unsigned *inlen,
+                                char **authzid);
+
+static int gs2_escape_authzid(const sasl_utils_t *utils,
+                              const char *in,
+                              unsigned inlen,
+                              char **authzid);
+
+/* sasl_gs_log: only logs status string returned from gss_display_status() */
+#define sasl_gs2_log(x,y,z) sasl_gs2_seterror_(x,y,z,1)
+#define sasl_gs2_seterror(x,y,z) sasl_gs2_seterror_(x,y,z,0)
+
+static int
+sasl_gs2_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
+                   int logonly);
+
+static context_t *
+sasl_gs2_new_context(const sasl_utils_t *utils)
+{
+    context_t *ret;
+
+    ret = utils->malloc(sizeof(context_t));
+    if (ret == NULL)
+        return NULL;
+
+    memset(ret, 0, sizeof(context_t));
+    ret->utils = utils;
+
+    return ret;
+}
+
+static int
+sasl_gs2_free_context_contents(context_t *text)
+{
+    OM_uint32 min_stat;
+
+    if (text == NULL)
+        return SASL_OK;
+
+    if (text->gss_ctx != GSS_C_NO_CONTEXT) {
+        gss_delete_sec_context(&min_stat,&text->gss_ctx,
+                               GSS_C_NO_BUFFER);
+        text->gss_ctx = GSS_C_NO_CONTEXT;
+    }
+
+    if (text->client_name != GSS_C_NO_NAME) {
+        gss_release_name(&min_stat,&text->client_name);
+        text->client_name = GSS_C_NO_NAME;
+    }
+
+    if (text->server_name != GSS_C_NO_NAME) {
+        gss_release_name(&min_stat,&text->server_name);
+        text->server_name = GSS_C_NO_NAME;
+    }
+
+    if (text->server_creds != GSS_C_NO_CREDENTIAL) {
+        gss_release_cred(&min_stat, &text->server_creds);
+        text->server_creds = GSS_C_NO_CREDENTIAL;
+    }
+
+    if (text->client_creds != GSS_C_NO_CREDENTIAL) {
+        gss_release_cred(&min_stat, &text->client_creds);
+        text->client_creds = GSS_C_NO_CREDENTIAL;
+    }
+
+    if (text->authid != NULL) {
+        text->utils->free(text->authid);
+        text->authid = NULL;
+    }
+
+    if (text->authzid != NULL) {
+        text->utils->free(text->authzid);
+        text->authzid = NULL;
+    }
+
+    gss_release_buffer(&min_stat, &text->gss_cbindings.application_data);
+
+    if (text->out_buf != NULL) {
+        text->utils->free(text->out_buf);
+        text->out_buf = NULL;
+    }
+
+    text->out_buf_len = 0;
+
+    if (text->cbindingname != NULL) {
+        text->utils->free(text->cbindingname);
+        text->cbindingname = NULL;
+    }
+
+    if (text->free_password)
+        _plug_free_secret(text->utils, &text->password);
+
+    memset(text, 0, sizeof(*text));
+
+    return SASL_OK;
+}
+
+static void
+gs2_common_mech_dispose(void *conn_context, const sasl_utils_t *utils)
+{
+    sasl_gs2_free_context_contents((context_t *)(conn_context));
+    utils->free(conn_context);
+}
+
+static void
+gs2_common_mech_free(void *global_context __attribute__((unused)),
+                     const sasl_utils_t *utils)
+{
+    OM_uint32 minor;
+
+    if (gs2_mechs != GSS_C_NO_OID_SET) {
+        gss_release_oid_set(&minor, &gs2_mechs);
+        gs2_mechs = GSS_C_NO_OID_SET;
+    }
+}
+
+/*****************************  Server Section  *****************************/
+
+static int
+gs2_server_mech_new(void *glob_context,
+                    sasl_server_params_t *params,
+                    const char *challenge __attribute__((unused)),
+                    unsigned challen __attribute__((unused)),
+                    void **conn_context)
+{
+    context_t *text;
+    int ret;
+
+    text = sasl_gs2_new_context(params->utils);
+    if (text == NULL) {
+        MEMERROR(params->utils);
+        return SASL_NOMEM;
+    }
+
+    text->gss_ctx = GSS_C_NO_CONTEXT;
+    text->client_name = GSS_C_NO_NAME;
+    text->server_name = GSS_C_NO_NAME;
+    text->server_creds = GSS_C_NO_CREDENTIAL;
+    text->client_creds = GSS_C_NO_CREDENTIAL;
+    text->plug.server = glob_context;
+
+    ret = gs2_map_sasl_name(params->utils, text->plug.server->mech_name,
+                            &text->mechanism);
+    if (ret != SASL_OK) {
+        gs2_common_mech_dispose(text, params->utils);
+        return ret;
+    }
+
+    *conn_context = text;
+
+    return SASL_OK;
+}
+
+static int
+gs2_server_mech_step(void *conn_context,
+                     sasl_server_params_t *params,
+                     const char *clientin,
+                     unsigned clientinlen,
+                     const char **serverout,
+                     unsigned *serveroutlen,
+                     sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *)conn_context;
+    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+    OM_uint32 maj_stat = GSS_S_FAILURE, min_stat = 0;
+    gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc short_name_buf = GSS_C_EMPTY_BUFFER;
+    gss_name_t without = GSS_C_NO_NAME;
+    gss_OID_set_desc mechs;
+    OM_uint32 out_flags = 0;
+    int ret = SASL_OK, equal = 0;
+    int initialContextToken = (text->gss_ctx == GSS_C_NO_CONTEXT);
+    char *p;
+
+    if (serverout == NULL) {
+        PARAMERROR(text->utils);
+        return SASL_BADPARAM;
+    }
+
+    *serverout = NULL;
+    *serveroutlen = 0;
+
+    if (initialContextToken) {
+        name_buf.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
+        name_buf.value = params->utils->malloc(name_buf.length + 1);
+        if (name_buf.value == NULL) {
+            MEMERROR(text->utils);
+            ret = SASL_NOMEM;
+            goto cleanup;
+        }
+        snprintf(name_buf.value, name_buf.length + 1,
+                 "%s@%s", params->service, params->serverFQDN);
+        maj_stat = gss_import_name(&min_stat,
+                                   &name_buf,
+                                   GSS_C_NT_HOSTBASED_SERVICE,
+                                   &text->server_name);
+        params->utils->free(name_buf.value);
+        name_buf.value = NULL;
+
+        if (GSS_ERROR(maj_stat))
+            goto cleanup;
+
+        assert(text->server_creds == GSS_C_NO_CREDENTIAL);
+
+        mechs.count = 1;
+        mechs.elements = (gss_OID)text->mechanism;
+
+        if (params->gss_creds == GSS_C_NO_CREDENTIAL) {
+            maj_stat = gss_acquire_cred(&min_stat,
+                                        text->server_name,
+                                        GSS_C_INDEFINITE,
+                                        &mechs,
+                                        GSS_C_ACCEPT,
+                                        &text->server_creds,
+                                        NULL,
+                                        &text->lifetime);
+            if (GSS_ERROR(maj_stat))
+                goto cleanup;
+        }
+
+        ret = gs2_verify_initial_message(text,
+                                         params,
+                                         clientin,
+                                         clientinlen,
+                                         &input_token);
+        if (ret != SASL_OK)
+            goto cleanup;
+    } else {
+        input_token.value = (void *)clientin;
+        input_token.length = clientinlen;
+    }
+
+    maj_stat = gss_accept_sec_context(&min_stat,
+                                      &text->gss_ctx,
+                                      (params->gss_creds != GSS_C_NO_CREDENTIAL)
+                                        ? (gss_cred_id_t)params->gss_creds
+                                        : text->server_creds,
+                                      &input_token,
+                                      &text->gss_cbindings,
+                                      &text->client_name,
+                                      NULL,
+                                      &output_token,
+                                      &out_flags,
+                                      &text->lifetime,
+                                      &text->client_creds);
+    if (GSS_ERROR(maj_stat)) {
+        sasl_gs2_log(text->utils, maj_stat, min_stat);
+        text->utils->seterror(text->utils->conn, SASL_NOLOG,
+                              "GS2 Failure: gss_accept_sec_context");
+        ret = (maj_stat == GSS_S_BAD_BINDINGS) ? SASL_BADBINDING : SASL_BADAUTH;
+        goto cleanup;
+    }
+
+    *serveroutlen = output_token.length;
+    if (output_token.value != NULL) {
+        ret = _plug_buf_alloc(text->utils, &text->out_buf,
+                              &text->out_buf_len, *serveroutlen);
+        if (ret != SASL_OK)
+            goto cleanup;
+        memcpy(text->out_buf, output_token.value, *serveroutlen);
+        *serverout = text->out_buf;
+    } else {
+        /* No output token, send an empty string */
+        *serverout = "";
+        serveroutlen = 0;
+    }
+
+    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+        ret = SASL_CONTINUE;
+        goto cleanup;
+    }
+
+    assert(maj_stat == GSS_S_COMPLETE);
+
+    if ((out_flags & GSS_C_SEQUENCE_FLAG) == 0)  {
+        ret = SASL_BADAUTH;
+        goto cleanup;
+    }
+
+    maj_stat = gss_display_name(&min_stat, text->client_name,
+                                &name_buf, NULL);
+    if (GSS_ERROR(maj_stat))
+        goto cleanup;
+
+    ret = gs2_duplicate_buffer(params->utils, &name_buf, &short_name_buf);
+    if (ret != 0)
+        goto cleanup;
+
+    p = (char *)memchr(name_buf.value, '@', name_buf.length);
+    if (p != NULL) {
+        short_name_buf.length = (p - (char *)name_buf.value);
+
+        maj_stat = gss_import_name(&min_stat,
+                                   &short_name_buf,
+                                   GSS_C_NT_USER_NAME,
+                                   &without);
+        if (GSS_ERROR(maj_stat)) {
+            goto cleanup;
+        }
+
+        maj_stat = gss_compare_name(&min_stat, text->client_name,
+                                    without, &equal);
+        if (GSS_ERROR(maj_stat)) {
+            goto cleanup;
+        }
+
+        if (equal)
+            ((char *)short_name_buf.value)[short_name_buf.length] = '\0';
+    }
+
+    text->authid = (char *)short_name_buf.value;
+    short_name_buf.value = NULL;
+    short_name_buf.length = 0;
+
+    if (text->authzid != NULL) {
+        ret = params->canon_user(params->utils->conn,
+                                 text->authzid, 0,
+                                 SASL_CU_AUTHZID, oparams);
+        if (ret != SASL_OK) {
+            goto cleanup;
+	}
+    }
+
+    ret = params->canon_user(params->utils->conn,
+                             text->authid, 0,
+                             text->authzid == NULL
+                                ? (SASL_CU_AUTHZID | SASL_CU_AUTHID)
+                                : SASL_CU_AUTHID,
+                             oparams);
+    if (ret != SASL_OK) {
+        goto cleanup;
+    }
+
+    switch (text->gs2_flags & GS2_CB_FLAG_MASK) {
+    case GS2_CB_FLAG_N:
+        oparams->cbindingdisp = SASL_CB_DISP_NONE;
+        break;
+    case GS2_CB_FLAG_P:
+        oparams->cbindingdisp = SASL_CB_DISP_USED;
+        oparams->cbindingname = text->cbindingname;
+        break;
+    case GS2_CB_FLAG_Y:
+        oparams->cbindingdisp = SASL_CB_DISP_WANT;
+        break;
+    }
+
+    if (text->client_creds != GSS_C_NO_CREDENTIAL)
+        oparams->client_creds = &text->client_creds;
+    else
+        oparams->client_creds = NULL;
+
+    oparams->gss_peer_name = text->client_name;
+    oparams->gss_local_name = text->server_name;
+    oparams->maxoutbuf = 0xFFFFFF;
+    oparams->encode = NULL;
+    oparams->decode = NULL;
+    oparams->mech_ssf = 0;
+    oparams->doneflag = 1;
+
+    ret = SASL_OK;
+
+cleanup:
+    if (ret == SASL_OK && maj_stat != GSS_S_COMPLETE) {
+        sasl_gs2_seterror(text->utils, maj_stat, min_stat);
+        ret = SASL_FAIL;
+    }
+
+    if (initialContextToken) {
+        gss_release_buffer(&min_stat, &input_token);
+    }
+    gss_release_buffer(&min_stat, &name_buf);
+    gss_release_buffer(&min_stat, &short_name_buf);
+    gss_release_buffer(&min_stat, &output_token);
+    gss_release_name(&min_stat, &without);
+
+    if (ret < SASL_OK) {
+        sasl_gs2_free_context_contents(text);
+    }
+
+    return ret;
+}
+
+static int
+gs2_common_plug_init(const sasl_utils_t *utils,
+                     size_t plugsize,
+                     int (*plug_alloc)(const sasl_utils_t *,
+                                       void *,
+                                       const gss_buffer_t,
+                                       const gss_OID),
+                     void **pluglist,
+                     int *plugcount)
+{
+    OM_uint32 major, minor;
+    size_t i, count = 0;
+    void *plugs = NULL;
+
+    *pluglist = NULL;
+    *plugcount = 0;
+
+    if (gs2_indicate_mechs(utils) != SASL_OK) {
+        return SASL_NOMECH;
+    }
+
+    plugs = utils->malloc(gs2_mechs->count * plugsize);
+    if (plugs == NULL) {
+        MEMERROR(utils);
+        return SASL_NOMEM;
+    }
+    memset(plugs, 0, gs2_mechs->count * plugsize);
+
+    for (i = 0; i < gs2_mechs->count; i++) {
+        gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER;
+
+        major = gss_inquire_saslname_for_mech(&minor,
+                                              &gs2_mechs->elements[i],
+                                              &sasl_mech_name,
+                                              GSS_C_NO_BUFFER,
+                                              GSS_C_NO_BUFFER);
+        if (GSS_ERROR(major))
+            continue;
+
+#define PLUG_AT(index)      (void *)((unsigned char *)plugs + (count * plugsize))
+
+        if (plug_alloc(utils, PLUG_AT(count), &sasl_mech_name,
+                       &gs2_mechs->elements[i]) == SASL_OK)
+            count++;
+
+        gss_release_buffer(&minor, &sasl_mech_name);
+    }
+
+    if (count == 0) {
+        utils->free(plugs);
+        return SASL_NOMECH;
+    }
+
+    *pluglist = plugs;
+    *plugcount = count;
+
+    return SASL_OK;
+}
+
+static int
+gs2_server_plug_alloc(const sasl_utils_t *utils,
+                      void *plug,
+                      gss_buffer_t sasl_name,
+                      gss_OID mech)
+{
+    int ret;
+    sasl_server_plug_t *splug = (sasl_server_plug_t *)plug;
+    gss_buffer_desc buf;
+
+    memset(splug, 0, sizeof(*splug));
+
+    ret = gs2_get_mech_attrs(utils, mech,
+                             &splug->security_flags,
+                             &splug->features,
+                             NULL);
+    if (ret != SASL_OK)
+        return ret;
+
+    ret = gs2_duplicate_buffer(utils, sasl_name, &buf);
+    if (ret != SASL_OK)
+        return ret;
+
+    splug->mech_name = (char *)buf.value;
+    splug->glob_context = plug;
+    splug->mech_new = gs2_server_mech_new;
+    splug->mech_step = gs2_server_mech_step;
+    splug->mech_dispose = gs2_common_mech_dispose;
+    splug->mech_free = gs2_common_mech_free;
+
+    return SASL_OK;
+}
+
+static sasl_server_plug_t *gs2_server_plugins;
+static int gs2_server_plugcount;
+
+int
+gs2_server_plug_init(const sasl_utils_t *utils,
+                     int maxversion,
+                     int *outversion,
+                     sasl_server_plug_t **pluglist,
+                     int *plugcount)
+{
+    int ret;
+
+    *pluglist = NULL;
+    *plugcount = 0;
+
+    if (maxversion < SASL_SERVER_PLUG_VERSION)
+        return SASL_BADVERS;
+
+    *outversion = SASL_SERVER_PLUG_VERSION;
+
+    if (gs2_server_plugins == NULL) {
+        ret = gs2_common_plug_init(utils,
+                                   sizeof(sasl_server_plug_t),
+                                   gs2_server_plug_alloc,
+                                   (void **)&gs2_server_plugins,
+                                   &gs2_server_plugcount);
+        if (ret != SASL_OK)
+            return ret;
+    }
+
+    *pluglist = gs2_server_plugins;
+    *plugcount = gs2_server_plugcount;
+
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+static int gs2_client_mech_step(void *conn_context,
+                                sasl_client_params_t *params,
+                                const char *serverin,
+                                unsigned serverinlen,
+                                sasl_interact_t **prompt_need,
+                                const char **clientout,
+                                unsigned *clientoutlen,
+                                sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *)conn_context;
+    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
+    OM_uint32 maj_stat = GSS_S_FAILURE, min_stat = 0;
+    OM_uint32 req_flags, ret_flags;
+    int ret = SASL_FAIL;
+    int initialContextToken;
+
+    *clientout = NULL;
+    *clientoutlen = 0;
+
+    if (text->gss_ctx == GSS_C_NO_CONTEXT) {
+        ret = gs2_get_init_creds(text, params, prompt_need, oparams);
+        if (ret != SASL_OK) {
+            goto cleanup;
+	}
+
+        initialContextToken = 1;
+    } else {
+        initialContextToken = 0;
+    }
+
+    if (text->server_name == GSS_C_NO_NAME) { /* only once */
+        name_buf.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
+        name_buf.value = params->utils->malloc(name_buf.length + 1);
+        if (name_buf.value == NULL) {
+            ret = SASL_NOMEM;
+            goto cleanup;
+        }
+        if (params->serverFQDN == NULL ||
+            strlen(params->serverFQDN) == 0) {
+            SETERROR(text->utils, "GS2 Failure: no serverFQDN");
+            ret = SASL_FAIL;
+            goto cleanup;
+        }
+
+        snprintf(name_buf.value, name_buf.length + 1,
+                 "%s@%s", params->service, params->serverFQDN);
+
+        maj_stat = gss_import_name(&min_stat,
+                                   &name_buf,
+                                   GSS_C_NT_HOSTBASED_SERVICE,
+                                   &text->server_name);
+        params->utils->free(name_buf.value);
+        name_buf.value = NULL;
+
+        if (GSS_ERROR(maj_stat)) {
+	    ret = SASL_OK;
+            goto cleanup;
+	}
+    }
+
+    /* From GSSAPI plugin: apparently this is for some IMAP bug workaround */
+    if (serverinlen == 0 && text->gss_ctx != GSS_C_NO_CONTEXT) {
+        gss_delete_sec_context(&min_stat, &text->gss_ctx, GSS_C_NO_BUFFER);
+        text->gss_ctx = GSS_C_NO_CONTEXT;
+    }
+
+    input_token.value = (void *)serverin;
+    input_token.length = serverinlen;
+
+    if (initialContextToken) {
+        if ((text->plug.client->features & SASL_FEAT_GSS_FRAMING) == 0)
+            text->gs2_flags |= GS2_NONSTD_FLAG;
+
+        switch (params->cbindingdisp) {
+        case SASL_CB_DISP_NONE:
+            text->gs2_flags |= GS2_CB_FLAG_N;
+            break;
+        case SASL_CB_DISP_USED:
+            text->gs2_flags |= GS2_CB_FLAG_P;
+            break;
+        case SASL_CB_DISP_WANT:
+            text->gs2_flags |= GS2_CB_FLAG_Y;
+            break;
+        }
+
+        ret = gs2_make_header(text, params,
+                              strcmp(oparams->user, oparams->authid) ?
+                                     (char *) oparams->user : NULL,
+                              &text->out_buf, &text->out_buf_len);
+        if (ret != 0) {
+            goto cleanup;
+	}
+    }
+
+    req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
+
+    maj_stat = gss_init_sec_context(&min_stat,
+                                    (params->gss_creds != GSS_C_NO_CREDENTIAL)
+                                        ? (gss_cred_id_t)params->gss_creds
+                                        : text->client_creds,
+                                    &text->gss_ctx,
+                                    text->server_name,
+                                    (gss_OID)text->mechanism,
+                                    req_flags,
+                                    GSS_C_INDEFINITE,
+                                    &text->gss_cbindings,
+                                    serverinlen ? &input_token : GSS_C_NO_BUFFER,
+                                    NULL,
+                                    &output_token,
+                                    &ret_flags,
+                                    &text->lifetime);
+    if (GSS_ERROR(maj_stat)) {
+	ret = SASL_OK;
+        goto cleanup;
+    }
+
+    ret = gs2_make_message(text, params, initialContextToken, &output_token,
+                           &text->out_buf, &text->out_buf_len);
+    if (ret != 0) {
+        goto cleanup;
+    }
+
+    *clientout = text->out_buf;
+    *clientoutlen = text->out_buf_len;
+
+    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+        ret = SASL_CONTINUE;
+        goto cleanup;
+    }
+
+    if (text->client_name != GSS_C_NO_NAME) {
+        gss_release_name(&min_stat, &text->client_name);
+    }
+    maj_stat = gss_inquire_context(&min_stat,
+                                   text->gss_ctx,
+                                   &text->client_name,
+                                   NULL,
+                                   &text->lifetime,
+                                   NULL,
+                                   &ret_flags, /* flags */
+                                   NULL,
+                                   NULL);
+    if (GSS_ERROR(maj_stat)) {
+	ret = SASL_OK;
+        goto cleanup;
+    }
+
+    if ((ret_flags & req_flags) != req_flags) {
+        ret = SASL_BADAUTH;
+        goto cleanup;
+    }
+
+    maj_stat = gss_display_name(&min_stat,
+                                text->client_name,
+                                &name_buf,
+                                NULL);
+    if (GSS_ERROR(maj_stat)) {
+	ret = SASL_OK;
+        goto cleanup;
+    }
+
+    oparams->gss_peer_name = text->server_name;
+    oparams->gss_local_name = text->client_name;
+    oparams->encode = NULL;
+    oparams->decode = NULL;
+    oparams->mech_ssf = 0;
+    oparams->maxoutbuf = 0xFFFFFF;
+    oparams->doneflag = 1;
+
+    ret = SASL_OK;
+
+cleanup:
+    if (ret == SASL_OK && maj_stat != GSS_S_COMPLETE) {
+        sasl_gs2_seterror(text->utils, maj_stat, min_stat);
+        ret = SASL_FAIL;
+    }
+
+    gss_release_buffer(&min_stat, &output_token);
+    gss_release_buffer(&min_stat, &name_buf);
+
+    if (ret < SASL_OK) {
+        sasl_gs2_free_context_contents(text);
+    }
+
+    return ret;
+}
+
+static int gs2_client_mech_new(void *glob_context,
+                               sasl_client_params_t *params,
+                               void **conn_context)
+{
+    context_t *text;
+    int ret;
+
+    text = sasl_gs2_new_context(params->utils);
+    if (text == NULL) {
+        MEMERROR(params->utils);
+        return SASL_NOMEM;
+    }
+
+    text->gss_ctx = GSS_C_NO_CONTEXT;
+    text->client_name = GSS_C_NO_NAME;
+    text->server_creds = GSS_C_NO_CREDENTIAL;
+    text->client_creds  = GSS_C_NO_CREDENTIAL;
+    text->plug.client = glob_context;
+
+    ret = gs2_map_sasl_name(params->utils, text->plug.client->mech_name,
+                            &text->mechanism);
+    if (ret != SASL_OK) {
+        gs2_common_mech_dispose(text, params->utils);
+        return ret;
+    }
+
+    *conn_context = text;
+
+    return SASL_OK;
+}
+
+static int
+gs2_client_plug_alloc(const sasl_utils_t *utils,
+                      void *plug,
+                      gss_buffer_t sasl_name,
+                      gss_OID mech)
+{
+    int ret;
+    sasl_client_plug_t *cplug = (sasl_client_plug_t *)plug;
+    gss_buffer_desc buf;
+
+    memset(cplug, 0, sizeof(*cplug));
+
+    ret = gs2_get_mech_attrs(utils, mech,
+                             &cplug->security_flags,
+                             &cplug->features,
+                             &cplug->required_prompts);
+    if (ret != SASL_OK)
+        return ret;
+
+    ret = gs2_duplicate_buffer(utils, sasl_name, &buf);
+    if (ret != SASL_OK)
+        return ret;
+
+    cplug->mech_name = (char *)buf.value;
+    cplug->features |= SASL_FEAT_NEEDSERVERFQDN;
+    cplug->glob_context = plug;
+    cplug->mech_new = gs2_client_mech_new;
+    cplug->mech_step = gs2_client_mech_step;
+    cplug->mech_dispose = gs2_common_mech_dispose;
+    cplug->mech_free = gs2_common_mech_free;
+
+    return SASL_OK;
+}
+
+static sasl_client_plug_t *gs2_client_plugins;
+static int gs2_client_plugcount;
+
+int
+gs2_client_plug_init(const sasl_utils_t *utils,
+                     int maxversion,
+                     int *outversion,
+                     sasl_client_plug_t **pluglist,
+                     int *plugcount)
+{
+    int ret;
+
+    *pluglist = NULL;
+    *plugcount = 0;
+
+    if (maxversion < SASL_CLIENT_PLUG_VERSION)
+        return SASL_BADVERS;
+
+    *outversion = SASL_CLIENT_PLUG_VERSION;
+
+    if (gs2_client_plugins == NULL) {
+        ret = gs2_common_plug_init(utils,
+                                   sizeof(sasl_client_plug_t),
+                                   gs2_client_plug_alloc,
+                                   (void **)&gs2_client_plugins,
+                                   &gs2_client_plugcount);
+        if (ret != SASL_OK)
+            return ret;
+    }
+
+    *pluglist = gs2_client_plugins;
+    *plugcount = gs2_client_plugcount;
+
+    return SASL_OK;
+}
+
+/*
+ * Copy header and application channel bindings to GSS channel bindings
+ * structure in context.
+ */
+static int
+gs2_save_cbindings(context_t *text,
+                   gss_buffer_t header,
+                   const sasl_channel_binding_t *cbinding)
+{
+    gss_buffer_t gss_cbindings = &text->gss_cbindings.application_data;
+    size_t len;
+    unsigned char *p;
+
+    assert(gss_cbindings->value == NULL);
+
+    /*
+     * The application-data field MUST be set to the gs2-header, excluding
+     * the initial [gs2-nonstd-flag ","] part, concatenated with, when a
+     * gs2-cb-flag of "p" is used, the application's channel binding data.
+     */
+    len = header->length;
+    if (text->gs2_flags & GS2_NONSTD_FLAG) {
+        assert(len > 2);
+        len -= 2;
+    }
+    if ((text->gs2_flags & GS2_CB_FLAG_MASK) == GS2_CB_FLAG_P &&
+        cbinding != NULL) {
+        len += cbinding->len;
+    }
+
+    gss_cbindings->length = len;
+    gss_cbindings->value = text->utils->malloc(len);
+    if (gss_cbindings->value == NULL)
+        return SASL_NOMEM;
+
+    p = (unsigned char *)gss_cbindings->value;
+    if (text->gs2_flags & GS2_NONSTD_FLAG) {
+        memcpy(p, (unsigned char *)header->value + 2, header->length - 2);
+        p += header->length - 2;
+    } else {
+        memcpy(p, header->value, header->length);
+        p += header->length;
+    }
+
+    if ((text->gs2_flags & GS2_CB_FLAG_MASK) == GS2_CB_FLAG_P &&
+        cbinding != NULL) {
+        memcpy(p, cbinding->data, cbinding->len);
+    }
+
+    return SASL_OK;
+}
+
+#define CHECK_REMAIN(n)     do { if (remain < (n)) return SASL_BADPROT; } while (0)
+
+/*
+ * Verify gs2-header, save authzid and channel bindings to context.
+ */
+static int
+gs2_verify_initial_message(context_t *text,
+                           sasl_server_params_t *sparams,
+                           const char *in,
+                           unsigned inlen,
+                           gss_buffer_t token)
+{
+    OM_uint32 major, minor;
+    char *p = (char *)in;
+    unsigned remain = inlen;
+    int ret;
+    gss_buffer_desc buf = GSS_C_EMPTY_BUFFER;
+
+    assert(text->cbindingname == NULL);
+    assert(text->authzid == NULL);
+
+    token->length = 0;
+    token->value = NULL;
+
+    /* minimum header includes CB flag and non-zero GSS token */
+    CHECK_REMAIN(4); /* [pny],,. */
+
+    /* non-standard GSS framing flag */
+    if (remain > 1 && memcmp(p, "F,", 2) == 0) {
+        text->gs2_flags |= GS2_NONSTD_FLAG;
+        remain -= 2;
+        p += 2;
+    }
+
+    /* SASL channel bindings */
+    CHECK_REMAIN(1); /* [pny] */
+    remain--;
+    switch (*p++) {
+    case 'p':
+        CHECK_REMAIN(1); /* = */
+        remain--;
+        if (*p++ != '=')
+            return SASL_BADPROT;
+
+        ret = gs2_unescape_authzid(text->utils, &p, &remain, &text->cbindingname);
+        if (ret != SASL_OK)
+            return ret;
+
+        text->gs2_flags |= GS2_CB_FLAG_P;
+        break;
+    case 'n':
+        text->gs2_flags |= GS2_CB_FLAG_N;
+        break;
+    case 'y':
+        text->gs2_flags |= GS2_CB_FLAG_Y;
+        break;
+    }
+
+    CHECK_REMAIN(1); /* , */
+    remain--;
+    if (*p++ != ',')
+        return SASL_BADPROT;
+
+    /* authorization identity */
+    if (remain > 1 && memcmp(p, "a=", 2) == 0) {
+        CHECK_REMAIN(2);
+        remain -= 2;
+        p += 2;
+
+        ret = gs2_unescape_authzid(text->utils, &p, &remain, &text->authzid);
+        if (ret != SASL_OK)
+            return ret;
+    }
+
+    /* end of header */
+    CHECK_REMAIN(1); /* , */
+    remain--;
+    if (*p++ != ',')
+        return SASL_BADPROT;
+
+    buf.length = inlen - remain;
+    buf.value = (void *)in;
+
+    /* stash channel bindings to pass into gss_accept_sec_context() */
+    ret = gs2_save_cbindings(text, &buf, sparams->cbinding);
+    if (ret != SASL_OK)
+        return ret;
+
+    if (text->gs2_flags & GS2_NONSTD_FLAG) {
+        buf.length = remain;
+        buf.value = p;
+    } else {
+        gss_buffer_desc tmp;
+
+        tmp.length = remain;
+        tmp.value = p;
+
+        major = gss_encapsulate_token(&tmp, text->mechanism, &buf);
+        if (GSS_ERROR(major))
+            return SASL_NOMEM;
+    }
+
+    token->value = text->utils->malloc(buf.length);
+    if (token->value == NULL)
+        return SASL_NOMEM;
+
+    token->length = buf.length;
+    memcpy(token->value, buf.value, buf.length);
+
+    if ((text->gs2_flags & GS2_NONSTD_FLAG) == 0)
+        gss_release_buffer(&minor, &buf);
+
+    return SASL_OK;
+}
+
+/*
+ * Create gs2-header, save channel bindings to context.
+ */
+static int
+gs2_make_header(context_t *text,
+                sasl_client_params_t *cparams,
+                const char *authzid,
+                char **out,
+                unsigned *outlen)
+{
+    size_t required = 0;
+    size_t wire_authzid_len = 0, cbnamelen = 0;
+    char *wire_authzid = NULL;
+    char *p;
+    int ret;
+    gss_buffer_desc buf;
+
+    *out = NULL;
+    *outlen = 0;
+
+    /* non-standard GSS framing flag */
+    if (text->gs2_flags & GS2_NONSTD_FLAG)
+        required += 2; /* F, */
+
+    /* SASL channel bindings */
+    switch (text->gs2_flags & GS2_CB_FLAG_MASK) {
+    case GS2_CB_FLAG_P:
+        if (!SASL_CB_PRESENT(cparams))
+            return SASL_BADPARAM;
+        cbnamelen = strlen(cparams->cbinding->name);
+        required += 1 /*=*/ + cbnamelen;
+        /* fallthrough */
+    case GS2_CB_FLAG_N:
+    case GS2_CB_FLAG_Y:
+        required += 2; /* [pny], */
+        break;
+    default:
+        return SASL_BADPARAM;
+    }
+
+    /* authorization identity */
+    if (authzid != NULL) {
+        ret = gs2_escape_authzid(text->utils, authzid,
+                                 strlen(authzid), &wire_authzid);
+        if (ret != SASL_OK)
+            return ret;
+
+        wire_authzid_len = strlen(wire_authzid);
+        required += 2 /* a= */ + wire_authzid_len;
+    }
+
+    required += 1; /* trailing comma */
+
+    ret = _plug_buf_alloc(text->utils, out, outlen, required);
+    if (ret != SASL_OK) {
+        text->utils->free(wire_authzid);
+        return ret;
+    }
+
+    *out = text->out_buf;
+    *outlen = required;
+
+    p = (char *)text->out_buf;
+    if (text->gs2_flags & GS2_NONSTD_FLAG) {
+        *p++ = 'F';
+        *p++ = ',';
+    }
+    switch (text->gs2_flags & GS2_CB_FLAG_MASK) {
+    case GS2_CB_FLAG_P:
+        memcpy(p, "p=", 2);
+        memcpy(p + 2, cparams->cbinding->name, cbnamelen);
+        p += 2 + cbnamelen;
+        break;
+    case GS2_CB_FLAG_N:
+        *p++ = 'n';
+        break;
+    case GS2_CB_FLAG_Y:
+        *p++ = 'y';
+        break;
+    }
+    *p++ = ',';
+    if (wire_authzid != NULL) {
+        memcpy(p, "a=", 2);
+        memcpy(p + 2, wire_authzid, wire_authzid_len);
+        text->utils->free(wire_authzid);
+        p += 2 + wire_authzid_len;
+    }
+    *p++ = ',';
+
+    assert(p == (char *)text->out_buf + required);
+
+    buf.length = required;
+    buf.value = *out;
+
+    ret = gs2_save_cbindings(text, &buf, cparams->cbinding);
+    if (ret != SASL_OK)
+        return ret;
+
+    return SASL_OK;
+}
+
+/*
+ * Convert a GSS token to a GS2 one
+ */
+static int
+gs2_make_message(context_t *text,
+                 sasl_client_params_t *cparams __attribute__((unused)),
+                 int initialContextToken,
+                 gss_buffer_t token,
+                 char **out,
+                 unsigned *outlen)
+{
+    OM_uint32 major, minor;
+    int ret;
+    unsigned header_len = 0;
+    gss_buffer_desc decap_token = GSS_C_EMPTY_BUFFER;
+
+    if (initialContextToken) {
+        header_len = *outlen;
+
+        major = gss_decapsulate_token(token, text->mechanism, &decap_token);
+        if ((major == GSS_S_DEFECTIVE_TOKEN &&
+             (text->plug.client->features & SASL_FEAT_GSS_FRAMING)) ||
+            GSS_ERROR(major))
+            return SASL_FAIL;
+
+        token = &decap_token;
+    }
+
+    ret = _plug_buf_alloc(text->utils, out, outlen,
+                          header_len + token->length);
+    if (ret != 0)
+        return ret;
+
+    memcpy(*out + header_len, token->value, token->length);
+    *outlen = header_len + token->length;
+
+    if (initialContextToken)
+        gss_release_buffer(&minor, &decap_token);
+
+    return SASL_OK;
+}
+
+static const unsigned long gs2_required_prompts[] = {
+    SASL_CB_LIST_END
+};
+
+/*
+ * Map GSS mechanism attributes to SASL ones
+ */
+static int
+gs2_get_mech_attrs(const sasl_utils_t *utils,
+                   const gss_OID mech,
+                   unsigned int *security_flags,
+                   unsigned int *features,
+                   const unsigned long **prompts)
+{
+    OM_uint32 major, minor;
+    int present;
+    gss_OID_set attrs = GSS_C_NO_OID_SET;
+
+    major = gss_inquire_attrs_for_mech(&minor, mech, &attrs, NULL);
+    if (GSS_ERROR(major)) {
+        utils->seterror(utils->conn, SASL_NOLOG,
+                        "GS2 Failure: gss_inquire_attrs_for_mech");
+        return SASL_FAIL;
+    }
+
+    *security_flags = SASL_SEC_NOPLAINTEXT | SASL_SEC_NOACTIVE;
+    *features = SASL_FEAT_WANT_CLIENT_FIRST | SASL_FEAT_CHANNEL_BINDING;
+    if (prompts != NULL)
+        *prompts = gs2_required_prompts;
+
+#define MA_PRESENT(a)   (gss_test_oid_set_member(&minor, (gss_OID)(a), \
+                                                 attrs, &present) == GSS_S_COMPLETE && \
+                         present)
+
+    if (MA_PRESENT(GSS_C_MA_PFS))
+        *security_flags |= SASL_SEC_FORWARD_SECRECY;
+    if (!MA_PRESENT(GSS_C_MA_AUTH_INIT_ANON))
+        *security_flags |= SASL_SEC_NOANONYMOUS;
+    if (MA_PRESENT(GSS_C_MA_DELEG_CRED))
+        *security_flags |= SASL_SEC_PASS_CREDENTIALS;
+    if (MA_PRESENT(GSS_C_MA_AUTH_TARG))
+        *security_flags |= SASL_SEC_MUTUAL_AUTH;
+    if (MA_PRESENT(GSS_C_MA_AUTH_INIT_INIT) && prompts != NULL)
+        *prompts = NULL;
+    if (MA_PRESENT(GSS_C_MA_ITOK_FRAMED))
+        *features |= SASL_FEAT_GSS_FRAMING;
+
+    gss_release_oid_set(&minor, &attrs);
+
+    return SASL_OK;
+}
+
+/*
+ * Enumerate GSS mechanisms that can be used for GS2
+ */
+static int gs2_indicate_mechs(const sasl_utils_t *utils)
+{
+    OM_uint32 major, minor;
+    gss_OID_desc desired_oids[3];
+    gss_OID_set_desc desired_attrs;
+    gss_OID_desc except_oids[3];
+    gss_OID_set_desc except_attrs;
+
+    if (gs2_mechs != GSS_C_NO_OID_SET)
+        return SASL_OK;
+
+    desired_oids[0] = *GSS_C_MA_AUTH_INIT;
+    desired_oids[1] = *GSS_C_MA_AUTH_TARG;
+    desired_oids[2] = *GSS_C_MA_CBINDINGS;
+    desired_attrs.count = sizeof(desired_oids)/sizeof(desired_oids[0]);
+    desired_attrs.elements = desired_oids;
+
+    except_oids[0] = *GSS_C_MA_MECH_NEGO;
+    except_oids[1] = *GSS_C_MA_NOT_MECH;
+    except_oids[2] = *GSS_C_MA_DEPRECATED;
+
+    except_attrs.count = sizeof(except_oids)/sizeof(except_oids[0]);
+    except_attrs.elements = except_oids;
+
+    major = gss_indicate_mechs_by_attrs(&minor,
+                                        &desired_attrs,
+                                        &except_attrs,
+                                        GSS_C_NO_OID_SET,
+                                        &gs2_mechs);
+    if (GSS_ERROR(major)) {
+        utils->seterror(utils->conn, SASL_NOLOG,
+                        "GS2 Failure: gss_indicate_mechs_by_attrs");
+        return SASL_FAIL;
+    }
+
+    return (gs2_mechs->count > 0) ? SASL_OK : SASL_NOMECH;
+}
+
+/*
+ * Map SASL mechanism name to OID
+ */
+static int
+gs2_map_sasl_name(const sasl_utils_t *utils,
+                  const char *mech,
+                  gss_OID *oid)
+{
+    OM_uint32 major, minor;
+    gss_buffer_desc buf;
+
+    buf.length = strlen(mech);
+    buf.value = (void *)mech;
+
+    major = gss_inquire_mech_for_saslname(&minor, &buf, oid);
+    if (GSS_ERROR(major)) {
+        utils->seterror(utils->conn, SASL_NOLOG,
+                        "GS2 Failure: gss_inquire_mech_for_saslname");
+        return SASL_FAIL;
+    }
+
+    return SASL_OK;
+}
+
+static int
+gs2_duplicate_buffer(const sasl_utils_t *utils,
+                     const gss_buffer_t src,
+                     gss_buffer_t dst)
+{
+    dst->value = utils->malloc(src->length + 1);
+    if (dst->value == NULL)
+        return SASL_NOMEM;
+
+    memcpy(dst->value, src->value, src->length);
+    ((char *)dst->value)[src->length] = '\0';
+    dst->length = src->length;
+
+    return SASL_OK;
+}
+
+static int
+gs2_unescape_authzid(const sasl_utils_t *utils,
+                     char **endp,
+                     unsigned *remain,
+                     char **authzid)
+{
+    char *in = *endp;
+    size_t i, len, inlen = *remain;
+    char *p;
+
+    *endp = NULL;
+
+    for (i = 0, len = 0; i < inlen; i++) {
+        if (in[i] == ',') {
+            *endp = &in[i];
+            *remain -= i;
+            break;
+        } else if (in[i] == '=') {
+            if (inlen <= i + 2)
+                return SASL_BADPROT;
+            i += 2;
+        }
+        len++;
+    }
+
+    if (len == 0 || *endp == NULL)
+        return SASL_BADPROT;
+
+    p = *authzid = utils->malloc(len + 1);
+    if (*authzid == NULL)
+        return SASL_NOMEM;
+
+    for (i = 0; i < inlen; i++) {
+        if (in[i] == ',')
+            break;
+        else if (in[i] == '=') {
+            if (memcmp(&in[i + 1], "2C", 2) == 0)
+                *p++ = ',';
+            else if (memcmp(&in[i + 1], "3D", 2) == 0)
+                *p++ = '=';
+            else {
+                utils->free(*authzid);
+                *authzid = NULL;
+                return SASL_BADPROT;
+            }
+            i += 2;
+        } else
+            *p++ = in[i];
+    }
+
+    *p = '\0';
+
+    return SASL_OK;
+}
+
+static int
+gs2_escape_authzid(const sasl_utils_t *utils,
+                   const char *in,
+                   unsigned inlen,
+                   char **authzid)
+{
+    size_t i;
+    char *p;
+
+    p = *authzid = utils->malloc((inlen * 3) + 1);
+    if (*authzid == NULL)
+        return SASL_NOMEM;
+
+    for (i = 0; i < inlen; i++) {
+        if (in[i] == ',') {
+            memcpy(p, "=2C", 3);
+            p += 3;
+        } else if (in[i] == '=') {
+            memcpy(p, "=3D", 3);
+            p += 3;
+        } else {
+            *p++ = in[i];
+        }
+    }
+
+    *p = '\0';
+
+    return SASL_OK;
+}
+
+#define GOT_CREDS(text, params) ((text)->client_creds != NULL || (params)->gss_creds != NULL)
+#define CRED_ERROR(status)      ((status) == GSS_S_CRED_UNAVAIL || (status) == GSS_S_NO_CRED)
+
+/*
+ * Determine the authentication identity from the application supplied
+ * GSS credential, the application supplied identity, and the default
+ * GSS credential, in that order. Then, acquire credentials.
+ */
+static int
+gs2_get_init_creds(context_t *text,
+                   sasl_client_params_t *params,
+                   sasl_interact_t **prompt_need,
+                   sasl_out_params_t *oparams)
+{
+    int result = SASL_OK;
+    const char *authid = NULL, *userid = NULL;
+    int user_result = SASL_OK;
+    int auth_result = SASL_OK;
+    int pass_result = SASL_OK;
+    OM_uint32 maj_stat = GSS_S_COMPLETE, min_stat = 0;
+    gss_OID_set_desc mechs;
+    gss_buffer_desc cred_authid = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
+
+    mechs.count = 1;
+    mechs.elements = (gss_OID)text->mechanism;
+
+    /*
+     * Get the authentication identity from the application.
+     */
+    if (oparams->authid == NULL) {
+        auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
+        if (auth_result != SASL_OK && auth_result != SASL_INTERACT) {
+            result = auth_result;
+            goto cleanup;
+        }
+    }
+
+    /*
+     * Get the authorization identity from the application.
+     */
+    if (oparams->user == NULL) {
+        user_result = _plug_get_userid(params->utils, &userid, prompt_need);
+        if (user_result != SASL_OK && user_result != SASL_INTERACT) {
+            result = user_result;
+            goto cleanup;
+        }
+    }
+
+    /*
+     * Canonicalize the authentication and authorization identities before
+     * calling GSS_Import_name.
+     */
+    if (auth_result == SASL_OK && user_result == SASL_OK &&
+        oparams->authid == NULL) {
+        if (userid == NULL || userid[0] == '\0') {
+            result = params->canon_user(params->utils->conn, authid, 0,
+                                        SASL_CU_AUTHID | SASL_CU_AUTHZID,
+                                        oparams);
+        } else {
+            result = params->canon_user(params->utils->conn,
+                                        authid, 0, SASL_CU_AUTHID, oparams);
+            if (result != SASL_OK)
+                goto cleanup;
+
+            result = params->canon_user(params->utils->conn,
+                                        userid, 0, SASL_CU_AUTHZID, oparams);
+            if (result != SASL_OK)
+                goto cleanup;
+        }
+
+        if (oparams->authid != NULL) {
+            name_buf.length = strlen(oparams->authid);
+            name_buf.value = (void *)oparams->authid;
+
+            assert(text->client_name == GSS_C_NO_NAME);
+
+            maj_stat = gss_import_name(&min_stat,
+                                       &name_buf,
+                                       GSS_C_NT_USER_NAME,
+                                       &text->client_name);
+            if (GSS_ERROR(maj_stat))
+                goto cleanup;
+        }
+    }
+
+    /*
+     * If application didn't provide an authid, then use the default
+     * credential. If that doesn't work, give up.
+     */
+    if (!GOT_CREDS(text, params) && oparams->authid == NULL) {
+        maj_stat = gss_acquire_cred(&min_stat,
+                                    GSS_C_NO_NAME,
+                                    GSS_C_INDEFINITE,
+                                    &mechs,
+                                    GSS_C_INITIATE,
+                                    &text->client_creds,
+                                    NULL,
+                                    &text->lifetime);
+        if (GSS_ERROR(maj_stat))
+            goto cleanup;
+
+        assert(text->client_name == GSS_C_NO_NAME);
+
+        maj_stat = gss_inquire_cred(&min_stat,
+                                    params->gss_creds
+                                        ? (gss_cred_id_t)params->gss_creds
+                                        : text->client_creds,
+                                    &text->client_name,
+                                    NULL,
+                                    NULL,
+                                    NULL);
+        if (GSS_ERROR(maj_stat))
+            goto cleanup;
+
+        maj_stat = gss_display_name(&min_stat,
+                                    text->client_name,
+                                    &cred_authid,
+                                    NULL);
+        if (GSS_ERROR(maj_stat))
+            goto cleanup;
+
+        if (userid == NULL || userid[0] == '\0') {
+            result = params->canon_user(params->utils->conn,
+                                        cred_authid.value, cred_authid.length,
+                                        SASL_CU_AUTHID | SASL_CU_AUTHZID,
+                                        oparams);
+        } else {
+            result = params->canon_user(params->utils->conn,
+                                        cred_authid.value, cred_authid.length,
+                                        SASL_CU_AUTHID, oparams);
+            if (result != SASL_OK)
+                goto cleanup;
+
+            result = params->canon_user(params->utils->conn,
+                                        cred_authid.value, cred_authid.length,
+                                        SASL_CU_AUTHZID, oparams);
+            if (result != SASL_OK)
+                goto cleanup;
+        }
+    }
+
+    /*
+     * Armed with the authentication identity, try to get a credential without
+     * a password.
+     */
+    if (!GOT_CREDS(text, params) && text->client_name != GSS_C_NO_NAME) {
+        maj_stat = gss_acquire_cred(&min_stat,
+                                    text->client_name,
+                                    GSS_C_INDEFINITE,
+                                    &mechs,
+                                    GSS_C_INITIATE,
+                                    &text->client_creds,
+                                    NULL,
+                                    &text->lifetime);
+        if (GSS_ERROR(maj_stat) && !CRED_ERROR(maj_stat))
+            goto cleanup;
+    }
+
+    /*
+     * If that failed, try to get a credential with a password.
+     */
+    if (!GOT_CREDS(text, params)) {
+        if (text->password == NULL) {
+            pass_result = _plug_get_password(params->utils, &text->password,
+                                             &text->free_password, prompt_need);
+            if (pass_result != SASL_OK && pass_result != SASL_INTERACT) {
+                result = pass_result;
+                goto cleanup;
+            }
+        }
+
+        if (text->password != NULL) {
+            gss_buffer_desc password_buf;
+
+            password_buf.length = text->password->len;
+            password_buf.value = text->password->data;
+
+            maj_stat = gss_acquire_cred_with_password(&min_stat,
+                                                      text->client_name,
+                                                      &password_buf,
+                                                      GSS_C_INDEFINITE,
+                                                      &mechs,
+                                                      GSS_C_INITIATE,
+                                                      &text->client_creds,
+                                                      NULL,
+                                                      &text->lifetime);
+            if (GSS_ERROR(maj_stat))
+                goto cleanup;
+        }
+    }
+
+    maj_stat = GSS_S_COMPLETE;
+
+    /* free prompts we got */
+    if (prompt_need && *prompt_need) {
+        params->utils->free(*prompt_need);
+        *prompt_need = NULL;
+    }
+
+    /* if there are prompts not filled in */
+    if (user_result == SASL_INTERACT || auth_result == SASL_INTERACT ||
+        pass_result == SASL_INTERACT) {
+        /* make the prompt list */
+        result =
+            _plug_make_prompts(params->utils, prompt_need,
+                               user_result == SASL_INTERACT ?
+                               "Please enter your authorization name" : NULL,
+                               NULL,
+                               auth_result == SASL_INTERACT ?
+                               "Please enter your authentication name" : NULL,
+                               NULL,
+                               pass_result == SASL_INTERACT ?
+                               "Please enter your password" : NULL, NULL,
+                               NULL, NULL, NULL,
+                               NULL,
+                               NULL, NULL);
+        if (result == SASL_OK)
+            result = SASL_INTERACT;
+    }
+
+cleanup:
+    if (result == SASL_OK && maj_stat != GSS_S_COMPLETE) {
+        sasl_gs2_seterror(text->utils, maj_stat, min_stat);
+        result = SASL_FAIL;
+    }
+
+    gss_release_buffer(&min_stat, &cred_authid);
+
+    return result;
+}
+
+static int
+sasl_gs2_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
+                   int logonly)
+{
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_desc msg;
+    OM_uint32 msg_ctx;
+    int ret;
+    char *out = NULL;
+    unsigned int len, curlen = 0;
+    const char prefix[] = "GS2 Error: ";
+
+    len = sizeof(prefix);
+    ret = _plug_buf_alloc(utils, &out, &curlen, 256);
+    if (ret != SASL_OK)
+        return SASL_OK;
+
+    strcpy(out, prefix);
+
+    msg_ctx = 0;
+    while (1) {
+        maj_stat = gss_display_status(&min_stat, maj,
+                                      GSS_C_GSS_CODE, GSS_C_NULL_OID,
+                                      &msg_ctx, &msg);
+
+        if (GSS_ERROR(maj_stat)) {
+            if (logonly) {
+                utils->log(utils->conn, SASL_LOG_FAIL,
+                        "GS2 Failure: (could not get major error message)");
+            } else {
+                utils->seterror(utils->conn, 0,
+                                "GS2 Failure "
+                                "(could not get major error message)");
+            }
+            utils->free(out);
+            return SASL_OK;
+        }
+
+        len += len + msg.length;
+        ret = _plug_buf_alloc(utils, &out, &curlen, len);
+        if (ret != SASL_OK) {
+            utils->free(out);
+            return SASL_OK;
+        }
+
+        strcat(out, msg.value);
+
+        gss_release_buffer(&min_stat, &msg);
+
+        if (!msg_ctx)
+            break;
+    }
+
+    /* Now get the minor status */
+
+    len += 2;
+    ret = _plug_buf_alloc(utils, &out, &curlen, len);
+    if (ret != SASL_OK) {
+        utils->free(out);
+        return SASL_NOMEM;
+    }
+
+    strcat(out, " (");
+
+    msg_ctx = 0;
+    while (1) {
+        maj_stat = gss_display_status(&min_stat, min,
+                                      GSS_C_MECH_CODE, GSS_C_NULL_OID,
+                                      &msg_ctx, &msg);
+
+        if (GSS_ERROR(maj_stat)) {
+            if (logonly) {
+                utils->log(utils->conn, SASL_LOG_FAIL,
+                        "GS2 Failure: (could not get minor error message)");
+            } else {
+                utils->seterror(utils->conn, 0,
+                                "GS2 Failure "
+                                "(could not get minor error message)");
+            }
+            utils->free(out);
+            return SASL_OK;
+        }
+
+        len += len + msg.length;
+
+        ret = _plug_buf_alloc(utils, &out, &curlen, len);
+        if (ret != SASL_OK) {
+            utils->free(out);
+            return SASL_NOMEM;
+        }
+
+        strcat(out, msg.value);
+
+        gss_release_buffer(&min_stat, &msg);
+
+        if (!msg_ctx)
+            break;
+    }
+
+    len += 1;
+    ret = _plug_buf_alloc(utils, &out, &curlen, len);
+    if (ret != SASL_OK) {
+        utils->free(out);
+        return SASL_NOMEM;
+    }
+
+    strcat(out, ")");
+
+    if (logonly) {
+        utils->log(utils->conn, SASL_LOG_FAIL, out);
+    } else {
+        utils->seterror(utils->conn, 0, out);
+    }
+    utils->free(out);
+
+    return SASL_OK;
+}

+ 43 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2_init.c

@@ -0,0 +1,43 @@
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_gs2_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+					 )
+{
+    switch (ul_reason_for_call)
+	{
+		case DLL_PROCESS_ATTACH:
+		case DLL_THREAD_ATTACH:
+		case DLL_THREAD_DETACH:
+		case DLL_PROCESS_DETACH:
+			break;
+    }
+    return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( gs2 )
+SASL_SERVER_PLUG_INIT( gs2 )
+

+ 324 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2_token.c

@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2011, PADL Software Pty Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of PADL Software nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "gs2_token.h"
+
+/*
+ * $Id: gs2_token.c,v 1.2 2011/05/23 14:45:40 mel Exp $
+ */
+
+#ifndef HAVE_GSS_ENCAPSULATE_TOKEN
+/* XXXX this code currently makes the assumption that a mech oid will
+   never be longer than 127 bytes.  This assumption is not inherent in
+   the interfaces, so the code can be fixed if the OSI namespace
+   balloons unexpectedly. */
+
+/*
+ * Each token looks like this:
+ * 0x60                 tag for APPLICATION 0, SEQUENCE
+ *                              (constructed, definite-length)
+ * <length>             possible multiple bytes, need to parse/generate
+ * 0x06                 tag for OBJECT IDENTIFIER
+ * <moid_length>        compile-time constant string (assume 1 byte)
+ * <moid_bytes>         compile-time constant string
+ * <inner_bytes>        the ANY containing the application token
+ * bytes 0,1 are the token type
+ * bytes 2,n are the token data
+ *
+ * Note that the token type field is a feature of RFC 1964 mechanisms and
+ * is not used by other GSSAPI mechanisms.  As such, a token type of -1
+ * is interpreted to mean that no token type should be expected or
+ * generated.
+ *
+ * For the purposes of this abstraction, the token "header" consists of
+ * the sequence tag and length octets, the mech OID DER encoding, and the
+ * first two inner bytes, which indicate the token type.  The token
+ * "body" consists of everything else.
+ */
+
+static size_t
+der_length_size(size_t length)
+{
+    if (length < (1<<7))
+        return 1;
+    else if (length < (1<<8))
+        return 2;
+#if INT_MAX == 0x7fff
+    else
+        return 3;
+#else
+    else if (length < (1<<16))
+        return 3;
+    else if (length < (1<<24))
+        return 4;
+    else
+        return 5;
+#endif
+}
+
+static void
+der_write_length(unsigned char **buf, size_t length)
+{
+    if (length < (1<<7)) {
+        *(*buf)++ = (unsigned char)length;
+    } else {
+        *(*buf)++ = (unsigned char)(der_length_size(length)+127);
+#if INT_MAX > 0x7fff
+        if (length >= (1<<24))
+            *(*buf)++ = (unsigned char)(length>>24);
+        if (length >= (1<<16))
+            *(*buf)++ = (unsigned char)((length>>16)&0xff);
+#endif
+        if (length >= (1<<8))
+            *(*buf)++ = (unsigned char)((length>>8)&0xff);
+        *(*buf)++ = (unsigned char)(length&0xff);
+    }
+}
+
+/* returns the length of a token, given the mech oid and the body size */
+
+static size_t
+token_size(const gss_OID_desc *mech, size_t body_size)
+{
+    /* set body_size to sequence contents size */
+    body_size += 2 + (size_t) mech->length;         /* NEED overflow check */
+    return 1 + der_length_size(body_size) + body_size;
+}
+
+/* fills in a buffer with the token header.  The buffer is assumed to
+   be the right size.  buf is advanced past the token header */
+
+static void
+make_token_header(
+    const gss_OID_desc *mech,
+    size_t body_size,
+    unsigned char **buf)
+{
+    *(*buf)++ = 0x60;
+    der_write_length(buf, 2 + mech->length + body_size);
+    *(*buf)++ = 0x06;
+    *(*buf)++ = (unsigned char)mech->length;
+    memcpy(*buf, mech->elements, mech->length);
+    *buf += mech->length;
+}
+
+OM_uint32
+gs2_encapsulate_token(const gss_buffer_t input_token,
+                      const gss_OID token_oid,
+                      gss_buffer_t output_token)
+{
+    size_t tokenSize;
+    unsigned char *buf;
+
+    if (input_token == GSS_C_NO_BUFFER || token_oid == GSS_C_NO_OID)
+        return GSS_S_CALL_INACCESSIBLE_READ;
+
+    if (output_token == GSS_C_NO_BUFFER)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    tokenSize = token_size(token_oid, input_token->length);
+
+    output_token->value = malloc(tokenSize);
+    if (output_token->value == NULL)
+        return GSS_S_FAILURE;
+
+    buf = output_token->value;
+
+    make_token_header(token_oid, input_token->length, &buf);
+    memcpy(buf, input_token->value, input_token->length);
+    output_token->length = tokenSize;
+
+    return GSS_S_COMPLETE;
+}
+#endif
+
+
+#ifndef HAVE_GSS_DECAPSULATE_TOKEN
+/* returns decoded length, or < 0 on failure.  Advances buf and
+   decrements bufsize */
+
+static int
+der_read_length(unsigned char **buf, ssize_t *bufsize)
+{
+    unsigned char sf;
+    int ret;
+
+    if (*bufsize < 1)
+        return -1;
+
+    sf = *(*buf)++;
+    (*bufsize)--;
+    if (sf & 0x80) {
+        if ((sf &= 0x7f) > ((*bufsize)-1))
+            return -1;
+        if (sf > sizeof(int))
+            return -1;
+        ret = 0;
+        for (; sf; sf--) {
+            ret = (ret<<8) + (*(*buf)++);
+            (*bufsize)--;
+        }
+    } else {
+        ret = sf;
+    }
+
+    return ret;
+}
+
+/*
+ * Given a buffer containing a token, reads and verifies the token,
+ * leaving buf advanced past the token header, and setting body_size
+ * to the number of remaining bytes.  Returns 0 on success,
+ * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
+ * mechanism in the token does not match the mech argument.  buf and
+ * *body_size are left unmodified on error.
+ */
+
+static OM_uint32
+verify_token_header(OM_uint32 *minor,
+                    const gss_OID mech,
+                    size_t *body_size,
+                    unsigned char **buf_in,
+                    size_t toksize_in)
+{
+    unsigned char *buf = *buf_in;
+    ssize_t seqsize;
+    gss_OID_desc toid;
+    ssize_t toksize = (ssize_t)toksize_in;
+
+    *minor = 0;
+
+    if ((toksize -= 1) < 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    if (*buf++ != 0x60)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    seqsize = der_read_length(&buf, &toksize);
+    if (seqsize < 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    if (seqsize != toksize)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    if ((toksize -= 1) < 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    if (*buf++ != 0x06)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    if ((toksize -= 1) < 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    toid.length = *buf++;
+
+    if ((toksize -= toid.length) < 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    toid.elements = buf;
+    buf += toid.length;
+
+    if (!gss_oid_equal(&toid, mech))
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    *buf_in = buf;
+    *body_size = toksize;
+
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gs2_decapsulate_token(const gss_buffer_t input_token,
+                      const gss_OID token_oid,
+                      gss_buffer_t output_token)
+{
+    OM_uint32 major, minor;
+    size_t body_size = 0;
+    unsigned char *buf_in;
+
+    if (input_token == GSS_C_NO_BUFFER || token_oid == GSS_C_NO_OID)
+        return GSS_S_CALL_INACCESSIBLE_READ;
+
+    if (output_token == GSS_C_NO_BUFFER)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    buf_in = input_token->value;
+
+    major = verify_token_header(&minor, token_oid, &body_size, &buf_in,
+                                input_token->length);
+    if (minor != 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    output_token->value = malloc(body_size);
+    if (output_token->value == NULL)
+        return GSS_S_FAILURE;
+
+    memcpy(output_token->value, buf_in, body_size);
+    output_token->length = body_size;
+
+    return GSS_S_COMPLETE;
+}
+#endif
+
+#ifndef HAVE_GSS_OID_EQUAL
+int
+gs2_oid_equal(const gss_OID o1, const gss_OID o2)
+{
+    return o1->length == o2->length &&
+        (memcmp(o1->elements, o2->elements, o1->length) == 0);
+}
+#endif

+ 58 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gs2_token.h

@@ -0,0 +1,58 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GS2_TOKEN_H_
+#define _GS2_TOKEN_H_ 1
+
+#include <config.h>
+
+#include <gssapi/gssapi.h>
+
+#ifndef KRB5_HEIMDAL
+#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
+#include <gssapi/gssapi_ext.h>
+#endif
+#endif
+
+#ifndef HAVE_GSS_DECAPSULATE_TOKEN
+OM_uint32
+gs2_decapsulate_token(const gss_buffer_t input_token,
+                      const gss_OID token_oid,
+                      gss_buffer_t output_token);
+#define gss_decapsulate_token gs2_decapsulate_token
+#endif
+
+#ifndef HAVE_GSS_ENCAPSULATE_TOKEN
+OM_uint32
+gs2_encapsulate_token(const gss_buffer_t input_token,
+                      const gss_OID token_oid,
+                      gss_buffer_t output_token);
+#define gss_encapsulate_token gs2_encapsulate_token
+#endif
+
+#ifndef HAVE_GSS_OID_EQUAL
+int
+gs2_oid_equal(const gss_OID o1, const gss_OID o2);
+#define gss_oid_equal gs2_oid_equal
+#endif
+
+#endif /* _GS2_TOKEN_H_ */

+ 2076 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gssapi.c

@@ -0,0 +1,2076 @@
+/* GSSAPI SASL plugin
+ * Leif Johansson
+ * Rob Siemborski (SASL v2 Conversion)
+ * $Id: gssapi.c,v 1.115 2011/11/21 15:12:35 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_GSSAPI_H
+#include <gssapi.h>
+#else
+#include <gssapi/gssapi.h>
+#endif
+
+#ifdef WIN32
+#  include <winsock2.h>
+
+#  ifndef R_OK
+#    define R_OK 04
+#  endif
+/* we also need io.h for access() prototype */
+#  include <io.h>
+#else
+#  include <sys/param.h>
+#  include <sys/socket.h>
+#  include <netinet/in.h>
+#  include <arpa/inet.h>
+#  include <netdb.h>
+#endif /* WIN32 */
+#include <fcntl.h>
+#include <stdio.h>
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: gssapi.c,v 1.115 2011/11/21 15:12:35 mel Exp $";
+
+static const char * GSSAPI_BLANK_STRING = "";
+
+static gss_OID_desc gss_spnego_oid = { 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
+
+#if !defined(HAVE_GSS_C_NT_HOSTBASED_SERVICE) && !defined(GSS_C_NT_HOSTBASED_SERVICE)
+extern gss_OID gss_nt_service_name;
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif
+
+#ifdef WANT_KERBEROS5_3DES
+/* Check if CyberSafe flag is defined */
+#ifdef CSF_GSS_C_DES3_FLAG
+#define K5_MAX_SSF	112
+#endif
+
+/* Heimdal and MIT use the following */
+#ifdef GSS_KRB5_CONF_C_QOP_DES3_KD
+#define K5_MAX_SSF	112
+#endif
+
+#endif
+
+#ifndef K5_MAX_SSF
+/* All Kerberos implementations support DES */
+#define K5_MAX_SSF	56
+#endif
+
+/* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
+ * inspired by the kerberos mechanism and the gssapi_server and
+ * gssapi_client from the heimdal distribution by Assar Westerlund
+ * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>. 
+ * See the configure.in file for details on dependencies.
+ *
+ * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
+ *
+ * This code was tested with the following distributions of Kerberos:
+ * Heimdal (http://www.pdc.kth.se/heimdal), MIT (http://web.mit.edu/kerberos/www/)
+ * CyberSafe (http://www.cybersafe.com/) and SEAM.
+ */
+
+#ifdef GSS_USE_MUTEXES
+#define GSS_LOCK_MUTEX(utils)  \
+    if(((sasl_utils_t *)(utils))->mutex_lock(gss_mutex) != 0) { \
+       return SASL_FAIL; \
+    }
+
+#define GSS_UNLOCK_MUTEX(utils) \
+    if(((sasl_utils_t *)(utils))->mutex_unlock(gss_mutex) != 0) { \
+        return SASL_FAIL; \
+    }
+
+static void *gss_mutex = NULL;
+#else
+#define GSS_LOCK_MUTEX(utils)
+#define GSS_UNLOCK_MUTEX(utils)
+#endif
+
+typedef struct context {
+    int state;
+
+    gss_OID mech_type;		     /* GSS-SPNEGO or GSSAPI */
+    int http_mode;		     /* use RFC 4559 compatible protocol? */
+    
+    gss_ctx_id_t gss_ctx;
+    gss_name_t   client_name;
+    gss_name_t   server_name;
+    gss_cred_id_t server_creds;
+    gss_cred_id_t client_creds;
+
+    sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
+					server */
+    unsigned char qop;		     /* as allowed by GSSAPI */
+
+    const sasl_utils_t *utils;
+    
+    /* layers buffering */
+    decode_context_t decode_context;
+    
+    char *encode_buf;                /* For encoding/decoding mem management */
+    char *decode_buf;
+    char *decode_once_buf;
+    unsigned encode_buf_len;
+    unsigned decode_buf_len;
+    unsigned decode_once_buf_len;
+    buffer_info_t *enc_in_buf;
+    
+    char *out_buf;                   /* per-step mem management */
+    unsigned out_buf_len;    
+    
+    char *authid; /* hold the authid between steps - server */
+    const char *user;   /* hold the userid between steps - client */
+} context_t;
+
+enum {
+    SASL_GSSAPI_STATE_AUTHNEG = 1,
+    SASL_GSSAPI_STATE_SSFCAP = 2,
+    SASL_GSSAPI_STATE_SSFREQ = 3,
+    SASL_GSSAPI_STATE_AUTHENTICATED = 4
+};
+
+#define LAYER_CONFIDENTIALITY	4
+#define LAYER_INTEGRITY		2
+#define LAYER_NONE		1
+
+/* sasl_gss_log: only logs status string returned from gss_display_status() */
+#define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1)
+#define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0)
+
+static int
+sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
+		   int logonly)
+{
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_desc msg;
+    OM_uint32 msg_ctx;
+    int ret;
+    char *out = NULL;
+    size_t len, curlen = 0;
+    const char prefix[] = "GSSAPI Error: ";
+
+    if (!utils) return SASL_OK;
+    
+    len = sizeof(prefix);
+    ret = _plug_buf_alloc(utils, &out, &curlen, 256);
+    if (ret != SASL_OK) return SASL_NOMEM;
+    
+    strcpy(out, prefix);
+    
+    msg_ctx = 0;
+    while (1) {
+	GSS_LOCK_MUTEX(utils);
+	maj_stat = gss_display_status(&min_stat, maj,
+				      GSS_C_GSS_CODE, GSS_C_NULL_OID,
+				      &msg_ctx, &msg);
+	GSS_UNLOCK_MUTEX(utils);
+	
+	if(GSS_ERROR(maj_stat)) {
+	    if (logonly) {
+		utils->log(utils->conn, SASL_LOG_FAIL,
+			"GSSAPI Failure: (could not get major error message)");
+	    } else {
+		utils->seterror(utils->conn, 0,
+				"GSSAPI Failure "
+				"(could not get major error message)");
+	    }
+	    utils->free(out);
+	    return SASL_OK;
+	}
+	
+	len += len + msg.length;
+	ret = _plug_buf_alloc(utils, &out, &curlen, len);
+	
+	if(ret != SASL_OK) {
+	    utils->free(out);
+	    return SASL_NOMEM;
+	}
+	
+	strcat(out, msg.value);
+	
+	GSS_LOCK_MUTEX(utils);
+	gss_release_buffer(&min_stat, &msg);
+	GSS_UNLOCK_MUTEX(utils);
+	
+	if (!msg_ctx)
+	    break;
+    }
+    
+    /* Now get the minor status */
+    
+    len += 2;
+    ret = _plug_buf_alloc(utils, &out, &curlen, len);
+    if(ret != SASL_OK) {
+	utils->free(out);
+	return SASL_NOMEM;
+    }
+    
+    strcat(out, " (");
+    
+    msg_ctx = 0;
+    while (1) {
+	GSS_LOCK_MUTEX(utils);
+	maj_stat = gss_display_status(&min_stat, min,
+				      GSS_C_MECH_CODE, GSS_C_NULL_OID,
+				      &msg_ctx, &msg);
+	GSS_UNLOCK_MUTEX(utils);
+	
+	if(GSS_ERROR(maj_stat)) {
+	    if (logonly) {
+		utils->log(utils->conn, SASL_LOG_FAIL,
+			"GSSAPI Failure: (could not get minor error message)");
+	    } else {
+		utils->seterror(utils->conn, 0,
+				"GSSAPI Failure "
+				"(could not get minor error message)");
+	    }
+	    utils->free(out);
+	    return SASL_OK;
+	}
+	
+	len += len + msg.length;
+
+	ret = _plug_buf_alloc(utils, &out, &curlen, len);
+	if(ret != SASL_OK) {
+	    utils->free(out);
+	    return SASL_NOMEM;
+	}
+	
+	strcat(out, msg.value);
+	
+	GSS_LOCK_MUTEX(utils);
+	gss_release_buffer(&min_stat, &msg);
+	GSS_UNLOCK_MUTEX(utils);
+	
+	if (!msg_ctx)
+	    break;
+    }
+    
+    len += 1;
+    ret = _plug_buf_alloc(utils, &out, &curlen, len);
+    if(ret != SASL_OK) {
+	utils->free(out);
+	return SASL_NOMEM;
+    }
+    
+    strcat(out, ")");
+    
+    if (logonly) {
+	utils->log(utils->conn, SASL_LOG_FAIL, out);
+    } else {
+	utils->seterror(utils->conn, 0, out);
+    }
+    utils->free(out);
+
+    return SASL_OK;
+}
+
+static int 
+sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
+		const char **output, unsigned *outputlen, int privacy)
+{
+    context_t *text = (context_t *)context;
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_t input_token, output_token;
+    gss_buffer_desc real_input_token, real_output_token;
+    int ret;
+    struct buffer_info *inblob, bufinfo;
+    
+    if (!output) return SASL_BADPARAM;
+    
+    if (numiov > 1) {
+	ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
+	if (ret != SASL_OK) return ret;
+	inblob = text->enc_in_buf;
+    } else {
+	bufinfo.data = invec[0].iov_base;
+	bufinfo.curlen = invec[0].iov_len;
+	inblob = &bufinfo;
+    }
+    
+    if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
+    
+    input_token = &real_input_token;
+    
+    real_input_token.value  = inblob->data;
+    real_input_token.length = inblob->curlen;
+    
+    output_token = &real_output_token;
+    output_token->value = NULL;
+    output_token->length = 0;
+    
+    GSS_LOCK_MUTEX(text->utils);
+    maj_stat = gss_wrap (&min_stat,
+			 text->gss_ctx,
+			 privacy,
+			 GSS_C_QOP_DEFAULT,
+			 input_token,
+			 NULL,
+			 output_token);
+    GSS_UNLOCK_MUTEX(text->utils);
+    
+    if (GSS_ERROR(maj_stat)) {
+	sasl_gss_seterror(text->utils, maj_stat, min_stat);
+	if (output_token->value) {
+	    GSS_LOCK_MUTEX(text->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(text->utils);
+	}
+	return SASL_FAIL;
+    }
+    
+    if (output_token->value && output) {
+	unsigned char * p;
+	
+	ret = _plug_buf_alloc(text->utils,
+			      &(text->encode_buf),
+			      &(text->encode_buf_len),
+			      output_token->length + 4);
+	
+	if (ret != SASL_OK) {
+	    GSS_LOCK_MUTEX(text->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(text->utils);
+	    return ret;
+	}
+
+	p = (unsigned char *) text->encode_buf;
+	
+	p[0] = (output_token->length>>24) & 0xFF;
+	p[1] = (output_token->length>>16) & 0xFF;
+	p[2] = (output_token->length>>8) & 0xFF;
+	p[3] = output_token->length & 0xFF;
+
+	memcpy(text->encode_buf + 4, output_token->value, output_token->length);
+    }
+    
+    if (outputlen) {
+	*outputlen = output_token->length + 4;
+    }
+    
+    *output = text->encode_buf;
+    
+    if (output_token->value) {
+	GSS_LOCK_MUTEX(text->utils);
+	gss_release_buffer(&min_stat, output_token);
+	GSS_UNLOCK_MUTEX(text->utils);
+    }
+
+    return SASL_OK;
+}
+
+static int gssapi_privacy_encode(void *context, const struct iovec *invec,
+				 unsigned numiov, const char **output,
+				 unsigned *outputlen)
+{
+    return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
+}
+
+static int gssapi_integrity_encode(void *context, const struct iovec *invec,
+				   unsigned numiov, const char **output,
+				   unsigned *outputlen) 
+{
+    return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
+}
+
+static int
+gssapi_decode_packet(void *context,
+		     const char *input,
+		     unsigned inputlen,
+		     char **output,
+		     unsigned *outputlen)
+{
+    context_t *text = (context_t *) context;
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_t input_token, output_token;
+    gss_buffer_desc real_input_token, real_output_token;
+    int result;
+    
+    if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
+	SETERROR(text->utils, "GSSAPI Failure");
+	return SASL_NOTDONE;
+    }
+    
+    input_token = &real_input_token; 
+    real_input_token.value = (char *) input;
+    real_input_token.length = inputlen;
+    
+    output_token = &real_output_token;
+    output_token->value = NULL;
+    output_token->length = 0;
+    
+    GSS_LOCK_MUTEX(text->utils);
+    maj_stat = gss_unwrap (&min_stat,
+			   text->gss_ctx,
+			   input_token,
+			   output_token,
+			   NULL,
+			   NULL);
+    GSS_UNLOCK_MUTEX(text->utils);
+    
+    if (GSS_ERROR(maj_stat)) {
+	sasl_gss_seterror(text->utils,maj_stat,min_stat);
+	if (output_token->value) {
+	    GSS_LOCK_MUTEX(text->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(text->utils);
+	}
+	return SASL_FAIL;
+    }
+    
+    if (outputlen) {
+	*outputlen = output_token->length;
+    }
+    
+    if (output_token->value) {
+	if (output) {
+	    result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
+				     &text->decode_once_buf_len,
+				     *outputlen);
+	    if (result != SASL_OK) {
+		GSS_LOCK_MUTEX(text->utils);
+		gss_release_buffer(&min_stat, output_token);
+		GSS_UNLOCK_MUTEX(text->utils);
+		return result;
+	    }
+	    *output = text->decode_once_buf;
+	    memcpy(*output, output_token->value, *outputlen);
+	}
+	GSS_LOCK_MUTEX(text->utils);
+	gss_release_buffer(&min_stat, output_token);
+	GSS_UNLOCK_MUTEX(text->utils);
+    }
+    
+    return SASL_OK;
+}
+
+static int gssapi_decode(void *context,
+			 const char *input, unsigned inputlen,
+			 const char **output, unsigned *outputlen)
+{
+    context_t *text = (context_t *) context;
+    int ret;
+    
+    ret = _plug_decode(&text->decode_context, input, inputlen,
+		       &text->decode_buf, &text->decode_buf_len, outputlen,
+		       gssapi_decode_packet, text);
+    
+    *output = text->decode_buf;
+    
+    return ret;
+}
+
+static context_t *sasl_gss_new_context(const sasl_utils_t *utils)
+{
+    context_t *ret;
+    
+    ret = utils->malloc(sizeof(context_t));
+    if(!ret) return NULL;
+    
+    memset(ret,0,sizeof(context_t));
+    ret->utils = utils;
+    
+    return ret;
+}
+
+static int sasl_gss_free_context_contents(context_t *text)
+{
+    OM_uint32 maj_stat, min_stat;
+    
+    if (!text) return SASL_OK;
+    
+    GSS_LOCK_MUTEX(text->utils);
+
+    if (text->gss_ctx != GSS_C_NO_CONTEXT) {
+	maj_stat = gss_delete_sec_context(&min_stat,&text->gss_ctx,
+					  GSS_C_NO_BUFFER);
+	text->gss_ctx = GSS_C_NO_CONTEXT;
+    }
+    
+    if (text->client_name != GSS_C_NO_NAME) {
+	maj_stat = gss_release_name(&min_stat,&text->client_name);
+	text->client_name = GSS_C_NO_NAME;
+    }
+    
+    if (text->server_name != GSS_C_NO_NAME) {
+	maj_stat = gss_release_name(&min_stat,&text->server_name);
+	text->server_name = GSS_C_NO_NAME;
+    }
+    
+    if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
+	maj_stat = gss_release_cred(&min_stat, &text->server_creds);
+	text->server_creds = GSS_C_NO_CREDENTIAL;
+    }
+
+    if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
+	maj_stat = gss_release_cred(&min_stat, &text->client_creds);
+	text->client_creds = GSS_C_NO_CREDENTIAL;
+    }
+
+    GSS_UNLOCK_MUTEX(text->utils);
+    
+    if (text->out_buf) {
+	text->utils->free(text->out_buf);
+	text->out_buf = NULL;
+    }
+    
+    if (text->encode_buf) {
+	text->utils->free(text->encode_buf);
+	text->encode_buf = NULL;
+    }
+    
+    if (text->decode_buf) {
+	text->utils->free(text->decode_buf);
+	text->decode_buf = NULL;
+    }
+    
+    if (text->decode_once_buf) {
+	text->utils->free(text->decode_once_buf);
+	text->decode_once_buf = NULL;
+    }
+    
+    if (text->enc_in_buf) {
+	if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
+	text->utils->free(text->enc_in_buf);
+	text->enc_in_buf = NULL;
+    }
+
+    _plug_decode_free(&text->decode_context);
+    
+    if (text->authid) { /* works for both client and server */
+	text->utils->free(text->authid);
+	text->authid = NULL;
+    }
+
+    return SASL_OK;
+
+}
+
+static void gssapi_common_mech_dispose(void *conn_context,
+				       const sasl_utils_t *utils)
+{
+    sasl_gss_free_context_contents((context_t *)(conn_context));
+    utils->free(conn_context);
+}
+
+static void gssapi_common_mech_free(void *global_context __attribute__((unused)),
+				    const sasl_utils_t *utils)
+{
+#ifdef GSS_USE_MUTEXES
+    if (gss_mutex) {
+      utils->mutex_free(gss_mutex);
+      gss_mutex=NULL;
+    }
+#endif
+}
+
+/*****************************  Server Section  *****************************/
+
+static int 
+gssapi_server_mech_new(void *glob_context __attribute__((unused)), 
+		       sasl_server_params_t *params,
+		       const char *challenge __attribute__((unused)), 
+		       unsigned challen __attribute__((unused)),
+		       void **conn_context)
+{
+    context_t *text;
+    
+    text = sasl_gss_new_context(params->utils);
+    if (text == NULL) {
+	MEMERROR(params->utils);
+	return SASL_NOMEM;
+    }
+    
+    text->gss_ctx = GSS_C_NO_CONTEXT;
+    text->client_name = GSS_C_NO_NAME;
+    text->server_name = GSS_C_NO_NAME;
+    text->server_creds = GSS_C_NO_CREDENTIAL;
+    text->client_creds = GSS_C_NO_CREDENTIAL;
+    text->state = SASL_GSSAPI_STATE_AUTHNEG;
+    
+    text->http_mode = (params->flags & SASL_NEED_HTTP);
+
+    *conn_context = text;
+    
+    return SASL_OK;
+}
+
+static int 
+gssapi_server_mech_authneg(context_t *text,
+			   sasl_server_params_t *params,
+			   const char *clientin,
+			   unsigned clientinlen,
+			   const char **serverout,
+			   unsigned *serveroutlen,
+			   sasl_out_params_t *oparams __attribute__((unused)))
+{
+    gss_buffer_t input_token, output_token;
+    gss_buffer_desc real_input_token, real_output_token;
+    OM_uint32 maj_stat = 0, min_stat = 0;
+    gss_buffer_desc name_token;
+    int ret, equal = 0;
+    unsigned out_flags = 0;
+    gss_cred_id_t server_creds = (gss_cred_id_t) params->gss_creds;
+    gss_buffer_desc name_without_realm;
+    gss_name_t client_name_MN = NULL, without = NULL;
+    gss_OID mech_type;
+	
+    input_token = &real_input_token;
+    output_token = &real_output_token;
+    output_token->value = NULL; output_token->length = 0;
+    input_token->value = NULL; input_token->length = 0;
+    
+    if (text->server_name == GSS_C_NO_NAME) { /* only once */
+	if (params->serverFQDN == NULL
+	    || strlen(params->serverFQDN) == 0) {
+	    SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
+	    sasl_gss_free_context_contents(text);
+	    return SASL_FAIL;
+	}
+	name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
+	name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
+	if (name_token.value == NULL) {
+	    MEMERROR(text->utils);
+	    sasl_gss_free_context_contents(text);
+	    return SASL_NOMEM;
+	}
+	sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
+
+	GSS_LOCK_MUTEX(params->utils);
+	maj_stat = gss_import_name (&min_stat,
+				    &name_token,
+				    GSS_C_NT_HOSTBASED_SERVICE,
+				    &text->server_name);
+	GSS_UNLOCK_MUTEX(params->utils);
+
+	params->utils->free(name_token.value);
+	name_token.value = NULL;
+
+	if (GSS_ERROR(maj_stat)) {
+	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
+	    sasl_gss_free_context_contents(text);
+	    return SASL_FAIL;
+	}
+
+	if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
+	    GSS_LOCK_MUTEX(params->utils);
+	    maj_stat = gss_release_cred(&min_stat, &text->server_creds);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	    text->server_creds = GSS_C_NO_CREDENTIAL;
+	}
+
+	/* If caller didn't provide creds already */
+	if ( server_creds == GSS_C_NO_CREDENTIAL) {
+	    GSS_LOCK_MUTEX(params->utils);
+	    maj_stat = gss_acquire_cred(&min_stat, 
+					text->server_name,
+					GSS_C_INDEFINITE, 
+					GSS_C_NO_OID_SET,
+					GSS_C_ACCEPT,
+					&text->server_creds, 
+					NULL, 
+					NULL);
+	    GSS_UNLOCK_MUTEX(params->utils);
+
+	    if (GSS_ERROR(maj_stat)) {
+		sasl_gss_seterror(text->utils, maj_stat, min_stat);
+		sasl_gss_free_context_contents(text);
+		return SASL_FAIL;
+	    }
+	    server_creds = text->server_creds;
+	}
+    }
+	
+    if (clientinlen) {
+	real_input_token.value = (void *)clientin;
+	real_input_token.length = clientinlen;
+    }
+
+
+    GSS_LOCK_MUTEX(params->utils);
+    maj_stat =
+	gss_accept_sec_context(&min_stat,
+			       &(text->gss_ctx),
+			       server_creds,
+			       input_token,
+			       GSS_C_NO_CHANNEL_BINDINGS,
+			       &text->client_name,
+			       &mech_type,
+			       output_token,
+			       &out_flags,
+			       NULL,	/* context validity period */
+			       &(text->client_creds));
+    GSS_UNLOCK_MUTEX(params->utils);
+
+    if (GSS_ERROR(maj_stat)) {
+	sasl_gss_log(text->utils, maj_stat, min_stat);
+	text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
+	if (output_token->value) {
+	    GSS_LOCK_MUTEX(params->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	}
+	sasl_gss_free_context_contents(text);
+	return SASL_BADAUTH;
+    }
+
+    if (serveroutlen) {
+	*serveroutlen = output_token->length;
+    }
+    if (output_token->value) {
+	if (serverout) {
+	    ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+				  &(text->out_buf_len), *serveroutlen);
+	    if(ret != SASL_OK) {
+		GSS_LOCK_MUTEX(params->utils);
+		gss_release_buffer(&min_stat, output_token);
+		GSS_UNLOCK_MUTEX(params->utils);
+		return ret;
+	    }
+	    memcpy(text->out_buf, output_token->value, *serveroutlen);
+	    *serverout = text->out_buf;
+	}
+
+	GSS_LOCK_MUTEX(params->utils);
+	gss_release_buffer(&min_stat, output_token);
+	GSS_UNLOCK_MUTEX(params->utils);
+    } else {
+	/* No output token, send an empty string */
+	*serverout = GSSAPI_BLANK_STRING;
+	*serveroutlen = 0;
+    }
+
+    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+	/* Context isn't complete */
+        return SASL_CONTINUE;
+    }
+
+    assert(maj_stat == GSS_S_COMPLETE);
+
+    /* When GSS_Accept_sec_context returns GSS_S_COMPLETE, the server
+       examines the context to ensure that it provides a level of protection
+       permitted by the server's security policy.  In particular, if the
+       integ_avail flag is not set in the context, then no security layer
+       can be offered or accepted.  If the conf_avail flag is not set in the
+       context, then no security layer with confidentiality can be offered
+       or accepted. */
+    if ((out_flags & GSS_C_INTEG_FLAG) == 0) {
+	/* if the integ_avail flag is not set in the context,
+	   then no security layer can be offered or accepted. */
+	text->qop = LAYER_NONE;
+    } else if ((out_flags & GSS_C_CONF_FLAG) == 0) {
+	/* If the conf_avail flag is not set in the context,
+	   then no security layer with confidentiality can be offered
+	   or accepted. */
+	text->qop = LAYER_NONE | LAYER_INTEGRITY;
+    } else {
+	text->qop = LAYER_NONE | LAYER_INTEGRITY | LAYER_CONFIDENTIALITY;
+    }
+
+    if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) &&
+	(!(out_flags & GSS_C_DELEG_FLAG) ||
+	 text->client_creds == GSS_C_NO_CREDENTIAL) ) 
+	{
+	    text->utils->seterror(text->utils->conn, SASL_LOG_WARN,
+				  "GSSAPI warning: no credentials were passed");
+	    /* continue with authentication */
+	}
+
+    GSS_LOCK_MUTEX(params->utils);
+    maj_stat = gss_canonicalize_name(&min_stat,
+				     text->client_name,
+				     mech_type,
+				     &client_name_MN);
+    GSS_UNLOCK_MUTEX(params->utils);
+
+    if (GSS_ERROR(maj_stat)) {
+	SETERROR(text->utils, "GSSAPI Failure: gss_canonicalize_name");
+	sasl_gss_free_context_contents(text);
+	return SASL_BADAUTH;
+    }
+
+    name_token.value = NULL;
+    name_without_realm.value = NULL;
+
+    GSS_LOCK_MUTEX(params->utils);
+    maj_stat = gss_display_name (&min_stat,
+				 client_name_MN,
+				 &name_token,
+				 NULL);
+    GSS_UNLOCK_MUTEX(params->utils);
+
+    if (GSS_ERROR(maj_stat)) {
+	SETERROR(text->utils, "GSSAPI Failure: gss_display_name");
+	sasl_gss_free_context_contents(text);
+	ret = SASL_BADAUTH;
+	goto cleanup;
+    }
+
+    /* If the id contains a realm get the identifier for the user
+       without the realm and see if it's the same id (i.e. 
+       tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
+       to return the id (i.e. just "tmartin" */
+    if (strchr((char *) name_token.value, (int) '@') != NULL) {
+	/* NOTE: libc malloc, as it is freed below by a gssapi internal
+	 *       function! */
+	name_without_realm.value = params->utils->malloc(strlen(name_token.value)+1);
+	if (name_without_realm.value == NULL) {
+	    MEMERROR(text->utils);
+	    ret = SASL_NOMEM;
+	    goto cleanup;
+	}
+
+	strcpy(name_without_realm.value, name_token.value);
+
+	/* cut off string at '@' */
+	(strchr(name_without_realm.value,'@'))[0] = '\0';
+
+	name_without_realm.length = strlen( (char *) name_without_realm.value );
+
+	GSS_LOCK_MUTEX(params->utils);
+	maj_stat = gss_import_name (&min_stat,
+				    &name_without_realm,
+	    /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
+	       so use GSS_C_NT_USER_NAME instead if available.  */
+#ifdef HAVE_GSS_C_NT_USER_NAME
+				    GSS_C_NT_USER_NAME,
+#else
+				    GSS_C_NULL_OID,
+#endif
+				    &without);
+	GSS_UNLOCK_MUTEX(params->utils);
+
+	if (GSS_ERROR(maj_stat)) {
+	    SETERROR(text->utils, "GSSAPI Failure: gss_import_name");
+	    sasl_gss_free_context_contents(text);
+	    ret = SASL_BADAUTH;
+	    goto cleanup;
+	}
+
+	GSS_LOCK_MUTEX(params->utils);
+	maj_stat = gss_compare_name(&min_stat,
+				    client_name_MN,
+				    without,
+				    &equal);
+	GSS_UNLOCK_MUTEX(params->utils);
+
+	if (GSS_ERROR(maj_stat)) {
+	    SETERROR(text->utils, "GSSAPI Failure: gss_compare_name");
+	    sasl_gss_free_context_contents(text);
+	    ret = SASL_BADAUTH;
+	    goto cleanup;
+	}
+
+    } else {
+	equal = 0;
+    }
+
+    if (equal) {
+	text->authid = strdup(name_without_realm.value);
+    } else {
+	text->authid = strdup(name_token.value);
+    }
+
+    if (text->authid == NULL) {
+	MEMERROR(params->utils);
+	ret = SASL_NOMEM;
+	goto cleanup;
+    }
+
+    if (text->http_mode) {
+	/* HTTP doesn't do any ssf negotiation */
+	text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
+	ret = SASL_OK;
+    }
+    else {
+	/* Switch to ssf negotiation */
+	text->state = SASL_GSSAPI_STATE_SSFCAP;
+	ret = SASL_CONTINUE;
+    }
+
+  cleanup:
+    if (client_name_MN) {
+	GSS_LOCK_MUTEX(params->utils);
+	gss_release_name(&min_stat, &client_name_MN);
+	GSS_UNLOCK_MUTEX(params->utils);
+    }
+    if (name_token.value) {
+	GSS_LOCK_MUTEX(params->utils);
+	gss_release_buffer(&min_stat, &name_token);
+	GSS_UNLOCK_MUTEX(params->utils);
+    }
+    if (name_without_realm.value) {
+	params->utils->free(name_without_realm.value);
+    }
+    if (without) {
+	GSS_LOCK_MUTEX(params->utils);
+	gss_release_name(&min_stat, &without);
+	GSS_UNLOCK_MUTEX(params->utils);
+    }
+
+    return ret;
+}
+
+static int 
+gssapi_server_mech_ssfcap(context_t *text,
+			  sasl_server_params_t *params,
+			  const char *clientin __attribute__((unused)),
+			  unsigned clientinlen,
+			  const char **serverout,
+			  unsigned *serveroutlen,
+			  sasl_out_params_t *oparams __attribute__((unused)))
+{
+    gss_buffer_t input_token, output_token;
+    gss_buffer_desc real_input_token, real_output_token;
+    OM_uint32 maj_stat = 0, min_stat = 0;
+    unsigned char sasldata[4];
+    int ret;
+
+    input_token = &real_input_token;
+    output_token = &real_output_token;
+    output_token->value = NULL; output_token->length = 0;
+    
+
+    if (clientinlen != 0) {
+	SETERROR(text->utils, "GSSAPI server is not expecting data at this stage");
+	sasl_gss_free_context_contents(text);
+	return SASL_BADAUTH;
+    }
+
+    /* we have to decide what sort of encryption/integrity/etc.,
+       we support */
+    if (params->props.max_ssf < params->external_ssf) {
+	text->limitssf = 0;
+    } else {
+	text->limitssf = params->props.max_ssf - params->external_ssf;
+    }
+    if (params->props.min_ssf < params->external_ssf) {
+	text->requiressf = 0;
+    } else {
+	text->requiressf = params->props.min_ssf - params->external_ssf;
+    }
+
+    /* build up our security properties token */
+    if (text->requiressf != 0 &&
+	(text->qop & (LAYER_INTEGRITY|LAYER_CONFIDENTIALITY))) {
+	if (params->props.maxbufsize > 0xFFFFFF) {
+	    /* make sure maxbufsize isn't too large */
+	    /* maxbufsize = 0xFFFFFF */
+	    sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
+	} else {
+	    sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
+	    sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
+	    sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
+	}
+    } else {
+	/* From RFC 4752: "The client verifies that the server maximum buffer is 0
+	   if the server does not advertise support for any security layer." */
+	sasldata[1] = sasldata[2] = sasldata[3] = 0;
+    }
+
+    sasldata[0] = 0;
+    if(text->requiressf != 0 && !params->props.maxbufsize) {
+	params->utils->seterror(params->utils->conn, 0,
+				"GSSAPI needs a security layer but one is forbidden");
+	return SASL_TOOWEAK;
+    }
+
+    if (text->requiressf == 0) {
+	sasldata[0] |= LAYER_NONE; /* authentication */
+    }
+    if ((text->qop & LAYER_INTEGRITY) &&
+	text->requiressf <= 1 &&
+	text->limitssf >= 1 &&
+	params->props.maxbufsize) {
+	sasldata[0] |= LAYER_INTEGRITY;
+    }
+    if ((text->qop & LAYER_CONFIDENTIALITY) &&
+	text->requiressf <= K5_MAX_SSF &&
+	text->limitssf >= K5_MAX_SSF &&
+	params->props.maxbufsize) {
+	sasldata[0] |= LAYER_CONFIDENTIALITY;
+    }
+
+    /* Remember what we want and can offer */
+    text->qop = sasldata[0];
+
+    real_input_token.value = (void *)sasldata;
+    real_input_token.length = 4;
+
+    GSS_LOCK_MUTEX(params->utils);
+    maj_stat = gss_wrap(&min_stat,
+			text->gss_ctx,
+			0, /* Just integrity checking here */
+			GSS_C_QOP_DEFAULT,
+			input_token,
+			NULL,
+			output_token);
+    GSS_UNLOCK_MUTEX(params->utils);
+
+    if (GSS_ERROR(maj_stat)) {
+	sasl_gss_seterror(text->utils, maj_stat, min_stat);
+	if (output_token->value) {
+	    GSS_LOCK_MUTEX(params->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	}
+	sasl_gss_free_context_contents(text);
+	return SASL_FAIL;
+    }
+
+
+    if (serveroutlen)
+	*serveroutlen = output_token->length;
+    if (output_token->value) {
+	if (serverout) {
+	    ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+				  &(text->out_buf_len), *serveroutlen);
+	    if(ret != SASL_OK) {
+		GSS_LOCK_MUTEX(params->utils);
+		gss_release_buffer(&min_stat, output_token);
+		GSS_UNLOCK_MUTEX(params->utils);
+		return ret;
+	    }
+	    memcpy(text->out_buf, output_token->value, *serveroutlen);
+	    *serverout = text->out_buf;
+	}
+
+	GSS_LOCK_MUTEX(params->utils);
+	gss_release_buffer(&min_stat, output_token);
+	GSS_UNLOCK_MUTEX(params->utils);
+    }
+
+    /* Wait for ssf request and authid */
+    text->state = SASL_GSSAPI_STATE_SSFREQ; 
+	
+    return SASL_CONTINUE;
+}
+
+static int 
+gssapi_server_mech_ssfreq(context_t *text,
+			  sasl_server_params_t *params,
+			  const char *clientin,
+			  unsigned clientinlen,
+			  const char **serverout __attribute__((unused)),
+			  unsigned *serveroutlen __attribute__((unused)),
+			  sasl_out_params_t *oparams)
+{
+    gss_buffer_t input_token, output_token;
+    gss_buffer_desc real_input_token, real_output_token;
+    OM_uint32 maj_stat = 0, min_stat = 0;
+    OM_uint32 max_input;
+    int layerchoice;
+	
+    input_token = &real_input_token;
+    output_token = &real_output_token;
+    output_token->value = NULL; output_token->length = 0;
+
+    real_input_token.value = (void *)clientin;
+    real_input_token.length = clientinlen;
+
+    GSS_LOCK_MUTEX(params->utils);
+    maj_stat = gss_unwrap(&min_stat,
+			  text->gss_ctx,
+			  input_token,
+			  output_token,
+			  NULL,
+			  NULL);
+    GSS_UNLOCK_MUTEX(params->utils);
+
+    if (GSS_ERROR(maj_stat)) {
+	sasl_gss_seterror(text->utils, maj_stat, min_stat);
+	sasl_gss_free_context_contents(text);
+	return SASL_FAIL;
+    }
+
+    if (output_token->length < 4) {
+	SETERROR(text->utils,
+		 "token too short");
+	GSS_LOCK_MUTEX(params->utils);
+	gss_release_buffer(&min_stat, output_token);
+	GSS_UNLOCK_MUTEX(params->utils);
+	sasl_gss_free_context_contents(text);
+	return SASL_FAIL;
+    }
+
+    layerchoice = (int)(((char *)(output_token->value))[0]);
+    if (layerchoice == LAYER_NONE &&
+	(text->qop & LAYER_NONE)) { /* no encryption */
+	oparams->encode = NULL;
+	oparams->decode = NULL;
+	oparams->mech_ssf = 0;
+    } else if (layerchoice == LAYER_INTEGRITY &&
+	       (text->qop & LAYER_INTEGRITY)) { /* integrity */
+	oparams->encode = &gssapi_integrity_encode;
+	oparams->decode = &gssapi_decode;
+	oparams->mech_ssf = 1;
+    } else if ((layerchoice == LAYER_CONFIDENTIALITY ||
+		/* For compatibility with broken clients setting both bits */
+		layerchoice == (LAYER_CONFIDENTIALITY|LAYER_INTEGRITY)) &&
+	       (text->qop & LAYER_CONFIDENTIALITY)) { /* privacy */
+	oparams->encode = &gssapi_privacy_encode;
+	oparams->decode = &gssapi_decode;
+	/* FIX ME: Need to extract the proper value here */
+	oparams->mech_ssf = K5_MAX_SSF;
+    } else {
+	/* not a supported encryption layer */
+	SETERROR(text->utils,
+		 "protocol violation: client requested invalid layer");
+	/* Mark that we attempted negotiation */
+	oparams->mech_ssf = 2;
+	if (output_token->value) {
+	    GSS_LOCK_MUTEX(params->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	}
+	sasl_gss_free_context_contents(text);
+	return SASL_FAIL;
+    }
+
+    if (output_token->length > 4) {
+	int ret;
+
+	ret = params->canon_user(params->utils->conn,
+				 ((char *) output_token->value) + 4,
+				 (output_token->length - 4) * sizeof(char),
+				 SASL_CU_AUTHZID, oparams);
+	
+	if (ret != SASL_OK) {
+	    sasl_gss_free_context_contents(text);
+	    return ret;
+	}
+    }
+	
+    /* No matter what, set the rest of the oparams */
+
+    oparams->maxoutbuf =
+	(((unsigned char *) output_token->value)[1] << 16) |
+	(((unsigned char *) output_token->value)[2] << 8) |
+	(((unsigned char *) output_token->value)[3] << 0);
+
+    if (oparams->mech_ssf) {
+	maj_stat = gss_wrap_size_limit( &min_stat,
+					text->gss_ctx,
+					1,
+					GSS_C_QOP_DEFAULT,
+					(OM_uint32) oparams->maxoutbuf,
+					&max_input);
+
+	if(max_input > oparams->maxoutbuf) {
+	    /* Heimdal appears to get this wrong */
+	    oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
+	} else {
+	    /* This code is actually correct */
+	    oparams->maxoutbuf = max_input;
+	}    
+    }
+	
+    GSS_LOCK_MUTEX(params->utils);
+    gss_release_buffer(&min_stat, output_token);
+    GSS_UNLOCK_MUTEX(params->utils);
+
+    text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
+
+    /* used by layers */
+    _plug_decode_init(&text->decode_context,
+		      text->utils,
+		      (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
+		      params->props.maxbufsize);
+	
+    return SASL_OK;
+}
+
+static int 
+gssapi_server_mech_step(void *conn_context,
+			sasl_server_params_t *params,
+			const char *clientin,
+			unsigned clientinlen,
+			const char **serverout,
+			unsigned *serveroutlen,
+			sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) conn_context;
+    int ret;
+
+    if (!serverout) {
+	PARAMERROR(text->utils);
+	return SASL_BADPARAM;
+    }
+
+    *serverout = NULL;
+    *serveroutlen = 0;
+
+    if (text == NULL) return SASL_BADPROT;
+
+    params->utils->log(NULL, SASL_LOG_DEBUG,
+		       "GSSAPI server step %d\n", text->state);
+
+    switch (text->state) {
+
+    case SASL_GSSAPI_STATE_AUTHNEG:
+	ret = gssapi_server_mech_authneg(text, params, clientin, clientinlen,
+					 serverout, serveroutlen, oparams);
+	if (ret != SASL_CONTINUE || *serveroutlen) break;
+
+	/* Pretend that we just got an empty response from the client */
+	clientinlen = 0;
+
+	/* fall through */
+
+    case SASL_GSSAPI_STATE_SSFCAP:
+	ret = gssapi_server_mech_ssfcap(text, params, clientin, clientinlen,
+					serverout, serveroutlen, oparams);
+	break;
+
+    case SASL_GSSAPI_STATE_SSFREQ:
+	ret = gssapi_server_mech_ssfreq(text, params, clientin, clientinlen,
+					serverout, serveroutlen, oparams);
+	break;
+
+    default:
+	params->utils->log(NULL, SASL_LOG_ERR,
+			   "Invalid GSSAPI server step %d\n", text->state);
+	return SASL_FAIL;
+    }
+
+    if (ret == SASL_OK) {
+	ret = params->canon_user(params->utils->conn,
+				 text->authid,
+				 0, /* strlen(text->authid) */
+				 (oparams->user ? 0 : SASL_CU_AUTHZID)
+				 | SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED,
+				 oparams);
+
+	if (ret != SASL_OK) {
+	    sasl_gss_free_context_contents(text);
+	    return ret;
+	}
+
+	if (text->client_creds != GSS_C_NO_CREDENTIAL)	{
+	    oparams->client_creds =  &text->client_creds;
+	}
+	else {
+	    oparams->client_creds = NULL;
+	}
+
+	oparams->doneflag = 1;
+    }
+    
+    return ret;
+}
+
+static sasl_server_plug_t gssapi_server_plugins[] = 
+{
+    {
+	"GSSAPI",			/* mech_name */
+	K5_MAX_SSF,			/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOACTIVE
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH		/* security_flags */
+	| SASL_SEC_PASS_CREDENTIALS,
+	SASL_FEAT_WANT_CLIENT_FIRST
+	| SASL_FEAT_ALLOWS_PROXY
+	| SASL_FEAT_DONTUSE_USERPASSWD,	/* features */
+	NULL,				/* glob_context */
+	&gssapi_server_mech_new,	/* mech_new */
+	&gssapi_server_mech_step,	/* mech_step */
+	&gssapi_common_mech_dispose,	/* mech_dispose */
+	&gssapi_common_mech_free,	/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	NULL,				/* mech_avail */
+	NULL				/* spare */
+    }
+#ifdef HAVE_GSS_SPNEGO
+    ,{
+	"GSS-SPNEGO",			/* mech_name */
+	K5_MAX_SSF,			/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOACTIVE
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH		/* security_flags */
+	| SASL_SEC_PASS_CREDENTIALS,
+	SASL_FEAT_WANT_CLIENT_FIRST
+	| SASL_FEAT_ALLOWS_PROXY
+	| SASL_FEAT_DONTUSE_USERPASSWD
+	| SASL_FEAT_SUPPORTS_HTTP,	/* features */
+	NULL,				/* glob_context */
+	&gssapi_server_mech_new,	/* mech_new */
+	&gssapi_server_mech_step,	/* mech_step */
+	&gssapi_common_mech_dispose,	/* mech_dispose */
+	&gssapi_common_mech_free,	/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	NULL,				/* mech_avail */
+	NULL				/* spare */
+    }
+#endif
+};
+
+int gssapiv2_server_plug_init(
+#ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
+    const sasl_utils_t *utils __attribute__((unused)),
+#else
+    const sasl_utils_t *utils,
+#endif 
+    int maxversion,
+    int *out_version,
+    sasl_server_plug_t **pluglist,
+    int *plugcount)
+{
+#ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
+    const char *keytab = NULL;
+    char keytab_path[1024];
+    unsigned int rl;
+#endif
+    
+    if (maxversion < SASL_SERVER_PLUG_VERSION) {
+	return SASL_BADVERS;
+    }
+    
+#ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
+    /* unfortunately, we don't check for readability of keytab if it's
+       the standard one, since we don't know where it is */
+    
+    /* FIXME: This code is broken */
+    
+    utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
+    if (keytab != NULL) {
+	if (access(keytab, R_OK) != 0) {
+	    utils->log(NULL, SASL_LOG_ERR,
+		       "Could not find keytab file: %s: %m",
+		       keytab, errno);
+	    return SASL_FAIL;
+	}
+	
+	if(strlen(keytab) > 1024) {
+	    utils->log(NULL, SASL_LOG_ERR,
+		       "path to keytab is > 1024 characters");
+	    return SASL_BUFOVER;
+	}
+	
+	strncpy(keytab_path, keytab, 1024);
+	
+	gsskrb5_register_acceptor_identity(keytab_path);
+    }
+#endif
+    
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = gssapi_server_plugins;
+#ifdef HAVE_GSS_SPNEGO
+    *plugcount = 2;
+#else
+    *plugcount = 1;  
+#endif
+
+#ifdef GSS_USE_MUTEXES
+    if (!gss_mutex) {
+       gss_mutex = utils->mutex_alloc();
+       if (!gss_mutex) {
+           return SASL_FAIL;
+       }
+    }
+#endif
+    
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+static int gssapi_client_mech_new(void *glob_context,
+				  sasl_client_params_t *params,
+				  void **conn_context)
+{
+    context_t *text;
+    
+    /* holds state are in */
+    text = sasl_gss_new_context(params->utils);
+    if (text == NULL) {
+	MEMERROR(params->utils);
+	return SASL_NOMEM;
+    }
+    
+    text->state = SASL_GSSAPI_STATE_AUTHNEG;
+    text->mech_type = (gss_OID) glob_context;
+    text->gss_ctx = GSS_C_NO_CONTEXT;
+    text->client_name = GSS_C_NO_NAME;
+    text->server_creds = GSS_C_NO_CREDENTIAL;
+    text->client_creds  = GSS_C_NO_CREDENTIAL;
+
+    text->http_mode = (params->flags & SASL_NEED_HTTP);
+
+    *conn_context = text;
+    
+    return SASL_OK;
+}
+
+static int gssapi_client_mech_step(void *conn_context,
+				   sasl_client_params_t *params,
+				   const char *serverin,
+				   unsigned serverinlen,
+				   sasl_interact_t **prompt_need,
+				   const char **clientout,
+				   unsigned *clientoutlen,
+				   sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *)conn_context;
+    gss_buffer_t input_token, output_token;
+    gss_buffer_desc real_input_token, real_output_token;
+    OM_uint32 maj_stat = 0, min_stat = 0;
+    OM_uint32 max_input;
+    gss_buffer_desc name_token;
+    int ret;
+    OM_uint32 req_flags = 0, out_req_flags = 0;
+    input_token = &real_input_token;
+    output_token = &real_output_token;
+    output_token->value = NULL;
+    input_token->value = NULL; 
+    input_token->length = 0;
+    gss_cred_id_t client_creds = (gss_cred_id_t)params->gss_creds;
+    
+    *clientout = NULL;
+    *clientoutlen = 0;
+    
+    params->utils->log(NULL, SASL_LOG_DEBUG,
+		       "GSSAPI client step %d", text->state);
+
+    switch (text->state) {
+
+    case SASL_GSSAPI_STATE_AUTHNEG:
+	/* try to get the userid */
+	if (text->user == NULL) {
+	    int user_result = SASL_OK;
+	    
+	    user_result = _plug_get_userid(params->utils, &text->user,
+					   prompt_need);
+	    
+	    if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+		sasl_gss_free_context_contents(text);
+		return user_result;
+	    }
+		    
+	    /* free prompts we got */
+	    if (prompt_need && *prompt_need) {
+		params->utils->free(*prompt_need);
+		*prompt_need = NULL;
+	    }
+		    
+	    /* if there are prompts not filled in */
+	    if (user_result == SASL_INTERACT) {
+		/* make the prompt list */
+		int result =
+		    _plug_make_prompts(params->utils, prompt_need,
+				       user_result == SASL_INTERACT ?
+				       "Please enter your authorization name" : NULL, NULL,
+				       NULL, NULL,
+				       NULL, NULL,
+				       NULL, NULL, NULL,
+				       NULL, NULL, NULL);
+		if (result != SASL_OK) return result;
+		
+		return SASL_INTERACT;
+	    }
+	}
+	    
+	if (text->server_name == GSS_C_NO_NAME) { /* only once */
+	    if (params->serverFQDN == NULL
+		|| strlen(params->serverFQDN) == 0) {
+		SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
+		sasl_gss_free_context_contents(text);
+		return SASL_FAIL;
+	    }
+	    name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
+	    name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
+	    if (name_token.value == NULL) {
+		sasl_gss_free_context_contents(text);
+		return SASL_NOMEM;
+	    }
+	    
+	    sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
+	    
+	    GSS_LOCK_MUTEX(params->utils);
+	    maj_stat = gss_import_name (&min_stat,
+					&name_token,
+					GSS_C_NT_HOSTBASED_SERVICE,
+					&text->server_name);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	    
+	    params->utils->free(name_token.value);
+	    name_token.value = NULL;
+	    
+	    if (GSS_ERROR(maj_stat)) {
+		sasl_gss_seterror(text->utils, maj_stat, min_stat);
+		sasl_gss_free_context_contents(text);
+		return SASL_FAIL;
+	    }
+	}
+	    
+	if (serverinlen == 0)
+	    input_token = GSS_C_NO_BUFFER;
+
+	if (serverinlen) {
+	    real_input_token.value = (void *)serverin;
+	    real_input_token.length = serverinlen;
+	}
+	else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
+	    /* This can't happen under GSSAPI: we have a non-null context
+	     * and no input from the server.  However, thanks to Imap,
+	     * which discards our first output, this happens all the time.
+	     * Throw away the context and try again. */
+	    GSS_LOCK_MUTEX(params->utils);
+	    maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	    text->gss_ctx = GSS_C_NO_CONTEXT;
+	}
+
+	/* Setup req_flags properly */
+	req_flags = GSS_C_INTEG_FLAG;
+	if (params->props.max_ssf > params->external_ssf) {
+	    /* We are requesting a security layer */
+	    req_flags |= GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
+	    /* Any SSF bigger than 1 is confidentiality. */
+	    /* Let's check if the client of the API requires confidentiality,
+	       and it wasn't already provided by an external layer */
+	    if (params->props.max_ssf - params->external_ssf > 1) {
+		/* We want to try for privacy */
+		req_flags |= GSS_C_CONF_FLAG;
+	    }
+	}
+
+	if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) {
+	    req_flags = req_flags |  GSS_C_DELEG_FLAG;
+	}
+
+	GSS_LOCK_MUTEX(params->utils);
+	maj_stat = gss_init_sec_context(&min_stat,
+					client_creds, /* GSS_C_NO_CREDENTIAL */
+					&text->gss_ctx,
+					text->server_name,
+					text->mech_type,
+					req_flags,
+					0,
+					GSS_C_NO_CHANNEL_BINDINGS,
+					input_token,
+					NULL,
+					output_token,
+					&out_req_flags,
+					NULL);
+	GSS_UNLOCK_MUTEX(params->utils);
+	
+	if (GSS_ERROR(maj_stat)) {
+	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
+	    if (output_token->value) {
+		GSS_LOCK_MUTEX(params->utils);
+		gss_release_buffer(&min_stat, output_token);
+		GSS_UNLOCK_MUTEX(params->utils);
+	    }
+	    sasl_gss_free_context_contents(text);
+	    return SASL_FAIL;
+	}
+
+	if ((out_req_flags & GSS_C_INTEG_FLAG) == 0) {
+	    /* if the integ_avail flag is not set in the context,
+	       then no security layer can be offered or accepted. */
+	    text->qop = LAYER_NONE;
+	} else if ((out_req_flags & GSS_C_CONF_FLAG) == 0) {
+	    /* If the conf_avail flag is not set in the context,
+	       then no security layer with confidentiality can be offered
+	       or accepted. */
+	    text->qop = LAYER_NONE | LAYER_INTEGRITY;
+	} else {
+	    text->qop = LAYER_NONE | LAYER_INTEGRITY | LAYER_CONFIDENTIALITY;
+	}
+
+	if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_FLAG)) {
+	    text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed");
+	    /* not a fatal error */
+	}
+  	    
+	*clientoutlen = output_token->length;
+	    
+	if (output_token->value) {
+	    if (clientout) {
+		ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+				      &(text->out_buf_len), *clientoutlen);
+		if(ret != SASL_OK) {
+		    GSS_LOCK_MUTEX(params->utils);
+		    gss_release_buffer(&min_stat, output_token);
+		    GSS_UNLOCK_MUTEX(params->utils);
+		    return ret;
+		}
+		memcpy(text->out_buf, output_token->value, *clientoutlen);
+		*clientout = text->out_buf;
+	    }
+	    
+	    GSS_LOCK_MUTEX(params->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	}
+	
+	if (maj_stat == GSS_S_COMPLETE) {
+	    GSS_LOCK_MUTEX(params->utils);
+	    maj_stat = gss_inquire_context(&min_stat,
+					   text->gss_ctx,
+					   &text->client_name,
+					   NULL,       /* targ_name */
+					   NULL,       /* lifetime */
+					   NULL,       /* mech */
+					   /* FIX ME: Should check the resulting flags here */
+					   NULL,       /* flags */
+					   NULL,       /* local init */
+					   NULL);      /* open */
+	    GSS_UNLOCK_MUTEX(params->utils);
+	    
+	    if (GSS_ERROR(maj_stat)) {
+		sasl_gss_seterror(text->utils, maj_stat, min_stat);
+		sasl_gss_free_context_contents(text);
+		return SASL_FAIL;
+	    }
+	    
+	    name_token.length = 0;
+	    GSS_LOCK_MUTEX(params->utils);
+	    maj_stat = gss_display_name(&min_stat,
+					text->client_name,
+					&name_token,
+					NULL);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	    
+	    if (GSS_ERROR(maj_stat)) {
+		if (name_token.value) {
+		    GSS_LOCK_MUTEX(params->utils);
+		    gss_release_buffer(&min_stat, &name_token);
+		    GSS_UNLOCK_MUTEX(params->utils);
+		}
+		SETERROR(text->utils, "GSSAPI Failure");
+		sasl_gss_free_context_contents(text);
+		return SASL_FAIL;
+	    }
+	    
+	    if (text->user && text->user[0]) {
+		ret = params->canon_user(params->utils->conn,
+					 text->user, 0,
+					 SASL_CU_AUTHZID, oparams);
+		if (ret == SASL_OK) 
+		    ret = params->canon_user(params->utils->conn,
+					     name_token.value, 0,
+					     SASL_CU_AUTHID, oparams);
+	    } else {
+		ret = params->canon_user(params->utils->conn,
+					 name_token.value, 0,
+					 SASL_CU_AUTHID | SASL_CU_AUTHZID,
+					 oparams);
+	    }
+	    GSS_LOCK_MUTEX(params->utils);
+	    gss_release_buffer(&min_stat, &name_token);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	    
+	    if (ret != SASL_OK) return ret;
+	    
+	    if (text->http_mode) {
+		/* HTTP doesn't do any ssf negotiation */
+		text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
+		oparams->doneflag = 1;
+		return SASL_OK;
+	    }
+
+	    /* Switch to ssf negotiation */
+	    text->state = SASL_GSSAPI_STATE_SSFCAP;
+	}
+	
+	return SASL_CONTINUE;
+
+    case SASL_GSSAPI_STATE_SSFCAP: {
+	sasl_security_properties_t *secprops = &(params->props);
+	unsigned int alen, external = params->external_ssf;
+	sasl_ssf_t need, allowed;
+	char serverhas, mychoice;
+	
+	real_input_token.value = (void *) serverin;
+	real_input_token.length = serverinlen;
+	
+	GSS_LOCK_MUTEX(params->utils);
+	maj_stat = gss_unwrap(&min_stat,
+			      text->gss_ctx,
+			      input_token,
+			      output_token,
+			      NULL,
+			      NULL);
+	GSS_UNLOCK_MUTEX(params->utils);
+	
+	if (GSS_ERROR(maj_stat)) {
+	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
+	    sasl_gss_free_context_contents(text);
+	    if (output_token->value) {
+		GSS_LOCK_MUTEX(params->utils);
+		gss_release_buffer(&min_stat, output_token);
+		GSS_UNLOCK_MUTEX(params->utils);
+	    }
+	    return SASL_FAIL;
+	}
+	
+	if (output_token->length != 4) {
+	    SETERROR(text->utils,
+		     (output_token->length < 4) ? "token too short" : "token too long");
+	    GSS_LOCK_MUTEX(params->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(params->utils);
+	    sasl_gss_free_context_contents(text);
+	    return SASL_FAIL;
+	}
+
+	/* taken from kerberos.c */
+	if (secprops->min_ssf > (K5_MAX_SSF + external)) {
+	    return SASL_TOOWEAK;
+	} else if (secprops->min_ssf > secprops->max_ssf) {
+	    return SASL_BADPARAM;
+	}
+	
+	/* need bits of layer -- sasl_ssf_t is unsigned so be careful */
+	if (secprops->max_ssf >= external) {
+	    allowed = secprops->max_ssf - external;
+	} else {
+	    allowed = 0;
+	}
+	if (secprops->min_ssf >= external) {
+	    need = secprops->min_ssf - external;
+	} else {
+	    /* good to go */
+	    need = 0;
+	}
+
+	/* bit mask of server support */
+	serverhas = ((char *)output_token->value)[0];
+	
+	/* use the strongest layer available */
+	if ((text->qop & LAYER_CONFIDENTIALITY) &&
+	    allowed >= K5_MAX_SSF &&
+	    need <= K5_MAX_SSF &&
+	    (serverhas & LAYER_CONFIDENTIALITY)) {
+	    
+	    const char *ad_compat;
+
+	    /* encryption */
+	    oparams->encode = &gssapi_privacy_encode;
+	    oparams->decode = &gssapi_decode;
+	    /* FIX ME: Need to extract the proper value here */
+	    oparams->mech_ssf = K5_MAX_SSF;
+	    mychoice = LAYER_CONFIDENTIALITY;
+
+	    if (serverhas & LAYER_INTEGRITY) {
+		/* should we send an AD compatible choice of security layers? */
+		params->utils->getopt(params->utils->getopt_context,
+				      "GSSAPI",
+				      "ad_compat",
+				      &ad_compat,
+				      NULL);
+		if (ad_compat &&
+		    (ad_compat[0] == '1' || ad_compat[0] == 'y' ||
+		     (ad_compat[0] == 'o' && ad_compat[1] == 'n') ||
+		     ad_compat[0] == 't')) {
+		    mychoice = LAYER_INTEGRITY|LAYER_CONFIDENTIALITY;
+		}
+	    }
+	} else if ((text->qop & LAYER_INTEGRITY) &&
+		    allowed >= 1 &&
+		    need <= 1 &&
+		    (serverhas & LAYER_INTEGRITY)) {
+	    /* integrity */
+	    oparams->encode = &gssapi_integrity_encode;
+	    oparams->decode = &gssapi_decode;
+	    oparams->mech_ssf = 1;
+	    mychoice = LAYER_INTEGRITY;
+	} else if ((text->qop & LAYER_NONE) &&
+		   need <= 0 && (serverhas & LAYER_NONE)) {
+	    /* no layer */
+	    oparams->encode = NULL;
+	    oparams->decode = NULL;
+	    oparams->mech_ssf = 0;
+	    mychoice = LAYER_NONE;
+	} else {
+	    /* there's no appropriate layering for us! */
+	    sasl_gss_free_context_contents(text);
+	    return SASL_TOOWEAK;
+	}
+	
+        oparams->maxoutbuf =
+	    (((unsigned char *) output_token->value)[1] << 16) |
+            (((unsigned char *) output_token->value)[2] << 8) |
+            (((unsigned char *) output_token->value)[3] << 0);
+
+	if (oparams->mech_ssf) {
+            maj_stat = gss_wrap_size_limit( &min_stat,
+                                            text->gss_ctx,
+                                            1,
+                                            GSS_C_QOP_DEFAULT,
+                                            (OM_uint32) oparams->maxoutbuf,
+                                            &max_input);
+
+	    if (max_input > oparams->maxoutbuf) {
+		/* Heimdal appears to get this wrong */
+		oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
+	    } else {
+		/* This code is actually correct */
+		oparams->maxoutbuf = max_input;
+	    }
+	}
+	
+	GSS_LOCK_MUTEX(params->utils);
+	gss_release_buffer(&min_stat, output_token);
+	GSS_UNLOCK_MUTEX(params->utils);
+	
+	/* oparams->user is always set, due to canon_user requirements.
+	 * Make sure the client actually requested it though, by checking
+	 * if our context was set.
+	 */
+	if (text->user && text->user[0]) {
+	    alen = strlen(oparams->user);
+	} else {
+	    alen = 0;
+	}
+	
+	input_token->length = 4 + alen;
+	input_token->value =
+	    (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
+	if (input_token->value == NULL) {
+	    sasl_gss_free_context_contents(text);
+	    return SASL_NOMEM;
+	}
+	
+	if (alen)
+	    memcpy((char *)input_token->value+4,oparams->user,alen);
+
+	/* build up our security properties token */
+	if (mychoice > 1) {
+	    if (params->props.maxbufsize > 0xFFFFFF) {
+		/* make sure maxbufsize isn't too large */
+		/* maxbufsize = 0xFFFFFF */
+		((unsigned char *)input_token->value)[1] = 0xFF;
+		((unsigned char *)input_token->value)[2] = 0xFF;
+		((unsigned char *)input_token->value)[3] = 0xFF;
+	    } else {
+		((unsigned char *)input_token->value)[1] = 
+		    (params->props.maxbufsize >> 16) & 0xFF;
+		((unsigned char *)input_token->value)[2] = 
+		    (params->props.maxbufsize >> 8) & 0xFF;
+		((unsigned char *)input_token->value)[3] = 
+		    (params->props.maxbufsize >> 0) & 0xFF;
+	    }
+	} else {
+	    ((unsigned char *)input_token->value)[1] = 0;
+	    ((unsigned char *)input_token->value)[2] = 0;
+	    ((unsigned char *)input_token->value)[3] = 0;
+	}
+	((unsigned char *)input_token->value)[0] = mychoice;
+	
+	GSS_LOCK_MUTEX(params->utils);
+	maj_stat = gss_wrap (&min_stat,
+			     text->gss_ctx,
+			     0, /* Just integrity checking here */
+			     GSS_C_QOP_DEFAULT,
+			     input_token,
+			     NULL,
+			     output_token);
+	GSS_UNLOCK_MUTEX(params->utils);
+	
+	params->utils->free(input_token->value);
+	input_token->value = NULL;
+	
+	if (GSS_ERROR(maj_stat)) {
+	    sasl_gss_seterror(text->utils, maj_stat, min_stat);
+	    if (output_token->value) {
+		GSS_LOCK_MUTEX(params->utils);
+		gss_release_buffer(&min_stat, output_token);
+		GSS_UNLOCK_MUTEX(params->utils);
+	    }
+	    sasl_gss_free_context_contents(text);
+	    return SASL_FAIL;
+	}
+	
+	if (clientoutlen) {
+	    *clientoutlen = output_token->length;
+	}
+	if (output_token->value) {
+	    if (clientout) {
+		ret = _plug_buf_alloc(text->utils,
+				      &(text->out_buf),
+				      &(text->out_buf_len),
+				      *clientoutlen);
+		if (ret != SASL_OK) {
+		    GSS_LOCK_MUTEX(params->utils);
+		    gss_release_buffer(&min_stat, output_token);
+		    GSS_UNLOCK_MUTEX(params->utils);
+		    return ret;
+		}
+		memcpy(text->out_buf, output_token->value, *clientoutlen);
+		*clientout = text->out_buf;
+	    }
+	    
+	    GSS_LOCK_MUTEX(params->utils);
+	    gss_release_buffer(&min_stat, output_token);
+	    GSS_UNLOCK_MUTEX(params->utils);
+
+	}
+	
+	text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
+	
+	oparams->doneflag = 1;
+	
+	/* used by layers */
+	_plug_decode_init(&text->decode_context, text->utils,
+			  (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
+			  params->props.maxbufsize);
+	
+	return SASL_OK;
+    }
+	
+    default:
+	params->utils->log(NULL, SASL_LOG_ERR,
+			   "Invalid GSSAPI client step %d\n", text->state);
+	return SASL_FAIL;
+    }
+    
+    return SASL_FAIL; /* should never get here */
+}
+
+static const unsigned long gssapi_required_prompts[] = {
+    SASL_CB_LIST_END
+};  
+
+static sasl_client_plug_t gssapi_client_plugins[] = 
+{
+    {
+	"GSSAPI",			/* mech_name */
+	K5_MAX_SSF,			/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOACTIVE
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH 
+	| SASL_SEC_PASS_CREDENTIALS,    /* security_flags */
+	SASL_FEAT_NEEDSERVERFQDN
+	| SASL_FEAT_WANT_CLIENT_FIRST
+	| SASL_FEAT_ALLOWS_PROXY,	/* features */
+	gssapi_required_prompts,	/* required_prompts */
+	GSS_C_NO_OID,			/* glob_context */
+	&gssapi_client_mech_new,	/* mech_new */
+	&gssapi_client_mech_step,	/* mech_step */
+	&gssapi_common_mech_dispose,	/* mech_dispose */
+	&gssapi_common_mech_free,	/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL				/* spare */
+    }
+#ifdef HAVE_GSS_SPNEGO
+    ,{
+	"GSS-SPNEGO",			/* mech_name */
+	K5_MAX_SSF,			/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOACTIVE
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH 
+	| SASL_SEC_PASS_CREDENTIALS,    /* security_flags */
+	SASL_FEAT_NEEDSERVERFQDN
+	| SASL_FEAT_WANT_CLIENT_FIRST
+	| SASL_FEAT_ALLOWS_PROXY
+	| SASL_FEAT_SUPPORTS_HTTP,	/* features */
+	gssapi_required_prompts,	/* required_prompts */
+	&gss_spnego_oid,		/* glob_context */
+	&gssapi_client_mech_new,	/* mech_new */
+	&gssapi_client_mech_step,	/* mech_step */
+	&gssapi_common_mech_dispose,	/* mech_dispose */
+	&gssapi_common_mech_free,	/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL				/* spare */
+    }
+#endif
+};
+
+int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)), 
+			      int maxversion,
+			      int *out_version, 
+			      sasl_client_plug_t **pluglist,
+			      int *plugcount)
+{
+    if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+	SETERROR(utils, "Version mismatch in GSSAPI");
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = gssapi_client_plugins;
+#ifdef HAVE_GSS_SPNEGO
+    *plugcount = 2;
+#else
+    *plugcount = 1;
+#endif
+
+#ifdef GSS_USE_MUTEXES
+    if(!gss_mutex) {
+      gss_mutex = utils->mutex_alloc();
+      if(!gss_mutex) {
+        return SASL_FAIL;
+      }
+    }
+#endif
+    
+    return SASL_OK;
+}

+ 43 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/gssapiv2_init.c

@@ -0,0 +1,43 @@
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_gssapiv2_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+					 )
+{
+    switch (ul_reason_for_call)
+	{
+		case DLL_PROCESS_ATTACH:
+		case DLL_THREAD_ATTACH:
+		case DLL_THREAD_DETACH:
+		case DLL_PROCESS_DETACH:
+			break;
+    }
+    return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( gssapiv2 )
+SASL_SERVER_PLUG_INIT( gssapiv2 )
+

+ 1406 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/kerberos4.c

@@ -0,0 +1,1406 @@
+/* Kerberos4 SASL plugin
+ * Rob Siemborski
+ * Tim Martin 
+ * $Id: kerberos4.c,v 1.100 2009/03/10 16:27:52 mel Exp $
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <krb.h>
+
+#ifdef WITH_DES
+# ifdef WITH_SSL_DES
+#  include <openssl/des.h>
+# else
+#  include <des.h>
+# endif /* WITH_SSL_DES */
+#endif /* WITH_DES */
+
+#ifdef WIN32
+# include <winsock2.h>
+#elif defined(macintosh)
+#include <kcglue_krb.h>
+#else
+# include <sys/param.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* WIN32 */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+
+#include <errno.h>
+#include <ctype.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+/*
+ * krb.h doenst include some functions and mac compiler is picky
+ * about declartions
+ */
+#include <extra_krb.h>
+#include <sasl_kerberos4_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+/* This must be after sasl.h, saslutil.h */
+# include "saslKERBEROSV4.h"
+
+/* KClient doesn't define this */
+typedef struct krb_principal {
+    char name[ANAME_SZ];
+    char instance[INST_SZ];
+    char realm[REALM_SZ];
+} krb_principal;
+
+/* This isn't defined under WIN32.  For access() */
+#ifndef R_OK
+#define R_OK 04
+#endif
+/* we also need io.h for access() prototype */
+#include <io.h>
+#endif /* WIN32 */
+
+#ifdef sun
+/* gotta define gethostname ourselves on suns */
+extern int gethostname(char *, int);
+#endif
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: kerberos4.c,v 1.100 2009/03/10 16:27:52 mel Exp $";
+
+#ifndef KEYFILE
+#define KEYFILE "/etc/srvtab";
+#endif
+
+#define KRB_SECFLAG_NONE (1)
+#define KRB_SECFLAG_INTEGRITY (2)
+#define KRB_SECFLAG_ENCRYPTION (4)
+#define KRB_SECFLAGS (7)
+#define KRB_SECFLAG_CREDENTIALS (8)
+
+#define KRB_DES_SECURITY_BITS (56)
+#define KRB_INTEGRITY_BITS (1)
+
+typedef enum Krb_sec {
+    KRB_SEC_NONE = 0,
+    KRB_SEC_INTEGRITY = 1,
+    KRB_SEC_ENCRYPTION = 2
+} Krb_sec_t;
+
+typedef struct context {
+    int state;
+    
+    int challenge;         /* this is the challenge (32 bit int) used 
+			      for the authentication */
+    
+    char *service;                   /* kerberos service */
+    char instance[ANAME_SZ];
+    char pname[ANAME_SZ];
+    char pinst[INST_SZ];
+    char prealm[REALM_SZ];
+    char *hostname;                  /* hostname */
+    char *realm;                     /* kerberos realm */
+    char *auth;                      /* */
+    
+    CREDENTIALS credentials;
+    
+    des_cblock key;                  /* session key */
+    des_cblock session;              /* session key */
+    
+    des_key_schedule init_keysched;  /* key schedule for initialization */
+    des_key_schedule enc_keysched;   /* encryption key schedule */
+    des_key_schedule dec_keysched;   /* decryption key schedule */
+    
+    
+    struct sockaddr_in ip_local;     /* local ip address and port.
+					needed for layers */
+    struct sockaddr_in ip_remote;    /* remote ip address and port.
+					needed for layers */
+    
+    const sasl_utils_t *utils;       /* this is useful to have around */
+    
+    Krb_sec_t sec_type;
+    char *encode_buf;                /* For encoding/decoding mem management */
+    char *decode_buf;
+    char *decode_once_buf;
+    unsigned encode_buf_len;
+    unsigned decode_buf_len;
+    unsigned decode_once_buf_len;
+    buffer_info_t *enc_in_buf;
+
+    decode_context_t decode_context;
+    
+    char *out_buf;                   /* per-step mem management */
+    unsigned out_buf_len;
+    
+    const char *user;                      /* used by client */
+    
+    int secflags; /* client/server supports layers? */
+    
+    long time_sec; /* These are used to make sure we are getting */
+    char time_5ms; /* strictly increasing timestamps */
+    
+} context_t;
+
+#define KRB_LOCK_MUTEX(utils)  \
+    if(((sasl_utils_t *)(utils))->mutex_lock(krb_mutex) != 0) { \
+       ((sasl_utils_t *)(utils))->seterror(((sasl_utils_t *)(utils))->conn, \
+                                           0, "error locking mutex"); \
+			           return SASL_FAIL; \
+                                }
+#define KRB_UNLOCK_MUTEX(utils) \
+    if(((sasl_utils_t *)(utils))->mutex_unlock(krb_mutex) != 0) { \
+       ((sasl_utils_t *)(utils))->seterror(((sasl_utils_t *)(utils))->conn, \
+                                           0, "error unlocking mutex"); \
+			           return SASL_FAIL; \
+                                }
+
+/* Mutex for not-thread-safe kerberos 4 library */
+static void *krb_mutex = NULL;
+static char *srvtab = NULL;
+static unsigned refcount = 0;
+
+static int kerberosv4_encode(void *context,
+			     const struct iovec *invec,
+			     unsigned numiov,
+			     const char **output,
+			     unsigned *outputlen)
+{
+    int len, ret;
+    context_t *text = (context_t *)context;
+    struct buffer_info *inblob, bufinfo;
+    
+    if(numiov > 1) {
+	ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
+	if(ret != SASL_OK) return ret;
+	inblob = text->enc_in_buf;
+    } else {
+	bufinfo.data = invec[0].iov_base;
+	bufinfo.curlen = invec[0].iov_len;
+	inblob = &bufinfo;
+    }
+    
+    ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
+			  &text->encode_buf_len, inblob->curlen+40);
+    
+    if(ret != SASL_OK) return ret;
+    
+    KRB_LOCK_MUTEX(text->utils);
+    
+    if (text->sec_type == KRB_SEC_ENCRYPTION) {
+	/* Type incompatibility on 4th arg probably means you're
+	   building against krb4 in MIT krb5, but got the OpenSSL
+	   headers in your way. You need to not use openssl/des.h with
+	   MIT kerberos. */
+	len=krb_mk_priv(inblob->data, (text->encode_buf+4),
+			inblob->curlen,  text->init_keysched, 
+			&text->session, &text->ip_local,
+			&text->ip_remote);
+    } else if (text->sec_type == KRB_SEC_INTEGRITY) {
+	len=krb_mk_safe(inblob->data, (text->encode_buf+4),
+			inblob->curlen,
+			&text->session, &text->ip_local, &text->ip_remote);
+    } else {
+	len = -1;
+    }
+    
+    KRB_UNLOCK_MUTEX(text->utils);
+    
+    /* returns -1 on error */
+    if (len==-1) return SASL_FAIL;
+    
+    /* now copy in the len of the buffer in network byte order */
+    *outputlen=len+4;
+    len=htonl(len);
+    memcpy(text->encode_buf, &len, 4);
+    
+    /* Setup the const pointer */
+    *output = text->encode_buf;
+    
+    return SASL_OK;
+}
+
+static int kerberosv4_decode_packet(void *context,
+				    const char *input, unsigned inputlen,
+				    char **output, unsigned *outputlen)
+{
+    context_t *text = (context_t *) context;
+    int result;
+    MSG_DAT data;
+    
+    memset(&data,0,sizeof(MSG_DAT));
+    
+    KRB_LOCK_MUTEX(text->utils);
+    
+    if (text->sec_type == KRB_SEC_ENCRYPTION) {
+	result=krb_rd_priv(input, inputlen, text->init_keysched, 
+			   &text->session, &text->ip_remote,
+			   &text->ip_local, &data);
+    } else if (text->sec_type == KRB_SEC_INTEGRITY) {
+        result = krb_rd_safe(input, inputlen,
+			     &text->session, &text->ip_remote,
+			     &text->ip_local, &data);
+    } else {
+        KRB_UNLOCK_MUTEX(text->utils);
+	text->utils->seterror(text->utils->conn, 0,
+			      "KERBEROS_4 decode called with KRB_SEC_NONE");
+	return SASL_FAIL;
+    }
+    
+    KRB_UNLOCK_MUTEX(text->utils);
+    
+    /* see if the krb library gave us a failure */
+    if (result != 0) {
+	text->utils->seterror(text->utils->conn, 0, get_krb_err_txt(result));
+	return SASL_FAIL;
+    }
+    
+    /* check to make sure the timestamps are ok */
+    if ((data.time_sec < text->time_sec) || /* if an earlier time */
+	(((data.time_sec == text->time_sec) && /* or the exact same time */
+	  (data.time_5ms < text->time_5ms)))) 
+	{
+	    text->utils->seterror(text->utils->conn, 0, "timestamps not ok");
+	    return SASL_FAIL;
+	}
+    
+    text->time_sec = data.time_sec;
+    text->time_5ms = data.time_5ms;
+    
+    result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
+			     &text->decode_once_buf_len,
+			     data.app_length + 1);
+    if(result != SASL_OK)
+	return result;
+    
+    *output = text->decode_once_buf;
+    *outputlen = data.app_length;
+    memcpy(*output, data.app_data, data.app_length);
+    (*output)[*outputlen] = '\0';
+    
+    return SASL_OK;
+}
+
+static int kerberosv4_decode(void *context,
+			     const char *input, unsigned inputlen,
+			     const char **output, unsigned *outputlen)
+{
+    context_t *text = (context_t *) context;
+    int ret;
+    
+    ret = _plug_decode(&text->decode_context, input, inputlen,
+		       &text->decode_buf, &text->decode_buf_len, outputlen,
+		       kerberosv4_decode_packet, text);
+    
+    *output = text->decode_buf;
+    
+    return ret;
+}
+
+static int new_text(const sasl_utils_t *utils, context_t **text)
+{
+    context_t *ret = (context_t *) utils->malloc(sizeof(context_t));
+
+    if (ret == NULL) {
+	MEMERROR(utils);
+	return SASL_NOMEM;
+    }
+    
+    memset(ret, 0, sizeof(context_t));
+    
+    ret->state = 1;
+    ret->utils = utils;
+    
+    *text = ret;
+    
+    return SASL_OK;
+}
+
+static void kerberosv4_common_mech_dispose(void *conn_context,
+					   const sasl_utils_t *utils)
+{
+    context_t *text = (context_t *)conn_context;
+    
+    if(!text) return;
+    
+    _plug_decode_free(&text->decode_context);
+    if (text->encode_buf) utils->free(text->encode_buf);
+    if (text->decode_buf) utils->free(text->decode_buf);
+    if (text->decode_once_buf) utils->free(text->decode_once_buf);
+    if (text->out_buf) utils->free(text->out_buf);
+    if (text->enc_in_buf) {
+	if(text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
+	utils->free(text->enc_in_buf);
+    }
+    /* no need to free userid, it's just the interaction result */
+    
+    utils->free(text);
+}
+
+static void
+kerberosv4_common_mech_free(void *glob_context __attribute__((unused)),
+			    const sasl_utils_t *utils)
+{
+    if (krb_mutex) {
+	utils->mutex_free(krb_mutex);
+	krb_mutex = NULL; /* in case we need to re-use it */
+    }
+    refcount--;
+    if (srvtab && !refcount) {
+	utils->free(srvtab);
+	srvtab = NULL;
+    }
+}
+
+/*****************************  Server Section  *****************************/
+
+static int cando_sec(sasl_security_properties_t *props,
+		     int external_ssf,
+		     int secflag)
+{
+    int need;
+    int musthave;
+    
+    if(props->maxbufsize == 0) {
+	need = musthave = 0;
+    } else {
+	need = props->max_ssf - external_ssf;
+	musthave = props->min_ssf - external_ssf;
+    }
+
+    switch (secflag) {
+    case KRB_SECFLAG_NONE:
+	if (musthave <= 0)
+	    return 1;
+	break;
+    case KRB_SECFLAG_INTEGRITY:
+	if ((musthave <= KRB_INTEGRITY_BITS)
+	    && (KRB_INTEGRITY_BITS <= need))
+	    return 1;
+	break;
+    case KRB_SECFLAG_ENCRYPTION:
+	if ((musthave <= KRB_DES_SECURITY_BITS)
+	    && (KRB_DES_SECURITY_BITS <= need))
+	    return 1;
+	break;
+    case KRB_SECFLAG_CREDENTIALS:
+	if (props->security_flags & SASL_SEC_PASS_CREDENTIALS)
+	    return 1;
+	break;
+    }
+    return 0;
+}
+
+static int ipv4_ipfromstring(const sasl_utils_t *utils, const char *addr,
+			     struct sockaddr_in *out) 
+{
+    struct sockaddr_storage ss;
+    int result;
+    
+    result = _plug_ipfromstring(utils, addr,
+				(struct sockaddr *)&ss, sizeof(ss));
+    if (result != SASL_OK) {
+	/* couldn't get local IP address */
+	return result;
+    }
+    /* Kerberos_V4 supports only IPv4 */
+    if (((struct sockaddr *)&ss)->sa_family != AF_INET)
+	return SASL_FAIL;
+    memcpy(out, &ss, sizeof(struct sockaddr_in));
+    
+    return SASL_OK;
+}
+
+#ifndef macintosh
+static int
+kerberosv4_server_mech_new(void *glob_context __attribute__((unused)),
+			   sasl_server_params_t *sparams,
+			   const char *challenge __attribute__((unused)),
+			   unsigned challen __attribute__((unused)),
+			   void **conn_context)
+{
+    return new_text(sparams->utils, (context_t **) conn_context);
+}
+
+static int kerberosv4_server_mech_step(void *conn_context,
+				       sasl_server_params_t *sparams,
+				       const char *clientin,
+				       unsigned clientinlen,
+				       const char **serverout,
+				       unsigned *serveroutlen,
+				       sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) conn_context;
+    int result;
+
+    *serverout = NULL;
+    *serveroutlen = 0;
+    
+    switch (text->state) {
+
+    case 1: {
+	/* random 32-bit number */
+	int randocts, nchal;
+	
+	/* shouldn't we check for erroneous client input here?!? */
+	
+	sparams->utils->rand(sparams->utils->rpool,(char *) &randocts ,
+			     sizeof(randocts));    
+	text->challenge=randocts; 
+	nchal = htonl(text->challenge);
+	
+	result = _plug_buf_alloc(text->utils, &text->out_buf,
+				 &text->out_buf_len, 5);
+	if (result != SASL_OK) return result;
+	
+	memcpy(text->out_buf,&nchal,4);
+	*serverout = text->out_buf;
+	*serveroutlen = 4;
+	
+	text->state = 2;
+
+	return SASL_CONTINUE;
+    }
+    
+    case 2: {
+	int nchal;
+	unsigned char sout[8];  
+	AUTH_DAT ad;
+	KTEXT_ST ticket;
+	unsigned lup;
+	struct sockaddr_in addr;
+	char *dot;
+	
+	/* received authenticator */
+	
+	/* create ticket */
+	if (clientinlen > MAX_KTXT_LEN) {
+	    text->utils->seterror(text->utils->conn,0,
+				  "request larger than maximum ticket size");
+	    return SASL_FAIL;
+	}
+	
+	ticket.length=clientinlen;
+	for (lup = 0; lup < clientinlen; lup++)      
+	    ticket.dat[lup] = clientin[lup];
+	
+	KRB_LOCK_MUTEX(sparams->utils);
+	
+	text->realm = krb_realmofhost(sparams->serverFQDN);
+	
+	/* get instance */
+	strncpy (text->instance, krb_get_phost (sparams->serverFQDN),
+		 sizeof (text->instance));
+	
+	KRB_UNLOCK_MUTEX(sparams->utils);
+	
+	text->instance[sizeof(text->instance)-1] = 0;
+
+	/* At some sites, krb_get_phost() sensibly but
+	 * atypically returns FQDNs, versus the first component,
+	 * which is what we need for RFC2222 section 7.1
+	 */
+	dot = strchr(text->instance, '.');
+	if (dot) *dot = '\0';
+
+	memset(&addr, 0, sizeof(struct sockaddr_in));
+	
+#ifndef KRB4_IGNORE_IP_ADDRESS
+	/* (we ignore IP addresses in krb4 tickets at CMU to facilitate moving
+	   from machine to machine) */
+	
+	/* get ip number in addr*/
+	result = ipv4_ipfromstring(sparams->utils, sparams->ipremoteport, &addr);
+	if (result != SASL_OK || !sparams->ipremoteport) {
+	    SETERROR(text->utils, "couldn't get remote IP address");
+	    return result;
+	}
+#endif
+	
+	/* check ticket */
+	
+	KRB_LOCK_MUTEX(sparams->utils);
+	result = krb_rd_req(&ticket, (char *) sparams->service, text->instance, 
+			    addr.sin_addr.s_addr, &ad, srvtab);
+	KRB_UNLOCK_MUTEX(sparams->utils);
+	
+	if (result) { /* if fails mechanism fails */
+	    text->utils->seterror(text->utils->conn,0,
+				  "krb_rd_req failed service=%s instance=%s error code=%s (%i)",
+				  sparams->service, text->instance,get_krb_err_txt(result),result);
+	    return SASL_BADAUTH;
+	}
+	
+	/* 8 octets of data
+	 * 1-4 checksum+1
+	 * 5 security layers
+	 * 6-8max cipher text buffer size
+	 * use DES ECB in the session key
+	 */
+	
+	nchal=htonl(text->challenge+1);
+	memcpy(sout, &nchal, 4);
+	sout[4]= 0;
+	if (cando_sec(&sparams->props, sparams->external_ssf,
+		      KRB_SECFLAG_NONE))
+	    sout[4] |= KRB_SECFLAG_NONE;
+	if (cando_sec(&sparams->props, sparams->external_ssf,
+		      KRB_SECFLAG_INTEGRITY))
+	    sout[4] |= KRB_SECFLAG_INTEGRITY;
+	if (cando_sec(&sparams->props, sparams->external_ssf,
+		      KRB_SECFLAG_ENCRYPTION))
+	    sout[4] |= KRB_SECFLAG_ENCRYPTION;
+	if (cando_sec(&sparams->props, sparams->external_ssf,
+		      KRB_SECFLAG_CREDENTIALS))
+	    sout[4] |= KRB_SECFLAG_CREDENTIALS;
+
+	if(sparams->props.maxbufsize) {
+	    int tmpmaxbuf = (sparams->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF : sparams->props.maxbufsize;
+
+	    sout[5]=((tmpmaxbuf >> 16) & 0xFF);
+	    sout[6]=((tmpmaxbuf >> 8) & 0xFF);
+	    sout[7]=(tmpmaxbuf & 0xFF);
+	} else {
+            /* let's say we can support up to 64K */
+	    /* no inherent inability with our layers to support more */
+
+	    sout[5]=0x00;  /* max ciphertext buffer size */
+	    sout[6]=0xFF;
+	    sout[7]=0xFF;
+	}
+    
+	memcpy(text->session, ad.session, 8);
+	memcpy(text->pname, ad.pname, sizeof(text->pname));
+	memcpy(text->pinst, ad.pinst, sizeof(text->pinst));
+	memcpy(text->prealm, ad.prealm, sizeof(text->prealm));
+	des_key_sched(&ad.session, text->init_keysched);
+	
+	/* make keyschedule for encryption and decryption */
+	des_key_sched(&ad.session, text->enc_keysched);
+	des_key_sched(&ad.session, text->dec_keysched);
+	
+	des_ecb_encrypt((des_cblock *)sout,
+			(des_cblock *)sout,
+			text->init_keysched,
+			DES_ENCRYPT);
+	
+	result = _plug_buf_alloc(text->utils, &text->out_buf,
+				 &text->out_buf_len, 9);
+	if(result != SASL_OK)
+	    return result;
+	
+	memcpy(text->out_buf,&sout,8);
+	*serverout = text->out_buf;
+	*serveroutlen = 8;
+	
+	text->state = 3;
+
+	return SASL_CONTINUE;
+    }
+    
+    case 3: {
+	int result;
+	int testnum;
+	int flag;
+	unsigned char *in;
+	
+	if ((clientinlen == 0) || (clientinlen % 8 != 0)) {
+	    text->utils->seterror(text->utils->conn,0,
+				  "Response to challengs is not a multiple of 8 octets (a DES block)");
+	    return SASL_FAIL;	
+	}
+	
+	/* we need to make a copy because des does in place decrpytion */
+	in = sparams->utils->malloc(clientinlen + 1);
+	if (in == NULL) {
+	    MEMERROR(sparams->utils);
+	    return SASL_NOMEM;
+	}
+	
+	memcpy(in, clientin, clientinlen);
+	in[clientinlen] = '\0';
+	
+	/* decrypt; verify checksum */
+	
+	des_pcbc_encrypt((des_cblock *)in,
+			 (des_cblock *)in,
+			 clientinlen,
+			 text->init_keysched,
+			 &text->session,
+			 DES_DECRYPT);
+	
+	testnum = (in[0]*256*256*256)+(in[1]*256*256)+(in[2]*256)+in[3];
+	
+	if (testnum != text->challenge) {
+	    SETERROR(sparams->utils, "incorrect response to challenge");
+	    return SASL_BADAUTH;
+	}
+	
+	if (!cando_sec(&sparams->props, sparams->external_ssf,
+		       in[4] & KRB_SECFLAGS)) {
+	    SETERROR(sparams->utils,
+		     "invalid security property specified");
+	    return SASL_BADPROT;
+	}
+	
+	oparams->encode = &kerberosv4_encode;
+	oparams->decode = &kerberosv4_decode;
+	
+	switch (in[4] & KRB_SECFLAGS) {
+	case KRB_SECFLAG_NONE:
+	    text->sec_type = KRB_SEC_NONE;
+	    oparams->encode = NULL;
+	    oparams->decode = NULL;
+	    oparams->mech_ssf = 0;
+	    break;
+	case KRB_SECFLAG_INTEGRITY:
+	    text->sec_type = KRB_SEC_INTEGRITY;
+	    oparams->mech_ssf = KRB_INTEGRITY_BITS;
+	    break;
+	case KRB_SECFLAG_ENCRYPTION:
+	    text->sec_type = KRB_SEC_ENCRYPTION;
+	    oparams->mech_ssf = KRB_DES_SECURITY_BITS;
+	    break;
+	default:
+	    /* Mark that we tried */
+	    oparams->mech_ssf = 2;
+	    SETERROR(sparams->utils, "not a supported encryption layer");
+	    return SASL_BADPROT;
+	}
+	
+	/* get ip data */
+	/* get ip number in addr*/
+	result = ipv4_ipfromstring(sparams->utils,
+				   sparams->iplocalport, &(text->ip_local));
+	if (result != SASL_OK) {
+	    SETERROR(sparams->utils, "couldn't get local ip address");
+	    /* couldn't get local IP address */
+	    return result;
+	}
+	
+	result = ipv4_ipfromstring(sparams->utils,
+				   sparams->ipremoteport, &(text->ip_remote));
+	if (result != SASL_OK) {
+	    SETERROR(sparams->utils, "couldn't get remote ip address");
+	    /* couldn't get remote IP address */
+	    return result;
+	}
+	
+	/* fill in oparams */
+	oparams->maxoutbuf = (in[5] << 16) + (in[6] << 8) + in[7];
+	if(oparams->mech_ssf) {
+	    /* FIXME: Likely to be too large */
+	    oparams->maxoutbuf -= 50;
+	}
+	
+	if (sparams->canon_user) {
+	    char *user=NULL, *authid=NULL;
+	    size_t ulen = 0, alen = strlen(text->pname);
+	    int ret, cflag = SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED;
+	    
+	    if (text->pinst[0]) {
+		alen += strlen(text->pinst) + 1 /* for the . */;
+	    }
+	    flag = 0;
+	    if (strcmp(text->realm, text->prealm)) {
+		alen += strlen(text->prealm) + 1 /* for the @ */;
+		flag = 1;
+	    }
+	    
+	    authid = sparams->utils->malloc(alen + 1);
+	    if (!authid) {
+		MEMERROR(sparams->utils);
+		return SASL_NOMEM;
+	    }
+	    
+	    strcpy(authid, text->pname);
+	    if (text->pinst[0]) {
+		strcat(authid, ".");
+		strcat(authid, text->pinst);
+	    }
+	    if (flag) {
+		strcat(authid, "@");
+		strcat(authid, text->prealm);
+	    }
+	    
+	    if (in[8]) {
+		user = sparams->utils->malloc(strlen((char *) in + 8) + 1);
+		if (!user) {
+		    MEMERROR(sparams->utils);
+		    return SASL_NOMEM;
+		}
+		
+		strcpy(user, (char *) in + 8);
+		ulen = strlen(user);
+	    } else {
+	    	cflag |= SASL_CU_AUTHZID;
+	    }
+	    
+	    ret = sparams->canon_user(sparams->utils->conn, authid, alen,
+				      cflag, oparams);
+	    sparams->utils->free(authid);
+	    if (ret != SASL_OK) {
+		if (user)
+		    sparams->utils->free(user);
+		return ret;
+	    }
+	    
+	    if (user) {
+	    	ret = sparams->canon_user(sparams->utils->conn, user, ulen,
+				      SASL_CU_AUTHZID, oparams);
+	    
+		sparams->utils->free(user);
+	    }
+	    
+	    if (ret != SASL_OK) return ret;
+	}
+	
+	/* nothing more to do; authenticated */
+	oparams->doneflag = 1;
+	oparams->param_version = 0;
+	
+	/* used by layers */
+	_plug_decode_init(&text->decode_context, text->utils,
+			  (sparams->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
+			  sparams->props.maxbufsize);
+	
+	sparams->utils->free(in);
+
+	return SASL_OK;
+    }
+    
+    default:
+	sparams->utils->log(NULL, SASL_LOG_ERR,
+			    "Invalid Kerberos server step %d\n", text->state);
+	return SASL_FAIL;
+    }
+    
+    return SASL_FAIL; /* should never get here */
+}
+
+static int kerberosv4_mech_avail(void *glob_context __attribute__((unused)),
+				 sasl_server_params_t *sparams,
+				 void **conn_context __attribute__((unused))) 
+{
+    struct sockaddr_in addr;
+    
+    if (!sparams->iplocalport || !sparams->ipremoteport
+	|| ipv4_ipfromstring(sparams->utils,
+			     sparams->iplocalport, &addr) != SASL_OK
+	|| ipv4_ipfromstring(sparams->utils,
+			     sparams->ipremoteport, &addr) != SASL_OK) {
+	SETERROR(sparams->utils,
+		 "KERBEROS_V4 unavailable due to lack of IPv4 information");
+	return SASL_NOMECH;
+    }
+    
+    return SASL_OK;
+}
+
+
+static sasl_server_plug_t kerberosv4_server_plugins[] = 
+{
+    {
+	"KERBEROS_V4",			/* mech_name */
+	KRB_DES_SECURITY_BITS,		/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOACTIVE
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
+	SASL_FEAT_SERVER_FIRST
+	| SASL_FEAT_ALLOWS_PROXY,	/* features */
+	NULL,				/* glob_context */
+	&kerberosv4_server_mech_new,	/* mech_new */
+	&kerberosv4_server_mech_step,	/* mech_step */
+	&kerberosv4_common_mech_dispose,/* mech_dispose */
+	&kerberosv4_common_mech_free,	/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	&kerberosv4_mech_avail,		/* mech_avail */
+	NULL				/* spare */
+    }
+};
+#endif /* macintosh */
+
+int kerberos4_server_plug_init(const sasl_utils_t *utils,
+			       int maxversion,
+			       int *out_version,
+			       sasl_server_plug_t **pluglist,
+			       int *plugcount)
+{
+#ifdef macintosh
+    return SASL_BADVERS;
+#else
+    const char *ret;
+    unsigned int rl;
+    
+    if (maxversion < SASL_SERVER_PLUG_VERSION) {
+	return SASL_BADVERS;
+    }
+    
+    
+    if (!krb_mutex) {
+	krb_mutex = utils->mutex_alloc();
+	if(!krb_mutex) {
+	    return SASL_FAIL;
+	}
+    }
+    
+    if (!srvtab) {	
+	utils->getopt(utils->getopt_context,
+		      "KERBEROS_V4", "srvtab", &ret, &rl);
+	
+	if (ret == NULL) {
+	    ret = KEYFILE;
+	    rl = strlen(ret);
+	}
+	
+	srvtab = utils->malloc(sizeof(char) * (rl + 1));
+	if(!srvtab) {
+	    MEMERROR(utils);
+	    return SASL_NOMEM;
+	}
+	
+	strcpy(srvtab, ret);
+    }
+    
+    refcount++;
+    
+    /* fail if we can't open the srvtab file */
+    if (access(srvtab, R_OK) != 0) {
+	utils->log(NULL, SASL_LOG_ERR,
+		   "can't access srvtab file %s: %m", srvtab, errno);
+	if(!(--refcount)) {
+	    utils->free(srvtab);
+	    srvtab=NULL;
+	}
+	return SASL_FAIL;
+    }
+    
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = kerberosv4_server_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+#endif
+}
+
+/*****************************  Client Section  *****************************/
+
+static int
+kerberosv4_client_mech_new(void *glob_context __attribute__((unused)), 
+			   sasl_client_params_t *params,
+			   void **conn_context)
+{
+    return new_text(params->utils, (context_t **) conn_context);
+}
+
+static int kerberosv4_client_mech_step(void *conn_context,
+				       sasl_client_params_t *cparams,
+				       const char *serverin,
+				       unsigned serverinlen,
+				       sasl_interact_t **prompt_need,
+				       const char **clientout,
+				       unsigned *clientoutlen,
+				       sasl_out_params_t *oparams)
+{
+    context_t *text = (context_t *) conn_context;
+    KTEXT_ST authent;
+    int ret;
+
+    *clientout = NULL;
+    *clientoutlen = 0;
+    
+    authent.length = MAX_KTXT_LEN;
+    
+    switch (text->state) {
+
+    case 1: {
+	/* We should've just recieved a 32-bit number in network byte order.
+	 * We want to reply with an authenticator. */
+	int result;
+	KTEXT_ST ticket;
+	char *dot;
+	
+	memset(&ticket, 0L, sizeof(ticket));
+	ticket.length = MAX_KTXT_LEN;   
+	
+	if (serverinlen != 4) {
+	    text->utils->seterror(text->utils->conn, 0,
+				  "server challenge not 4 bytes long");
+	    return SASL_BADPROT; 
+	}
+	
+	memcpy(&text->challenge, serverin, 4);
+	
+	text->challenge=ntohl(text->challenge); 
+	
+	if (cparams->serverFQDN == NULL) {
+	    cparams->utils->log(NULL, SASL_LOG_ERR,
+				"no 'serverFQDN' set");
+	    SETERROR(text->utils, "paramater error");
+	    return SASL_BADPARAM;
+	}
+	if (cparams->service == NULL) {
+	    cparams->utils->log(NULL, SASL_LOG_ERR,
+				"no 'service' set");
+	    SETERROR(text->utils, "paramater error");
+	    return SASL_BADPARAM;
+	}
+	
+	KRB_LOCK_MUTEX(cparams->utils);
+	text->realm=krb_realmofhost(cparams->serverFQDN);
+	text->hostname=(char *) cparams->serverFQDN;
+	
+	/* the instance of the principal we're authenticating with */
+	strncpy (text->instance, krb_get_phost (cparams->serverFQDN), 
+		 sizeof (text->instance));
+	
+	/* text->instance is NULL terminated unless it was too long */
+	text->instance[sizeof(text->instance)-1] = '\0';
+
+	/* At some sites, krb_get_phost() sensibly but
+	 * atypically returns FQDNs, versus the first component,
+	 * which is what we need for RFC2222 section 7.1
+	 */
+	dot = strchr(text->instance, '.');
+	if (dot) *dot = '\0';
+	
+#ifndef macintosh
+	if ((result = krb_mk_req(&ticket, (char *) cparams->service, 
+				 text->instance, text->realm, text->challenge)))
+#else
+	    memset(&text->credentials,0,sizeof(text->credentials));
+	if (kcglue_krb_mk_req(ticket.dat,
+			      &ticket.length,
+			      cparams->service,
+			      text->instance,
+			      text->realm,
+			      text->challenge,
+			      &text->credentials.session,
+			      text->credentials.pname,
+			      text->credentials.pinst) != 0)
+#endif
+	    {
+		KRB_UNLOCK_MUTEX(cparams->utils);
+		
+		text->utils->seterror(text->utils->conn,SASL_NOLOG,
+				      "krb_mk_req() failed");
+		
+		cparams->utils->log(NULL, SASL_LOG_ERR, 
+				    "krb_mk_req() failed: %s (%d)",
+				    get_krb_err_txt(result), result);
+		return SASL_FAIL;
+	    }
+	
+	KRB_UNLOCK_MUTEX(cparams->utils);
+	
+	ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+			      &(text->out_buf_len), ticket.length);
+	if (ret != SASL_OK) return ret;
+	
+	memcpy(text->out_buf, ticket.dat, ticket.length);
+	
+	*clientout = text->out_buf;
+	*clientoutlen = ticket.length;
+	
+	text->state = 2;
+
+	return SASL_CONTINUE;
+    }
+    
+    /* challenge #2 */
+    case 2: {
+	int need = 0;
+	int musthave = 0;
+	int testnum;
+	int nchal;    
+	unsigned char *sout = NULL;
+	unsigned len;
+	unsigned char in[8];
+	int result;
+	int servermaxbuf;
+	char *buf;
+	int user_result = SASL_OK;
+	
+	/* try to get the authid */
+	if (text->user == NULL) {
+	    user_result = _plug_get_userid(cparams->utils, &text->user,
+					   prompt_need);
+	    
+	    if (user_result != SASL_OK && user_result != SASL_INTERACT)
+		return user_result;
+	}
+	
+	/* free prompts we got */
+	if (prompt_need && *prompt_need) {
+	    cparams->utils->free(*prompt_need);
+	    *prompt_need = NULL;
+	}
+	
+	/* if there are prompts not filled in */
+	if (user_result == SASL_INTERACT) {
+	    /* make the prompt list */
+	    int result =
+		_plug_make_prompts(cparams->utils, prompt_need,
+				   user_result == SASL_INTERACT ?
+				   "Please enter your authorization name" : NULL, NULL,
+				   NULL, NULL,
+				   NULL, NULL,
+				   NULL, NULL, NULL,
+				   NULL, NULL, NULL);
+	    if (result!=SASL_OK) return result;
+	    
+	    return SASL_INTERACT;
+	}
+	
+	/* must be 8 octets */
+	if (serverinlen!=8) {
+	    SETERROR(cparams->utils,
+		     "server response not 8 bytes long");
+	    return SASL_BADAUTH;
+	}
+	
+	memcpy(in, serverin, 8);
+	
+#ifndef macintosh
+	/* get credentials */
+	KRB_LOCK_MUTEX(cparams->utils);
+	result = krb_get_cred((char *)cparams->service,
+			      text->instance,
+			      text->realm,
+			      &text->credentials);
+	KRB_UNLOCK_MUTEX(cparams->utils);
+	
+	if(result != 0) {
+	    cparams->utils->log(NULL, SASL_LOG_ERR,
+				"krb_get_cred() failed: %s (%d)",
+				get_krb_err_txt(result), result);
+	    SETERROR(cparams->utils, "krb_get_cred() failed");
+	    return SASL_BADAUTH;
+	}
+#endif
+	memcpy(text->session, text->credentials.session, 8);
+	
+	/* make key schedule for encryption and decryption */
+	des_key_sched(&text->session, text->init_keysched);
+	des_key_sched(&text->session, text->enc_keysched);
+	des_key_sched(&text->session, text->dec_keysched);
+	
+	/* decrypt from server */
+	des_ecb_encrypt((des_cblock *)in, (des_cblock *)in,
+			text->init_keysched, DES_DECRYPT);
+	
+	/* convert to 32bit int */
+	testnum = (in[0]*256*256*256)+(in[1]*256*256)+(in[2]*256)+in[3];
+	
+	/* verify data 1st 4 octets must be equal to chal+1 */
+	if (testnum != text->challenge+1) {
+	    SETERROR(cparams->utils,"server response incorrect");
+	    return SASL_BADAUTH;
+	}
+	
+	/* construct 8 octets
+	 * 1-4 - original checksum
+	 * 5 - bitmask of sec layer
+	 * 6-8 max buffer size
+	 */
+	if (cparams->props.min_ssf > 
+	    KRB_DES_SECURITY_BITS + cparams->external_ssf) {
+	    SETERROR(cparams->utils,
+		     "minimum ssf too strong for this mechanism");
+	    return SASL_TOOWEAK;
+	} else if (cparams->props.min_ssf > cparams->props.max_ssf) {
+	    SETERROR(cparams->utils,
+		     "minimum ssf larger than maximum ssf");
+	    return SASL_BADPARAM;
+	}
+	
+	/* create stuff to send to server */
+	sout = (char *)
+	    cparams->utils->malloc(9+(text->user ? strlen(text->user) : 0)+9);
+	if (!sout) {
+	    MEMERROR(cparams->utils);
+	    return SASL_NOMEM;
+	}
+	
+	nchal = htonl(text->challenge);
+	memcpy(sout, &nchal, 4);
+	
+	/* need bits of layer */
+	if(cparams->props.maxbufsize == 0) {
+	    need = musthave = 0;
+	} else {
+	    need = cparams->props.max_ssf - cparams->external_ssf;
+	    musthave = cparams->props.min_ssf - cparams->external_ssf;
+	}
+	
+	oparams->decode = &kerberosv4_decode;
+	oparams->encode = &kerberosv4_encode;
+	
+	if ((in[4] & KRB_SECFLAG_ENCRYPTION)
+	    && (need>=56) && (musthave <= 56)) {
+	    /* encryption */
+	    text->sec_type = KRB_SEC_ENCRYPTION;
+	    oparams->mech_ssf = 56;
+	    sout[4] = KRB_SECFLAG_ENCRYPTION;
+	    /* using encryption layer */
+	} else if ((in[4] & KRB_SECFLAG_INTEGRITY)
+		   && (need >= 1) && (musthave <= 1)) {
+	    /* integrity */
+	    text->sec_type = KRB_SEC_INTEGRITY;
+	    oparams->mech_ssf=1;
+	    sout[4] = KRB_SECFLAG_INTEGRITY;
+	    /* using integrity layer */
+	} else if ((in[4] & KRB_SECFLAG_NONE) && (musthave <= 0)) {
+	    /* no layer */
+	    text->sec_type = KRB_SEC_NONE;
+	    oparams->encode=NULL;
+	    oparams->decode=NULL;
+	    oparams->mech_ssf=0;
+	    sout[4] = KRB_SECFLAG_NONE;
+	} else {
+	    /* Mark that we tried */
+	    oparams->mech_ssf=2;
+	    SETERROR(cparams->utils,
+		     "unable to agree on layers with server");
+	    return SASL_BADPROT;
+	}
+	
+	servermaxbuf = in[5]*256*256+in[6]*256+in[7];
+	oparams->maxoutbuf = servermaxbuf;
+	if (oparams->mech_ssf) {
+	    /* FIXME: Likely to be too large */
+	    oparams->maxoutbuf -= 50;
+	}
+	
+	if(cparams->props.maxbufsize) {
+	    int tmpmaxbuf = ( cparams->props.maxbufsize > 0xFFFFFF ) ? 0xFFFFFF : cparams->props.maxbufsize;
+
+	    sout[5]=((tmpmaxbuf >> 16) & 0xFF);
+	    sout[6]=((tmpmaxbuf >> 8) & 0xFF);
+	    sout[7]=(tmpmaxbuf & 0xFF);
+	} else {
+            /* let's say we can support up to 64K */
+	    /* no inherent inability with our layers to support more */
+
+	    sout[5]=0x00;  /* max ciphertext buffer size */
+	    sout[6]=0xFF;
+	    sout[7]=0xFF;
+	}
+	
+	sout[8] = 0x00; /* just to be safe */
+	
+	/* append userid */
+	len = 9;			/* 8 + trailing NULL */
+	if (text->user) {
+	    strcpy((char *)sout + 8, text->user);
+	    len += strlen(text->user);
+	}
+	
+	/* append 0 based octets so is multiple of 8 */
+	while(len % 8) {
+	    sout[len]=0;
+	    len++;
+	}
+	sout[len]=0;
+	
+	des_pcbc_encrypt((des_cblock *)sout,
+			 (des_cblock *)sout,
+			 len,
+			 text->init_keysched,
+			 (des_cblock *)text->session,
+			 DES_ENCRYPT);
+	
+	result = _plug_buf_alloc(text->utils, &text->out_buf,
+				 &text->out_buf_len, len);
+	if (result != SASL_OK)  return result;
+	
+	memcpy(text->out_buf, sout, len);
+	
+	*clientout = text->out_buf;
+	*clientoutlen = len;
+	
+	/* nothing more to do; should be authenticated */
+	if(cparams->iplocalport) {   
+	    result = ipv4_ipfromstring(cparams->utils,
+				       cparams->iplocalport,
+				       &(text->ip_local));
+	    if (result != SASL_OK) {
+		/* couldn't get local IP address */
+		return result;
+	    }
+	}
+	
+	if (cparams->ipremoteport) {
+	    result = ipv4_ipfromstring(cparams->utils,
+				       cparams->ipremoteport,
+				       &(text->ip_remote));
+	    if (result != SASL_OK) {
+		/* couldn't get local IP address */
+		return result;
+	    }
+	}
+	
+	buf = cparams->utils->malloc(strlen(text->credentials.pname)
+				     + strlen(text->credentials.pinst)
+				     + 2);
+	if (!buf) {
+	    MEMERROR(cparams->utils);
+	    return SASL_NOMEM;
+	}
+	strcpy(buf, text->credentials.pname);
+	if (text->credentials.pinst[0]) {
+	    strcat(buf, ".");
+	    strcat(buf, text->credentials.pinst);
+	}
+	
+	if (text->user && !text->user[0]) {
+	    text->user = NULL;
+	}
+	
+	ret = cparams->canon_user(cparams->utils->conn, buf, 0,
+				  SASL_CU_AUTHID, oparams);
+	if (ret != SASL_OK) {
+	    cparams->utils->free(buf);
+	    cparams->utils->free(sout);
+	    return ret;
+	}
+	
+	if (!text->user) {
+	    /* 0 in length fields means use strlen() */
+	    ret = cparams->canon_user(cparams->utils->conn, buf, 0,
+				      SASL_CU_AUTHZID, oparams);
+	} else {
+	    ret = cparams->canon_user(cparams->utils->conn, text->user, 0,
+				      SASL_CU_AUTHZID, oparams);
+	}
+	
+	cparams->utils->free(buf);
+	
+	oparams->doneflag = 1;
+	oparams->param_version = 0;
+	
+	/* used by layers */
+	_plug_decode_init(&text->decode_context, text->utils,
+			  (cparams->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
+			  cparams->props.maxbufsize);
+	
+	if (sout) cparams->utils->free(sout);
+	
+	return SASL_OK;
+    }
+    
+    default:
+	cparams->utils->log(NULL, SASL_LOG_ERR,
+			    "Invalid Kerberos client step %d\n", text->state);
+	return SASL_FAIL;
+    }
+
+    return SASL_FAIL; /* should never get here */
+}
+
+static const long kerberosv4_required_prompts[] = {
+    SASL_CB_LIST_END
+};
+
+static sasl_client_plug_t kerberosv4_client_plugins[] = 
+{
+    {
+	"KERBEROS_V4",			/* mech_name */
+	KRB_DES_SECURITY_BITS,		/* max_ssf */
+	SASL_SEC_NOPLAINTEXT
+	| SASL_SEC_NOACTIVE
+	| SASL_SEC_NOANONYMOUS
+	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
+	SASL_FEAT_NEEDSERVERFQDN
+	| SASL_FEAT_SERVER_FIRST
+	| SASL_FEAT_ALLOWS_PROXY,	/* features */
+	kerberosv4_required_prompts,	/* required_prompts */
+	NULL,				/* glob_context */
+	&kerberosv4_client_mech_new,	/* mech_new */
+	&kerberosv4_client_mech_step,	/* mech_step */
+	&kerberosv4_common_mech_dispose,/* mech_dispose */
+	&kerberosv4_common_mech_free,	/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL				/* spare */
+    }
+};
+
+int kerberos4_client_plug_init(const sasl_utils_t *utils,
+			       int maxversion,
+			       int *out_version,
+			       sasl_client_plug_t **pluglist,
+			       int *plugcount)
+{
+    if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+	SETERROR(utils, "Wrong KERBEROS_V4 version");
+	return SASL_BADVERS;
+    }
+    
+    if(!krb_mutex) {
+	krb_mutex = utils->mutex_alloc();
+	if(!krb_mutex) {
+	    return SASL_FAIL;
+	}
+    }
+    
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = kerberosv4_client_plugins;
+    *plugcount = 1;
+    
+    refcount++;
+    
+    return SASL_OK;
+}

+ 43 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/kerberos4_init.c

@@ -0,0 +1,43 @@
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_kerberos4_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+					 )
+{
+    switch (ul_reason_for_call)
+	{
+		case DLL_PROCESS_ATTACH:
+		case DLL_THREAD_ATTACH:
+		case DLL_THREAD_DETACH:
+		case DLL_PROCESS_DETACH:
+			break;
+    }
+    return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( kerberos4 )
+SASL_SERVER_PLUG_INIT( kerberos4 )
+

+ 569 - 0
deltachat-ios/libraries/deltachat-core/libs/cyrussasl/plugins/ldapdb.c

@@ -0,0 +1,569 @@
+/* $OpenLDAP: pkg/ldap/contrib/ldapsasl/ldapdb.c,v 1.1.2.7 2003/11/29 22:10:03 hyc Exp $ */
+/* SASL LDAP auxprop+canonuser implementation
+ * Copyright (C) 2002-2007 Howard Chu, All rights reserved. <hyc@symas.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "sasl.h"
+#include "saslutil.h"
+#include "saslplug.h"
+
+#include "plugin_common.h"
+
+#include <ldap.h>
+
+static char ldapdb[] = "ldapdb";
+
+typedef struct ldapctx {
+	int inited;		/* Have we already read the config? */
+	const char *uri;	/* URI of LDAP server */
+	struct berval id;	/* SASL authcid to bind as */
+	struct berval pw;	/* password for bind */
+	struct berval mech;	/* SASL mech */
+	int use_tls;		/* Issue StartTLS request? */
+	struct berval canon;	/* Use attr in user entry for canonical name */
+} ldapctx;
+
+static ldapctx ldapdb_ctx;
+
+static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)),
+	void *def, void *inter)
+{
+	sasl_interact_t *in = inter;
+	ldapctx *ctx = def;
+	struct berval p;
+
+	for (;in->id != SASL_CB_LIST_END;in++)
+	{
+		p.bv_val = NULL;
+		switch(in->id)
+		{
+			case SASL_CB_GETREALM:
+				ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &p.bv_val);
+				if (p.bv_val) p.bv_len = strlen(p.bv_val);
+				break;		
+			case SASL_CB_AUTHNAME:
+				p = ctx->id;
+				break;
+			case SASL_CB_PASS:
+				p = ctx->pw;
+				break;
+		}
+		if (p.bv_val)
+		{
+			in->result = p.bv_val;
+			in->len = p.bv_len;
+		}
+	}
+	return LDAP_SUCCESS;
+}
+
+typedef struct connparm {
+	LDAP *ld;
+	LDAPControl c;
+	LDAPControl *ctrl[2];
+	struct berval *dn;
+} connparm;
+
+static int ldapdb_connect(ldapctx *ctx, sasl_server_params_t *sparams,
+	const char *user, unsigned ulen, connparm *cp)
+{
+    int i;
+    char *authzid;
+
+    if((i=ldap_initialize(&cp->ld, ctx->uri))) {
+	return i;
+    }
+
+    authzid = sparams->utils->malloc(ulen + sizeof("u:"));
+    if (!authzid) {
+    	return LDAP_NO_MEMORY;
+    } 
+    strcpy(authzid, "u:");
+    strcpy(authzid+2, user);
+    cp->c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
+    cp->c.ldctl_value.bv_val = authzid;
+    cp->c.ldctl_value.bv_len = ulen + 2;
+    cp->c.ldctl_iscritical = 1;
+
+    i = LDAP_VERSION3;
+    ldap_set_option(cp->ld, LDAP_OPT_PROTOCOL_VERSION, &i);
+
+    /* If TLS is set and it fails, continue or bail out as requested */
+    if (ctx->use_tls && (i=ldap_start_tls_s(cp->ld, NULL, NULL)) != LDAP_SUCCESS
+    	&& ctx->use_tls > 1) {
+    	sparams->utils->free(authzid);
+	return i;
+    }
+
+    i = ldap_sasl_interactive_bind_s(cp->ld, NULL, ctx->mech.bv_val, NULL,
+    	NULL, LDAP_SASL_QUIET, ldapdb_interact, ctx);
+    if (i != LDAP_SUCCESS) {
+    	sparams->utils->free(authzid);
+	return i;
+    }
+    
+    cp->ctrl[0] = &cp->c;
+    cp->ctrl[1] = NULL;
+    i = ldap_whoami_s(cp->ld, &cp->dn, cp->ctrl, NULL);
+    if (i == LDAP_SUCCESS && cp->dn) {
+    	if (!cp->dn->bv_val || strncmp(cp->dn->bv_val, "dn:", 3)) {
+	    ber_bvfree(cp->dn);
+	    cp->dn = NULL;
+	    i = LDAP_INVALID_SYNTAX;
+	} else {
+    	    cp->c.ldctl_value = *(cp->dn);
+	}
+    }
+    sparams->utils->free(authzid);
+    return i;
+}
+
+static int ldapdb_auxprop_lookup(void *glob_context,
+				  sasl_server_params_t *sparams,
+				  unsigned flags,
+				  const char *user,
+				  unsigned ulen)
+{
+    ldapctx *ctx = glob_context;
+    connparm cp;
+    int ret, i, n, *aindx;
+    int result;
+    int j;
+    const struct propval *pr;
+    struct berval **bvals;
+    LDAPMessage *msg, *res;
+    char **attrs = NULL;
+    
+    if(!ctx || !sparams || !user) return SASL_BADPARAM;
+
+    pr = sparams->utils->prop_get(sparams->propctx);
+    if (!pr) return SASL_FAIL;
+
+    /* count how many attrs to fetch */
+    for(i = 0, n = 0; pr[i].name; i++) {
+	if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID))
+	    continue;
+	if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE))
+	    continue;
+	n++;
+    }
+
+    /* nothing to do, bail out */
+    if (!n) return SASL_OK;
+
+    /* alloc an array of attr names for search, and index to the props */
+    attrs = sparams->utils->malloc((n+1)*sizeof(char *)*2);
+    if (!attrs) {
+	result = SASL_NOMEM;
+        goto done;
+    }
+
+    aindx = (int *)(attrs + n + 1);
+
+    /* copy attr list */
+    for (i=0, n=0; pr[i].name; i++) {
+	if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID))
+	    continue;
+	if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE))
+	    continue;
+    	attrs[n] = (char *)pr[i].name;
+	if (pr[i].name[0] == '*') attrs[n]++;
+	aindx[n] = i;
+	n++;
+    }
+    attrs[n] = NULL;
+
+    if ((ret = ldapdb_connect(ctx, sparams, user, ulen, &cp)) != LDAP_SUCCESS) {
+	goto process_ldap_error;
+    }
+
+    ret = ldap_search_ext_s(cp.ld, cp.dn->bv_val+3, LDAP_SCOPE_BASE,
+    	"(objectclass=*)", attrs, 0, cp.ctrl, NULL, NULL, 1, &res);
+    ber_bvfree(cp.dn);
+
+    if (ret != LDAP_SUCCESS) {
+	goto process_ldap_error;
+    }
+
+    /* Assume no user by default */
+    ret = LDAP_NO_SUCH_OBJECT;
+
+    for (msg = ldap_first_message(cp.ld, res);
+         msg;
+         msg = ldap_next_message(cp.ld, msg)) {
+    	if (ldap_msgtype(msg) != LDAP_RES_SEARCH_ENTRY) continue;
+
+	/* Presence of a search result response indicates that the user exists */
+	ret = LDAP_SUCCESS;
+
+        for (i = 0; i < n; i++) {
+	    bvals = ldap_get_values_len(cp.ld, msg, attrs[i]);
+	    if (!bvals) continue;
+
+	    if (pr[aindx[i]].values) {
+	    	sparams->utils->prop_erase(sparams->propctx, pr[aindx[i]].name);
+	    }
+
+            for ( j = 0; bvals[j] != NULL; j++ ) {
+	        sparams->utils->prop_set(sparams->propctx,
+                                         pr[aindx[i]].name,
+				         bvals[j]->bv_val,
+                                         bvals[j]->bv_len);
+            }
+	    ber_bvecfree(bvals);
+	}
+    }
+    ldap_msgfree(res);
+
+ process_ldap_error:
+    switch (ret) {
+	case LDAP_SUCCESS:
+            result = SASL_OK;
+            break;
+
+	case LDAP_NO_SUCH_OBJECT:
+            result = SASL_NOUSER;
+            break;
+
+        case LDAP_NO_MEMORY:
+            result = SASL_NOMEM;
+            break;
+
+	case LDAP_SERVER_DOWN:
+	case LDAP_BUSY:
+	case LDAP_UNAVAILABLE:
+	case LDAP_CONNECT_ERROR:
+	    result = SASL_UNAVAIL;
+	    break;
+
+#if defined(LDAP_PROXY_AUTHZ_FAILURE)
+	case LDAP_PROXY_AUTHZ_FAILURE:
+#endif
+	case LDAP_INAPPROPRIATE_AUTH:
+	case LDAP_INVALID_CREDENTIALS:
+	case LDAP_INSUFFICIENT_ACCESS:
+	    result = SASL_BADAUTH;
+	    break;
+
+        default:
+            result = SASL_FAIL;
+            break;
+    }
+
+ done:
+    if(attrs) sparams->utils->free(attrs);
+    if(cp.ld) ldap_unbind_ext(cp.ld, NULL, NULL);
+
+    return result;
+}
+
+static int ldapdb_auxprop_store(void *glob_context,
+				  sasl_server_params_t *sparams,
+				  struct propctx *prctx,
+				  const char *user,
+				  unsigned ulen)
+{
+    ldapctx *ctx = glob_context;
+    connparm cp;
+    const struct propval *pr;
+    int i, n;
+    LDAPMod **mods;
+
+    /* just checking if we are enabled */
+    if (!prctx) return SASL_OK;
+
+    if (!sparams || !user) return SASL_BADPARAM;
+
+    pr = sparams->utils->prop_get(prctx);
+    if (!pr) return SASL_BADPARAM;
+
+    for (n=0; pr[n].name; n++);
+    if (!n) return SASL_BADPARAM;
+
+    mods = sparams->utils->malloc((n+1) * sizeof(LDAPMod*) + n * sizeof(LDAPMod));
+    if (!mods) return SASL_NOMEM;
+
+    if((i=ldapdb_connect(ctx, sparams, user, ulen, &cp)) == 0) {
+
+	for (i=0; i<n; i++) {
+	    mods[i] = (LDAPMod *)((char *)(mods+n+1) + i * sizeof(LDAPMod));
+	    mods[i]->mod_op = LDAP_MOD_REPLACE;
+	    mods[i]->mod_type = (char *)pr[i].name;
+	    mods[i]->mod_values = (char **)pr[i].values;
+	}
+	mods[i] = NULL;
+
+	i = ldap_modify_ext_s(cp.ld, cp.dn->bv_val+3, mods, cp.ctrl, NULL);
+	ber_bvfree(cp.dn);
+    }
+
+    sparams->utils->free(mods);
+
+    if (i) {
+    	sparams->utils->seterror(sparams->utils->conn, 0,
+	    ldap_err2string(i));
+	if (i == LDAP_NO_MEMORY) i = SASL_NOMEM;
+	else i = SASL_FAIL;
+    }
+    if(cp.ld) ldap_unbind_ext(cp.ld, NULL, NULL);
+    return i;
+}
+
+static int
+ldapdb_canon_server(void *glob_context,
+		    sasl_server_params_t *sparams,
+		    const char *user,
+		    unsigned ulen,
+		    unsigned flags,
+		    char *out,
+		    unsigned out_max,
+		    unsigned *out_ulen)
+{
+    ldapctx *ctx = glob_context;
+    connparm cp;
+    struct berval **bvals;
+    LDAPMessage *msg, *res;
+    char *rdn, *attrs[2];
+    unsigned len;
+    int ret;
+    
+    if(!ctx || !sparams || !user) return SASL_BADPARAM;
+
+    /* If no canon attribute was configured, we can't do anything */
+    if(!ctx->canon.bv_val) return SASL_BADPARAM;
+
+    /* Trim whitespace */
+    while(isspace(*(unsigned char *)user)) {
+	user++;
+	ulen--;
+    }
+    while(isspace((unsigned char)user[ulen-1])) {
+    	ulen--;
+    }
+    
+    if (!ulen) {
+    	sparams->utils->seterror(sparams->utils->conn, 0,
+	    "All-whitespace username.");
+	return SASL_FAIL;
+    }
+
+    ret = ldapdb_connect(ctx, sparams, user, ulen, &cp);
+    if ( ret ) goto done;
+
+    /* See if the RDN uses the canon attr. If so, just use the RDN
+     * value, we don't need to do a search.
+     */
+    rdn = cp.dn->bv_val+3;
+    if (!strncasecmp(ctx->canon.bv_val, rdn, ctx->canon.bv_len) &&
+    	rdn[ctx->canon.bv_len] == '=') {
+	char *comma;
+	rdn += ctx->canon.bv_len + 1;
+	comma = strchr(rdn, ',');
+	if ( comma )
+	    len = comma - rdn;
+	else 
+	    len = cp.dn->bv_len - (rdn - cp.dn->bv_val);
+	if ( len > out_max )
+	    len = out_max;
+	memcpy(out, rdn, len);
+	out[len] = '\0';
+	*out_ulen = len;
+	ret = SASL_OK;
+	ber_bvfree(cp.dn);
+	goto done;
+    }
+
+    /* Have to read the user's entry */
+    attrs[0] = ctx->canon.bv_val;
+    attrs[1] = NULL;
+    ret = ldap_search_ext_s(cp.ld, cp.dn->bv_val+3, LDAP_SCOPE_BASE,
+    	"(objectclass=*)", attrs, 0, cp.ctrl, NULL, NULL, 1, &res);
+    ber_bvfree(cp.dn);
+
+    if (ret != LDAP_SUCCESS) goto done;
+
+    for(msg=ldap_first_message(cp.ld, res); msg; msg=ldap_next_message(cp.ld, msg))
+    {
+    	if (ldap_msgtype(msg) != LDAP_RES_SEARCH_ENTRY) continue;
+	bvals = ldap_get_values_len(cp.ld, msg, attrs[0]);
+	if (!bvals) continue;
+	len = bvals[0]->bv_len;
+	if ( len > out_max )
+	    len = out_max;
+	memcpy(out, bvals[0]->bv_val, len);
+	*out_ulen = len;
+	ber_bvecfree(bvals);
+    }
+    ldap_msgfree(res);
+
+ done:
+    if(cp.ld) ldap_unbind_ext(cp.ld, NULL, NULL);
+    if (ret) {
+    	sparams->utils->seterror(sparams->utils->conn, 0,
+	    ldap_err2string(ret));
+	if (ret == LDAP_NO_MEMORY) ret = SASL_NOMEM;
+	else ret = SASL_FAIL;
+    }
+    return ret;
+}
+
+static int
+ldapdb_canon_client(void *glob_context,
+		    sasl_client_params_t *cparams,
+		    const char *user,
+		    unsigned ulen,
+		    unsigned flags,
+		    char *out,
+		    unsigned out_max,
+		    unsigned *out_ulen)
+{
+    if(!cparams || !user) return SASL_BADPARAM;
+
+    /* Trim whitespace */
+    while(isspace(*(unsigned char *)user)) {
+	user++;
+	ulen--;
+    }
+    while(isspace((unsigned char)user[ulen-1])) {
+    	ulen--;
+    }
+    
+    if (!ulen) {
+    	cparams->utils->seterror(cparams->utils->conn, 0,
+	    "All-whitespace username.");
+	return SASL_FAIL;
+    }
+
+    if (ulen > out_max) return SASL_BUFOVER;
+
+    memcpy(out, user, ulen);
+    out[ulen] = '\0';
+    *out_ulen = ulen;
+    return SASL_OK;
+}
+
+static int
+ldapdb_config(const sasl_utils_t *utils)
+{
+    ldapctx *p = &ldapdb_ctx;
+    const char *s;
+    unsigned len;
+
+    if(p->inited) return SASL_OK;
+
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_uri", &p->uri, NULL);
+    if(!p->uri) return SASL_BADPARAM;
+
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_id",
+    	(const char **)&p->id.bv_val, &len);
+    p->id.bv_len = len;
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_pw",
+    	(const char **)&p->pw.bv_val, &len);
+    p->pw.bv_len = len;
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_mech",
+    	(const char **)&p->mech.bv_val, &len);
+    p->mech.bv_len = len;
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_starttls", &s, NULL);
+    if (s)
+    {
+    	if (!strcasecmp(s, "demand")) p->use_tls = 2;
+	else if (!strcasecmp(s, "try")) p->use_tls = 1;
+    }
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_rc", &s, &len);
+    if (s)
+    {
+    	char *str = utils->malloc(sizeof("LDAPRC=")+len);
+	if (!str) return SASL_NOMEM;
+	strcpy( str, "LDAPRC=" );
+	strcpy( str + sizeof("LDAPRC=")-1, s );
+	if (putenv(str))
+	{
+	    utils->free(str);
+	    return SASL_NOMEM;
+	}
+    }
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_canon_attr",
+	(const char **)&p->canon.bv_val, &len);
+    p->canon.bv_len = len;
+    p->inited = 1;
+
+    return SASL_OK;
+}
+
+static sasl_auxprop_plug_t ldapdb_auxprop_plugin = {
+    0,				/* Features */
+    0,				/* spare */
+    &ldapdb_ctx,		/* glob_context */
+    NULL,	/* auxprop_free */
+    ldapdb_auxprop_lookup,	/* auxprop_lookup */
+    ldapdb,			/* name */
+    ldapdb_auxprop_store	/* auxprop store */
+};
+
+int ldapdb_auxprop_plug_init(const sasl_utils_t *utils,
+                             int max_version,
+                             int *out_version,
+                             sasl_auxprop_plug_t **plug,
+                             const char *plugname __attribute__((unused))) 
+{
+    int rc;
+
+    if(!out_version || !plug) return SASL_BADPARAM;
+
+    if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
+    
+    rc = ldapdb_config(utils);
+
+    *out_version = SASL_AUXPROP_PLUG_VERSION;
+
+    *plug = &ldapdb_auxprop_plugin;
+
+    return rc;
+}
+
+static sasl_canonuser_plug_t ldapdb_canonuser_plugin = {
+	0,	/* features */
+	0,	/* spare */
+	&ldapdb_ctx,	/* glob_context */
+	ldapdb,	/* name */
+	NULL,	/* canon_user_free */
+	ldapdb_canon_server,	/* canon_user_server */
+	ldapdb_canon_client,	/* canon_user_client */
+	NULL,
+	NULL,
+	NULL
+};
+
+int ldapdb_canonuser_plug_init(const sasl_utils_t *utils,
+                             int max_version,
+                             int *out_version,
+                             sasl_canonuser_plug_t **plug,
+                             const char *plugname __attribute__((unused))) 
+{
+    int rc;
+
+    if(!out_version || !plug) return SASL_BADPARAM;
+
+    if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
+    
+    rc = ldapdb_config(utils);
+
+    *out_version = SASL_CANONUSER_PLUG_VERSION;
+
+    *plug = &ldapdb_canonuser_plugin;
+
+    return rc;
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов