pcsc: guide by PolicyKit actions, not a pcscd group
A headless/SSH box can show a world-writable /run/pcscd/pcscd.comm (srw-rw-rw- root root) and still be denied: pcscd enforces its PolicyKit policy, whose defaults allow only active local sessions. The startup report, the start.sh pre-flight and the README troubleshooting now name the exact rule (99-pcscd-allow.rules, org.debian.pcsc-lite.access_pcsc and access_card) and explain why the socket mode does not matter. The pcscd-group instruction is gone: there may be no such group, and it is not the gate. The group route stays only as a note for a pcscd built without PolicyKit. Tests: tests/test_pcsc_startup.py asserts the polkit action IDs, the rule filename and the 0666-socket explanation. 1088 Python + 1075 frontend.
This commit is contained in:
+5
-3
@@ -32,9 +32,11 @@ every change carries a descriptive commit message.
|
||||
the user may not use `pcscd`), the error was swallowed and pySim fell back to
|
||||
the serial transport, failing on `/dev/ttyUSB0` while the server still printed
|
||||
"listening". The startup now probes PC/SC and reports **`PC/SC access
|
||||
denied`** (with the `pcscd` group/polkit guidance and the `pcsc_scan`
|
||||
cross-check), **`pcscd is not running`** or **`no PC/SC reader found`**, then
|
||||
exits 2; `start.sh` runs the same access pre-flight before launching. An
|
||||
denied`** (naming the pcsc-lite PolicyKit actions and the
|
||||
`99-pcscd-allow.rules` rule — a world-writable `pcscd.comm` does not bypass
|
||||
polkit's active-session policy — plus the `pcsc_scan` cross-check),
|
||||
**`pcscd is not running`** or **`no PC/SC reader found`**, then exits 2;
|
||||
`start.sh` runs the same access pre-flight before launching. An
|
||||
explicit `-d <device>` keeps the serial path, and a reader present but no card
|
||||
is still a normal cardless start.
|
||||
- **`setup.sh`/`setup.bat` recover from an incomplete `.venv`.** A failed venv
|
||||
|
||||
@@ -800,7 +800,19 @@ its MSVC build chain) is not pulled in.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- **"Failed to establish context: Access denied"** — the user may not use `pcscd`: add the user to the `pcscd` group (`sudo usermod -a -G pcscd $USER`, then log out/in) or configure the polkit rule; start the service if needed (`sudo systemctl enable --now pcscd`). `start.sh` and the server report this and exit instead of falling back to a serial reader; `pcsc_scan` shows the same error.
|
||||
- **"Failed to establish context: Access denied"** — the user may not use `pcscd`. On a headless/SSH box the socket is often world-writable (`srw-rw-rw- root root`) yet access is still denied: pcscd checks **PolicyKit**, whose default policy allows only *active local* sessions (`allow_active=yes`, `allow_inactive=no`, `allow_any=no`). Allow the user with `/etc/polkit-1/rules.d/99-pcscd-allow.rules` (replace `YOUR_USER`; any `*.rules` file name works):
|
||||
|
||||
```js
|
||||
polkit.addRule(function(action, subject) {
|
||||
if ((action.id == "org.debian.pcsc-lite.access_pcsc" ||
|
||||
action.id == "org.debian.pcsc-lite.access_card") &&
|
||||
subject.user == "YOUR_USER") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
then `sudo systemctl restart polkit` (or log out/in). Start the service if needed (`sudo systemctl enable --now pcscd`); `start.sh` and the server report this and exit instead of falling back to a serial reader, and `pcsc_scan` shows the same error until the rule is active. If your `pcscd` was built without PolicyKit and the socket is group-owned, adding the user to that group works instead.
|
||||
- **"device file /dev/ttyUSB0 does not exist"** — only with an explicit `-d <device>`: the device is not connected (or the path is wrong). Without `-d` the server no longer uses the serial transport.
|
||||
- **"no PC/SC reader found"** — connect a reader (`pcsc_scan` lists them) and restart; the server exits instead of starting without a reader.
|
||||
- **"Service not available" (0x8010001D) / reader gone after a `pcscd` restart** — the server recovers by itself: a watchdog revives pyscard's presence monitor and the next equip (automatic after re-insertion, or the **Equip** button) recreates the PC/SC transport (releasing the old link first). No server restart needed.
|
||||
|
||||
+13
-1
@@ -784,7 +784,19 @@ pysim-simple-server --http-port 8080
|
||||
|
||||
### Устранение неполадок
|
||||
|
||||
- **"Failed to establish context: Access denied"** — у пользователя нет прав на `pcscd`: добавьте его в группу `pcscd` (`sudo usermod -a -G pcscd $USER`, затем выйдите и войдите) или настройте правило polkit; при необходимости запустите службу (`sudo systemctl enable --now pcscd`). `start.sh` и сервер сообщают об этом и завершаются вместо отката на serial-ридер; `pcsc_scan` показывает ту же ошибку.
|
||||
- **"Failed to establish context: Access denied"** — у пользователя нет прав на `pcscd`. На headless/SSH-системе сокет часто доступен всем (`srw-rw-rw- root root`), но доступ всё равно запрещён: pcscd проверяет **PolicyKit**, политика по умолчанию разрешает только *активные локальные* сессии (`allow_active=yes`, `allow_inactive=no`, `allow_any=no`). Разрешите пользователя в `/etc/polkit-1/rules.d/99-pcscd-allow.rules` (замените `YOUR_USER`; имя файла `*.rules` может быть любым):
|
||||
|
||||
```js
|
||||
polkit.addRule(function(action, subject) {
|
||||
if ((action.id == "org.debian.pcsc-lite.access_pcsc" ||
|
||||
action.id == "org.debian.pcsc-lite.access_card") &&
|
||||
subject.user == "YOUR_USER") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
затем `sudo systemctl restart polkit` (или выйдите и войдите). При необходимости запустите службу (`sudo systemctl enable --now pcscd`); `start.sh` и сервер сообщают об этом и завершаются вместо отката на serial-ридер, а `pcsc_scan` показывает ту же ошибку, пока правило не начнёт действовать. Если `pcscd` собран без PolicyKit и сокет принадлежит отдельной группе, вместо этого можно добавить пользователя в неё.
|
||||
- **"device file /dev/ttyUSB0 does not exist"** — только при явном `-d <устройство>`: устройство не подключено (или путь неверен). Без `-d` сервер больше не использует последовательный транспорт.
|
||||
- **"no PC/SC reader found"** — подключите ридер (`pcsc_scan` покажет список) и перезапустите; сервер завершается, а не стартует без ридера.
|
||||
- **"Service not available" (0x8010001D) / ридер пропал после перезапуска `pcscd`** — сервер восстанавливается сам: сторож перезапускает монитор присутствия pyscard, а следующий equip (автоматически после повторной вставки карты или кнопкой **Equip**) пересоздаёт транспорт PC/SC (сначала освобождая старый линк). Перезапуск сервера не нужен.
|
||||
|
||||
@@ -65,10 +65,18 @@ def _report_pcsc_unavailable(kind, exc=None):
|
||||
if kind == 'access':
|
||||
user = os.environ.get('USER') or os.environ.get('LOGNAME') or '$USER'
|
||||
sys.stderr.write('INIT: PC/SC access denied - the current user may not use pcscd.\n')
|
||||
sys.stderr.write(' Add the user to the pcscd group: sudo usermod -aG pcscd %s\n' % user)
|
||||
sys.stderr.write(' (then log out and back in), or configure the polkit rule that\n')
|
||||
sys.stderr.write(' allows the user to use pcscd. `pcsc_scan` shows the same\n')
|
||||
sys.stderr.write(' "SCardEstablishContext: Access denied" error.\n')
|
||||
sys.stderr.write(' pcscd gates access through PolicyKit: the default policy allows\n')
|
||||
sys.stderr.write(' only *active local* sessions, so an SSH/headless session is denied\n')
|
||||
sys.stderr.write(' even when /run/pcscd/pcscd.comm is world-writable (0666).\n')
|
||||
sys.stderr.write(' Allow the user in /etc/polkit-1/rules.d/99-pcscd-allow.rules:\n')
|
||||
sys.stderr.write(' polkit.addRule(function(a, s) {\n')
|
||||
sys.stderr.write(' if ((a.id == "org.debian.pcsc-lite.access_pcsc" ||\n')
|
||||
sys.stderr.write(' a.id == "org.debian.pcsc-lite.access_card") &&\n')
|
||||
sys.stderr.write(' s.user == "%s") return polkit.Result.YES;\n' % user)
|
||||
sys.stderr.write(' });\n')
|
||||
sys.stderr.write(' then restart polkit (sudo systemctl restart polkit) or log out/in;\n')
|
||||
sys.stderr.write(' `pcsc_scan` shows the same "SCardEstablishContext: Access denied"\n')
|
||||
sys.stderr.write(' error until the rule is active.\n')
|
||||
elif kind == 'service':
|
||||
sys.stderr.write('INIT: pcscd is not running or not reachable.\n')
|
||||
sys.stderr.write(' Start it (sudo systemctl start pcscd) and restart the server.\n')
|
||||
|
||||
@@ -54,10 +54,13 @@ PY
|
||||
)" || {
|
||||
echo "Error: PC/SC is not accessible: ${PCSC_ERR:-unknown error}"
|
||||
echo " The server will not fall back to a serial reader silently."
|
||||
echo " - add the user to the pcscd group: sudo usermod -aG pcscd \"$USER\" (then log out/in),"
|
||||
echo " or configure the polkit rule that allows the user to use pcscd;"
|
||||
echo " - pcscd uses PolicyKit (the default allows only active local sessions,"
|
||||
echo " so SSH/headless is denied even with a 0666 socket). Allow the user in"
|
||||
echo " /etc/polkit-1/rules.d/99-pcscd-allow.rules: return polkit.Result.YES for"
|
||||
echo " org.debian.pcsc-lite.access_pcsc and access_card, subject.user == \"$USER\";"
|
||||
echo " then 'sudo systemctl restart polkit' (or log out/in);"
|
||||
echo " - 'sudo systemctl start pcscd' if the service is not running;"
|
||||
echo " - 'pcsc_scan' shows the same 'Access denied' error when access is denied."
|
||||
echo " - 'pcsc_scan' shows the same 'Access denied' error until the rule is active."
|
||||
exit 2
|
||||
}
|
||||
READER_ARGS="-p 0"
|
||||
|
||||
@@ -102,7 +102,12 @@ class ReportTests(unittest.TestCase):
|
||||
low = text.lower()
|
||||
self.assertIn('access denied', low)
|
||||
self.assertIn('pcscd', low)
|
||||
self.assertIn('usermod -aG pcscd'.lower(), low)
|
||||
# polkit, not the socket group, is the gate (the socket can be 0666)
|
||||
self.assertIn('polkit', low)
|
||||
self.assertIn('org.debian.pcsc-lite.access_pcsc', low)
|
||||
self.assertIn('org.debian.pcsc-lite.access_card', low)
|
||||
self.assertIn('99-pcscd-allow.rules', low)
|
||||
self.assertIn('0666', low)
|
||||
self.assertIn('pcsc_scan', low)
|
||||
self.assertIn('0x80100027', text)
|
||||
|
||||
@@ -136,8 +141,12 @@ class SourcePins(unittest.TestCase):
|
||||
def test_the_start_script_probes_access_and_guides(self):
|
||||
src = (Path(m.__file__).parent.parent / 'start.sh').read_text()
|
||||
self.assertIn('from smartcard.System import readers', src)
|
||||
self.assertIn('usermod -aG pcscd', src)
|
||||
self.assertIn('polkit', src)
|
||||
self.assertIn('org.debian.pcsc-lite.access_pcsc', src)
|
||||
self.assertIn('99-pcscd-allow.rules', src)
|
||||
self.assertIn('pcsc_scan', src)
|
||||
# the group route is not the gate (the socket may be 0666)
|
||||
self.assertNotIn('usermod -aG pcscd', src)
|
||||
# the old "is pcscd running" heuristic is gone
|
||||
self.assertNotIn('pgrep -x pcscd', src)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user