administrators, users, they all seem to find a reason to "need" root
access. Since normally these needs are for access to particular files
or to perform very specific tasks, only a subset of root's access is
actually needed. File access should be trivial enough, just configure
the appropriate permissions or FACLs. For executable processes,
traditionally 'sudo' or 'op' would come to mind. In Solaris, however,
we could instead use RBAC and privileges, which are natively available.
Our host details for this are:
HOST: snorkle PROMPT: user@snorkle [0] OS: Solaris 10 10/09 USER: johnc ROLE: netroleFor a sample setup, we have user 'johnc' from group 'neteng' who is tasked
with managing the network interfaces and routes on a system. He will need
access to 'ifconfig', 'route', 'dladm', 'snoop', and 'tcpdump'. Since we
won't give him root access, let's see how he fares with each command
and what we can do to help. Starting simple, 'johnc' uses 'ifconfig'
to check the available interfaces and attempt to bring "e1000g0" online:
johnc@snorkle [0] /usr/sbin/ifconfig -a lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1 inet 127.0.0.1 netmask ff000000 e1000g1: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2 inet 192.168.56.15 netmask ffffff00 broadcast 192.168.56.255 johnc@snorkle [0] /usr/sbin/ifconfig e1000g0 plumb ifconfig: cannot open link "e1000g0": Permission denied johnc@snorkle [1]As expected, he can review what's already configured but gets "Permission
denied" for trying to online "e1000g0". Being the diligent user he is,
'johnc' tries to online "e1000g0" again, but this time he uses 'ppriv'
(see note 1) to determine what's preventing him:
johnc@snorkle [1] /bin/ppriv -eD /usr/sbin/ifconfig e1000g0 plumb ifconfig[514]: missing privilege "net_rawaccess" (euid = 1002, syscall = 5) for \ "devpolicy" needed at spec_open+0xbf ifconfig[514]: missing privilege "net_rawaccess" (euid = 1002, syscall = 5) for \ "devpolicy" needed at spec_open+0xbf ifconfig[514]: missing privilege "net_rawaccess" (euid = 1002, syscall = 5) for \ "devpolicy" needed at spec_open+0xbf ifconfig: cannot open link "e1000g0": Permission deniedAlright, 'johnc' needs the "net_rawaccess" privilege to actually manage
interfaces. So that he doesn't have to keep running back to us, 'johnc'
tries the rest of the commands:
johnc@snorkle [1] /bin/ppriv -eD /usr/sbin/snoop -d e1000g1 snoop[516]: missing privilege "net_rawaccess" (euid = 1002, syscall = 5) for \ "devpolicy" needed at spec_open+0xbf snoop[516]: missing privilege "net_rawaccess" (euid = 1002, syscall = 5) for \ "devpolicy" needed at spec_open+0xbf snoop[516]: missing privilege "net_rawaccess" (euid = 1002, syscall = 5) for \ "devpolicy" needed at spec_open+0xbf snoop: cannot open "e1000g1": Permission denied johnc@snorkle [1] /bin/ppriv -eD /usr/local/sbin/tcpdump -i e1000g1 tcpdump[874]: missing privilege "net_rawaccess" (euid = 1002, syscall = 225) for \ "devpolicy" needed at spec_open+0xbf tcpdump: e1000g1: You don't have permission to capture on that device (/dev/e1000g: Permission denied) johnc@snorkle [0] /usr/sbin/dladm show-dev -p /usr/sbin/dladm: insufficient privileges johnc@snorkle [1] /bin/ppriv -eDv /usr/sbin/dladm show-dev -p /usr/sbin/dladm: insufficient privileges johnc@snorkle [1] /usr/sbin/route add -net 192.168.75.0/24 192.168.56.2 add net 192.168.75.0/24: gateway 192.168.56.2: insufficient privileges johnc@snorkle [1] /bin/ppriv -eDv /usr/sbin/route add -net 192.168.75.0/24 192.168.56.2 route[688]: missing privilege "sys_ip_config" (euid = 1002, syscall = 4) needed \ at ip_rts_request+0x164 add net 192.168.75.0/24: gateway 192.168.56.2: insufficient privilegesAll of the above commands have failed due to missing privileges.
Aside from 'dladm', each command executed through 'ppriv' returned the
missing privileges. As a final check, 'johnc' runs 'ppriv' against
his current terminal process to see what privileges he currently has
(see note 2):
johnc@snorkle [0] /bin/ppriv $$ 501: -ksh flags = <none> E: basic I: basic P: basic L: all johnc@snorkle [0]Having returned to us with the above information, let's see what other
details we can dig up to help 'johnc'. Since RBAC and privileges
are closely related, we can check for the commands 'johnc' needs in
RBAC's execution database 'exec_attr':
root@snorkle [0] /bin/egrep 'ifconfig|snoop|tcpdump|dladm|route' /etc/security/exec_attr Network Management:solaris:cmd:::/sbin/dladm:privs=sys_net_config Network Management:solaris:cmd:::/sbin/ifconfig:uid=0 Network Management:solaris:cmd:::/sbin/route:privs=sys_ip_config Network Management:solaris:cmd:::/sbin/routeadm:euid=0; privs=proc_chroot,\ proc_owner,sys_ip_config Network Management:suser:cmd:::/usr/sbin/ifconfig:uid=0 Network Management:suser:cmd:::/usr/sbin/route:uid=0 Network Management:suser:cmd:::/usr/sbin/snoop:uid=0Based on the format for 'exec_attr', all but 'tcpdump' are part of
the preconfigured "Network Management" RBAC profile. We also see the
"sys_net_config" privilege for 'dladm' which we didn't previously know.
Reviewing 'exec_attr' for the "Network Management" profile, we see it
has 18 commands associated with it:
root@snorkle [0] grep "Network Management:" /etc/security/exec_attr | grep ":cmd:" Network Management:solaris:cmd:::/sbin/dladm:privs=sys_net_config Network Management:solaris:cmd:::/sbin/ifconfig:uid=0 Network Management:solaris:cmd:::/sbin/route:privs=sys_ip_config Network Management:solaris:cmd:::/sbin/routeadm:euid=0; privs=proc_chroot,proc_owner,\ sys_ip_config Network Management:solaris:cmd:::/usr/sbin/quaggaadm:privs=basic Network Management:solaris:cmd:::/usr/sbin/zebraadm:privs=basic Network Management:suser:cmd:::/usr/bin/netstat:uid=0 Network Management:suser:cmd:::/usr/bin/rup:euid=0 Network Management:suser:cmd:::/usr/bin/ruptime:euid=0 Network Management:suser:cmd:::/usr/bin/setuname:euid=0 Network Management:suser:cmd:::/usr/sbin/asppp2pppd:euid=0 Network Management:suser:cmd:::/usr/sbin/ifconfig:uid=0 Network Management:suser:cmd:::/usr/sbin/ipaddrsel:euid=0 Network Management:suser:cmd:::/usr/sbin/ipqosconf:euid=0 Network Management:suser:cmd:::/usr/sbin/rndc:privs=file_dac_read Network Management:suser:cmd:::/usr/sbin/route:uid=0 Network Management:suser:cmd:::/usr/sbin/snoop:uid=0 Network Management:suser:cmd:::/usr/sbin/spray:euid=0Since 'johnc' currently only needs access to 5 commands, we can create
a role for him and group 'neteng' to use. The following creates a new
role, netrole, and sets a password to it (see note 3):
root@snorkle [0] /usr/sbin/groupadd -g 10300 netrole root@snorkle [0] /usr/sbin/roleadd -u 10300 -g 10300 -c "Minimal Network Role" \ -d /export/roles/netrole -m -s /bin/pfksh netrole 64 blocks root@snorkle [0] /bin/passwd netrole New Password: Re-enter new Password: passwd: password successfully changed for netrole root@snorkle [0]Of note, in Solaris 11 (Express) a role can be configured to allow
a user to use their own login password to access the role:
root@snorkle [0] /usr/sbin/rolemod -K roleauth=user netroleSince we don't want this role associated with the default profile
(ALL), we add profile "NetRole" to 'prof_attr' and set 'netrole' with
the profile. We also set the default privileges to be those identified
above (see note 4):
root@snorkle [0] echo "NetRole:::profile managing NICs and routes:">> /etc/security/prof_attr root@snorkle [0] /usr/sbin/rolemod -P NetRole -K defaultpriv=basic,net_rawaccess,\ sys_ip_config,sys_net_config netroleAfter associating 'johnc' with role 'netrole' below via 'usermod', we
can see that our user's account hasn't been modified with a check of
'id' and review of '/etc/passwd':
root@snorkle [0] /usr/sbin/usermod -R netrole johnc root@snorkle [0] /bin/id -a johnc uid=1002(johnc) gid=1002(neteng) groups=1002(neteng) root@snorkle [0] /bin/id -a netrole uid=10300(netrole) gid=10300(netrole) groups=10300(netrole) root@snorkle [0] /bin/egrep 'johnc|netrole' /etc/passwd johnc:x:1002:1002:John Chambers:/export/home/johnc:/bin/ksh netrole:x:10300:10300:Minimal Network Role:/export/roles/netrole:/bin/pfksh root@snorkle [0] /bin/egrep 'johnc|netrole' /etc/user_attr netrole::::type=role;profiles=NetRole;defaultpriv=basic,net_rawaccess,sys_ip_config,\ sys_net_config johnc::::type=normal;roles=netrole root@snorkle [0] /bin/roles johnc netroleThe association of 'johnc' to role 'netrole' is contained within
'/etc/user_attr' and verified with 'roles' above. At this point, we've
given 'johnc' a subset of root's privileges allowing him to accomplish
only what he needs:
johnc@snorkle [0] /usr/sbin/ifconfig e1000g0 plumb ifconfig: cannot open link "e1000g0": Permission denied johnc@snorkle [1] /sbin/su - netrole Password: netrole@snorkle [0] /bin/ppriv $$ 945: -pfksh flags = <none> E: basic,net_rawaccess,sys_ip_config,sys_net_config I: basic,net_rawaccess,sys_ip_config,sys_net_config P: basic,net_rawaccess,sys_ip_config,sys_net_config L: allTo illustrate how 'johnc' can use the new 'netrole', we have 'johnc'
try to online "e1000g0" again, only to fail. We didn't give any extra
privileges to 'johnc', we gave them to 'netrole' which we can see above
after the 'su'. In the following, we see that by using role 'netrole',
'johnc' now has the access and privileges he needs:
netrole@snorkle [0] /usr/sbin/ifconfig e1000g0 plumb netrole@snorkle [0] /bin/grep snorkle /etc/hosts 192.168.56.15 snorkle loghost 10.0.23.191 snorkle-priv netrole@snorkle [0] /usr/sbin/ifconfig e1000g0 10.0.23.191 netmask 255.255.254.0 \ broadcast + up netrole@snorkle [0] /usr/sbin/ifconfig -a lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1 inet 127.0.0.1 netmask ff000000 e1000g0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 3 inet 10.0.23.191 netmask fffffe00 broadcast 10.0.23.255 ether 8:0:27:56:c2:d e1000g1: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2 inet 192.168.56.15 netmask ffffff00 broadcast 192.168.56.255 ether 8:0:27:cb:f8:20 netrole@snorkle [0] /usr/sbin/snoop -d e1000g0 Using device e1000g1 (promiscuous mode) 10.0.23.181 -> snorkle-priv ICMP Echo request (ID: 63848 Sequence number: 1) snorkle-priv -> 10.0.23.181 ICMP Echo reply (ID: 63848 Sequence number: 1) 10.0.23.181 -> snorkle-priv ICMP Echo request (ID: 63848 Sequence number: 2) snorkle-priv -> 10.0.23.181 ICMP Echo reply (ID: 63848 Sequence number: 2) <snip...> netrole@snorkle [0] /usr/local/sbin/tcpdump -i e1000g1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on e1000g1, link-type EN10MB (Ethernet), capture size 65535 bytes 18:37:10.382886 IP 10.0.23.181 > snorkle-priv: ICMP echo request, id 5993, seq 22, length 64 18:37:10.382920 IP snorkle-priv > 10.0.23.181: ICMP echo reply, id 5993, seq 22, length 64 18:37:11.383959 IP 10.0.23.181 > snorkle-priv: ICMP echo request, id 5993, seq 23, length 64 18:37:11.383999 IP snorkle-priv > 10.0.23.181: ICMP echo reply, id 5993, seq 23, length 64 <snip...> netrole@snorkle [0] /usr/sbin/dladm show-dev -p e1000g0 link=up speed=1000 duplex=full e1000g1 link=up speed=1000 duplex=full netrole@snorkle [0] /usr/sbin/route add -net 192.168.75.0/24 192.168.56.2 add net 192.168.75.0/24: gateway 192.168.56.2 netrole@snorkle [0] /bin/netstat -rn Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 127.0.0.1 U 1 0 lo0 10.0.22.0 10.0.23.191 U 1 0 e1000g0 192.168.56.0 192.168.56.15 U 1 5 e1000g1 192.168.75.0 192.168.56.2 UG 1 0 224.0.0.0 192.168.56.15 U 1 0 e1000g1 127.0.0.1 127.0.0.1 UH 1 0 lo0
Notes
Note 1: To see what privileges are available on the overall system,
execute 'ppriv -l'. To get further information, execute 'ppriv -lv'
or see the privileges(5) man page:
root@snorkle [0] /bin/ppriv -l contract_event contract_observer cpc_cpu dtrace_kernel dtrace_proc <snip...> root@snorkle [0] /bin/ppriv -lv contract_event Allows a process to request critical events without limitation. Allows a process to request reliable delivery of all events on any event queue. contract_observer Allows a process to observe contract events generated by contracts created and owned by users other than the process's effective user ID. Allows a process to open contract event endpoints belonging to contracts created and owned by users other than the process's effective user ID. cpc_cpu Allow a process to access per-CPU hardware performance counters. dtrace_kernel Allows DTrace kernel-level tracing. dtrace_proc Allows DTrace process-level tracing. Allows process-level tracing probes to be placed and enabled in processes to which the user has permissions. dtrace_user <snip...>Note 2: Default privileges allowed to a user:
johnc@snorkle [0] /bin/ppriv -v $$ 501: -ksh flags = <none> E: file_link_any,proc_exec,proc_fork,proc_info,proc_session I: file_link_any,proc_exec,proc_fork,proc_info,proc_session P: file_link_any,proc_exec,proc_fork,proc_info,proc_session L: contract_event,contract_observer,cpc_cpu,dtrace_kernel,... johnc@snorkle [0] E => effective privileges currently in effect I => privileges inherited on exec P => the maximum set of privileges for the process L => upper limit of privileges a process and its offspring can obtain "basic" privileges: file_link_any Allows a process to create hardlinks to files owned by a uid different from the process' effective uid. proc_exec Allows a process to call execve(). proc_fork Allows a process to call fork1()/forkall()/vfork() proc_info Allows a process to examine the status of processes other than those it can send signals to. Processes which cannot be examined cannot be seen in /proc and appear not to exist. proc_session Allows a process to send signals or trace processes outside its session.Note 3: The parameters for 'roleadd' are very similar to 'useradd'.
If not specified, the default role values are::
root@snorkle [0] /usr/sbin/roleadd -D group=other,1 project=default,3 basedir=/home skel=/etc/skel shell=/bin/pfsh inactive=0 expire= auths= profiles=All limitpriv= defaultpriv= lock_after_retries=Note 4: Rather than assigning privileges, we could have updated
/etc/security/exec_attr, associating each command (and tcpdump)
to the new "NetRole" profile. We didn't since this was entirely an
exercise in using privileges.
References:
Joerg Moellenkamp's site
Oracle: Managing RBAC
exec_attr(4) user_attr(4) privileges(5)
ppriv(1) roleadd(1M)