VPN کنکشن کے بعد کارروائی کو ڈیمن کے بجائے صارف کے طور پر چلائیں
USER=alice کہنے والا ماحول متغیر یہ نہیں بدلتا کہ hook کس اکاؤنٹ میں چلتا ہے۔ واقعہ، محرک اور کارروائی الگ کریں، پھر UID ثابت کریں۔
VPN ڈیمن پر کنکشن hook ڈیمن ہی کی طرح چلتے ہیں، اور عام طور پر اس کا مطلب یہ ہے کہ وہ root کے طور پر چلتے ہیں۔ جس لمحے ان hook میں سے کوئی کسی کے ہوم ڈائریکٹری میں لکھتا ہے یا ڈیسک ٹاپ معاون کو دوبارہ شروع کرتا ہے، آپ نے ایک نیٹ ورک واقعے کو کسی بھی مقامی صارف کے طور پر کام کرنے کی صلاحیت دے دی ہے۔ معمول کا مختصر راستہ، یعنی ماحول متغیر سے صارف کا نام پڑھ کر آگے بھیجنا، اسے درست نہیں کرتا۔ یہ صرف کارروائی کو دوبارہ لیبل کرتا ہے، لیکن یہ نہیں بدلتا کہ کون سا اکاؤنٹ اسے انجام دیتا ہے۔ جو کام کرتا ہے وہ تین حصوں کی سپردگی ہے، جس میں صاحبِ اختیار قدم بتاتا ہے کہ کیا ہوا اور ایک الگ یونٹ درست شناخت کے تحت کارروائی کرتا ہے۔
ماحول میں صارف کا نام شناخت کا سوئچ نہیں ہے
یونکس فیصلہ کرتا ہے کہ کوئی عمل کیا چھو سکتا ہے، اس کی مؤثر صارف ID سے، اس کے ماحول کی تاروں سے نہیں۔ USER=alice مقرر کرنا یا LOGNAME برآمد کرنا یہ بدلتا ہے کہ لاپرواہ سافٹ ویئر اپنی آؤٹ پٹ میں کیا چھاپتا ہے؛ فائل ملکیت کی جانچ میں یہ کچھ نہیں بدلتا۔ اس متغیر کے ساتھ root کے طور پر چلنے والا hook پھر بھی Alice کی فائلیں root ہی کے طور پر کھولتا ہے۔
نام بھی ایک ہی نام نہیں ہیں۔ دور دراز رسائی کا لاگ ان، مقامی یونکس اکاؤنٹ اور سرٹیفکیٹ کا عام نام تین شناخت کنندہ ہیں جو اکثر ملتے ہیں اور کبھی نہیں بھی۔ a.smith کے طور پر تصدیق کرنے والے صارف کا مقامی اکاؤنٹ بالکل نہ ہو، یا ڈائریکٹری سروس کے ذریعے asmith پر میپ ہو جائے۔ کوئی بھی ڈیزائن جو یہ فرض کرے کہ ایک تار تینوں کردار ادا کرتی ہے، پہلے ٹھیکیدار پر ہی ٹوٹ جائے گا۔
اس لیے پہلا سوال یہ نہیں کہ «کون سا صارف جڑا ہوا ہے» بلکہ یہ ہے کہ «کس مقامی اکاؤنٹ کو یہ کارروائی کرنے کی اجازت ہے»۔ اس کا جواب اپنے اکاؤنٹ ڈیٹا بیس سے دیں، کلائنٹ کی بھیجی ہوئی چیز سے نہیں:
id -u alice
getent passwd alice | cut -d: -f1,3,6
stat -c '%U:%G %a %n' /home/alice/.local/state/vpn-status.json
تیسرا حکم وہی ہے جسے لوگ چھوڑ دیتے ہیں۔ اگر ہدف فائل root کی ملکیت میں ہے کیونکہ پچھلے hook نے اسے بنایا تھا، تو درست طریقے سے تشکیل شدہ صارف کارروائی اجازت کی غلطی سے ناکام ہو گی جو systemd مسئلے جیسی لگتی ہے اور ہے نہیں۔
ڈیمن اپنی جگہ پر ہی رہتا ہے
VPN سروس کا اپنا User= Alice پر بدلنا غلط لیور ہے۔ یہ بدلتا ہے کہ ڈیمن انٹرفیس کیسے باندھتا ہے، چابیاں کیسے پڑھتا ہے، اپنی حالت فائل کیسے لکھتا ہے اور راستے کیسے سنبھالتا ہے، اور یہ سارا خطرہ ایک کام کرتی یونٹ میں منتقل کر دیتا ہے۔ ڈیمن کو اپنے اختیارات درکار ہیں؛ اگلی کارروائی کو نہیں۔
یونٹ کو چھونے سے پہلے دیکھیں کہ وہ واقعی کیا کر رہی ہے۔ دو حکم آپ کو عمل درآمد کی شناخت اور نافذ دقیق حکم سطریں بتاتے ہیں، بشمول ہر وہ چیز جو کسی اوور رائیڈ نے شامل کی:
systemctl show -p User -p Group -p ExecStart openvpn-server@server
systemctl cat openvpn-server@server
ڈیفالٹ پیکج انسٹال میں ڈیمن root ہے اور --up اسکرپٹ اسے وراثت میں پاتا ہے۔ فرض کرنے کے بجائے اس کی تصدیق کریں، کیونکہ سخت کی گئی تقسیم نے اسے مخصوص اکاؤنٹ پر منتقل کیا ہو سکتا ہے، اور ہاتھ سے لکھی گئی drop-in hook کو مختلف قواعد والے ریپر کے ذریعے چلا سکتی ہے۔
تین نامزد حصے، ایک تنگ محرک
دیکھ بھال میں ٹکنے والی ترتیب میں ایک واقعہ، ایک محرک اور ایک کارروائی ہوتی ہے۔ ڈیمن بتاتا ہے کہ نامزد سیشن اوپر آیا۔ محرک اس چھوٹی حقیقت کو قبول کرتا ہے اور ایک مقررہ کارروائی مانگتا ہے۔ کارروائی اس مقامی اکاؤنٹ کے تحت چلتی ہے جس کی ملکیت میں چھوئی گئی فائلیں ہیں۔ زنجیر میں کچھ بھی من مانی حکم راستہ قبول نہیں کرتا۔
کارروائی خود ایک عام سروس یونٹ ہے، اور شناخت اس کے اندر ایک ہدایت ہے:
[Service]
Type=oneshot
User=alice
Group=alice
ExecStart=/usr/local/bin/refresh-vpn-status --slot %i
غور کریں کہ User=alice پوری یونٹ پر لاگو ہوتا ہے، اور systemd ایک ایسی استثنا درج کرتا ہے جو جاننے کے قابل ہے: + سابقہ والا حکم اس سے قطع نظر مکمل اختیارات کے ساتھ چلتا ہے۔ وہ سابقہ ایک واحد صاحبِ اختیار قدم کے لیے جائز اوزار ہے اور ابھی بنائی گئی علیحدگی کو کالعدم کرنے کا آسان طریقہ ہے، اس لیے اس یونٹ میں کسی بھی + کو نظرثانی میں جواز پیش کرنے والی چیز سمجھیں۔
محرک کا ان پٹ کم سے کم اور غیر خفیہ رکھیں۔ سیشن شناخت کنندہ، میپ شدہ اکاؤنٹ اور وقت کی مہر عام طور پر ضروری سب کچھ ہیں۔ کبھی بھی حد سے پار شیل کا ٹکڑا، قابل عمل فائل کا راستہ یا کلائنٹ کا فراہم کردہ ماحول بلاک نہ بھیجیں، کیونکہ وصول کرنے والے فریق کے پاس جائز قدر اور داخل شدہ قدر میں فرق کرنے کا کوئی طریقہ نہیں ہے۔
اصل میں چلی شناخت کی تصدیق کریں
تشکیل کی نظرثانی ثبوت نہیں ہے۔ منظور شدہ آزمائشی کنکشن کے بعد، فائل کو چھونے والی UID اور ڈیمن کی اب بھی استعمال ہونے والی UID کی تصدیق کریں:
stat -c '%U %G %y %n' /home/alice/.local/state/vpn-status.json
ps -o user=,pid=,cmd= -p "$(pgrep -o -f 'openvpn --daemon')"
systemd-run --uid=alice --pipe /usr/local/bin/refresh-vpn-status --dry-run
پہلی سطر Alice اور آپ کی آزمائش کی کھڑکی کے اندر وقت کی مہر دکھانی چاہیے۔ دوسری اب بھی root یا پیکج کا سروس اکاؤنٹ دکھانی چاہیے، جو ثابت کرتا ہے کہ ڈیمن ہلا نہیں۔ تیسری حقیقی دوبارہ کنکشن کا انتظار کیے بغیر کارروائی کی اجازتوں کی جانچ کا سب سے سستا طریقہ ہے۔
اگر فائل کا مالک Alice ہے لیکن اس کا گروپ یا وضع چلانے کے دوران بدل گیا ہے، تو منطقی نقص کے بجائے UMask= یا ڈائریکٹری اجازت کا فرق تلاش کریں۔ اگر وقت کی مہر بالکل نہ ہلی، تو محرک کبھی فعال ہی نہیں ہوا، اور مفید اگلا قدم دوسرا کلائنٹ دوبارہ کنکشن نہیں، بلکہ کارروائی یونٹ کے لیے journalctl -u ہے۔
کنکشن کا واقعہ اب بھی کیا ثابت نہیں کرتا
قائم شدہ سرنگ ایک حقیقت ہے۔ اس کا مطلب یہ نہیں کہ ڈیسک ٹاپ سیشن کھلا ہے، سیشن بس قابل رسائی ہے، یا کارروائی جو نجی وسیلہ چاہتی ہے وہ اب دستیاب ہے۔ Alice کی UID کے تحت oneshot یونٹ کے پاس اس کی شناخت ہے اور اس کے سیشن سے کچھ نہیں، اس لیے گرافیکل بس درکار ہر چیز کو تعاون یافتہ صارف سیشن میکانزم سے گزرنا ہو گا اور یہ متعین کرنا ہو گا کہ وہ لاگ آؤٹ ہونے پر کیا ہوتا ہے۔
دوبارہ کنکشن بھی دہرائے جاتے ہیں۔ ٹرین میں سوئے لیپ ٹاپ ایک گھنٹے میں درجن بھر کنکشن واقعات پیدا کر سکتا ہے، اور ہر بار ایک سطر شامل کرنے والا hook حالت فائل کو ایسے لاگ میں بدل دیتا ہے جو کوئی پڑھ نہیں سکتا۔ کارروائی کو idempotent بنائیں، یا اسے سیشن کی کلید والا ایک ہی ریکارڈ بدلنے دیں۔
آخر میں، نقصان کا دائرہ خود یونٹ کے اندر محدود کریں: حالت ڈائریکٹری سے باہر صرف پڑھنے کے قابل فائل سسٹم منظر، نئے اختیارات نہیں، اور واضح وقت کی حد۔ ڈیمن اور صارف کارروائی کے درمیان علیحدگی بذات خود قیمتی ہے، لیکن جب کارروائی آپ کی منظور کردہ صرف ایک چیز کے سوا کچھ نہ کر سکے تو یہ کہیں زیادہ قیمتی ہے۔