1 /*  commands/changepincommand.cpp
2 
3     This file is part of Kleopatra, the KDE keymanager
4     SPDX-FileCopyrightText: 2020 g10 Code GmbH
5     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include "changepincommand.h"
11 
12 #include "cardcommand_p.h"
13 
14 #include "smartcard/netkeycard.h"
15 #include "smartcard/openpgpcard.h"
16 #include "smartcard/pivcard.h"
17 #include "smartcard/readerstatus.h"
18 
19 #include <KLocalizedString>
20 
21 #include <gpgme++/error.h>
22 
23 #include "kleopatra_debug.h"
24 
25 using namespace Kleo;
26 using namespace Kleo::Commands;
27 using namespace Kleo::SmartCard;
28 using namespace GpgME;
29 
30 class ChangePinCommand::Private : public CardCommand::Private
31 {
32     friend class ::Kleo::Commands::ChangePinCommand;
q_func() const33     ChangePinCommand *q_func() const
34     {
35         return static_cast<ChangePinCommand *>(q);
36     }
37 public:
38     explicit Private(ChangePinCommand *qq, const std::string &serialNumber, const std::string &appName, QWidget *p);
39     ~Private() override;
40 
41     void init();
42 
43 private:
44     void slotResult(const Error &err);
45 
46 private:
47     void changePin();
48 
49 private:
50     std::string appName;
51     std::string keyRef;
52     ChangePinMode mode = NormalMode;
53 };
54 
d_func()55 ChangePinCommand::Private *ChangePinCommand::d_func()
56 {
57     return static_cast<Private *>(d.get());
58 }
d_func() const59 const ChangePinCommand::Private *ChangePinCommand::d_func() const
60 {
61     return static_cast<const Private *>(d.get());
62 }
63 
64 #define d d_func()
65 #define q q_func()
66 
Private(ChangePinCommand * qq,const std::string & serialNumber,const std::string & appName_,QWidget * p)67 ChangePinCommand::Private::Private(ChangePinCommand *qq, const std::string &serialNumber, const std::string &appName_, QWidget *p)
68     : CardCommand::Private(qq, serialNumber, p)
69     , appName(appName_)
70 {
71 }
72 
~Private()73 ChangePinCommand::Private::~Private()
74 {
75     qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::Private::~Private()";
76 }
77 
ChangePinCommand(const std::string & serialNumber,const std::string & appName,QWidget * p)78 ChangePinCommand::ChangePinCommand(const std::string &serialNumber, const std::string &appName, QWidget *p)
79     : CardCommand(new Private(this, serialNumber, appName, p))
80 {
81     d->init();
82 }
83 
init()84 void ChangePinCommand::Private::init()
85 {
86 }
87 
~ChangePinCommand()88 ChangePinCommand::~ChangePinCommand()
89 {
90     qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::~ChangePinCommand()";
91 }
92 
setKeyRef(const std::string & keyRef)93 void ChangePinCommand::setKeyRef(const std::string &keyRef)
94 {
95     d->keyRef = keyRef;
96 }
97 
setMode(ChangePinMode mode)98 void ChangePinCommand::setMode(ChangePinMode mode)
99 {
100     d->mode = mode;
101 }
102 
103 
doStart()104 void ChangePinCommand::doStart()
105 {
106     qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::doStart()";
107 
108     d->changePin();
109 }
110 
doCancel()111 void ChangePinCommand::doCancel()
112 {
113 }
114 
changePin()115 void ChangePinCommand::Private::changePin()
116 {
117     qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::changePin()";
118 
119     const auto card = SmartCard::ReaderStatus::instance()->getCard(serialNumber(), appName);
120     if (!card) {
121         error(i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(serialNumber())));
122         finished();
123         return;
124     }
125 
126     QByteArrayList command;
127     command << "SCD PASSWD";
128     if (mode == ResetMode) {
129         command << "--reset";
130     } else if (mode == NullPinMode) {
131         command << "--nullpin";
132     }
133     command << QByteArray::fromStdString(keyRef);
134     ReaderStatus::mutableInstance()->startSimpleTransaction(card, command.join(' '), q, "slotResult");
135 }
136 
137 namespace {
errorMessage(const std::string & keyRef,ChangePinCommand::ChangePinMode mode,const QString & errorText)138 static QString errorMessage(const std::string &keyRef, ChangePinCommand::ChangePinMode mode, const QString &errorText)
139 {
140     // see cmd_passwd() in gpg-card.c
141     if (keyRef == PIVCard::pukKeyRef()) {
142         return i18nc("@info", "Changing the PUK failed: %1", errorText);
143     }
144     if (keyRef == OpenPGPCard::resetCodeKeyRef()) {
145         return i18nc("@info", "Unblocking the PIN failed: %1", errorText);
146     }
147     if (keyRef == OpenPGPCard::adminPinKeyRef()) {
148         return i18nc("@info", "Changing the Admin PIN failed: %1", errorText);
149     }
150     if (keyRef == OpenPGPCard::resetCodeKeyRef() && mode == ChangePinCommand::ResetMode) {
151         return i18nc("@info", "Changing the Reset Code failed: %1", errorText);
152     }
153     if (keyRef == NetKeyCard::nksPinKeyRef()) {
154         if (mode == ChangePinCommand::NullPinMode) {
155             return i18nc("@info", "Setting the NKS PIN failed: %1", errorText);
156         } else {
157             return i18nc("@info", "Changing the NKS PIN failed: %1", errorText);
158         }
159     }
160     if (keyRef == NetKeyCard::sigGPinKeyRef()) {
161         if (mode == ChangePinCommand::NullPinMode) {
162             return i18nc("@info", "Setting the SigG PIN failed: %1", errorText);
163         } else {
164             return i18nc("@info", "Changing the SigG PIN failed: %1", errorText);
165         }
166     }
167     return i18nc("@info", "Changing the PIN failed: %1", errorText);
168 }
169 
successMessage(const std::string & keyRef,ChangePinCommand::ChangePinMode mode)170 static QString successMessage(const std::string &keyRef, ChangePinCommand::ChangePinMode mode)
171 {
172     // see cmd_passwd() in gpg-card.c
173     if (keyRef == PIVCard::pukKeyRef()) {
174         return i18nc("@info", "PUK successfully changed.");
175     }
176     if (keyRef == OpenPGPCard::resetCodeKeyRef()) {
177         return i18nc("@info", "Unblocked and set a new PIN successfully.");
178     }
179     if (keyRef == OpenPGPCard::adminPinKeyRef()) {
180         return i18nc("@info", "Admin PIN changed successfully.");
181     }
182     if (keyRef == OpenPGPCard::resetCodeKeyRef() && mode == ChangePinCommand::ResetMode) {
183         return i18nc("@info", "Reset Code changed successfully.");
184     }
185     if (keyRef == NetKeyCard::nksPinKeyRef()) {
186         if (mode == ChangePinCommand::NullPinMode) {
187             return i18nc("@info", "NKS PIN set successfully.");
188         } else {
189             return i18nc("@info", "NKS PIN changed successfully.");
190         }
191     }
192     if (keyRef == NetKeyCard::sigGPinKeyRef()) {
193         if (mode == ChangePinCommand::NullPinMode) {
194             return i18nc("@info", "SigG PIN set successfully.");
195         } else {
196             return i18nc("@info", "SigG PIN changed successfully.");
197         }
198     }
199     return i18nc("@info", "PIN changed successfully.");
200 }
201 }
202 
slotResult(const GpgME::Error & err)203 void ChangePinCommand::Private::slotResult(const GpgME::Error& err)
204 {
205     qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::slotResult():"
206                            << err.asString() << "(" << err.code() << ")";
207     if (err) {
208         error(errorMessage(keyRef, mode, QString::fromLatin1(err.asString())),
209               i18nc("@title", "Error"));
210     } else if (!err.isCanceled()) {
211         information(successMessage(keyRef, mode), i18nc("@title", "Success"));
212         ReaderStatus::mutableInstance()->updateStatus();
213     }
214     finished();
215 }
216 
217 #undef d
218 #undef q
219 
220 #include "moc_changepincommand.cpp"
221