SecItemAdd und SecItemCopyMatching geben den Fehlercode -34018 (errSecMissingEntitlement) zurück.


116

Wenn ich eine Anwendung auf einem Gerät über Xcode ausführe, versuche ich manchmal, auf den Schlüsselbund zuzugreifen, was jedoch aufgrund des Fehlers -34018 fehlschlägt. Dies stimmt mit keinem der dokumentierten Schlüsselbund-Fehlercodes überein und kann nicht konsistent reproduziert werden. (passiert vielleicht 30% der Zeit und mir ist nicht klar, warum es passiert). Was das Debuggen dieses Problems sehr schwierig macht, ist der völlige Mangel an Dokumentation. Irgendeine Idee, was dies verursacht und wie man es behebt? Ich verwende Xcode 5 und verwende iOS 7.0.4 auf dem Gerät.

Hier gibt es ein offenes Problem: https://github.com/soffes/sskeychain/issues/52

BEARBEITEN: Hinzufügen eines Schlüsselbund-Zugangscodes pro Anfrage

Ich benutze die SSKeychainBibliothek für die Schnittstelle mit Schlüsselbund. Hier ist der Ausschnitt.

#define SERVICE @"default"

@implementation SSKeychain (EXT)

+ (void)setValue:(NSString *)value forKey:(NSString *)key {
    NSError *error = nil;
    BOOL success = NO;
    if (value) {
        success = [self setPassword:value forService:SERVICE account:key error:&error];
    } else {
        success = [self deletePasswordForService:SERVICE account:key error:&error];
    }
    NSAssert(success, @"Unable to set keychain value %@ for key %@ error %@", value, key, error);
    if (!success) {
        LogError(@"Unable to set value to keychain %@", error);
    }
    LogTrace(@"Will set keychain account %@. is to nil? %d", key, value == nil);
    if (value == nil)
        LogWarn(@"Setting keychain %@ to nil!!!", key);
}

+ (NSString *)valueForKey:(NSString *)key {
    NSError *error = nil;
    NSString *value = [self passwordForService:SERVICE account:key error:&error];
    if (error && error.code != errSecItemNotFound) {
        NSAssert(!error, @"Unable to retrieve keychain value for key %@ error %@", key, error);
        LogError(@"Unable to retrieve keychain value for key %@ error %@", key, error);
    }
    return value;
}

+ (BOOL)removeAllValues {
    LogInfo(@"Completely Reseting Keychain");
    return [[self accountsForService:SERVICE] all:^BOOL(NSDictionary *accountInfo) {
        return [self deletePasswordForService:SERVICE account:accountInfo[@"acct"]];
    }];
}

@end

Die meiste Zeit ist es in Ordnung. Manchmal stoße ich auf Assertionsfehler, bei denen ich weder in den Schlüsselbund schreiben noch aus diesem lesen kann, was zu einem kritischen Assertionsfehler führt.


Ich habe das gleiche Problem und kann es nicht reproduzieren ... Ich verwende die KeychainItemWrapper-Klasse von Apple. Manchmal stürzt es in Google Analytics mit derselben Fehlermeldung ab. Ich verwende Google Analytics v3.02.
Joey

Außerdem scheint es in der App von AppStore in Ordnung zu sein. es passiert nur in der Entwicklungsversion App.
Joey

2
Ich habe Crashlytics für App Store-Version und leider scheint es auch im App Store zu passieren, wenn auch weniger häufig als auf dev: /
Tony

3
Ich denke darüber nach, vom Schlüsselbund abzuweichen, da die Tatsache, dass im Schlüsselbund gespeicherte Daten zufällig verloren gehen können, ein schwerwiegender Fehler für die Anwendung ist.
Tony

2
Wir sehen auch dieses zeitweise auftretende Problem. Wir lösen eine Ausnahme aus, wenn wir von secItemCopyMatching einen unerwarteten RC erhalten, einschließlich des Falls -34018. Wir haben (widerwillig) versucht, einen Mechanismus hinzuzufügen, bei dem wir den Wert, den wir vom Schlüsselbund benötigen, im App-Speicher zwischenspeichern und von dort ohne Schlüsselbundzugriff bereitstellen. Aber jetzt sehen wir seltene Fälle, in denen dieser eine Schlüsselbundzugriff, um ihn überhaupt zu erhalten, mit einem -34018 fehlschlägt. Hat jemand versucht, die Operation nach einem -34018 erneut zu versuchen?
Chris Markle

Antworten:


45

iOS 10 / XCode 8 Fix:

Fügen Sie die KeyChain-Berechtigung hinzu, gehen Sie zu Projekteinstellungen-> Funktionen-> Schlüsselbundfreigabe-> Schlüsselbundgruppen hinzufügen + Aktivieren

Eine Antwort hier von Apple:

UPDATE: Wir konnten den Fehler -34018 endlich unter iOS 8.3 reproduzieren. Dies ist der erste Schritt, um die Grundursache zu identifizieren und dann eine Lösung zu finden.

Wie üblich können wir uns nicht auf einen Release-Zeitrahmen festlegen, aber dies hat viele Entwickler betroffen und wir möchten wirklich, dass dies gelöst wird.

Zuvor habe ich vorgeschlagen, eine kleine Verzögerung in der Anwendung hinzuzufügen: didFinishLaunchingWithOptions und applicationDidBecomeActive: bevor Sie als Problemumgehung auf den Schlüsselbund zugreifen. Dies scheint jedoch nicht wirklich zu helfen. Das bedeutet, dass derzeit keine andere Problemumgehung als der Neustart der App bekannt ist.

Das Problem scheint mit dem Speicherdruck in Zusammenhang zu stehen. Wenn Sie also aggressiver mit Speicherwarnungen umgehen, kann das Problem möglicherweise behoben werden

https://forums.developer.apple.com/thread/4743#14441

AKTUALISIEREN

OK, hier ist das Neueste.
Dies ist ein komplexes Problem mit mehreren möglichen Ursachen:

  • Einige Fälle des Problems werden durch falsche App-Signatur verursacht. Sie können diesen Fall leicht unterscheiden, da das Problem zu 100% reproduzierbar ist.
  • Einige Fälle des Problems werden durch einen Fehler in der Unterstützung der App-Entwicklung durch iOS verursacht (r. 23.991.853). Das Debuggen wurde durch die Tatsache erschwert, dass ein anderer Fehler im Betriebssystem (r. 23.770.418) seine Wirkung maskierte, was bedeutete, dass das Problem nur auftrat, wenn das Gerät unter Speicherdruck stand. Wir glauben, dass diese Probleme in iOS 9.3 behoben wurden.
  • Wir vermuten, dass es noch weitere Ursachen für dieses Problem gibt.

Wenn Sie dieses Problem auf einem Benutzergerät sehen (mit dem Xcode nicht gesprochen hat), auf dem iOS 9.3 oder höher ausgeführt wird, reichen Sie bitte einen Fehlerbericht darüber ein. Versuchen Sie, das Gerätesystemprotokoll in Ihren Fehlerbericht aufzunehmen (mir ist klar, dass dies beim Umgang mit Kundengeräten schwierig sein kann; eine Möglichkeit besteht darin, den Kunden zu bitten, Apple Configurator zu installieren, mit dem er das Systemprotokoll anzeigen kann). Und wenn Sie einen Fehler melden, geben Sie bitte Ihre Fehlernummer nur zur Aufzeichnung an.

Im Namen von Apple möchte ich mich bei allen für ihre Bemühungen bedanken, dieses ziemlich schreckliche Problem aufzuspüren. Teile und genieße

https://forums.developer.apple.com/thread/4743#126088


2
Das Problem wird weiterhin auf iOS 9.2, iPhone 5S reproduziert.
DevGansta

1
Es sieht so aus, als ob iOS 9.3 dieses Problem gemäß der neuesten Antwort von Apple in dem von Ihnen verlinkten Thread beheben sollte . @daidai, könnten Sie bitte Ihre Antwort mit diesen neuen Informationen aktualisieren?
jf

1
@YoonLee sieht dies auch mit iOS10 - auch mit dem 2.4.8 SDK von AWS. Fehler in Zeile 54 von AWSClientContext.m ausgelöst. Haben Sie Glück, dies zu lösen?
CharlesA

1
@YoonLee übrigens, habe dies gerade mit einer der folgenden Antworten gelöst: 'KeyChain Sharing für Zielfunktionen
aktiviert

1
@ CharlesA Ja, ich habe an diesem Tag gelöst. Du hast recht. Scheint "KeyChain-Berechtigung aktivieren" zu sein, um das Problem zu beheben. Überraschenderweise wird dieser Fehler nicht immer ausgelöst. Wie auch immer, jetzt schalte ich das ein.
Yoon Lee

25

Grundsätzlich müssen Sie Ihren .xcttest-Ordner mit einem Codesign versehen, indem Sie Folgendes als Ausführungsskript in Ihr Testziel einfügen.

codesign --verify --force --sign "$CODE_SIGN_IDENTITY" "$CODESIGNING_FOLDER_PATH"

Beim Testen meines Schlüsselbunds auf dem Gerät sind viele -34018-Fehler aufgetreten, die behoben werden konnten.

Wenn das Problem in Ihrem Testziel nicht vorhanden ist, ist dies wahrscheinlich nicht die Lösung.


Bestätigt, dass dies in der Testumgebung behoben wurde. Ich musste das Ausführungsskript zum eigentlichen Testziel hinzufügen (z. B. diejenigen mit allen Komponententests, nicht das Build-Ziel, das auf dem Gerät ausgeführt wird). Außerdem wurde bestätigt, dass dies nur ein Problem auf dem Gerät war, nicht auf dem Simulator.
Ich wurde am

2
Ich erhalte ": keine Identität gefunden Befehl / bin / sh mit Exit-Code 1 fehlgeschlagen", wenn ich das mache? Ich schätze, ich habe keine $ CODE_SIGN_IDENTITY. Irgendeine Idee, wie ich das behebe?
Daniel Coffman

1
@DanielCoffman, Sie müssen zu Ihren Zieleinstellungen gehen und unter Code Signing Identity "iOS Developer" (oder eine andere gültige Identität) auswählen. Dies behebt den Erstellungsfehler, aber zumindest für mich behebt es das Schlüsselbundproblem nicht. Ich erhalte immer noch den Fehlercode -34018.
Marcin

3
Danke Marcin. Ich bekam diesen Fehler, als ich zu xcode 6 beta wechselte. Kein Vorschlag in diesem Thread behoben. Zurückgesetzt auf xcode 5 und -34018 tritt nicht mehr auf.
Daniel Coffman

Ich habe auch diesen Fehler zum ersten Mal seit ich XCode 6.3 benutze.
Vladimír Slavík

13

Nach der Überprüfung des Quellcodes . Ich habe festgestellt, dass auf die Schlüsselbundfunktionen über einen Sicherheitsdämon zugegriffen wird, der in einem eigenen Prozess ausgeführt wird (vom App-Prozess getrennt).

Ihre App und der Sicherheitsprozess "sprechen" über eine Technologie namens XPC miteinander .

Bei Bedarf wird securityd über den bekannten Befehl launchd von XPC gestartet. Sie können wahrscheinlich überprüfen, ob der Dämon in der Activity Monitor-App ausgeführt wird (wenn er natürlich in Simulator ausgeführt wird) und ob der übergeordnete Prozess gestartet wird.

Ich vermute hier, dass es möglich ist, dass der Sicherheitsdämon aus einem unbekannten Grund nicht oder zu langsam gestartet wird und nicht bereit ist, wenn Sie versuchen, ihn zu verwenden.

Vielleicht könnten Sie darüber nachdenken, wie Sie den Daemon vorab starten können.

Ich entschuldige mich dafür, dass ich nicht genauer bin. Ich hoffe, es könnte Ihnen helfen, bei Ihren Ermittlungen noch einen Schritt weiter zu gehen.


2
Ich bekomme dieses Problem nur, wenn meine App über einen Deep Link mit der folgenden App-Delegate-Methode erneut geöffnet wird: - (BOOL) -Anwendung: (UIApplication *) application handleOpenURL: (NSURL *) url. Wenn ich nur die App starte, funktioniert das Schreiben von Schlüsselbunden, und wenn ich die App minimiere und maximiere, funktioniert sie immer noch. Erst wenn ich mit dem Deep Link wieder öffne, tritt dieses Problem auf. Ich habe MyApp.entitlements in meinem Projekt konfiguriert (Schlüsselbundfreigabe auf der Registerkarte Funktionen) Xcode 7 Beta 4.
FranticRock

Mein Fall ähnelt dem von Alex, was nur passiert, wenn die App tief verknüpft ist. Ansonsten läuft es gut. Möglicherweise stimmt ein Kontext nicht, wenn die App von einer anderen App aus geöffnet wird.
CodeBrew

12

Ich beobachte ein ähnliches Verhalten, nachdem ich meinen Code in Xcode 6 Beta mit iOS 8 SDK erstellt und ausgeführt habe (es funktioniert ordnungsgemäß mit Xcode 5 / iOS 7). In Xcode 6 gibt SecItemCopyMatching in iOS Simulator immer -34018 zurück. Es begann zu funktionieren, nachdem die Option "Schlüsselbundfreigabe" auf der Registerkarte "Funktionen" aktiviert wurde.

Ich habe jedoch ein anderes Problem. Ich entwickle eine statische Bibliothek, die (unter anderem) von der Demo-Anwendung verwendet wird. Die obige Lösung funktioniert für Demo-Anwendungsprojekte, aber wenn ich versuche, mein statisches Bibliotheksprojekt einem Komponententest zu unterziehen, tritt genau der gleiche Fehler auf. Das Problem ist, dass mein statisches Bibliotheksprojekt nicht über die Registerkarte Funktionen verfügt (da es sich nicht um eine eigenständige Anwendung handelt).

Ich habe die hier von JorgeDeCorte veröffentlichte Lösung mit Codesignierung im Testziel ausprobiert, aber sie funktioniert bei mir nicht.


8
Und zurück in iOS 8 Beta 3 :)
Mustafa

7
Und zurück in iOS 9.0
Alex Stone

4
Und jetzt zurück in iOS 9.2 :-(
Vamos

4
Zurück in iOS 10 Beta 2
Pranjal Bikash Das

3
Und zurück in iOS 10 Beta 5
Pascal

6

Versuchen Sie alle Haltepunkte zu deaktivieren , wenn Sie die App starten von Xcode. Sie können sie anschließend aktivieren.

(Keine der oben genannten Problemumgehungen hat bei mir funktioniert)


Seltsam. Scheint dieses Problem auch für mich zu beheben! Jedes Mal, wenn ich anfing, auf dem Simulator zu debuggen, konnte ich den OSStatus -34018 erleben.
Midori

4

Ich hatte gerade das gleiche Problem auf dem Simulator mit 7.1 und 8.0. Beim Graben stellte ich fest, dass in der Apple-Beispiel-App KeyChain Sharing für die Zielfunktionen aktiviert war. Ich habe es für meine App aktiviert, was dazu führte, dass eine Berechtigungsdatei erstellt wurde, die ich mit den Standardwerten belassen habe. Jetzt werden keine -34018-Fehler mehr angezeigt. Dies ist nicht ideal, aber ich werde die KeyChain-Freigabeoption vorerst leben.


4

Das Codesignieren eines .xctest-Bundles ist in einigen Fällen nicht so einfach, wie es sich anhört. Grundsätzlich hat JorgeDeCorte mit seiner Antwort Recht , dass die angegebene kurze Zeile als a Run Scriptfür die meisten Entwickler ausreicht.

codesign --verify --force --sign "$CODE_SIGN_IDENTITY" "$CODESIGNING_FOLDER_PATH"

Wenn Sie jedoch mehrere Zertifikate in Ihrem Schlüsselbund haben, schlägt dies in der folgenden Zeile fehl

iPhone Developer: ambiguous (matches "iPhone Developer: Your Name (ABC123DEF45)" and "iPhone Developer: Your Name (123ABC456DE)"

Eine Lösung, um auch bei mehreren das richtige Zertifikat zu erhalten, ist dieses kurze Skript. Dies ist zwar nicht ideal, aber meines Wissens haben Sie keine Chance, das Zertifikat zu erhalten, das Xcode gefunden und zum Signieren Ihrer .app verwendet hat.

echo "codesign --verify --force --sign \"$CODE_SIGN_IDENTITY\" \"$CODESIGNING_FOLDER_PATH\""
IDENTITIES=`security find-identity -v -s "Code Signing" | grep "iPhone Developer" | awk '{ print $2 }'`

for SHA in $IDENTITIES; do
    codesign --verify --force --sign $SHA "$CODESIGNING_FOLDER_PATH"
    if [ $? -eq 0 ]; then
        echo "Matching identity found: $SHA"
        exit 0
    fi
done;

exit 1

4

Ich wurde auch davon gebissen und hatte mit keiner der anderen Problemumgehungen Erfolg. Ich habe dann meine Bereitstellungsprofile auf den Geräten selbst bereinigt, indem ich alle mit meiner App verbundenen Profile sowie alle Platzhalterprofile gelöscht habe (dies scheint der Punkt zu sein). Gehen Sie dazu in Xcode zum Fenster "Geräte" und klicken Sie mit der rechten Maustaste auf Ihr (verbundenes) Telefon:

Klicken Sie auf "Bereitstellungsprofile anzeigen" und löschen Sie die zugehörigen Profile, insbesondere die Teamprofile:

einschließlich der mit dem Sternchen. Nach der Neuinstallation der App wurde alles wieder normal.


Dies hat mir geholfen, die App von Xcode aus auszuführen und den Entwicklungsprozess fortzusetzen.
Salabaha

Beim Erstellen einer AdHoc-Version können Sie überprüfen, welche PPs verwendet werden. Wenn Sie XC: -Profile sehen, löschen Sie diese und aktualisieren Sie Ihre PP!
Hundegott

Ich kann sehen, wie dies ein Faktor sein könnte. Was für ein Durcheinander da drin !! Aufräumen im Herbst
David

3

Ich habe dieses Problem behoben (glaube ich). Ich hatte ein Wildcard-Bereitstellungsprofil auf meinem Gerät, das zeigte, dass es keine gültige Signaturidentität hatte. Ich hatte auch ein Bereitstellungsprofil für meine App, das gültig war. Als ich das Platzhalterprofil löschte, wurden die Fehler -34018 nicht mehr angezeigt.

Ich habe auch sichergestellt, dass die Codesignaturidentität und das Bereitstellungsprofil, die im Abschnitt Codesignatur der Build-Einstellungen des Ziels aufgeführt sind, mit denen für die App identisch sind (nicht mit dem generischen "iPhone Developer").


Ähnlich hat das für mich behoben. Stellen Sie die Codesignatur auf Projektebene für das Debuggen auf "iPhone Developer" und für das Release auf "iPhone Distribution" ein. Ich habe dann die Überschreibungen auf dem Hauptziel entfernt, damit sie dasselbe anzeigen. Zuvor schlug das Speichern im Schlüsselbund zu 100% fehl. Danach scheint das Speichern im Schlüsselbund stabil zu sein.
Jowie

2

Ich habe sehr selten einen Fehler von -34018 in meiner App (iOS 8.4) erhalten. Nach einigen Nachforschungen habe ich festgestellt, dass dieses Problem auftritt, wenn die App zu oft Daten vom Schlüsselbund anfordert .
In meiner Situation waren es beispielsweise zwei Leseanforderungen für einen bestimmten Schlüssel gleichzeitig von verschiedenen Anwendungsmodulen.
Um dies zu beheben, habe ich gerade das Zwischenspeichern dieses Werts im Speicher hinzugefügt


1

Ich hatte aus heiterem Himmel das gleiche Problem auf einem Testgerät mit Xcode 6.2, iPhone 6, iOS 8.3. Dies wurde nicht beim Ausführen von Xcode-Tests, sondern beim Ausführen der eigentlichen App auf meinem Gerät festgestellt. Im Simulator war es in Ordnung, und auf der App selbst war es bis vor kurzem vollkommen in Ordnung.

Ich habe alle Vorschläge ausprobiert, die ich hier finden konnte, z. B. das Entfernen der Bereitstellungsprofile auf meinem Gerät (ich habe ALLE entfernt) und vorübergehend die Funktion zur Schlüsselbundfreigabe in meinem Projekt aktiviert (obwohl wir das nicht wirklich benötigen) Sicher, mein Entwicklungskonto in Xcode wurde mit allen Zertifikaten und Bereitstellungsprofilen usw. vollständig aktualisiert. Nichts hat geholfen.

Dann habe ich vorübergehend die Eingabehilfenstufe von kSecAttrAccessibleAfterFirstUnlockauf geändert kSecAttrAccessibleAlwaysThisDeviceOnly, die App ausgeführt, sie hat einwandfrei funktioniert und konnte in den Schlüsselbund schreiben. Dann habe ich es wieder geändert kSecAttrAccessibleAfterFirstUnlockund das Problem scheint "dauerhaft" verschwunden zu sein.


1

Ich bin gerade von diesem Fehler in Xcode 8 Beta 3 gebissen worden. Das Aktivieren der Schlüsselbundfreigabe scheint die einzige Lösung zu sein.


1

Ich hatte das gleiche Problem. Es wurde behoben, indem die Schlüsselbundfreigabe eingerichtet wurde.


1

(Dies ist keine direkte Antwort auf die Frage des OP, könnte aber anderen helfen.)

Nach dem Aktualisieren von Xcode von Version 7.3.1 auf 8.0 wurde der Schlüsselbundfehler -34018 im Simulator konsistent angezeigt.

Nach diesem Tipp aus Daidais Antwort :

Einige Fälle des Problems werden durch falsche App-Signatur verursacht. Sie können diesen Fall leicht unterscheiden, da das Problem zu 100% reproduzierbar ist.

Es wurde festgestellt, dass das Bereitstellungsprofil in den Signaturabschnitten des Ziels auf "Keine" gesetzt war.

Das Festlegen der Felder für das Bereitstellungsprofil auf gültige Werte reichte jedoch nicht aus, um das Problem in diesem Fall zu beheben.

Weitere Untersuchungen ergaben, dass die Berechtigung Push-Benachrichtigungen ebenfalls einen Fehler aufwies. Darin stand die Funktion "Push-Benachrichtigungen zu Ihrer App-ID hinzufügen". Schritt wurde abgeschlossen, Schritt "Push-Benachrichtigungen zu Ihrer Berechtigungsdatei hinzufügen" jedoch nicht.

Nachdem Sie auf "Problem beheben" geklickt haben, um das Problem mit der Push-Benachrichtigung zu beheben, wurde der Schlüsselbundfehler behoben.

Für dieses spezielle Ziel war die Berechtigung "Schlüsselbundfreigabe" bereits zu einem früheren Zeitpunkt aktiviert worden. Das Deaktivieren hat bisher nicht dazu geführt, dass der Schlüsselbundfehler erneut auftritt. Daher ist nicht klar, ob dies in diesem Fall erforderlich ist.


0

In iOS 9 habe ich Address Sanitizer deaktiviert und es funktioniert auf dem Gerät.


0

Die einzige Lösung, die für mich funktioniert hat, war, zuerst Null für den angegebenen Schlüssel zu speichern und dann meinen neuen Wert mit einer separaten Operation zu speichern. Es würde aufgrund des Fehlers -34018 fehlschlagen, wenn ich versuchen würde, den vorhandenen Wert zu überschreiben. Aber solange ich zuerst null gespeichert habe , wird der aktualisierte Wert unmittelbar danach erfolgreich gespeichert.


0

Ich habe dieses Problem -34018 heute beim Ausführen der SecItemDelete-API festgestellt. Um dies zu beheben, habe ich Folgendes getan: 1. Befolgen Sie die @ k1th-Lösung https://stackoverflow.com/a/33085955/889892. 2. Führen Sie SecItemDelete im Hauptthread aus. .

Entschuldigung, es kommt wieder zurück :(


0

Aktivieren Sie die Schlüsselbundfreigabe in den Funktionen Ihres Projekts, um das Problem zu lösen. Geben Sie hier die Bildbeschreibung ein


0

Was hat bei mir funktioniert?

  • Aktivieren Sie die Schlüsselbundfreigabe.
  • Verwenden Sie den Schlüsselbund so wenig wie möglich und speichern Sie die Daten im Speicher, in den Benutzerreferenzen, auf der Festplatte usw. zwischen.
  • Wiederholen Sie die CRUD-Operationen des Schlüsselbunds mehrmals, wenn diese fehlgeschlagen sind.
  • Verwenden Sie DispatchQueue.sync zum Speichern / Löschen / Aktualisieren der Daten.

0

Für mich war es ein Problem beim Signieren von Apps. Ich habe einfach in Xcode zum richtigen Signierteam gewechselt und der Fehler ist nicht mehr aufgetreten

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.