Ubuntu 26.04 میں sudo-rs کے لیے sudoers rules کیسے بدلیں
Ubuntu 26.04 میں sudo-rs default ہے۔ sudoers میں arguments کے wildcard match نہیں ہوتے؛ پرانے rule کے بجائے درست syntax اور متاثرہ versions یہاں دیکھیں۔
Ubuntu میں sudo-rs کی تبدیلیاں
Ubuntu 26.04 LTS میں sudo-rs بطور default sudo شامل ہے، اس لیے نئے server پر sudo command چلانے سے اصل C program کے بجائے Rust کی دوبارہ تیار کردہ implementation چلتی ہے۔ زیادہ تر sudoers files پہلے کی طرح بالکل کام کرتی رہتی ہیں۔ مسئلہ اس rule میں پیدا ہوتا ہے جس میں command کے arguments کے اندر wildcard شامل ہو، کیونکہ sudo-rs argument کے متن کے مقابل glob patterns match نہیں کرتا۔
Ubuntu 25.10 میں یہ تبدیلی پہلے کی گئی تھی اور Ubuntu 26.04 LTS میں بھی برقرار رکھی گئی ہے۔ Ubuntu 24.04 LTS متاثر نہیں ہوتا، کیونکہ sudo-rs کو دستی طور پر install کرنے تک وہ اصل sudo ہی منتخب کرتا ہے۔ یہ تبدیلی اس وقت اہم ہو جاتی ہے جب آپ Ubuntu 24.04 سے 26.04 پر upgrade کریں، یا نئی release پر نیا server بنائیں۔ اگر آپ interim releases بھی چلاتے ہیں تو server پر LTS اور interim Ubuntu releases میں فرق بتاتا ہے کہ اس جیسی تبدیلی سب سے پہلے کس machine پر لاگو ہوگی۔
چیک کریں کہ آپ کا سرور حقیقت میں کون سا sudo چلا رہا ہے
یہ فیصلہ release number سے نہ کریں۔ مشین سے براہ راست معلوم کریں۔
sudo --version
update-alternatives --config sudo
dpkg -l 'sudo*'اپنے سرور پر موجود sudo --version کو انٹرنیٹ پر موجود کسی بھی version table، حتیٰ کہ اس صفحے، پر ترجیح دیں۔ update-alternatives --config sudo جواب کا دوسرا حصہ ہے: یہ /usr/bin/sudo کے تمام installed providers کی فہرست دکھاتا ہے اور منتخب provider کو نشان زد کرتا ہے۔ کسی package کا installed ہونا اور اس کا selected ہونا ایک بات نہیں۔ اس لیے package list نہیں، selection دیکھیں۔
transition کے دوران دونوں implementations کو package کیا جاتا ہے۔ Rust والی implementation sudo-rs ہے، جو August 2026 تک 26.04 میں version 0.2.13 پر ہے۔ Todd C. Miller کی maintained اصل implementation sudo.ws کے نام سے packaged ہے، اور اس کے programs کے آخر میں .ws suffix ہوتا ہے: sudo.ws اور visudo.ws۔
Ubuntu نے sudo-rs پر کیوں منتقل کیا
sudo setuid root ہے۔ سسٹم کا کوئی بھی صارف اسے شروع کر سکتا ہے، اور یہ مکمل مراعات کے ساتھ شروع ہوتا ہے، اس لیے اس کے اندر موجود memory bug مقامی root exploit بن جاتا ہے۔ CVE-2021-3156 بھی بالکل ایسا ہی مسئلہ تھا: heap buffer overflow جس تک کوئی بھی مقامی صارف پہنچ سکتا تھا، اور یہ تقریباً دس سال تک released code میں موجود رہا۔ Rust اس نوعیت کے bug کو compile time پر پکڑ لیتا ہے، اور rewrite کی بنیادی وجہ یہی ہے۔
دوسری وجہ scope ہے، اور یہی وجہ آپ کی configuration پر اثر ڈالتی ہے۔ اصل sudo نے تین دہائیوں کے دوران features کا بڑا مجموعہ حاصل کیا، اور ہر feature مزید code ہے جو root کے طور پر چلتا ہے۔ sudo-rs جان بوجھ کر اس کا ایک subset implement کرتا ہے۔ اس کے مصنفین نے جن چیزوں کو کم استعمال ہونے والا یا براہ راست نقصان دہ سمجھا، انہیں شامل نہیں کیا۔ اس لیے sudoers کا وہ construct جو برسوں سے کام کر رہا تھا، بالکل موجود نہ بھی ہو سکتا ہے۔ آپ کا wildcard rule بھی انہی میں سے ایک ہے۔
Memory safety ایک قسم کے bug کو ختم کرتی ہے۔ اس سے پروگرام bug سے پاک نہیں ہو جاتا، اور default بننے کے بعد sudo-rs کے اپنے security fixes بھی released ہوئے ہیں۔ اسے بھی دوسری software کی طرح patch کریں۔
کون سے sudoers قواعد اب بھی کام کرتے ہیں
فائل وہی ہے۔ sudo-rs /etc/sudoers اور /etc/sudoers.d/ میں موجود drop-in فائلیں پڑھتا ہے، اور سرور آپریٹر کے عام طور پر لکھے جانے والے یہ قواعد معاونت یافتہ ہیں:
deploy ALL=(ALL:ALL) ALL، اور گروپ کی صورتیں، مثلاً%sudo ALL=(ALL:ALL) ALLNOPASSWD:اورPASSWD:tagsUser_Alias،Runas_Alias،Host_AliasاورCmnd_Alias- exact argument list کے ساتھ command، مثلاً
/usr/bin/systemctl restart app-api ""کے بعد آنے والی command، جو command کو صرف بغیر arguments کے چلانے کی اجازت دیتی ہے- آخری argument کے طور پر
*کے بعد آنے والی command، جو آخر میں آنے والے کسی بھی arguments کی اجازت دیتی ہے /پر ختم ہونے والا directory path، جو اس directory میں موجود کسی بھی command کی اجازت دیتا ہے!، کسی فہرست سے command خارج کرنے کے لیےDefaultsکا مفید subset، جس میںsecure_path،env_keep،env_check،timestamp_timeout،passwd_tries،editor،umask،targetpw،rootpwاورuse_ptyشامل ہیں
دو defaults مختلف انداز میں کام کرتے ہیں اور اکثر لوگوں کو الجھن میں ڈالتے ہیں۔ sudo-rs میں env_reset کو بند نہیں کیا جا سکتا: یہ ہمیشہ فعال رہتا ہے۔ use_pty پہلے سے فعال ہوتا ہے، اس لیے command اپنے الگ pseudo-terminal میں چلتی ہے۔
آپ کا wildcard sudoers rule match ہونا کیوں بند ہو گیا
Wildcards کی اجازت اب بھی ایک جگہ ہے: command کا file name۔ %ops ALL = /sbin/fsck* کا rule اب بھی sudo fsck اور sudo fsck_exfat کی اجازت دیتا ہے، کیونکہ * اس path کا حصہ ہے جسے filesystem کے خلاف match کیا جا رہا ہے۔
argument list کے اندر sudo-rs صرف دو special forms قبول کرتا ہے، اور ان میں سے کوئی بھی pattern نہیں ہے۔ "" کا مطلب ہے کہ کوئی argument نہیں ہے۔ آخر میں موجود * کا مطلب ہے کہ آخر میں کوئی بھی arguments آ سکتے ہیں۔ ہر دوسرے argument کا موازنہ literal text کے طور پر کیا جاتا ہے۔ اس لیے %ops ALL = /sbin/service ntp * درست ہے، کیونکہ ntp literal ہے اور * آخر میں ہے۔ تاہم، اس طرح کا rule آپ کی مطلوبہ کوئی اجازت نہیں دیتا:
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart app-*app-* ایک argument کے درمیان موجود pattern ہے۔ sudo-rs اسے expand نہیں کرتا، اس لیے یہ rule systemctl restart app-api کو cover نہیں کرتا اور sudo command مسترد کر دیتا ہے۔ اپنے server پر کسی بھی rule کے بارے میں حقیقت جاننے کے لیے دو commands مدد دیتی ہیں: sudo -l -U deploy کو root کے طور پر چلانے سے معلوم ہوتا ہے کہ وہ account حقیقت میں کون سے commands چلا سکتا ہے، جبکہ sudo visudo -c بتاتا ہے کہ file parse ہوتی ہے یا نہیں۔ بے ترتیب editing شروع کرنے سے پہلے انہیں چلائیں۔
وائلڈ کارڈ rule ہمیشہ ایک security hole تھی
اصل sudo میں آپ کے درج کردہ arguments کو ایک string میں جوڑ کر rule کی argument string سے glob کے ذریعے match کیا جاتا ہے۔ glob whitespace سے بھی match کرتا ہے۔ یہی وہ نکتہ ہے جسے تقریباً سب نظر انداز کر دیتے ہیں۔
sudo-rs documentation اس کی سب سے واضح مثال پیش کرتی ہے۔ /bin/rm *.txt کا rule، sudo rm -rf /home .txt کی بھی اجازت دیتا ہے، کیونکہ واحد *، -rf /home کو نگل لیتا ہے اور joined string پھر بھی .txt پر ختم ہوتی ہے۔ اس rule کا مطلب بظاہر "صرف text files" ہے۔ اصل مطلب یہ ہے: "کوئی بھی arguments، بشرطیکہ line .txt پر ختم ہو۔"
یہی بات systemctl کی مثال پر بھی لاگو ہوتی ہے۔ چونکہ arguments کا موازنہ ایک joined string کے طور پر کیا جاتا ہے، اس لیے آخر میں موجود pattern اس کے بعد append کیے گئے ہر متن سے بھی match کر جاتا ہے۔ چنانچہ restart app-*، restart app-api اور caller کی طرف سے شامل کیے گئے مزید arguments، سب کو allow کرتا ہے۔ کسی argument کے اندر موجود pattern، اس کے اردگرد موجود arguments کو بھی بے اثر کر دیتا ہے، جبکہ command کی طاقت arguments ہی میں ہوتی ہے۔ sudo-rs اس construct کو محفوظ بنانے کی کوشش کرنے کے بجائے اسے مسترد کرتا ہے، کیونکہ اس کی کوئی عمومی محفوظ شکل موجود نہیں۔
وائلڈ کارڈ کو واضح command list سے تبدیل کریں
زیادہ تر وائلڈ کارڈ rules اس لیے موجود ہوتے ہیں کہ کسی نے چار lines ٹائپ نہیں کرنا چاہیں۔ چاروں lines ٹائپ کریں۔
Cmnd_Alias APP_RESTART = /usr/bin/systemctl restart app-api, /usr/bin/systemctl restart app-worker
Cmnd_Alias APP_STATUS = /usr/bin/systemctl status app-api, /usr/bin/systemctl status app-worker
deploy ALL=(root) NOPASSWD: APP_RESTART, APP_STATUSpath درست رکھیں۔ جس system میں binary /usr/bin/systemctl ہو، وہاں /bin/systemctl کا نام دینے والا rule کبھی match نہیں ہوتا۔ اس کی failure بالکل permissions کے مسئلے جیسی دکھائی دیتی ہے۔ command -v systemctl سے تصدیق کریں اور اس کا output paste کریں۔
Rule کو /etc/sudoers میں رکھنے کے بجائے اپنی الگ drop-in file میں رکھیں، تاکہ package upgrade آپ کی edit سے متصادم نہ ہو:
sudo visudo -f /etc/sudoers.d/90-deploy
sudo visudo -c
sudo -l -U deployFile کا نام dot کے بغیر اور آخری tilde کے بغیر رکھیں۔ اصل sudo sudoers.d میں ان files کو نظر انداز کرتا ہے جن کے نام میں dot ہو۔ اس لیے 90-deploy.conf ایک عام silent no-op ہے، اور اس convention پر عمل کرنے میں کوئی اضافی محنت نہیں لگتی۔
جب فہرست طویل ہو جائے تو root کی ملکیت والا wrapper استعمال کریں
جب اجازت یافتہ set اتنا بڑا ہو کہ اسے فہرست میں شامل کرنا مشکل ہو، تو یہ فیصلہ sudoers سے نکال کر ایک ایسے چھوٹے program میں منتقل کریں جس کا مالک root ہو۔
sudo tee /usr/local/sbin/app-restart >/dev/null <<'EOF'
#!/bin/sh
set -eu
case "${1:-}" in
app-api|app-worker) ;;
*) echo "app-restart: not allowed: ${1:-}" >&2; exit 1 ;;
esac
exec /usr/bin/systemctl restart "$1"
EOF
sudo chown root:root /usr/local/sbin/app-restart
sudo chmod 0755 /usr/local/sbin/app-restart
ls -l /usr/local/sbin/app-restartاس کے بعد sudoers میں صرف ایک command درج کی جاتی ہے:
deploy ALL=(root) NOPASSWD: /usr/local/sbin/app-restart *آخر میں موجود * یہاں قابل قبول ہے، کیونکہ کیا اجازت ہے، اس کا فیصلہ sudo نہیں بلکہ script کرتی ہے۔ یہ صرف اسی وقت محفوظ ہے جب script کا مالک root ہو اور کوئی دوسرا اسے writable نہ بنا سکے۔ اگر deploy file میں لکھ سکتا ہو تو deploy اس کا content تبدیل کر کے root کے طور پر کچھ بھی چلا سکتا ہے، جو اس wildcard rule سے بھی زیادہ خطرناک ہے جسے آپ نے ہٹایا ہے۔ ls -l سے mode چیک کریں۔ اگر output آپ کے لیے واضح نہ ہو تو drwxr-xr-x permission string پڑھنا سیکھنے میں پانچ منٹ لگتے ہیں۔ یہی rule directory پر بھی لاگو ہوتا ہے: account کے لیے /usr/local/sbin writable نہیں ہونا چاہیے، کیونکہ writable directory کا مطلب ہے کہ file کو مکمل طور پر تبدیل کیا جا سکتا ہے۔
کمانڈ کو sudo rule کے بجائے اس کے اپنے account کے تحت چلائیں
اکثر بہتر سوال یہ ہوتا ہے کہ اس کمانڈ کو آخر root کی ضرورت کیوں ہے۔ جو service اپنے الگ user کے طور پر چلتی ہے، اسے وہی user manage کر سکتا ہے، اور sudoers میں کسی line کی ضرورت نہیں رہتی۔ System units کے لیے systemd یہ فیصلہ پہلے ہی polkit کو سونپتا ہے، اس لیے ایک rule میں ایک unit اور ایک operator کا نام دیا جا سکتا ہے:
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "app-api.service" &&
subject.user == "deploy") {
return polkit.Result.YES;
}
});اسے /etc/polkit-1/rules.d/50-app-api.rules کے طور پر محفوظ کریں، اور deploy بغیر کسی sudo کے systemctl restart app-api چلا سکتا ہے۔ اسے اسی context سے test کریں جس میں یہ استعمال ہوگی، کیونکہ جو rule آپ کے SSH session میں کام کرتی ہے، اسے استعمال پر انحصار کرنے سے پہلے cron سے بھی verify کرنا ضروری ہے۔ دونوں صورتوں میں کام کرنے والا account صرف اسی کام کے لیے موجود ہونا چاہیے۔ یہی اصول VPS پر کم سے کم مراعات والے user accounts کے پیچھے بھی ہے۔
sudo-rs میں مزید کیا شامل نہیں ہے
sudo -E نافذ نہیں کیا گیا۔ اس کے بجائے مطلوبہ variables کو Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY" کے ساتھ نام دیں، اور یاد رکھیں کہ env_reset ہمیشہ فعال رہتا ہے، اس لیے جو کچھ محفوظ نہ کیا جائے وہ صاف کر دیا جاتا ہے۔
LDAP میں مرکزی sudoers storage دستیاب نہیں ہے۔ sudoers.ldap اور cvtsudoers نافذ نہیں کیے گئے، اور sudo-ldap package کو 26.04 میں ہٹا دیا گیا تھا۔ PAM یا SSSD کے ذریعے LDAP authentication اب بھی کام کرتی ہے۔ دائرۂ کار سے باہر صرف directory میں policy رکھنے والا حصہ ہے۔
INTERCEPT نافذ نہیں کیا گیا۔ اس کا مقصد کسی مجاز command سے shell escapes کو روکنا تھا۔ ویسے بھی یہ عزم رکھنے والے user کے خلاف مؤثر نہیں تھا۔ اگر کوئی rule کسی شخص کو root کے طور پر editor یا interpreter چلانے دیتا ہے تو اسے root حاصل ہے، اور sudo کا کوئی option اس حقیقت کو تبدیل نہیں کرتا۔
Session recording نافذ نہیں کی گئی، اس لیے I/O log اور sudoreplay موجود نہیں ہیں۔ Logging صرف syslog کو بھیجی جاتی ہے، اور اسے کسی دوسری جگہ redirect کرنے کے لیے logfile option موجود نہیں ہے۔ لہٰذا sudo کے messages وہیں پہنچتے ہیں جہاں آپ کا system پہلے سے syslog بھیجتا ہے۔
کیا آپ کو sudo.ws پر واپس جانا چاہیے؟
آپ واپس جا سکتے ہیں، اور 26.04 سائیکل کے دوران اصل پیکیج اسی وجہ سے دستیاب رہتا ہے۔
sudo apt install sudo.ws
update-alternatives --config sudo
sudo update-alternatives --set sudo /usr/bin/sudo.ws--config کے output سے درست paths نقل کریں، اس صفحے سے نہیں، کیونکہ آپ کا اپنا system اسی فہرست کو قبول کرے گا۔ بعد میں sudo-rs پر واپس جانے کے لیے اسی فہرست میں موجود sudo-rs binary path کو alternative کے طور پر set کریں۔
sudo پر اثر انداز ہونے والی کسی بھی تبدیلی سے پہلے دوسری SSH session کھلی رکھیں، اس میں login کریں اور اسے idle رہنے دیں۔ اگر sudoers file parse نہ ہو سکے، یا alternative ایسی binary کی طرف اشارہ کرے جو installed نہ ہو، تو remote box پر root بننے کا کوئی راستہ باقی نہیں رہ سکتا۔ یہ عادت ہر اس کام کا حصہ ہونی چاہیے جو آپ نئے VPS کے پہلے دس منٹ میں کرتے ہیں۔
واپس جانے کے عمل کو fix کے بجائے deadline سمجھیں۔ اس سے rules کو درست طریقے سے دوبارہ لکھنے کے لیے آپ کو ایک ہفتہ ملتا ہے۔ یہ rewrite اپنی جگہ بھی ضروری ہے، کیونکہ آپ جو بھی wildcard rule حذف کرتے ہیں، وہ اپنے مصنف کے اندازے سے زیادہ اجازت دے رہا تھا۔
FAQ
Ubuntu 26.04 میں میرا sudoers wildcard rule کیوں کام کرنا بند ہو گیا؟
کیونکہ Ubuntu 26.04 LTS میں sudo-rs کو default sudo منتخب کیا گیا ہے، اور sudo-rs کسی command کے arguments کے اندر wildcard patterns کو match نہیں کرتا۔ یہ command کے file name میں wildcard کی اجازت دیتا ہے، "" کو no arguments کے معنی میں لیتا ہے، اور آخری argument کے طور پر صرف ایک * قبول کرتا ہے۔ /usr/bin/systemctl restart app-* جیسا rule کسی argument کے درمیان pattern رکھتا ہے، اس لیے یہ کوئی اجازت نہیں دیتا اور command مسترد ہو جاتی ہے۔ root کے طور پر sudo -l -U deploy چلائیں تاکہ معلوم ہو سکے کہ account کو حقیقتاً کیا اجازت حاصل ہے، پھر rule کو exact commands یا root-owned wrapper script سے تبدیل کریں۔
Ubuntu 26.04 میں اصل sudo پر واپس کیسے جاؤں؟
اصل package کے طور پر sudo.ws دستیاب ہے۔ اسے sudo apt install sudo.ws کے ذریعے install کریں، پھر sudo update-alternatives --set sudo /usr/bin/sudo.ws سے alternative کو اس کی طرف مقرر کریں۔ پہلے update-alternatives --config sudo چلائیں تاکہ آپ کے system میں دستیاب exact paths دیکھ سکیں، اور تبدیلی کے دوران دوسری SSH session کھلی رکھیں۔ اس سے sudo-ldap واپس نہیں آتا، کیونکہ implementation سے قطع نظر اسے 26.04 سے ہٹا دیا گیا ہے۔
کیا sudo-rs وہی /etc/sudoers file پڑھتا ہے؟
جی ہاں۔ sudo-rs /etc/sudoers اور /etc/sudoers.d/ کے تحت موجود drop-in files پڑھتا ہے۔ Users، groups، aliases، run-as specifications اور NOPASSWD tag کے لیے syntax بھی وہی ہے۔ یہ sudoers language کا ایک subset implement کرتا ہے، اس لیے فرق ان constructs کی صورت میں ظاہر ہوتے ہیں جو موجود نہیں، نہ کہ ان constructs کی صورت میں جو مختلف طریقے سے کام کرتے ہیں۔ sudo visudo سے edit کریں، پھر session بند کرنے سے پہلے sudo visudo -c سے تصدیق کریں۔
sudo-rs میں sudo -E کی جگہ کیا استعمال ہوتا ہے؟
sudo -E implement نہیں کیا گیا، اور اصل sudo میں بھی اس کے استعمال کی حوصلہ شکنی کی جاتی تھی، کیونکہ root process کو ایسا environment دینا جسے caller control کرتا ہو، اس process کے رویے کو تبدیل کرنے کا معروف طریقہ ہے۔ sudoers میں صرف وہ variables نامزد کریں جن کی واقعی ضرورت ہے، مثلاً Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY" جیسی line کے ذریعے۔ sudo-rs میں env_reset ہمیشہ enabled رہتا ہے اور اسے disabled نہیں کیا جا سکتا، اس لیے ہر وہ variable جسے آپ برقرار نہیں رکھتے، clear کر دیا جاتا ہے۔