Hãy xem samba để biết ví dụ về việc này có thể được thực hiện. Các samba daemon chạy như root nhưng dĩa và giả định các thông tin của một người dùng bình thường càng sớm càng tốt.
Hệ thống Unix có hai bộ thông tin xác thực riêng biệt: id người dùng/nhóm thực và id người dùng/nhóm hiệu quả. Bộ thực sự xác định bạn thực sự là ai và tập hợp hiệu quả xác định những gì bạn có thể truy cập. Bạn có thể thay đổi uid/gid hiệu quả như bạn vui lòng nếu bạn là root — bao gồm cả người dùng thông thường và ngược lại — khi id người dùng/nhóm thực của bạn vẫn còn trong quá trình chuyển đổi. Vì vậy, một cách khác để làm điều này trong một quá trình duy nhất là sử dụng seteuid/gid
để áp dụng các quyền của người dùng khác nhau qua lại khi cần. Nếu daemon máy chủ của bạn chạy dưới dạng root hoặc có CAP_SETUID
thì điều này sẽ được cho phép. Tuy nhiên, lưu ý rằng nếu bạn có khả năng chuyển đổi uid/gid hiệu quả khi ứng dụng của bạn bị lật đổ, thì lật đổ đó có thể chuyển đổi uid/gid thành 0 và bạn có thể có một bảo mật nghiêm trọng dễ bị tổn thương. Đây là lý do tại sao bạn nên loại bỏ tất cả các đặc quyền vĩnh viễn càng sớm càng tốt, bao gồm cả người dùng thực sự của bạn uid/gid.
Vì lý do này bình thường và an toàn hơn để có một ổ cắm nghe duy nhất chạy dưới dạng gốc, sau đó tắt và thay đổi cả id người dùng thực và hiệu quả bằng cách gọi setuid
. Sau đó, nó không thể thay đổi trở lại. Quá trình chia đôi của bạn sẽ có ổ cắm là accept()
ed vì nó là một ngã ba. Mỗi quá trình chỉ đóng các bộ mô tả tập tin mà chúng không cần; các ổ cắm vẫn còn sống khi chúng được tham chiếu bởi các bộ mô tả tập tin trong các quy trình ngược lại. Bạn cũng có thể thử và thực thi các điều khoản bằng cách kiểm tra riêng từng cá nhân, nhưng tôi hy vọng rõ ràng rằng điều này có khả năng xảy ra lỗi, có nhiều trường hợp cạnh và có nhiều khả năng xảy ra lỗi hơn (ví dụ: làm việc với POSIX ACL trừ khi bạn thực hiện cụ thể quá).
Vì vậy, bạn có ba lựa chọn:
- Fork và
setgid()
/setuid()
cho người dùng mà bạn muốn. Nếu giao tiếp là bắt buộc, hãy sử dụng pipe(2)
hoặc socketpair(2)
trước khi bạn ngã ba.
- Không ngã ba và
seteuid()
/setegid()
xung quanh khi cần (ít an toàn: có khả năng dễ dàng xâm phạm máy chủ của bạn).
- Không gây rối với thông tin đăng nhập hệ thống; thực thi quyền cho phép theo cách thủ công (kém an toàn hơn: có nhiều khả năng nhận ủy quyền sai).
Nếu bạn cần liên lạc với daemon, thì có thể khó thực hiện nó xuống ổ cắm hoặc ống, tùy chọn đầu tiên thực sự là cách bảo mật phù hợp. Xem ví dụ how ssh does privilege separation. Bạn cũng có thể xem xét nếu có thể thay đổi kiến trúc của bạn vì vậy thay vì bất kỳ thông tin liên lạc, quá trình chỉ có thể chia sẻ một số bộ nhớ hoặc không gian đĩa thay thế.
Bạn đề cập đến việc bạn xem xét việc có một quá trình riêng biệt chạy cho mỗi người dùng, nhưng cần một cổng TCP đang nghe. Bạn vẫn có thể làm điều này. Chỉ cần có một daemon tổng thể lắng nghe trên cổng TCP và gửi các yêu cầu tới mỗi daemon người dùng và giao tiếp theo yêu cầu (ví dụ: thông qua các socket của miền Unix). Điều này thực sự sẽ gần giống như có một daemon chủ forking; Tôi nghĩ rằng sau này sẽ trở nên dễ dàng hơn để thực hiện.
Đọc thêm: trang chủ credentials(7)
. Cũng lưu ý rằng Linux có hệ thống tập tin uid/gids; điều này gần giống như uid/gids hiệu quả ngoại trừ những thứ khác như gửi tín hiệu. Nếu người dùng của bạn không có quyền truy cập trình bao và không thể chạy mã tùy ý thì bạn không cần phải lo lắng về sự khác biệt.
Nguồn
2011-02-13 23:08:35
Cảm ơn bạn đã có câu trả lời rất hay! Nó sẽ có thể tạo ra một quá trình tổng thể lắng nghe trên một cổng và sau đó chuyển tiếp dữ liệu đến một quá trình trên một kết nối socket? Đó có phải là những gì bạn đang nói trong đoạn thứ hai của bạn không? –
Vâng, đúng vậy, và bạn có thể làm điều đó. Tuy nhiên, dựa trên tất cả mọi thứ bạn nói tôi khá chắc chắn rằng nó sẽ được dễ dàng hơn và đơn giản hơn cho bạn để thực hiện một daemon thầy chủ forking và có các đặc quyền thả con.Quá trình chia sẽ tự động có quyền truy cập vào socket yêu cầu giống như daemon chủ; không cần phải truyền đạt phần đó. –
OK. Tôi đang tìm một giải pháp mà sẽ làm việc tốt với Qt là tốt, mặc dù nó không phải là một yêu cầu. Vì vậy, tôi xem xét điều đó khi quyết định cách tiếp cận đúng. –