unit kern_prot; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface const MAXLOGNAME =17; { max login name length (incl. NUL) } function sys_getpid():Integer; function sys_getppid():Integer; function sys_getpgrp():Integer; function sys_getpgid(pid:Integer):Integer; function sys_getsid(pid:Integer):Integer; function sys_getuid():Integer; function sys_geteuid():Integer; function sys_getgid():Integer; function sys_getegid():Integer; function sys_getgroups(gidsetsize:DWORD;gidset:PInteger):Integer; function sys_setsid():Integer; function sys_setpgid(pid,pgid:Integer):Integer; function sys_setuid(uid:Integer):Integer; function sys_seteuid(euid:Integer):Integer; function sys_setgid(gid:Integer):Integer; function sys_setegid(egid:Integer):Integer; function sys_setgroups(gidsetsize:DWORD;gidset:PInteger):Integer; function sys_setreuid(ruid,euid:Integer):Integer; function sys_setregid(rgid,egid:Integer):Integer; function sys_setresuid(ruid,euid,suid:Integer):Integer; function sys_setresgid(rgid,egid,sgid:Integer):Integer; function sys_getresuid(ruid,euid,suid:PInteger):Integer; function sys_getresgid(rgid,egid,sgid:PInteger):Integer; function sys_issetugid():Integer; function sys_getlogin(namebuf:PChar;namelen:DWORD):Integer; function sys_setlogin(namebuf:PChar):Integer; function p_cansignal(signum:Integer):Integer; implementation uses errno, systm, signal, kern_thr, kern_proc; { * System calls related to processes and protection } function sys_getpid():Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); td^.td_retval[0]:=p_proc.p_pid; Exit(0); end; function sys_getppid():Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); td^.td_retval[0]:=1; //psevodo parent id Exit(0); end; { * Get process group ID; note that POSIX getpgrp takes no parameter. } function sys_getpgrp():Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); td^.td_retval[0]:=0; //psevodo group id Exit(0); end; { Get an arbitary pid's process group id } function sys_getpgid(pid:Integer):Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); if (pid<>0) and (pid<>p_proc.p_pid) then begin Exit(ESRCH); end; td^.td_retval[0]:=0; //psevodo group id Exit(0); end; { * Get an arbitary pid's session id. } function sys_getsid(pid:Integer):Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); if (pid<>0) and (pid<>p_proc.p_pid) then begin Exit(ESRCH); end; td^.td_retval[0]:=0; //psevodo session id Exit(0); end; function sys_getuid():Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); td^.td_retval[0]:=0; //psevodo user id Exit(0); end; function sys_geteuid():Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); td^.td_retval[0]:=0; //psevodo user id Exit(0); end; function sys_getgid():Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); td^.td_retval[0]:=0; //psevodo group id Exit(0); end; { * Get effective group ID. The 'egid' is groups[0], and could be obtained * via getgroups. This syscall exists because it is somewhat painful to do * correctly in a library function. } function sys_getegid():Integer; var td:p_kthread; begin td:=curkthread; if (td=nil) then Exit(-1); td^.td_retval[0]:=0; //psevodo group id Exit(0); end; function sys_getgroups(gidsetsize:DWORD;gidset:PInteger):Integer; const cr_ngroups=1; var td:p_kthread; ngrp:Integer; groups:array[0..0] of Integer; begin td:=curkthread; if (td=nil) then Exit(-1); if (gidsetsize < cr_ngroups) then begin if (gidsetsize=0) then ngrp:=0 else Exit(EINVAL); end else ngrp:=cr_ngroups; groups[0]:=0; if (gidsetsize > 0) then Result:=copyout(@groups, gidset, ngrp * sizeof(Integer)); if (Result=0) then td^.td_retval[0]:=ngrp; end; function sys_setsid():Integer; begin Exit(EPERM); end; { * set process group (setpgid/old setpgrp) * * caller does setpgid(targpid, targpgid) * * pid must be caller or child of caller (ESRCH) * if a child * pid must be in same session (EPERM) * pid can't have done an exec (EACCES) * if pgid<>pid * there must exist some pid in same session having pgid (EPERM) * pid must not be session leader (EPERM) } function sys_setpgid(pid,pgid:Integer):Integer; begin if (pid<>0) and (pid<>p_proc.p_pid) then begin Exit(ESRCH); end; Exit(EPERM); end; { * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD * compatible. It says that setting the uid/gid to euid/egid is a special * case of 'appropriate privilege'. Once the rules are expanded out, this * basically means that setuid(nnn) sets all three id's, in all permitted * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) * does not set the saved id - this is dangerous for traditional BSD * programs. For this reason, we *really* do not want to set * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. } function sys_setuid(uid:Integer):Integer; begin Result:=0; if (uid<>0) then //not psevodo user id begin Exit(EPERM); end; end; function sys_seteuid(euid:Integer):Integer; begin Result:=0; if (euid<>0) then //not psevodo user id begin Exit(EPERM); end; end; function sys_setgid(gid:Integer):Integer; begin Result:=0; if (gid<>0) then //not group user id begin Exit(EPERM); end; end; function sys_setegid(egid:Integer):Integer; begin Result:=0; if (egid<>0) then //not group user id begin Exit(EPERM); end; end; function sys_setgroups(gidsetsize:DWORD;gidset:PInteger):Integer; const ngroups_max=1023; var groups:array[0..0] of Integer; begin Result:=0; if (gidsetsize > ngroups_max + 1) then Exit(EINVAL); Result:=copyin(gidset, @groups, 1 * sizeof(Integer)); if (Result<>0) then Exit; if (gidsetsize<>1) then Exit(EPERM); if (groups[0]<>0) then //not group user id begin Exit(EPERM); end; end; function sys_setreuid(ruid,euid:Integer):Integer; begin Result:=0; if (ruid<>0) and (ruid<>-1) then //not psevodo user id begin Exit(EPERM); end; if (euid<>0) and (euid<>-1) then //not psevodo user id begin Exit(EPERM); end; end; function sys_setregid(rgid,egid:Integer):Integer; begin Result:=0; if (rgid<>0) and (rgid<>-1) then //not psevodo group id begin Exit(EPERM); end; if (egid<>0) and (egid<>-1) then //not psevodo group id begin Exit(EPERM); end; end; { * setresuid(ruid, euid, suid) is like setreuid except control over the saved * uid is explicit. } function sys_setresuid(ruid,euid,suid:Integer):Integer; begin Result:=0; if (ruid<>0) and (ruid<>-1) then //not psevodo user id begin Exit(EPERM); end; if (euid<>0) and (euid<>-1) then //not psevodo user id begin Exit(EPERM); end; if (suid<>0) and (suid<>-1) then //not psevodo session id begin Exit(EPERM); end; end; { * setresgid(rgid, egid, sgid) is like setregid except control over the saved * gid is explicit. } function sys_setresgid(rgid,egid,sgid:Integer):Integer; begin Result:=0; if (rgid<>0) and (rgid<>-1) then //not psevodo group id begin Exit(EPERM); end; if (egid<>0) and (egid<>-1) then //not psevodo group id begin Exit(EPERM); end; if (sgid<>0) and (sgid<>-1) then //not psevodo group id begin Exit(EPERM); end; end; function sys_getresuid(ruid,euid,suid:PInteger):Integer; var cr_uid:Integer; error1,error2,error3:Integer; begin cr_uid:=0; //psevodo user id error1:=0; error2:=0; error3:=0; if (ruid<>nil) then error1:=copyout(@cr_uid, ruid, sizeof(Integer)); if (euid<>nil) then error2:=copyout(@cr_uid, euid, sizeof(Integer)); if (suid<>nil) then error3:=copyout(@cr_uid, suid, sizeof(Integer)); if (error1<>0) then begin Exit(error1); end else if (error2<>0) then begin Exit(error2); end else begin Exit(error3); end; end; function sys_getresgid(rgid,egid,sgid:PInteger):Integer; var cr_gid:Integer; error1,error2,error3:Integer; begin cr_gid:=0; //psevodo group id error1:=0; error2:=0; error3:=0; if (rgid<>nil) then error1:=copyout(@cr_gid, rgid, sizeof(Integer)); if (egid<>nil) then error2:=copyout(@cr_gid, egid, sizeof(Integer)); if (sgid<>nil) then error3:=copyout(@cr_gid, sgid, sizeof(Integer)); if (error1<>0) then begin Exit(error1); end else if (error2<>0) then begin Exit(error2); end else begin Exit(error3); end; end; function sys_issetugid():Integer; begin Exit(0); end; { * Get login name, if available. } function sys_getlogin(namebuf:PChar;namelen:DWORD):Integer; var login:array[0..MAXLOGNAME-1] of AnsiChar; len:ptrint; begin if (namelen > MAXLOGNAME) then namelen:=MAXLOGNAME; login:='root'; len:=strlen(@login); if (len > namelen) then begin Exit(ERANGE); end; Exit(copyout(@login, namebuf, len)); end; { * Set login name. } function sys_setlogin(namebuf:PChar):Integer; begin //error:=priv_check(td, PRIV_PROC_SETLOGIN); Exit(EPERM); end; {- * Determine whether td may deliver the specified signal to p. * Returns: 0 for permitted, an errno value otherwise * Locks: Sufficient locks to protect various components of td and p * must be held. td must be curthread, and a lock must be * held for p. * References: td and p must be valid for the lifetime of the call } function p_cansignal(signum:Integer):Integer; begin if (curkthread=nil) then Exit(-1); { * UNIX signalling semantics require that processes in the same * session always be able to deliver SIGCONT to one another, * overriding the remaining protections. } { XXX: This will require an additional lock of some sort. } if (signum=SIGCONT) {and (td^.td_proc^.p_session=p^.p_session)} then begin Exit(0); end; { * Some compat layers use SIGTHR and higher signals for * communication between different kernel threads of the same * process, so that they expect that it's always possible to * deliver them, even for suid applications where cr_cansignal() can * deny such ability for security consideration. It should be * pretty safe to do since the only way to create two processes * with the same p_leader is via rfork(2). } if (signum >= SIGTHR) and (signum < SIGTHR + 4) then begin Exit(0); end; //Exit(cr_cansignal(td^.td_ucred, p, signum)); Exit(0); end; end.