Saya sedang mengerjakan modul Linux-PAM dan saya mengimplementasikan fungsi ini untuk mendapatkan pengguna.

pub fn get_user(pamh: PamHandleT) -> PamResult<&'static CStr> {
    let mut raw_user: *const c_char = ptr::null();
    let r = unsafe { pam_get_user(pamh, &mut raw_user, ptr::null()) };
    if raw_user.is_null() {
        Err(r)
    } else {
        let user = unsafe {CStr::from_ptr(raw_user)};
        Ok(user)
    }
}

pam_get_user adalah fungsi C dari libpam yang mengembalikan * const c_char melalui argumen kedua. Dokumentasi PAM menyatakan bahwa saya tidak boleh membebaskan penunjuk itu untuk memungkinkan interoperabilitas dengan modul lain.

Dengan menggunakan masa pakai 'static untuk nilai pengembalian, saya yakin nilai ini tidak akan dialokasikan, apakah itu benar? Mungkin saya bisa menyalin nilainya untuk menggunakannya dengan cara yang lebih idiomatis Rust, bagaimana saya bisa melakukannya?

0
Nautigsam 12 Mei 2021, 09:43

2 jawaban

Jawaban Terbaik

CStr bertanggung jawab untuk menangani nilai dan berbeda dengan CString ia tidak mengalokasikan atau membatalkan alokasi memori, seperti str dan String. Anda cukup memberikan pointer ke sana dan harus memastikan persyaratannya. Pastikan untuk membaca std::ffi::CStr dengan cermat dan memahami apa yang kamu lakukan.

Kode Anda terlihat baik-baik saja sejauh ini, jadi Anda harus siap untuk pergi.

1
hellow 12 Mei 2021, 07:16

Anda, mungkin, perlu membuat nilai yang dimiliki. Ini akan mengalokasikan sekalipun.

pub fn get_user(pamh: PamHandleT) -> PamResult<CString> {
    let mut raw_user: *const c_char = ptr::null();
    let r = unsafe { pam_get_user(pamh, &mut raw_user, ptr::null()) };
    if raw_user.is_null() {
        Err(r)
    } else {
        let user = unsafe {CStr::from_ptr(raw_user)};
        Ok(user.to_owned())
    }
}

Jika Anda ingin menghindari alokasi, Anda harus membuat beberapa objek konteks.

"Fungsi pam_end mengakhiri transaksi PAM dan merupakan fungsi terakhir yang harus dipanggil aplikasi dalam konteks PAM. Setelah kembali, pamh handle tidak lagi valid dan semua memori yang terkait dengannya akan menjadi tidak valid."

struct TransactionContext{
   pamh: PamHandleT
}

impl Drop for TransactionContext{
  fn drop(&mut self){
     unsafe {pam_end(pamh);}
  }
}

pub fn get_user(pamh: &TransactionContext) -> PamResult<&CStr> {
    let mut raw_user: *const c_char = ptr::null();
    let r = unsafe { pam_get_user(pamh.pamh, &mut raw_user, ptr::null()) };
    if raw_user.is_null() {
        Err(r)
    } else {
        let user = unsafe {CStr::from_ptr(raw_user)};
        Ok(user)
    }
}

Ini akan membuat CStr hasil memiliki masa pakai yang sama dengan TransactionContext dan pemeriksa pinjaman akan memastikan bahwa Anda tidak menggunakan CStr hasil setelah TransactionContext Anda dijatuhkan.

1
Angelicos Phosphoros 12 Mei 2021, 14:56