Compare commits
310 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f9124b7f7 | ||
|
|
496fc2919d | ||
|
|
905eb76cec | ||
|
|
0c821fcf0c | ||
|
|
93086e9aa7 | ||
|
|
c3cf23b00c | ||
|
|
ffd35d8902 | ||
|
|
c7b4f317f9 | ||
|
|
9b58a623f4 | ||
|
|
1a20189b83 | ||
|
|
bd102eaa35 | ||
|
|
ea04eb301d | ||
|
|
c93897a8d7 | ||
|
|
c82ed0c15e | ||
|
|
9eb191edc4 | ||
|
|
e65cc6aebc | ||
|
|
b3b1f5d4a4 | ||
|
|
bc8257cf73 | ||
|
|
dbf230e4cf | ||
|
|
2f0d14eb21 | ||
|
|
d4535015a0 | ||
|
|
14b108728a | ||
|
|
dbfad7d1c9 | ||
|
|
738d92a4bd | ||
|
|
7a3bb4d0ea | ||
|
|
a026ea6bbf | ||
|
|
5939e066db | ||
|
|
af9984bff1 | ||
|
|
0faec51bf0 | ||
|
|
5d0d784197 | ||
|
|
1aed7ae945 | ||
|
|
68ebbf9360 | ||
|
|
83db204477 | ||
|
|
456bdb78f8 | ||
|
|
8281c82e32 | ||
|
|
a6154b8572 | ||
|
|
9d37173b24 | ||
|
|
bd920ab36a | ||
|
|
1d767fb779 | ||
|
|
8eb6f8ace4 | ||
|
|
0871122443 | ||
|
|
d5b15f8633 | ||
|
|
ec1951c181 | ||
|
|
9d169ffc41 | ||
|
|
0fe42f571c | ||
|
|
b0e86b959f | ||
|
|
ea7af4e154 | ||
|
|
3d670ba7ed | ||
|
|
2f1f45d64f | ||
|
|
663824ef4c | ||
|
|
c6cab4a7ba | ||
|
|
e34f49c196 | ||
|
|
322db32971 | ||
|
|
f9831a4a1a | ||
|
|
2b22a6909d | ||
|
|
ca1d912e6b | ||
|
|
3ac8d97825 | ||
|
|
e9e8e3270f | ||
|
|
91d4ab622b | ||
|
|
b8cbc2c113 | ||
|
|
dfe95bd08b | ||
|
|
eb1d2de0e9 | ||
|
|
5f7649fb37 | ||
|
|
e367d111e5 | ||
|
|
95fd179683 | ||
|
|
c0aa8a876e | ||
|
|
6e4b2fe25d | ||
|
|
e6416fd81b | ||
|
|
186b1b7ac1 | ||
|
|
38c079366d | ||
|
|
77e39de1e6 | ||
|
|
2c542f6c65 | ||
|
|
b30e9614c3 | ||
|
|
cc7ea6e8e5 | ||
|
|
fa90ac11c8 | ||
|
|
716f3f99ce | ||
|
|
0f4347d148 | ||
|
|
8492dee663 | ||
|
|
514c1328b6 | ||
|
|
7cfe134090 | ||
|
|
df6ec1d169 | ||
|
|
b865e14f25 | ||
|
|
697901a328 | ||
|
|
9f1a43996c | ||
|
|
7273c25cc2 | ||
|
|
c0818ab01d | ||
|
|
f4cbf38ad7 | ||
|
|
0409c91a7f | ||
|
|
4faf42b31b | ||
|
|
786e44f6dd | ||
|
|
bc22009031 | ||
|
|
4ea269d23e | ||
|
|
f28660f5dd | ||
|
|
246d5c1c25 | ||
|
|
c464ec5570 | ||
|
|
b628850a09 | ||
|
|
fe159b7668 | ||
|
|
325bf584ce | ||
|
|
5cd04d03f9 | ||
|
|
ae169c4046 | ||
|
|
0dffc7c612 | ||
|
|
5d53e0bf07 | ||
|
|
b5fb1b38ee | ||
|
|
c917ed7b76 | ||
|
|
08f5577018 | ||
|
|
1021195bfe | ||
|
|
a8361e7410 | ||
|
|
7384865775 | ||
|
|
fd9d79a1a3 | ||
|
|
c44b71cec2 | ||
|
|
bbf4b79bc4 | ||
|
|
abb5c99114 | ||
|
|
88128000c9 | ||
|
|
599cc003da | ||
|
|
e7938d5a30 | ||
|
|
bd32c1c8fc | ||
|
|
fb0f702cbf | ||
|
|
a04287cf24 | ||
|
|
569bd1d54f | ||
|
|
2df8c0728d | ||
|
|
bd4dc81a82 | ||
|
|
f8642a1986 | ||
|
|
e24700fd5d | ||
|
|
18c5c6139d | ||
|
|
af0f55a625 | ||
|
|
3f09f7b6fb | ||
|
|
dfd19fc35b | ||
|
|
0407fa8813 | ||
|
|
e84df9e163 | ||
|
|
46ad1856ac | ||
|
|
87257a49a1 | ||
|
|
9d3546c695 | ||
|
|
287a9041a1 | ||
|
|
22bfaf9e26 | ||
|
|
2748b4230a | ||
|
|
6bd08f7d18 | ||
|
|
00f01dd416 | ||
|
|
01a8df79b3 | ||
|
|
9a10373ddb | ||
|
|
b065fa4741 | ||
|
|
3f35983656 | ||
|
|
c32743808d | ||
|
|
ec98f190c1 | ||
|
|
cf8101aaae | ||
|
|
4047d1fe8e | ||
|
|
6f38f43fdd | ||
|
|
dc732e7734 | ||
|
|
291c6fcc87 | ||
|
|
94d40b4521 | ||
|
|
3c9836a298 | ||
|
|
a271076041 | ||
|
|
e8c44a4c12 | ||
|
|
d041eec354 | ||
|
|
b215e9d02c | ||
|
|
994a3b463c | ||
|
|
508b968cb1 | ||
|
|
6afa2aaf9d | ||
|
|
342c934a35 | ||
|
|
49930bd3a6 | ||
|
|
7ea342579e | ||
|
|
875d2d49c1 | ||
|
|
83aa88466d | ||
|
|
607f1dd549 | ||
|
|
6baeb25038 | ||
|
|
32cfa176f2 | ||
|
|
b01bd3b139 | ||
|
|
0a7888b1fa | ||
|
|
43a917cce5 | ||
|
|
089cf55e2c | ||
|
|
316a153abb | ||
|
|
6e6494680d | ||
|
|
6155e91f4e | ||
|
|
967bfb0376 | ||
|
|
9cb21c2bdf | ||
|
|
5cb839d977 | ||
|
|
b128222477 | ||
|
|
fc95155aa4 | ||
|
|
320707fcb0 | ||
|
|
4086aed1ed | ||
|
|
096dad6305 | ||
|
|
4772689d27 | ||
|
|
1566921dd8 | ||
|
|
04062cda11 | ||
|
|
c040058fe3 | ||
|
|
c56fe7117b | ||
|
|
e2f74c347b | ||
|
|
f929bfd90b | ||
|
|
c889ebc2c9 | ||
|
|
a3a1cf6536 | ||
|
|
7e0e931519 | ||
|
|
97a76bd9e6 | ||
|
|
69332884b1 | ||
|
|
992c1723af | ||
|
|
8eee5d03fd | ||
|
|
77be9c35c7 | ||
|
|
f7ae4d48f4 | ||
|
|
1d8487d851 | ||
|
|
52aba825af | ||
|
|
25b1a8d591 | ||
|
|
5de28353d4 | ||
|
|
7b36b160f7 | ||
|
|
00e629c0ba | ||
|
|
942f1945bb | ||
|
|
69301dfa24 | ||
|
|
8762f465d4 | ||
|
|
140510de9d | ||
|
|
125a5dc309 | ||
|
|
e78be3df43 | ||
|
|
d60b59b156 | ||
|
|
6543c600d8 | ||
|
|
5070132ee6 | ||
|
|
143b97193d | ||
|
|
3f2bbcfa91 | ||
|
|
8a2e3d500c | ||
|
|
c48011d19c | ||
|
|
ebe6def4b7 | ||
|
|
a8533719ed | ||
|
|
c667083c81 | ||
|
|
e5bb71b2fd | ||
|
|
b2753b146a | ||
|
|
724442c3af | ||
|
|
b6aaaba35e | ||
|
|
fa6c58a773 | ||
|
|
8a1e92aff1 | ||
|
|
12ce42be44 | ||
|
|
915cc6bb9c | ||
|
|
2cc7da6058 | ||
|
|
142d788c81 | ||
|
|
33c6a170a5 | ||
|
|
fd4405b763 | ||
|
|
dfceca8427 | ||
|
|
54c1660969 | ||
|
|
eebcacfae8 | ||
|
|
4ed08824e5 | ||
|
|
3e942adb21 | ||
|
|
085d04c3dd | ||
|
|
ed4a0157c4 | ||
|
|
93f1f35123 | ||
|
|
9f7f3b013e | ||
|
|
5a6ddf3b57 | ||
|
|
0512c187c8 | ||
|
|
f32d4a359b | ||
|
|
401d0743af | ||
|
|
a847899b52 | ||
|
|
88c1a6d98d | ||
|
|
ef095ceef1 | ||
|
|
4c9ec2f5a4 | ||
|
|
d7add53f06 | ||
|
|
2aa7427e2b | ||
|
|
1ec36eabb2 | ||
|
|
bd3c39f1c8 | ||
|
|
258944e331 | ||
|
|
51d65f37e5 | ||
|
|
0f332f48bc | ||
|
|
a73d4aee75 | ||
|
|
7f53048875 | ||
|
|
b1a5cda91e | ||
|
|
66b7bc0dcf | ||
|
|
eaaac67d4f | ||
|
|
3cc3948d71 | ||
|
|
08096ed24a | ||
|
|
92a678c250 | ||
|
|
81de782d1e | ||
|
|
d83eccdded | ||
|
|
681b66b13c | ||
|
|
2958bd050b | ||
|
|
38f493aff2 | ||
|
|
19bac44dde | ||
|
|
b49712ed32 | ||
|
|
cdbe1310cc | ||
|
|
b462f5335f | ||
|
|
115a4e89e2 | ||
|
|
9d935d9be1 | ||
|
|
7eca1112fb | ||
|
|
fe2a266c50 | ||
|
|
e97df9b1ec | ||
|
|
d048459d36 | ||
|
|
88fa0651bf | ||
|
|
4e038f3ae7 | ||
|
|
6c6c8d3a33 | ||
|
|
a8a921184f | ||
|
|
cbd2472b7c | ||
|
|
a0efca4581 | ||
|
|
4e1da34601 | ||
|
|
b03df41906 | ||
|
|
8ca6eea938 | ||
|
|
1c2ad5e6b9 | ||
|
|
991fee82df | ||
|
|
b52ce71c27 | ||
|
|
e78d22469f | ||
|
|
c4e8b411d4 | ||
|
|
3a51b90145 | ||
|
|
a2cd3e9ef0 | ||
|
|
1cbb562c23 | ||
|
|
558977bb2b | ||
|
|
332709da65 | ||
|
|
a74587a4ea | ||
|
|
1e13749483 | ||
|
|
1a1b8fcc36 | ||
|
|
23262b249c | ||
|
|
5687be5f31 | ||
|
|
e293aa9cfc | ||
|
|
edf7547ad5 | ||
|
|
2cac079ef4 | ||
|
|
5afc1c5b5f | ||
|
|
3025fefc41 | ||
|
|
00a5cff244 | ||
|
|
fc0ed79e5d | ||
|
|
13c618465d | ||
|
|
3c52a84ff8 |
46
.travis.yml
46
.travis.yml
@@ -1,20 +1,52 @@
|
||||
dist: bionic
|
||||
sudo: false
|
||||
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- autopoint
|
||||
- xsltproc
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get -y install -qq automake autopoint xsltproc libselinux1-dev gettext expect
|
||||
- sudo apt-get -y install -qq byacc libtool
|
||||
script:
|
||||
- ./autogen.sh --without-selinux --disable-man
|
||||
- grep ENABLE_ config.status
|
||||
- make
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: "G47VYFrtzqalrVjixTqBG9Qsa8EZRcaqsh1k6fq5JgEyHmMQActpvTUDs9FXf1MEqiY5XX3VDVfBsZgKPHgmHsMzD1bX11xpnpGByB8g7gr8I3u2ZkCREqgi77a5l3LeBh+seWiambe/DYOgvPCNa6pCynLgR9advqtgKhpCruU="
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
|
||||
project:
|
||||
name: "shadow-maint/shadow"
|
||||
description: "Upstream shadow utils tree"
|
||||
|
||||
notification_email: christian.brauner@ubuntu.com,serge@hallyn.com
|
||||
|
||||
build_command_prepend: "./autogen.sh --without-selinux --disable-man"
|
||||
build_command: "make -j4"
|
||||
branch_pattern: master
|
||||
|
||||
script:
|
||||
- cat /proc/self/uid_map
|
||||
- cat /proc/self/status
|
||||
- systemd-detect-virt
|
||||
- ./autogen.sh --without-selinux --disable-man
|
||||
- grep ENABLE_ config.status
|
||||
- make
|
||||
- sudo make install
|
||||
- (cd tests; sudo ./run_some; cat testsuite.log)
|
||||
|
||||
# vim:et:ts=2:sw=2
|
||||
|
||||
64
ChangeLog
64
ChangeLog
@@ -1,3 +1,67 @@
|
||||
2021-07-22 Serge Hallyn <serge@hallyn.com>
|
||||
|
||||
* Updated translations (Björn Esser, Juergen Hoetzel)
|
||||
* Major salt updates (Björn Esser)
|
||||
* Various coverity and cleanup fixes (Iker Pedrosa)
|
||||
* Consistently use 0 to disable PASS_MIN_DAYS in man (tzccinct)
|
||||
* Implement NSS support for subids and a libsubid (Serge Hallyn)
|
||||
* setfcap: retain setfcap when mapping uid 0 (Christian Brauner)
|
||||
* login.defs: include HMAC_CRYPTO_ALGO key (Iker Pedrosa)
|
||||
* selinux fixes (Christian Göttsche)
|
||||
* Fix path prefix path handling (Lucas Servén Marín)
|
||||
* Manpage updates (tzccinct, Sevan Janiyan, Iker Pedrosa, Geert Ijewski,
|
||||
谭九鼎, Jamin W. Collins, towerpark, andydna, Frans Spiesschaert)
|
||||
* Treat an empty passwd field as invalid (Haelwenn Monnier)
|
||||
* newxidmap: allow running under alternative gid (Martijn de Gouw)
|
||||
* usermod: check that shell is executable (Geert Ijewski)
|
||||
* Add yescript support (Rodolphe Bréard)
|
||||
* useradd memleak fixes (whzhe)
|
||||
* useradd: use built-in settings by default (Ludwig Nussel)
|
||||
* getdefs: add foreign (non-shadow-utils) items (Karel Zak)
|
||||
* buffer overflow fixes (Tobias Stoeckmann)
|
||||
* Adding run-parts style for pre and post useradd/del (ed@s5h.net)
|
||||
|
||||
2020-01-23 Serge Hallyn <serge@hallyn.com>
|
||||
|
||||
* selinux: inclue stdio (Michael Vetter)
|
||||
* man: don't suggest making groupmems user-writeable (Michael Weiser)
|
||||
* Makefile: bail out on error in for loops (Wolfgang Bumiller)
|
||||
* Adding logging of SSH_ORIGINAL_COMMAND to nologin. (ed@s5h.net)
|
||||
* add new HOME_MODE login.defs option (Duncan Overbruck)
|
||||
* Add tty logging to useradd (ed@s5h.net)
|
||||
* Useradd: make non-executable shell check only a warning (Tomas Mraz)
|
||||
* Update Dutch translation (Frans-Spiesschaert)
|
||||
* user_busy: Do not mistake a regular user process for a namespaced one (Tomas Mraz)
|
||||
* Revert "Honor --sbindir and --bindir for binary installation" Patrick McLean)
|
||||
|
||||
2019-12-20 Dave Reisner <dreisner@archlinux.org>
|
||||
|
||||
* Do not auto-enable acct_tools_setuid just because
|
||||
pam is enabled. NOTE - any distros which are relying
|
||||
on this behavior will need to switch to configure
|
||||
--enable-account-tools-setuid
|
||||
|
||||
2019-12-01 Serge Hallyn <serge@hallyn.com>
|
||||
|
||||
* Release 4.8
|
||||
* Initial optional bcrypt support.
|
||||
* Make build/install of 'su' optional.
|
||||
* Fix for vipw not resuming correctly when suspended
|
||||
* Sync password field descriptions in manpages
|
||||
* Check for valid shell argument in useradd
|
||||
* Allow translation of new strings through POTFILES.in
|
||||
* Migrate to itstool for translations
|
||||
* Migrate to new SELinux api
|
||||
* Support --enable-vendordir
|
||||
* pwck: Only check homedir if set and not a system user
|
||||
* Support nonstandard usernames
|
||||
* sget{pw,gr}ent: check for data at EOL
|
||||
* Add YYY-MM-DD support in chage
|
||||
* Fix failing chmod calls for suidubins
|
||||
* Fix --sbindir and --bindir for binary installations
|
||||
* Fix LASTLOG_UID_MAX in login.defs
|
||||
* Fix configure error with dash
|
||||
|
||||
2019-06-13 Serge Hallyn <serge@hallyn.com>
|
||||
|
||||
* Release 4.7
|
||||
|
||||
13
Makefile.am
13
Makefile.am
@@ -2,5 +2,14 @@
|
||||
|
||||
EXTRA_DIST = NEWS README TODO shadow.spec.in
|
||||
|
||||
SUBDIRS = po man libmisc lib src \
|
||||
contrib doc etc
|
||||
SUBDIRS = libmisc lib
|
||||
|
||||
if ENABLE_SUBIDS
|
||||
SUBDIRS += libsubid
|
||||
endif
|
||||
|
||||
SUBDIRS += src po contrib doc etc
|
||||
|
||||
if ENABLE_REGENERATE_MAN
|
||||
SUBDIRS += man
|
||||
endif
|
||||
|
||||
15
README
15
README
@@ -11,16 +11,16 @@ Releases
|
||||
https://github.com/shadow-maint/shadow/releases
|
||||
|
||||
Mailing lists
|
||||
for general discuss: pkg-shadow-devel@lists.alioth.debian.org
|
||||
commit list: pkg-shadow-commits@lists.alioth.debian.org
|
||||
for general discuss: pkg-shadow-devel@alioth-lists.debian.net
|
||||
commit list: pkg-shadow-commits@alioth-lists.debian.net
|
||||
|
||||
Mailing lists subscription
|
||||
http://lists.alioth.debian.org/mailman/listinfo/pkg-shadow-devel
|
||||
http://lists.alioth.debian.org/mailman/listinfo/pkg-shadow-commits
|
||||
http://alioth-lists.debian.net/mailman/listinfo/pkg-shadow-devel
|
||||
http://alioth-lists.debian.net/mailman/listinfo/pkg-shadow-commits
|
||||
|
||||
Mailing lists archives:
|
||||
http://lists.alioth.debian.org/pipermail/pkg-shadow-devel/
|
||||
http://lists.alioth.debian.org/pipermail/pkg-shadow-commits/
|
||||
http://alioth-lists.debian.net/pipermail/pkg-shadow-devel/
|
||||
http://alioth-lists.debian.net/pipermail/pkg-shadow-commits/
|
||||
|
||||
S/Key support:
|
||||
Shadow can be built with S/Key support using the S/Key package from:
|
||||
@@ -59,6 +59,7 @@ Dave Hagewood <admin@arrowweb.com>
|
||||
David A. Holland <dholland@hcs.harvard.edu>
|
||||
David Frey <David.Frey@lugs.ch>
|
||||
Ed Carp <ecarp@netcom.com>
|
||||
Ed Neville <ed@s5h.net>
|
||||
Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Floody <flood@evcom.net>
|
||||
Frank Denis <j@4u.net>
|
||||
@@ -69,6 +70,7 @@ Guy Maor <maor@debian.org>
|
||||
Hrvoje Dogan <hdogan@bjesomar.srce.hr>
|
||||
Jakub Hrozek <jhrozek@redhat.com>
|
||||
Janos Farkas <chexum@bankinf.banki.hu>
|
||||
Jason Franklin <jason.franklin@quoininc.com>
|
||||
Jay Soffian <jay@lw.net>
|
||||
Jesse Thilo <Jesse.Thilo@pobox.com>
|
||||
Joey Hess <joey@kite.ml.org>
|
||||
@@ -90,6 +92,7 @@ Martin Bene <mb@sime.com>
|
||||
Martin Mares <mj@gts.cz>
|
||||
Michael Meskes <meskes@topsystem.de>
|
||||
Michael Talbot-Wilson <mike@calypso.bns.com.au>
|
||||
Michael Vetter <jubalh@iodoru.org>
|
||||
Mike Frysinger <vapier@gentoo.org>
|
||||
Mike Pakovic <mpakovic@users.southeast.net>
|
||||
Nicolas François <nicolas.francois@centraliens.net>
|
||||
|
||||
@@ -6,7 +6,7 @@ autoreconf -v -f --install || exit 1
|
||||
CFLAGS="-O2 -Wall" \
|
||||
--enable-man \
|
||||
--enable-maintainer-mode \
|
||||
--disable-shared \
|
||||
--enable-shared \
|
||||
--without-libpam \
|
||||
--with-selinux \
|
||||
"$@"
|
||||
|
||||
82
configure.ac
82
configure.ac
@@ -1,19 +1,29 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ([2.64])
|
||||
AC_INIT([shadow], [4.7], [pkg-shadow-devel@lists.alioth.debian.org], [],
|
||||
AC_PREREQ([2.69])
|
||||
m4_define([libsubid_abi_major], 3)
|
||||
m4_define([libsubid_abi_minor], 0)
|
||||
m4_define([libsubid_abi_micro], 0)
|
||||
m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro])
|
||||
AC_INIT([shadow], [4.9], [pkg-shadow-devel@lists.alioth.debian.org], [],
|
||||
[https://github.com/shadow-maint/shadow])
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz])
|
||||
AC_CONFIG_MACRO_DIRS([m4])
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AC_SUBST([LIBSUBID_ABI_MAJOR], [libsubid_abi_major])
|
||||
AC_SUBST([LIBSUBID_ABI_MINOR], [libsubid_abi_minor])
|
||||
AC_SUBST([LIBSUBID_ABI_MICRO], [libsubid_abi_micro])
|
||||
AC_SUBST([LIBSUBID_ABI], [libsubid_abi])
|
||||
|
||||
dnl Some hacks...
|
||||
test "$prefix" = "NONE" && prefix="/usr"
|
||||
test "$prefix" = "/usr" && exec_prefix=""
|
||||
|
||||
AC_GNU_SOURCE
|
||||
|
||||
AM_DISABLE_SHARED
|
||||
AM_ENABLE_STATIC
|
||||
AM_ENABLE_SHARED
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
@@ -32,20 +42,21 @@ AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_HEADER_STDBOOL
|
||||
|
||||
AC_CHECK_HEADERS(errno.h fcntl.h limits.h unistd.h sys/time.h utmp.h \
|
||||
AC_CHECK_HEADERS(crypt.h errno.h fcntl.h limits.h unistd.h sys/time.h utmp.h \
|
||||
utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h paths.h \
|
||||
utime.h ulimit.h sys/capability.h sys/resource.h gshadow.h lastlog.h \
|
||||
locale.h rpc/key_prot.h netdb.h acl/libacl.h attr/libattr.h \
|
||||
attr/error_context.h)
|
||||
utime.h ulimit.h sys/capability.h sys/random.h sys/resource.h \
|
||||
gshadow.h lastlog.h locale.h rpc/key_prot.h netdb.h acl/libacl.h \
|
||||
attr/libattr.h attr/error_context.h)
|
||||
|
||||
dnl shadow now uses the libc's shadow implementation
|
||||
AC_CHECK_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
|
||||
|
||||
AC_CHECK_FUNCS(l64a fchmod fchown fsync futimes getgroups gethostname getspnam \
|
||||
gettimeofday getusershell getutent initgroups lchown lckpwdf lstat \
|
||||
lutimes memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
|
||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo \
|
||||
ruserok)
|
||||
AC_CHECK_FUNCS(arc4random_buf l64a fchmod fchown fsync futimes getgroups \
|
||||
gethostname getentropy getrandom getspnam gettimeofday getusershell \
|
||||
getutent initgroups lchown lckpwdf lstat lutimes memcpy memset \
|
||||
setgroups sigaction strchr updwtmp updwtmpx innetgr getpwnam_r \
|
||||
getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo ruserok \
|
||||
dlopen)
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
@@ -226,7 +237,7 @@ AC_ARG_ENABLE(account-tools-setuid,
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-account-tools-setuid)
|
||||
;;
|
||||
esac],
|
||||
[enable_acct_tools_setuid="maybe"]
|
||||
[enable_acct_tools_setuid="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(utmpx,
|
||||
@@ -247,7 +258,7 @@ AC_ARG_ENABLE(subordinate-ids,
|
||||
[enable_subids="maybe"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(audit,
|
||||
AC_ARG_WITH(audit,
|
||||
[AC_HELP_STRING([--with-audit], [use auditing support @<:@default=yes if found@:>@])],
|
||||
[with_audit=$withval], [with_audit=maybe])
|
||||
AC_ARG_WITH(libpam,
|
||||
@@ -277,6 +288,12 @@ AC_ARG_WITH(libcrack,
|
||||
AC_ARG_WITH(sha-crypt,
|
||||
[AC_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])],
|
||||
[with_sha_crypt=$withval], [with_sha_crypt=yes])
|
||||
AC_ARG_WITH(bcrypt,
|
||||
[AC_HELP_STRING([--with-bcrypt], [allow the bcrypt password encryption algorithm @<:@default=no@:>@])],
|
||||
[with_bcrypt=$withval], [with_bcrypt=no])
|
||||
AC_ARG_WITH(yescrypt,
|
||||
[AC_HELP_STRING([--with-yescrypt], [allow the yescrypt password encryption algorithm @<:@default=no@:>@])],
|
||||
[with_yescrypt=$withval], [with_yescrypt=no])
|
||||
AC_ARG_WITH(nscd,
|
||||
[AC_HELP_STRING([--with-nscd], [enable support for nscd @<:@default=yes@:>@])],
|
||||
[with_nscd=$withval], [with_nscd=yes])
|
||||
@@ -286,6 +303,9 @@ AC_ARG_WITH(sssd,
|
||||
AC_ARG_WITH(group-name-max-length,
|
||||
[AC_HELP_STRING([--with-group-name-max-length], [set max group name length @<:@default=16@:>@])],
|
||||
[with_group_name_max_length=$withval], [with_group_name_max_length=yes])
|
||||
AC_ARG_WITH(su,
|
||||
[AC_HELP_STRING([--with-su], [build and install su program and man page @<:@default=yes@:>@])],
|
||||
[with_su=$withval], [with_su=yes])
|
||||
|
||||
if test "$with_group_name_max_length" = "no" ; then
|
||||
with_group_name_max_length=0
|
||||
@@ -301,6 +321,16 @@ if test "$with_sha_crypt" = "yes"; then
|
||||
AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(USE_BCRYPT, test "x$with_bcrypt" = "xyes")
|
||||
if test "$with_bcrypt" = "yes"; then
|
||||
AC_DEFINE(USE_BCRYPT, 1, [Define to allow the bcrypt password encryption algorithm])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(USE_YESCRYPT, test "x$with_yescrypt" = "xyes")
|
||||
if test "$with_yescrypt" = "yes"; then
|
||||
AC_DEFINE(USE_YESCRYPT, 1, [Define to allow the yescrypt password encryption algorithm])
|
||||
fi
|
||||
|
||||
if test "$with_nscd" = "yes"; then
|
||||
AC_CHECK_FUNC(posix_spawn,
|
||||
[AC_DEFINE(USE_NSCD, 1, [Define to support flushing of nscd caches])],
|
||||
@@ -313,6 +343,9 @@ if test "$with_sssd" = "yes"; then
|
||||
[AC_MSG_ERROR([posix_spawn is needed for sssd support])])
|
||||
fi
|
||||
|
||||
AS_IF([test "$with_su" != "no"], AC_DEFINE(WITH_SU, 1, [Build with su])])
|
||||
AM_CONDITIONAL([WITH_SU], [test "x$with_su" != "xno"])
|
||||
|
||||
dnl Check for some functions in libc first, only if not found check for
|
||||
dnl other libraries. This should prevent linking libnsl if not really
|
||||
dnl needed (Linux glibc, Irix), but still link it if needed (Solaris).
|
||||
@@ -321,6 +354,17 @@ AC_SEARCH_LIBS(inet_ntoa, inet)
|
||||
AC_SEARCH_LIBS(socket, socket)
|
||||
AC_SEARCH_LIBS(gethostbyname, nsl)
|
||||
|
||||
AC_CHECK_LIB([econf],[econf_readDirs],[LIBECONF="-leconf"],[LIBECONF=""])
|
||||
if test -n "$LIBECONF"; then
|
||||
ECONF_CPPFLAGS="-DUSE_ECONF=1"
|
||||
AC_ARG_ENABLE([vendordir],
|
||||
AS_HELP_STRING([--enable-vendordir=DIR], [Directory for distribution provided configuration files]),,[])
|
||||
fi
|
||||
AC_SUBST(ECONF_CPPFLAGS)
|
||||
AC_SUBST(LIBECONF)
|
||||
AC_SUBST([VENDORDIR], [$enable_vendordir])
|
||||
AM_CONDITIONAL([HAVE_VENDORDIR], [test "x$enable_vendordir" != x])
|
||||
|
||||
if test "$enable_shadowgrp" = "yes"; then
|
||||
AC_DEFINE(SHADOWGRP, 1, [Define to support the shadow group file.])
|
||||
fi
|
||||
@@ -367,6 +411,10 @@ AC_SUBST(LIBCRYPT)
|
||||
AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
|
||||
[AC_MSG_ERROR([crypt() not found])])
|
||||
|
||||
AC_SUBST(LIYESCRYPT)
|
||||
AC_CHECK_LIB(crypt, crypt, [LIYESCRYPT=-lcrypt],
|
||||
[AC_MSG_ERROR([crypt() not found])])
|
||||
|
||||
AC_SUBST(LIBACL)
|
||||
if test "$with_acl" != "no"; then
|
||||
AC_CHECK_HEADERS(acl/libacl.h attr/error_context.h, [acl_header="yes"], [acl_header="no"])
|
||||
@@ -500,7 +548,7 @@ if test "$with_selinux" != "no"; then
|
||||
AC_MSG_ERROR([libsemanage not found])
|
||||
fi
|
||||
|
||||
if test "$selinux_lib$semanage_lib" == "yesyes" ; then
|
||||
if test "$selinux_lib$semanage_lib" = "yesyes" ; then
|
||||
AC_DEFINE(WITH_SELINUX, 1,
|
||||
[Build shadow with SELinux support])
|
||||
LIBSELINUX="-lselinux"
|
||||
@@ -690,6 +738,7 @@ AC_CONFIG_FILES([
|
||||
man/zh_TW/Makefile
|
||||
libmisc/Makefile
|
||||
lib/Makefile
|
||||
libsubid/Makefile
|
||||
src/Makefile
|
||||
contrib/Makefile
|
||||
etc/Makefile
|
||||
@@ -715,8 +764,11 @@ echo " tcb support (incomplete): $with_tcb"
|
||||
echo " shadow group support: $enable_shadowgrp"
|
||||
echo " S/Key support: $with_skey"
|
||||
echo " SHA passwords encryption: $with_sha_crypt"
|
||||
echo " bcrypt passwords encryption: $with_bcrypt"
|
||||
echo " yescrypt passwords encryption: $with_yescrypt"
|
||||
echo " nscd support: $with_nscd"
|
||||
echo " sssd support: $with_sssd"
|
||||
echo " subordinate IDs support: $enable_subids"
|
||||
echo " use file caps: $with_fcaps"
|
||||
echo " install su: $with_su"
|
||||
echo
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
sysconf_DATA = login.defs
|
||||
|
||||
defaultdir = $(sysconfdir)/default
|
||||
default_DATA = \
|
||||
useradd
|
||||
default_DATA =
|
||||
|
||||
nonpam_files = \
|
||||
limits \
|
||||
|
||||
@@ -31,6 +31,15 @@ LOG_OK_LOGINS no
|
||||
#
|
||||
LASTLOG_ENAB yes
|
||||
|
||||
#
|
||||
# Limit the highest user ID number for which the lastlog entries should
|
||||
# be updated.
|
||||
#
|
||||
# No LASTLOG_UID_MAX means that there is no user ID limit for writing
|
||||
# lastlog entries.
|
||||
#
|
||||
#LASTLOG_UID_MAX
|
||||
|
||||
#
|
||||
# Enable checking and display of mailbox status upon login.
|
||||
#
|
||||
@@ -186,12 +195,17 @@ KILLCHAR 025
|
||||
# Default initial "umask" value used by login(1) on non-PAM enabled systems.
|
||||
# Default "umask" value for pam_umask(8) on PAM enabled systems.
|
||||
# UMASK is also used by useradd(8) and newusers(8) to set the mode for new
|
||||
# home directories.
|
||||
# home directories if HOME_MODE is not set.
|
||||
# 022 is the default value, but 027, or even 077, could be considered
|
||||
# for increased privacy. There is no One True Answer here: each sysadmin
|
||||
# must make up their mind.
|
||||
UMASK 022
|
||||
|
||||
# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new
|
||||
# home directories.
|
||||
# If HOME_MODE is not set, the value of UMASK is used to create the mode.
|
||||
#HOME_MODE 0700
|
||||
|
||||
#
|
||||
# Password aging controls:
|
||||
#
|
||||
@@ -281,7 +295,7 @@ CHFN_AUTH yes
|
||||
# any combination of letters "frwh" (full name, room number, work
|
||||
# phone, home phone). If not defined, no changes are allowed.
|
||||
# For backward compatibility, "yes" = "rwh" and "no" = "frwh".
|
||||
#
|
||||
#
|
||||
CHFN_RESTRICT rwh
|
||||
|
||||
#
|
||||
@@ -311,7 +325,10 @@ CHFN_RESTRICT rwh
|
||||
# If set to MD5, MD5-based algorithm will be used for encrypting password
|
||||
# If set to SHA256, SHA256-based algorithm will be used for encrypting password
|
||||
# If set to SHA512, SHA512-based algorithm will be used for encrypting password
|
||||
# If set to BCRYPT, BCRYPT-based algorithm will be used for encrypting password
|
||||
# If set to YESCRYPT, YESCRYPT-based algorithm will be used for encrypting password
|
||||
# If set to DES, DES-based algorithm will be used for encrypting password (default)
|
||||
# MD5 and DES should not be used for new hashes, see crypt(5) for recommendations.
|
||||
# Overrides the MD5_CRYPT_ENAB option
|
||||
#
|
||||
# Note: If you use PAM, it is recommended to use a value consistent with
|
||||
@@ -327,13 +344,42 @@ CHFN_RESTRICT rwh
|
||||
# However, more CPU resources will be needed to authenticate users if
|
||||
# this value is increased.
|
||||
#
|
||||
# If not specified, the libc will choose the default number of rounds (5000).
|
||||
# If not specified, the libc will choose the default number of rounds (5000),
|
||||
# which is orders of magnitude too low for modern hardware.
|
||||
# The values must be within the 1000-999999999 range.
|
||||
# If only one of the MIN or MAX values is set, then this value will be used.
|
||||
# If MIN > MAX, the highest value will be used.
|
||||
#
|
||||
# SHA_CRYPT_MIN_ROUNDS 5000
|
||||
# SHA_CRYPT_MAX_ROUNDS 5000
|
||||
#SHA_CRYPT_MIN_ROUNDS 5000
|
||||
#SHA_CRYPT_MAX_ROUNDS 5000
|
||||
|
||||
#
|
||||
# Only works if ENCRYPT_METHOD is set to BCRYPT.
|
||||
#
|
||||
# Define the number of BCRYPT rounds.
|
||||
# With a lot of rounds, it is more difficult to brute-force the password.
|
||||
# However, more CPU resources will be needed to authenticate users if
|
||||
# this value is increased.
|
||||
#
|
||||
# If not specified, 13 rounds will be attempted.
|
||||
# If only one of the MIN or MAX values is set, then this value will be used.
|
||||
# If MIN > MAX, the highest value will be used.
|
||||
#
|
||||
#BCRYPT_MIN_ROUNDS 13
|
||||
#BCRYPT_MAX_ROUNDS 13
|
||||
|
||||
#
|
||||
# Only works if ENCRYPT_METHOD is set to YESCRYPT.
|
||||
#
|
||||
# Define the YESCRYPT cost factor.
|
||||
# With a higher cost factor, it is more difficult to brute-force the password.
|
||||
# However, more CPU time and more memory will be needed to authenticate users
|
||||
# if this value is increased.
|
||||
#
|
||||
# If not specified, a cost factor of 5 will be used.
|
||||
# The value must be within the 1-11 range.
|
||||
#
|
||||
#YESCRYPT_COST_FACTOR 5
|
||||
|
||||
#
|
||||
# List of groups to add to the user's supplementary group set
|
||||
@@ -352,6 +398,14 @@ CHFN_RESTRICT rwh
|
||||
#
|
||||
DEFAULT_HOME yes
|
||||
|
||||
#
|
||||
# The pwck(8) utility emits a warning for any system account with a home
|
||||
# directory that does not exist. Some system accounts intentionally do
|
||||
# not have a home directory. Such accounts may have this string as
|
||||
# their home directory in /etc/passwd to avoid a spurious warning.
|
||||
#
|
||||
NONEXISTENT /nonexistent
|
||||
|
||||
#
|
||||
# If this file exists and is readable, login environment will be
|
||||
# read from it. Every line should be in the form name=value.
|
||||
@@ -398,3 +452,28 @@ USERGROUPS_ENAB yes
|
||||
# missing.
|
||||
#
|
||||
#FORCE_SHADOW yes
|
||||
|
||||
#
|
||||
# Allow newuidmap and newgidmap when running under an alternative
|
||||
# primary group.
|
||||
#
|
||||
#GRANT_AUX_GROUP_SUBIDS yes
|
||||
|
||||
#
|
||||
# Prevents an empty password field to be interpreted as "no authentication
|
||||
# required".
|
||||
# Set to "yes" to prevent for all accounts
|
||||
# Set to "superuser" to prevent for UID 0 / root (default)
|
||||
# Set to "no" to not prevent for any account (dangerous, historical default)
|
||||
|
||||
PREVENT_NO_AUTH superuser
|
||||
|
||||
#
|
||||
# Select the HMAC cryptography algorithm.
|
||||
# Used in pam_timestamp module to calculate the keyed-hash message
|
||||
# authentication code.
|
||||
#
|
||||
# Note: It is recommended to check hmac(3) to see the possible algorithms
|
||||
# that are available in your system.
|
||||
#
|
||||
#HMAC_CRYPTO_ALGO SHA512
|
||||
|
||||
@@ -6,8 +6,7 @@ pamd_files = \
|
||||
chsh \
|
||||
groupmems \
|
||||
login \
|
||||
passwd \
|
||||
su
|
||||
passwd
|
||||
|
||||
pamd_acct_tools_files = \
|
||||
chage \
|
||||
@@ -29,4 +28,8 @@ pamd_DATA += $(pamd_acct_tools_files)
|
||||
endif
|
||||
endif
|
||||
|
||||
if WITH_SU
|
||||
pamd_files += su
|
||||
endif
|
||||
|
||||
EXTRA_DIST = $(pamd_files) $(pamd_acct_tools_files)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# useradd defaults file
|
||||
GROUP=1000
|
||||
HOME=/home
|
||||
INACTIVE=-1
|
||||
EXPIRE=
|
||||
SHELL=/bin/bash
|
||||
SKEL=/etc/skel
|
||||
CREATE_MAIL_SPOOL=yes
|
||||
@@ -5,7 +5,10 @@ DEFS =
|
||||
|
||||
noinst_LTLIBRARIES = libshadow.la
|
||||
|
||||
libshadow_la_LDFLAGS = -version-info 0:0:0
|
||||
libshadow_la_CPPFLAGS = $(ECONF_CPPFLAGS)
|
||||
if HAVE_VENDORDIR
|
||||
libshadow_la_CPPFLAGS += -DVENDORDIR=\"$(VENDORDIR)\"
|
||||
endif
|
||||
|
||||
libshadow_la_SOURCES = \
|
||||
commonio.c \
|
||||
@@ -28,6 +31,7 @@ libshadow_la_SOURCES = \
|
||||
groupio.h \
|
||||
gshadow.c \
|
||||
lockpw.c \
|
||||
nss.c \
|
||||
nscd.c \
|
||||
nscd.h \
|
||||
sssd.c \
|
||||
@@ -41,6 +45,8 @@ libshadow_la_SOURCES = \
|
||||
pwio.c \
|
||||
pwio.h \
|
||||
pwmem.c \
|
||||
run_part.h \
|
||||
run_part.c \
|
||||
subordinateio.h \
|
||||
subordinateio.c \
|
||||
selinux.c \
|
||||
|
||||
@@ -144,7 +144,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
fd = open (file, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (-1 == fd) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: %s: %s\n",
|
||||
Prog, file, strerror (errno));
|
||||
}
|
||||
@@ -156,8 +156,18 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
len = (ssize_t) strlen (buf) + 1;
|
||||
if (write (fd, buf, (size_t) len) != len) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: %s: %s\n",
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: %s file write error: %s\n",
|
||||
Prog, file, strerror (errno));
|
||||
}
|
||||
(void) close (fd);
|
||||
unlink (file);
|
||||
return 0;
|
||||
}
|
||||
if (fdatasync (fd) == -1) {
|
||||
if (log) {
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: %s file sync error: %s\n",
|
||||
Prog, file, strerror (errno));
|
||||
}
|
||||
(void) close (fd);
|
||||
@@ -169,7 +179,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
if (link (file, lock) == 0) {
|
||||
retval = check_link_count (file);
|
||||
if ((0==retval) && log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: %s: lock file already used\n",
|
||||
Prog, file);
|
||||
}
|
||||
@@ -180,7 +190,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
fd = open (lock, O_RDWR);
|
||||
if (-1 == fd) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: %s: %s\n",
|
||||
Prog, lock, strerror (errno));
|
||||
}
|
||||
@@ -192,7 +202,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
close (fd);
|
||||
if (len <= 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: existing lock file %s without a PID\n",
|
||||
Prog, lock);
|
||||
}
|
||||
@@ -203,7 +213,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
buf[len] = '\0';
|
||||
if (get_pid (buf, &pid) == 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: existing lock file %s with an invalid PID '%s'\n",
|
||||
Prog, lock, buf);
|
||||
}
|
||||
@@ -213,7 +223,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
}
|
||||
if (kill (pid, 0) == 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: lock %s already used by PID %lu\n",
|
||||
Prog, lock, (unsigned long) pid);
|
||||
}
|
||||
@@ -223,7 +233,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
}
|
||||
if (unlink (lock) != 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: cannot get lock %s: %s\n",
|
||||
Prog, lock, strerror (errno));
|
||||
}
|
||||
@@ -235,13 +245,13 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
if (link (file, lock) == 0) {
|
||||
retval = check_link_count (file);
|
||||
if ((0==retval) && log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: %s: lock file already used\n",
|
||||
Prog, file);
|
||||
}
|
||||
} else {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: cannot get lock %s: %s\n",
|
||||
Prog, lock, strerror (errno));
|
||||
}
|
||||
@@ -326,8 +336,12 @@ static int create_backup (const char *backup, FILE * fp)
|
||||
/* FIXME: unlink the backup file? */
|
||||
return -1;
|
||||
}
|
||||
if ( (fsync (fileno (bkfp)) != 0)
|
||||
|| (fclose (bkfp) != 0)) {
|
||||
if (fsync (fileno (bkfp)) != 0) {
|
||||
(void) fclose (bkfp);
|
||||
/* FIXME: unlink the backup file? */
|
||||
return -1;
|
||||
}
|
||||
if (fclose (bkfp) != 0) {
|
||||
/* FIXME: unlink the backup file? */
|
||||
return -1;
|
||||
}
|
||||
@@ -432,7 +446,7 @@ int commonio_lock (struct commonio_db *db)
|
||||
if (0 == lock_count) {
|
||||
if (lckpwdf () == -1) {
|
||||
if (geteuid () != 0) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
"%s: Permission denied.\n",
|
||||
Prog);
|
||||
}
|
||||
@@ -468,7 +482,7 @@ int commonio_lock (struct commonio_db *db)
|
||||
}
|
||||
/* no unnecessary retries on "permission denied" errors */
|
||||
if (geteuid () != 0) {
|
||||
(void) fprintf (stderr, "%s: Permission denied.\n",
|
||||
(void) fprintf (shadow_logfd, "%s: Permission denied.\n",
|
||||
Prog);
|
||||
return 0;
|
||||
}
|
||||
@@ -964,7 +978,7 @@ int commonio_close (struct commonio_db *db)
|
||||
snprintf (buf, sizeof buf, "%s-", db->filename);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (buf) != 0) {
|
||||
if (set_selinux_file_context (db->filename, S_IFREG) != 0) {
|
||||
errors++;
|
||||
}
|
||||
#endif
|
||||
@@ -997,7 +1011,7 @@ int commonio_close (struct commonio_db *db)
|
||||
snprintf (buf, sizeof buf, "%s+", db->filename);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (buf) != 0) {
|
||||
if (set_selinux_file_context (db->filename, S_IFREG) != 0) {
|
||||
errors++;
|
||||
}
|
||||
#endif
|
||||
@@ -1099,7 +1113,7 @@ int commonio_update (struct commonio_db *db, const void *eptr)
|
||||
p = find_entry_by_name (db, db->ops->getname (eptr));
|
||||
if (NULL != p) {
|
||||
if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) {
|
||||
fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename);
|
||||
fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename);
|
||||
db->ops->free (nentry);
|
||||
return 0;
|
||||
}
|
||||
@@ -1204,7 +1218,7 @@ int commonio_remove (struct commonio_db *db, const char *name)
|
||||
return 0;
|
||||
}
|
||||
if (next_entry_by_name (db, p->next, name) != NULL) {
|
||||
fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename);
|
||||
fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,6 @@
|
||||
#ifndef COMMONIO_H
|
||||
#define COMMONIO_H
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "defines.h" /* bool */
|
||||
|
||||
/*
|
||||
@@ -121,7 +117,7 @@ struct commonio_db {
|
||||
/*@dependent@*/ /*@null@*/FILE *fp;
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
/*@null@*/security_context_t scontext;
|
||||
/*@null@*/char *scontext;
|
||||
#endif
|
||||
/*
|
||||
* Default permissions and owner for newly created data file.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#ifndef _DEFINES_H_
|
||||
#define _DEFINES_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
@@ -94,6 +96,14 @@ char *strchr (), *strrchr (), *strtok ();
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* crypt(3), crypt_gensalt(3), and their
|
||||
* feature test macros may be defined in here.
|
||||
*/
|
||||
#if HAVE_CRYPT_H
|
||||
# include <crypt.h>
|
||||
#endif
|
||||
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
|
||||
@@ -65,12 +65,18 @@
|
||||
case '1':
|
||||
method = "MD5";
|
||||
break;
|
||||
case '2':
|
||||
method = "BCRYPT";
|
||||
break;
|
||||
case '5':
|
||||
method = "SHA256";
|
||||
break;
|
||||
case '6':
|
||||
method = "SHA512";
|
||||
break;
|
||||
case 'y':
|
||||
method = "YESCRYPT";
|
||||
break;
|
||||
default:
|
||||
{
|
||||
static char nummethod[4] = "$x$";
|
||||
@@ -78,7 +84,7 @@
|
||||
method = &nummethod[0];
|
||||
}
|
||||
}
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("crypt method not supported by libcrypt? (%s)\n"),
|
||||
method);
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
112
lib/getdef.c
112
lib/getdef.c
@@ -40,6 +40,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#ifdef USE_ECONF
|
||||
#include <libeconf.h>
|
||||
#endif
|
||||
#include "getdef.h"
|
||||
/*
|
||||
* A configuration item definition.
|
||||
@@ -58,6 +61,7 @@ struct itemdef {
|
||||
{"ENV_TZ", NULL}, \
|
||||
{"FAILLOG_ENAB", NULL}, \
|
||||
{"FTMP_FILE", NULL}, \
|
||||
{"HMAC_CRYPTO_ALGO", NULL}, \
|
||||
{"ISSUE_FILE", NULL}, \
|
||||
{"LASTLOG_ENAB", NULL}, \
|
||||
{"LOGIN_STRING", NULL}, \
|
||||
@@ -74,6 +78,16 @@ struct itemdef {
|
||||
{"SU_WHEEL_ONLY", NULL}, \
|
||||
{"ULIMIT", NULL},
|
||||
|
||||
/*
|
||||
* Items used in other tools (util-linux, etc.)
|
||||
*/
|
||||
#define FOREIGNDEFS \
|
||||
{"ALWAYS_SET_PATH", NULL}, \
|
||||
{"ENV_ROOTPATH", NULL}, \
|
||||
{"LOGIN_KEEP_USERNAME", NULL}, \
|
||||
{"LOGIN_PLAIN_PROMPT", NULL}, \
|
||||
{"MOTD_FIRSTONLY", NULL}, \
|
||||
|
||||
|
||||
#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
|
||||
static struct itemdef def_table[] = {
|
||||
@@ -90,6 +104,7 @@ static struct itemdef def_table[] = {
|
||||
{"FAKE_SHELL", NULL},
|
||||
{"GID_MAX", NULL},
|
||||
{"GID_MIN", NULL},
|
||||
{"HOME_MODE", NULL},
|
||||
{"HUSHLOGIN_FILE", NULL},
|
||||
{"KILLCHAR", NULL},
|
||||
{"LASTLOG_UID_MAX", NULL},
|
||||
@@ -101,12 +116,20 @@ static struct itemdef def_table[] = {
|
||||
{"MAIL_FILE", NULL},
|
||||
{"MAX_MEMBERS_PER_GROUP", NULL},
|
||||
{"MD5_CRYPT_ENAB", NULL},
|
||||
{"NONEXISTENT", NULL},
|
||||
{"PASS_MAX_DAYS", NULL},
|
||||
{"PASS_MIN_DAYS", NULL},
|
||||
{"PASS_WARN_AGE", NULL},
|
||||
#ifdef USE_SHA_CRYPT
|
||||
{"SHA_CRYPT_MAX_ROUNDS", NULL},
|
||||
{"SHA_CRYPT_MIN_ROUNDS", NULL},
|
||||
#endif
|
||||
#ifdef USE_BCRYPT
|
||||
{"BCRYPT_MAX_ROUNDS", NULL},
|
||||
{"BCRYPT_MIN_ROUNDS", NULL},
|
||||
#endif
|
||||
#ifdef USE_YESCRYPT
|
||||
{"YESCRYPT_COST_FACTOR", NULL},
|
||||
#endif
|
||||
{"SUB_GID_COUNT", NULL},
|
||||
{"SUB_GID_MAX", NULL},
|
||||
@@ -141,6 +164,8 @@ static struct itemdef def_table[] = {
|
||||
{"USE_TCB", NULL},
|
||||
#endif
|
||||
{"FORCE_SHADOW", NULL},
|
||||
{"GRANT_AUX_GROUP_SUBIDS", NULL},
|
||||
{"PREVENT_NO_AUTH", NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -149,14 +174,24 @@ static struct itemdef knowndef_table[] = {
|
||||
#ifdef USE_PAM
|
||||
PAMDEFS
|
||||
#endif
|
||||
FOREIGNDEFS
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
#ifdef USE_ECONF
|
||||
#ifdef VENDORDIR
|
||||
static const char* vendordir = VENDORDIR;
|
||||
#else
|
||||
static const char* vendordir = NULL;
|
||||
#endif
|
||||
static const char* sysconfdir = "/etc";
|
||||
#else
|
||||
#ifndef LOGINDEFS
|
||||
#define LOGINDEFS "/etc/login.defs"
|
||||
#endif
|
||||
|
||||
static const char* def_fname = LOGINDEFS; /* login config defs file */
|
||||
#endif
|
||||
static bool def_loaded = false; /* are defs already loaded? */
|
||||
|
||||
/* local function prototypes */
|
||||
@@ -232,7 +267,7 @@ int getdef_num (const char *item, int dflt)
|
||||
if ( (getlong (d->value, &val) == 0)
|
||||
|| (val > INT_MAX)
|
||||
|| (val < INT_MIN)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
@@ -267,7 +302,7 @@ unsigned int getdef_unum (const char *item, unsigned int dflt)
|
||||
if ( (getlong (d->value, &val) == 0)
|
||||
|| (val < 0)
|
||||
|| (val > INT_MAX)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
@@ -300,7 +335,7 @@ long getdef_long (const char *item, long dflt)
|
||||
}
|
||||
|
||||
if (getlong (d->value, &val) == 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
@@ -333,7 +368,7 @@ unsigned long getdef_ulong (const char *item, unsigned long dflt)
|
||||
|
||||
if (getulong (d->value, &val) == 0) {
|
||||
/* FIXME: we should have a getulong */
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
@@ -371,7 +406,7 @@ int putdef_str (const char *name, const char *value)
|
||||
cp = strdup (value);
|
||||
if (NULL == cp) {
|
||||
(void) fputs (_("Could not allocate space for config info.\n"),
|
||||
stderr);
|
||||
shadow_logfd);
|
||||
SYSLOG ((LOG_ERR, "could not allocate space for config info"));
|
||||
return -1;
|
||||
}
|
||||
@@ -396,7 +431,6 @@ static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
|
||||
{
|
||||
struct itemdef *ptr;
|
||||
|
||||
|
||||
/*
|
||||
* Search into the table.
|
||||
*/
|
||||
@@ -416,7 +450,7 @@ static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("configuration error - unknown item '%s' (notify administrator)\n"),
|
||||
name);
|
||||
SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name));
|
||||
@@ -433,7 +467,27 @@ out:
|
||||
|
||||
void setdef_config_file (const char* file)
|
||||
{
|
||||
#ifdef USE_ECONF
|
||||
size_t len;
|
||||
char* cp;
|
||||
|
||||
len = strlen(file) + strlen(sysconfdir) + 2;
|
||||
cp = malloc(len);
|
||||
if (cp == NULL)
|
||||
exit (13);
|
||||
snprintf(cp, len, "%s/%s", file, sysconfdir);
|
||||
sysconfdir = cp;
|
||||
#ifdef VENDORDIR
|
||||
len = strlen(file) + strlen(vendordir) + 2;
|
||||
cp = malloc(len);
|
||||
if (cp == NULL)
|
||||
exit (13);
|
||||
snprintf(cp, len, "%s/%s", file, vendordir);
|
||||
vendordir = cp;
|
||||
#endif
|
||||
#else
|
||||
def_fname = file;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -444,9 +498,16 @@ void setdef_config_file (const char* file)
|
||||
|
||||
static void def_load (void)
|
||||
{
|
||||
#ifdef USE_ECONF
|
||||
econf_file *defs_file = NULL;
|
||||
econf_err error;
|
||||
char **keys;
|
||||
size_t key_number;
|
||||
#else
|
||||
int i;
|
||||
FILE *fp;
|
||||
char buf[1024], *name, *value, *s;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the initialized flag.
|
||||
@@ -454,6 +515,42 @@ static void def_load (void)
|
||||
*/
|
||||
def_loaded = true;
|
||||
|
||||
#ifdef USE_ECONF
|
||||
|
||||
error = econf_readDirs (&defs_file, vendordir, sysconfdir, "login", "defs", " \t", "#");
|
||||
if (error) {
|
||||
if (error == ECONF_NOFILE)
|
||||
return;
|
||||
|
||||
SYSLOG ((LOG_CRIT, "cannot open login definitions [%s]",
|
||||
econf_errString(error)));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ((error = econf_getKeys(defs_file, NULL, &key_number, &keys))) {
|
||||
SYSLOG ((LOG_CRIT, "cannot read login definitions [%s]",
|
||||
econf_errString(error)));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < key_number; i++) {
|
||||
char *value;
|
||||
|
||||
econf_getStringValue(defs_file, NULL, keys[i], &value);
|
||||
|
||||
/*
|
||||
* Store the value in def_table.
|
||||
*
|
||||
* Ignore failures to load the login.defs file.
|
||||
* The error was already reported to the user and to
|
||||
* syslog. The tools will just use their default values.
|
||||
*/
|
||||
(void)putdef_str (keys[i], value);
|
||||
}
|
||||
|
||||
econf_free (keys);
|
||||
econf_free (defs_file);
|
||||
#else
|
||||
/*
|
||||
* Open the configuration definitions file.
|
||||
*/
|
||||
@@ -517,6 +614,7 @@ static void def_load (void)
|
||||
}
|
||||
|
||||
(void) fclose (fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,18 @@
|
||||
return gr;
|
||||
}
|
||||
|
||||
void gr_free_members (struct group *grent)
|
||||
{
|
||||
if (NULL != grent->gr_mem) {
|
||||
size_t i;
|
||||
for (i = 0; NULL != grent->gr_mem[i]; i++) {
|
||||
free (grent->gr_mem[i]);
|
||||
}
|
||||
free (grent->gr_mem);
|
||||
grent->gr_mem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
||||
{
|
||||
free (grent->gr_name);
|
||||
@@ -94,13 +106,36 @@ void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
||||
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
||||
free (grent->gr_passwd);
|
||||
}
|
||||
if (NULL != grent->gr_mem) {
|
||||
size_t i;
|
||||
for (i = 0; NULL != grent->gr_mem[i]; i++) {
|
||||
free (grent->gr_mem[i]);
|
||||
}
|
||||
free (grent->gr_mem);
|
||||
}
|
||||
gr_free_members(grent);
|
||||
free (grent);
|
||||
}
|
||||
|
||||
bool gr_append_member(struct group *grp, char *member)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (NULL == grp->gr_mem || grp->gr_mem[0] == NULL) {
|
||||
grp->gr_mem = (char **)malloc(2 * sizeof(char *));
|
||||
if (!grp->gr_mem) {
|
||||
return false;
|
||||
}
|
||||
grp->gr_mem[0] = strdup(member);
|
||||
if (!grp->gr_mem[0]) {
|
||||
return false;
|
||||
}
|
||||
grp->gr_mem[1] = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; grp->gr_mem[i]; i++) ;
|
||||
grp->gr_mem = realloc(grp->gr_mem, (i + 2) * sizeof(char *));
|
||||
if (NULL == grp->gr_mem) {
|
||||
return false;
|
||||
}
|
||||
grp->gr_mem[i] = strdup(member);
|
||||
if (NULL == grp->gr_mem[i]) {
|
||||
return false;
|
||||
}
|
||||
grp->gr_mem[i + 1] = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ int nscd_flush_cache (const char *service)
|
||||
|
||||
if (run_command (cmd, spawnedArgs, spawnedEnv, &status) != 0) {
|
||||
/* run_command writes its own more detailed message. */
|
||||
(void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||
(void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||
return -1;
|
||||
}
|
||||
|
||||
code = WEXITSTATUS (status);
|
||||
if (!WIFEXITED (status)) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: nscd did not terminate normally (signal %d)\n"),
|
||||
Prog, WTERMSIG (status));
|
||||
return -1;
|
||||
@@ -43,9 +43,9 @@ int nscd_flush_cache (const char *service)
|
||||
/* nscd is installed, but it isn't active. */
|
||||
return 0;
|
||||
} else if (code != 0) {
|
||||
(void) fprintf (stderr, _("%s: nscd exited with status %d\n"),
|
||||
(void) fprintf (shadow_logfd, _("%s: nscd exited with status %d\n"),
|
||||
Prog, code);
|
||||
(void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||
(void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
149
lib/nss.c
Normal file
149
lib/nss.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
#include <stdatomic.h>
|
||||
#include "prototypes.h"
|
||||
#include "../libsubid/subid.h"
|
||||
|
||||
#define NSSWITCH "/etc/nsswitch.conf"
|
||||
|
||||
// NSS plugin handling for subids
|
||||
// If nsswitch has a line like
|
||||
// subid: sssd
|
||||
// then sssd will be consulted for subids. Unlike normal NSS dbs,
|
||||
// only one db is supported at a time. That's open to debate, but
|
||||
// the subids are a pretty limited resource, and local files seem
|
||||
// bound to step on any other allocations leading to insecure
|
||||
// conditions.
|
||||
static atomic_flag nss_init_started;
|
||||
static atomic_bool nss_init_completed;
|
||||
|
||||
static struct subid_nss_ops *subid_nss;
|
||||
|
||||
bool nss_is_initialized() {
|
||||
return atomic_load(&nss_init_completed);
|
||||
}
|
||||
|
||||
void nss_exit() {
|
||||
if (nss_is_initialized() && subid_nss) {
|
||||
dlclose(subid_nss->handle);
|
||||
free(subid_nss);
|
||||
subid_nss = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// nsswitch_path is an argument only to support testing.
|
||||
void nss_init(char *nsswitch_path) {
|
||||
FILE *nssfp = NULL;
|
||||
char *line = NULL, *p, *token, *saveptr;
|
||||
size_t len = 0;
|
||||
|
||||
if (atomic_flag_test_and_set(&nss_init_started)) {
|
||||
// Another thread has started nss_init, wait for it to complete
|
||||
while (!atomic_load(&nss_init_completed))
|
||||
usleep(100);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nsswitch_path)
|
||||
nsswitch_path = NSSWITCH;
|
||||
|
||||
// read nsswitch.conf to check for a line like:
|
||||
// subid: files
|
||||
nssfp = fopen(nsswitch_path, "r");
|
||||
if (!nssfp) {
|
||||
fprintf(shadow_logfd, "Failed opening %s: %m", nsswitch_path);
|
||||
atomic_store(&nss_init_completed, true);
|
||||
return;
|
||||
}
|
||||
while ((getline(&line, &len, nssfp)) != -1) {
|
||||
if (line[0] == '\0' || line[0] == '#')
|
||||
continue;
|
||||
if (strlen(line) < 8)
|
||||
continue;
|
||||
if (strncasecmp(line, "subid:", 6) != 0)
|
||||
continue;
|
||||
p = &line[6];
|
||||
while ((*p) && isspace(*p))
|
||||
p++;
|
||||
if (!*p)
|
||||
continue;
|
||||
for (token = strtok_r(p, " \n\t", &saveptr);
|
||||
token;
|
||||
token = strtok_r(NULL, " \n\t", &saveptr)) {
|
||||
char libname[65];
|
||||
void *h;
|
||||
if (strcmp(token, "files") == 0) {
|
||||
subid_nss = NULL;
|
||||
goto done;
|
||||
}
|
||||
if (strlen(token) > 50) {
|
||||
fprintf(shadow_logfd, "Subid NSS module name too long (longer than 50 characters): %s\n", token);
|
||||
fprintf(shadow_logfd, "Using files\n");
|
||||
subid_nss = NULL;
|
||||
goto done;
|
||||
}
|
||||
snprintf(libname, 64, "libsubid_%s.so", token);
|
||||
h = dlopen(libname, RTLD_LAZY);
|
||||
if (!h) {
|
||||
fprintf(shadow_logfd, "Error opening %s: %s\n", libname, dlerror());
|
||||
fprintf(shadow_logfd, "Using files\n");
|
||||
subid_nss = NULL;
|
||||
goto done;
|
||||
}
|
||||
subid_nss = malloc(sizeof(*subid_nss));
|
||||
if (!subid_nss) {
|
||||
dlclose(h);
|
||||
goto done;
|
||||
}
|
||||
subid_nss->has_range = dlsym(h, "shadow_subid_has_range");
|
||||
if (!subid_nss->has_range) {
|
||||
fprintf(shadow_logfd, "%s did not provide @has_range@\n", libname);
|
||||
dlclose(h);
|
||||
free(subid_nss);
|
||||
subid_nss = NULL;
|
||||
goto done;
|
||||
}
|
||||
subid_nss->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges");
|
||||
if (!subid_nss->list_owner_ranges) {
|
||||
fprintf(shadow_logfd, "%s did not provide @list_owner_ranges@\n", libname);
|
||||
dlclose(h);
|
||||
free(subid_nss);
|
||||
subid_nss = NULL;
|
||||
goto done;
|
||||
}
|
||||
subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners");
|
||||
if (!subid_nss->find_subid_owners) {
|
||||
fprintf(shadow_logfd, "%s did not provide @find_subid_owners@\n", libname);
|
||||
dlclose(h);
|
||||
free(subid_nss);
|
||||
subid_nss = NULL;
|
||||
goto done;
|
||||
}
|
||||
subid_nss->handle = h;
|
||||
goto done;
|
||||
}
|
||||
fprintf(shadow_logfd, "No usable subid NSS module found, using files\n");
|
||||
// subid_nss has to be null here, but to ease reviews:
|
||||
free(subid_nss);
|
||||
subid_nss = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
atomic_store(&nss_init_completed, true);
|
||||
free(line);
|
||||
if (nssfp) {
|
||||
atexit(nss_exit);
|
||||
fclose(nssfp);
|
||||
}
|
||||
}
|
||||
|
||||
struct subid_nss_ops *get_subid_nss_handle() {
|
||||
nss_init(NULL);
|
||||
return subid_nss;
|
||||
}
|
||||
@@ -59,7 +59,8 @@
|
||||
#include "defines.h"
|
||||
#include "commonio.h"
|
||||
|
||||
extern /*@observer@*/ const char *Prog;
|
||||
extern /*@observer@*/ const char *Prog; /* Program name showed in error messages */
|
||||
extern FILE *shadow_logfd; /* file descripter to which error messages are printed */
|
||||
|
||||
/* addgrps.c */
|
||||
#if defined (HAVE_SETGROUPS) && ! defined (USE_PAM)
|
||||
@@ -161,12 +162,10 @@ extern int find_new_uid (bool sys_user,
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
/* find_new_sub_gids.c */
|
||||
extern int find_new_sub_gids (const char *owner,
|
||||
gid_t *range_start, unsigned long *range_count);
|
||||
extern int find_new_sub_gids (gid_t *range_start, unsigned long *range_count);
|
||||
|
||||
/* find_new_sub_uids.c */
|
||||
extern int find_new_sub_uids (const char *owner,
|
||||
uid_t *range_start, unsigned long *range_count);
|
||||
extern int find_new_sub_uids (uid_t *range_start, unsigned long *range_count);
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
|
||||
|
||||
@@ -208,7 +207,9 @@ extern void __gr_set_changed (void);
|
||||
|
||||
/* groupmem.c */
|
||||
extern /*@null@*/ /*@only@*/struct group *__gr_dup (const struct group *grent);
|
||||
extern void gr_free_members (struct group *grent);
|
||||
extern void gr_free (/*@out@*/ /*@only@*/struct group *grent);
|
||||
extern bool gr_append_member (struct group *grp, char *member);
|
||||
|
||||
/* hushed.c */
|
||||
extern bool hushed (const char *username);
|
||||
@@ -262,6 +263,62 @@ extern void motd (void);
|
||||
/* myname.c */
|
||||
extern /*@null@*//*@only@*/struct passwd *get_my_pwent (void);
|
||||
|
||||
/* nss.c */
|
||||
#include <libsubid/subid.h>
|
||||
extern void nss_init(char *nsswitch_path);
|
||||
extern bool nss_is_initialized();
|
||||
|
||||
struct subid_nss_ops {
|
||||
/*
|
||||
* nss_has_range: does a user own a given subid range
|
||||
*
|
||||
* @owner: username
|
||||
* @start: first subid in queried range
|
||||
* @count: number of subids in queried range
|
||||
* @idtype: subuid or subgid
|
||||
* @result: true if @owner has been allocated the subid range.
|
||||
*
|
||||
* returns success if the module was able to determine an answer (true or false),
|
||||
* else an error status.
|
||||
*/
|
||||
enum subid_status (*has_range)(const char *owner, unsigned long start, unsigned long count, enum subid_type idtype, bool *result);
|
||||
|
||||
/*
|
||||
* nss_list_owner_ranges: list the subid ranges delegated to a user.
|
||||
*
|
||||
* @owner - string representing username being queried
|
||||
* @id_type - subuid or subgid
|
||||
* @ranges - pointer to an array of struct subid_range, or NULL. The
|
||||
* returned array must be freed by the caller.
|
||||
* @count - pointer to an integer into which the number of returned ranges
|
||||
* is written.
|
||||
|
||||
* returns success if the module was able to determine an answer,
|
||||
* else an error status.
|
||||
*/
|
||||
enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subid_range **ranges, int *count);
|
||||
|
||||
/*
|
||||
* nss_find_subid_owners: find uids who own a given subuid or subgid.
|
||||
*
|
||||
* @id - the delegated id (subuid or subgid) being queried
|
||||
* @id_type - subuid or subgid
|
||||
* @uids - pointer to an array of uids which will be allocated by
|
||||
* nss_find_subid_owners()
|
||||
* @count - number of uids found
|
||||
*
|
||||
* returns success if the module was able to determine an answer,
|
||||
* else an error status.
|
||||
*/
|
||||
enum subid_status (*find_subid_owners)(unsigned long id, enum subid_type id_type, uid_t **uids, int *count);
|
||||
|
||||
/* The dlsym handle to close */
|
||||
void *handle;
|
||||
};
|
||||
|
||||
extern struct subid_nss_ops *get_subid_nss_handle();
|
||||
|
||||
|
||||
/* pam_pass_non_interactive.c */
|
||||
#ifdef USE_PAM
|
||||
extern int do_pam_passwd_non_interactive (const char *pam_service,
|
||||
@@ -334,8 +391,9 @@ extern /*@observer@*/const char *crypt_make_salt (/*@null@*//*@observer@*/const
|
||||
|
||||
/* selinux.c */
|
||||
#ifdef WITH_SELINUX
|
||||
extern int set_selinux_file_context (const char *dst_name);
|
||||
extern int set_selinux_file_context (const char *dst_name, mode_t mode);
|
||||
extern int reset_selinux_file_context (void);
|
||||
extern int check_selinux_permit (const char *perm_name);
|
||||
#endif
|
||||
|
||||
/* semanage.c */
|
||||
@@ -447,6 +505,7 @@ extern bool valid (const char *, const struct passwd *);
|
||||
extern /*@maynotreturn@*/ /*@only@*//*@out@*//*@notnull@*/char *xmalloc (size_t size)
|
||||
/*@ensures MaxSet(result) == (size - 1); @*/;
|
||||
extern /*@maynotreturn@*/ /*@only@*//*@notnull@*/char *xstrdup (const char *);
|
||||
extern void xfree(void *ap);
|
||||
|
||||
/* xgetpwnam.c */
|
||||
extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *);
|
||||
|
||||
102
lib/run_part.c
Normal file
102
lib/run_part.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <lib/prototypes.h>
|
||||
|
||||
int run_part (char *script_path, char *name, char *action)
|
||||
{
|
||||
int pid;
|
||||
int wait_status;
|
||||
int pid_status;
|
||||
char *args[] = { script_path, NULL };
|
||||
|
||||
pid=fork();
|
||||
if (pid==-1){
|
||||
perror ("Could not fork");
|
||||
return 1;
|
||||
}
|
||||
if (pid==0) {
|
||||
setenv ("ACTION",action,1);
|
||||
setenv ("SUBJECT",name,1);
|
||||
execv (script_path,args);
|
||||
perror ("execv");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pid_status = wait (&wait_status);
|
||||
if (pid_status == pid) {
|
||||
return (wait_status);
|
||||
}
|
||||
|
||||
perror ("waitpid");
|
||||
return (1);
|
||||
}
|
||||
|
||||
int run_parts (char *directory, char *name, char *action)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
int scanlist;
|
||||
int n;
|
||||
int execute_result;
|
||||
|
||||
scanlist = scandir (directory, &namelist, 0, alphasort);
|
||||
if (scanlist<0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (n=0; n<scanlist; n++) {
|
||||
int path_length;
|
||||
struct stat sb;
|
||||
|
||||
path_length=strlen(directory) + strlen(namelist[n]->d_name) + 2;
|
||||
char *s = (char*)malloc(path_length);
|
||||
if (!s) {
|
||||
printf ("could not allocate memory\n");
|
||||
for (; n<scanlist; n++) {
|
||||
free (namelist[n]);
|
||||
}
|
||||
free (namelist);
|
||||
return (1);
|
||||
}
|
||||
snprintf (s, path_length, "%s/%s", directory, namelist[n]->d_name);
|
||||
|
||||
execute_result = 0;
|
||||
if (stat (s, &sb) == -1) {
|
||||
perror ("stat");
|
||||
free (s);
|
||||
for (; n<scanlist; n++) {
|
||||
free (namelist[n]);
|
||||
}
|
||||
free (namelist);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (S_ISREG (sb.st_mode) || S_ISLNK (sb.st_mode)) {
|
||||
execute_result = run_part (s, name, action);
|
||||
}
|
||||
|
||||
free (s);
|
||||
|
||||
if (execute_result!=0) {
|
||||
fprintf (shadow_logfd,
|
||||
"%s: did not exit cleanly.\n",
|
||||
namelist[n]->d_name);
|
||||
for (; n<scanlist; n++) {
|
||||
free (namelist[n]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
free (namelist[n]);
|
||||
}
|
||||
free (namelist);
|
||||
|
||||
return (execute_result);
|
||||
}
|
||||
|
||||
2
lib/run_part.h
Normal file
2
lib/run_part.h
Normal file
@@ -0,0 +1,2 @@
|
||||
int run_part (char *script_path, char *name, char *action);
|
||||
int run_parts (char *directory, char *name, char *action);
|
||||
151
lib/selinux.c
151
lib/selinux.c
@@ -31,14 +31,24 @@
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
|
||||
#include <stdio.h>
|
||||
#include "defines.h"
|
||||
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
|
||||
static bool selinux_checked = false;
|
||||
static bool selinux_enabled;
|
||||
static /*@null@*/struct selabel_handle *selabel_hnd = NULL;
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
if (selabel_hnd) {
|
||||
selabel_close(selabel_hnd);
|
||||
selabel_hnd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* set_selinux_file_context - Set the security context before any file or
|
||||
@@ -50,10 +60,8 @@ static bool selinux_enabled;
|
||||
* Callers may have to Reset SELinux to create files with default
|
||||
* contexts with reset_selinux_file_context
|
||||
*/
|
||||
int set_selinux_file_context (const char *dst_name)
|
||||
int set_selinux_file_context (const char *dst_name, mode_t mode)
|
||||
{
|
||||
/*@null@*/security_context_t scontext = NULL;
|
||||
|
||||
if (!selinux_checked) {
|
||||
selinux_enabled = is_selinux_enabled () > 0;
|
||||
selinux_checked = true;
|
||||
@@ -61,18 +69,34 @@ int set_selinux_file_context (const char *dst_name)
|
||||
|
||||
if (selinux_enabled) {
|
||||
/* Get the default security context for this file */
|
||||
if (matchpathcon (dst_name, 0, &scontext) < 0) {
|
||||
if (security_getenforce () != 0) {
|
||||
return 1;
|
||||
|
||||
/*@null@*/char *fcontext_raw = NULL;
|
||||
int r;
|
||||
|
||||
if (selabel_hnd == NULL) {
|
||||
selabel_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
||||
if (selabel_hnd == NULL) {
|
||||
return security_getenforce () != 0;
|
||||
}
|
||||
(void) atexit(cleanup);
|
||||
}
|
||||
|
||||
r = selabel_lookup_raw(selabel_hnd, &fcontext_raw, dst_name, mode);
|
||||
if (r < 0) {
|
||||
/* No context specified for the searched path */
|
||||
if (errno == ENOENT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return security_getenforce () != 0;
|
||||
}
|
||||
|
||||
/* Set the security context for the next created file */
|
||||
if (setfscreatecon (scontext) < 0) {
|
||||
if (security_getenforce () != 0) {
|
||||
return 1;
|
||||
}
|
||||
r = setfscreatecon_raw (fcontext_raw);
|
||||
freecon (fcontext_raw);
|
||||
if (r < 0) {
|
||||
return security_getenforce () != 0;
|
||||
}
|
||||
freecon (scontext);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -91,13 +115,112 @@ int reset_selinux_file_context (void)
|
||||
selinux_checked = true;
|
||||
}
|
||||
if (selinux_enabled) {
|
||||
if (setfscreatecon (NULL) != 0) {
|
||||
return 1;
|
||||
if (setfscreatecon_raw (NULL) != 0) {
|
||||
return security_getenforce () != 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log callback for libselinux internal error reporting.
|
||||
*/
|
||||
__attribute__((__format__ (printf, 2, 3)))
|
||||
static int selinux_log_cb (int type, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char *buf;
|
||||
int r;
|
||||
#ifdef WITH_AUDIT
|
||||
static int selinux_audit_fd = -2;
|
||||
#endif
|
||||
|
||||
va_start (ap, fmt);
|
||||
r = vasprintf (&buf, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (r < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_AUDIT
|
||||
if (-2 == selinux_audit_fd) {
|
||||
selinux_audit_fd = audit_open ();
|
||||
|
||||
if (-1 == selinux_audit_fd) {
|
||||
/* You get these only when the kernel doesn't have
|
||||
* audit compiled in. */
|
||||
if ( (errno != EINVAL)
|
||||
&& (errno != EPROTONOSUPPORT)
|
||||
&& (errno != EAFNOSUPPORT)) {
|
||||
|
||||
(void) fputs (_("Cannot open audit interface.\n"),
|
||||
shadow_logfd);
|
||||
SYSLOG ((LOG_WARN, "Cannot open audit interface."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-1 != selinux_audit_fd) {
|
||||
if (SELINUX_AVC == type) {
|
||||
if (audit_log_user_avc_message (selinux_audit_fd,
|
||||
AUDIT_USER_AVC, buf, NULL, NULL,
|
||||
NULL, 0) > 0) {
|
||||
goto skip_syslog;
|
||||
}
|
||||
} else if (SELINUX_ERROR == type) {
|
||||
if (audit_log_user_avc_message (selinux_audit_fd,
|
||||
AUDIT_USER_SELINUX_ERR, buf, NULL, NULL,
|
||||
NULL, 0) > 0) {
|
||||
goto skip_syslog;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SYSLOG ((LOG_WARN, "libselinux: %s", buf));
|
||||
|
||||
skip_syslog:
|
||||
free (buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* check_selinux_permit - Check whether SELinux grants the given
|
||||
* operation
|
||||
*
|
||||
* Parameter is the SELinux permission name, e.g. rootok
|
||||
*
|
||||
* Returns 0 when permission is granted
|
||||
* or something failed but running in
|
||||
* permissive mode
|
||||
*/
|
||||
int check_selinux_permit (const char *perm_name)
|
||||
{
|
||||
char *user_context_raw;
|
||||
int r;
|
||||
|
||||
if (0 == is_selinux_enabled ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
selinux_set_callback (SELINUX_CB_LOG, (union selinux_callback) selinux_log_cb);
|
||||
|
||||
if (getprevcon_raw (&user_context_raw) != 0) {
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: can not get previous SELinux process context: %s\n"),
|
||||
Prog, strerror (errno));
|
||||
SYSLOG ((LOG_WARN,
|
||||
"can not get previous SELinux process context: %s",
|
||||
strerror (errno)));
|
||||
return (security_getenforce () != 0);
|
||||
}
|
||||
|
||||
r = selinux_check_access (user_context_raw, user_context_raw, "passwd", perm_name, NULL);
|
||||
freecon (user_context_raw);
|
||||
return r;
|
||||
}
|
||||
|
||||
#else /* !WITH_SELINUX */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !WITH_SELINUX */
|
||||
|
||||
@@ -69,7 +69,7 @@ static void semanage_error_callback (unused void *varg,
|
||||
switch (semanage_msg_get_level (handle)) {
|
||||
case SEMANAGE_MSG_ERR:
|
||||
case SEMANAGE_MSG_WARN:
|
||||
fprintf (stderr, _("[libsemanage]: %s\n"), message);
|
||||
fprintf (shadow_logfd, _("[libsemanage]: %s\n"), message);
|
||||
break;
|
||||
case SEMANAGE_MSG_INFO:
|
||||
/* nop */
|
||||
@@ -87,7 +87,7 @@ static semanage_handle_t *semanage_init (void)
|
||||
|
||||
handle = semanage_handle_create ();
|
||||
if (NULL == handle) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Cannot create SELinux management handle\n"));
|
||||
return NULL;
|
||||
}
|
||||
@@ -96,26 +96,26 @@ static semanage_handle_t *semanage_init (void)
|
||||
|
||||
ret = semanage_is_managed (handle);
|
||||
if (ret != 1) {
|
||||
fprintf (stderr, _("SELinux policy not managed\n"));
|
||||
fprintf (shadow_logfd, _("SELinux policy not managed\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = semanage_access_check (handle);
|
||||
if (ret < SEMANAGE_CAN_READ) {
|
||||
fprintf (stderr, _("Cannot read SELinux policy store\n"));
|
||||
fprintf (shadow_logfd, _("Cannot read SELinux policy store\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = semanage_connect (handle);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Cannot establish SELinux management connection\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = semanage_begin_transaction (handle);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Cannot begin SELinux transaction\n"));
|
||||
fprintf (shadow_logfd, _("Cannot begin SELinux transaction\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ static int semanage_user_mod (semanage_handle_t *handle,
|
||||
|
||||
semanage_seuser_query (handle, key, &seuser);
|
||||
if (NULL == seuser) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not query seuser for %s\n"), login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
@@ -145,7 +145,7 @@ static int semanage_user_mod (semanage_handle_t *handle,
|
||||
|
||||
ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not set serange for %s\n"), login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
@@ -153,7 +153,7 @@ static int semanage_user_mod (semanage_handle_t *handle,
|
||||
|
||||
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not set sename for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
@@ -162,7 +162,7 @@ static int semanage_user_mod (semanage_handle_t *handle,
|
||||
|
||||
ret = semanage_seuser_modify_local (handle, key, seuser);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not modify login mapping for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
@@ -186,7 +186,7 @@ static int semanage_user_add (semanage_handle_t *handle,
|
||||
|
||||
ret = semanage_seuser_create (handle, &seuser);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Cannot create SELinux login mapping for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
@@ -195,14 +195,14 @@ static int semanage_user_add (semanage_handle_t *handle,
|
||||
|
||||
ret = semanage_seuser_set_name (handle, seuser, login_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Could not set name for %s\n"), login_name);
|
||||
fprintf (shadow_logfd, _("Could not set name for %s\n"), login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not set serange for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
@@ -211,7 +211,7 @@ static int semanage_user_add (semanage_handle_t *handle,
|
||||
|
||||
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not set SELinux user for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
@@ -220,7 +220,7 @@ static int semanage_user_add (semanage_handle_t *handle,
|
||||
|
||||
ret = semanage_seuser_modify_local (handle, key, seuser);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not add login mapping for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
@@ -248,21 +248,21 @@ int set_seuser (const char *login_name, const char *seuser_name)
|
||||
|
||||
handle = semanage_init ();
|
||||
if (NULL == handle) {
|
||||
fprintf (stderr, _("Cannot init SELinux management\n"));
|
||||
fprintf (shadow_logfd, _("Cannot init SELinux management\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_key_create (handle, login_name, &key);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Cannot create SELinux user key\n"));
|
||||
fprintf (shadow_logfd, _("Cannot create SELinux user key\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_exists (handle, key, &seuser_exists);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot verify the SELinux user\n"));
|
||||
fprintf (shadow_logfd, _("Cannot verify the SELinux user\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
@@ -270,7 +270,7 @@ int set_seuser (const char *login_name, const char *seuser_name)
|
||||
if (0 != seuser_exists) {
|
||||
ret = semanage_user_mod (handle, key, login_name, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Cannot modify SELinux user mapping\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
@@ -278,7 +278,7 @@ int set_seuser (const char *login_name, const char *seuser_name)
|
||||
} else {
|
||||
ret = semanage_user_add (handle, key, login_name, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Cannot add SELinux user mapping\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
@@ -287,7 +287,7 @@ int set_seuser (const char *login_name, const char *seuser_name)
|
||||
|
||||
ret = semanage_commit (handle);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot commit SELinux transaction\n"));
|
||||
fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
@@ -310,27 +310,27 @@ int del_seuser (const char *login_name)
|
||||
|
||||
handle = semanage_init ();
|
||||
if (NULL == handle) {
|
||||
fprintf (stderr, _("Cannot init SELinux management\n"));
|
||||
fprintf (shadow_logfd, _("Cannot init SELinux management\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_key_create (handle, login_name, &key);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Cannot create SELinux user key\n"));
|
||||
fprintf (shadow_logfd, _("Cannot create SELinux user key\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_exists (handle, key, &exists);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot verify the SELinux user\n"));
|
||||
fprintf (shadow_logfd, _("Cannot verify the SELinux user\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 == exists) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Login mapping for %s is not defined, OK if default mapping was used\n"),
|
||||
login_name);
|
||||
ret = 0; /* probably default mapping */
|
||||
@@ -339,13 +339,13 @@ int del_seuser (const char *login_name)
|
||||
|
||||
ret = semanage_seuser_exists_local (handle, key, &exists);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot verify the SELinux user\n"));
|
||||
fprintf (shadow_logfd, _("Cannot verify the SELinux user\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 == exists) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Login mapping for %s is defined in policy, cannot be deleted\n"),
|
||||
login_name);
|
||||
ret = 0; /* Login mapping defined in policy can't be deleted */
|
||||
@@ -354,7 +354,7 @@ int del_seuser (const char *login_name)
|
||||
|
||||
ret = semanage_seuser_del_local (handle, key);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Could not delete login mapping for %s"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
@@ -363,7 +363,7 @@ int del_seuser (const char *login_name)
|
||||
|
||||
ret = semanage_commit (handle);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot commit SELinux transaction\n"));
|
||||
fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ struct group *sgetgrent (const char *buf)
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
if (i < (NFIELDS - 1) || *grpfields[2] == '\0') {
|
||||
if (i < (NFIELDS - 1) || *grpfields[2] == '\0' || cp != NULL) {
|
||||
return (struct group *) 0;
|
||||
}
|
||||
grent.gr_name = grpfields[0];
|
||||
|
||||
@@ -90,6 +90,11 @@ struct passwd *sgetpwent (const char *buf)
|
||||
}
|
||||
}
|
||||
|
||||
/* something at the end, columns over shot */
|
||||
if( cp != NULL ) {
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
* There must be exactly NFIELDS colon separated fields or
|
||||
* the entry is invalid. Also, the UID and GID must be non-blank.
|
||||
|
||||
@@ -52,7 +52,6 @@ struct spwd *sgetspent (const char *string)
|
||||
static struct spwd spwd;
|
||||
char *fields[FIELDS];
|
||||
char *cp;
|
||||
char *cpp;
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
||||
@@ -130,7 +130,6 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
static struct spwd spwd;
|
||||
char *fields[FIELDS];
|
||||
char *cp;
|
||||
char *cpp;
|
||||
int i;
|
||||
|
||||
/*
|
||||
@@ -389,7 +388,6 @@ struct spwd *getspent (void)
|
||||
#ifdef USE_NIS
|
||||
int nis_1_user = 0;
|
||||
struct spwd *val;
|
||||
char buf[BUFSIZ];
|
||||
#endif
|
||||
if (NULL == shadow) {
|
||||
setspent ();
|
||||
@@ -484,7 +482,6 @@ struct spwd *getspnam (const char *name)
|
||||
struct spwd *sp;
|
||||
|
||||
#ifdef USE_NIS
|
||||
char buf[BUFSIZ];
|
||||
static char save_name[16];
|
||||
bool nis_disabled = false;
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,7 @@ int run_command (const char *cmd, const char *argv[],
|
||||
}
|
||||
|
||||
(void) fflush (stdout);
|
||||
(void) fflush (stderr);
|
||||
(void) fflush (shadow_logfd);
|
||||
|
||||
pid = fork ();
|
||||
if (0 == pid) {
|
||||
@@ -57,11 +57,11 @@ int run_command (const char *cmd, const char *argv[],
|
||||
if (ENOENT == errno) {
|
||||
exit (E_CMD_NOTFOUND);
|
||||
}
|
||||
fprintf (stderr, "%s: cannot execute %s: %s\n",
|
||||
fprintf (shadow_logfd, "%s: cannot execute %s: %s\n",
|
||||
Prog, cmd, strerror (errno));
|
||||
exit (E_CMD_NOEXEC);
|
||||
} else if ((pid_t)-1 == pid) {
|
||||
fprintf (stderr, "%s: cannot execute %s: %s\n",
|
||||
fprintf (shadow_logfd, "%s: cannot execute %s: %s\n",
|
||||
Prog, cmd, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
@@ -74,7 +74,7 @@ int run_command (const char *cmd, const char *argv[],
|
||||
|| ((pid_t)-1 != wpid && wpid != pid));
|
||||
|
||||
if ((pid_t)-1 == wpid) {
|
||||
fprintf (stderr, "%s: waitpid (status: %d): %s\n",
|
||||
fprintf (shadow_logfd, "%s: waitpid (status: %d): %s\n",
|
||||
Prog, *status, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
14
lib/sssd.c
14
lib/sssd.c
@@ -11,7 +11,7 @@
|
||||
#include "prototypes.h"
|
||||
#include "sssd.h"
|
||||
|
||||
#define MSG_SSSD_FLUSH_CACHE_FAILED "%s: Failed to flush the sssd cache.\n"
|
||||
#define MSG_SSSD_FLUSH_CACHE_FAILED "%s: Failed to flush the sssd cache."
|
||||
|
||||
int sssd_flush_cache (int dbflags)
|
||||
{
|
||||
@@ -46,24 +46,22 @@ int sssd_flush_cache (int dbflags)
|
||||
free(sss_cache_args);
|
||||
if (rv != 0) {
|
||||
/* run_command writes its own more detailed message. */
|
||||
(void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog);
|
||||
SYSLOG ((LOG_WARN, MSG_SSSD_FLUSH_CACHE_FAILED, Prog));
|
||||
return -1;
|
||||
}
|
||||
|
||||
code = WEXITSTATUS (status);
|
||||
if (!WIFEXITED (status)) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: sss_cache did not terminate normally (signal %d)\n"),
|
||||
Prog, WTERMSIG (status));
|
||||
SYSLOG ((LOG_WARN, "%s: sss_cache did not terminate normally (signal %d)",
|
||||
Prog, WTERMSIG (status)));
|
||||
return -1;
|
||||
} else if (code == E_CMD_NOTFOUND) {
|
||||
/* sss_cache is not installed, or it is installed but uses an
|
||||
interpreter that is missing. Probably the former. */
|
||||
return 0;
|
||||
} else if (code != 0) {
|
||||
(void) fprintf (stderr, _("%s: sss_cache exited with status %d\n"),
|
||||
Prog, code);
|
||||
(void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog);
|
||||
SYSLOG ((LOG_WARN, "%s: sss_cache exited with status %d", Prog, code));
|
||||
SYSLOG ((LOG_WARN, MSG_SSSD_FLUSH_CACHE_FAILED, Prog));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,16 +11,11 @@
|
||||
#include <stdio.h>
|
||||
#include "commonio.h"
|
||||
#include "subordinateio.h"
|
||||
#include "../libsubid/subid.h"
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
struct subordinate_range {
|
||||
const char *owner;
|
||||
unsigned long start;
|
||||
unsigned long count;
|
||||
};
|
||||
|
||||
#define NFIELDS 3
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/*
|
||||
* subordinate_dup: create a duplicate range
|
||||
@@ -78,7 +73,7 @@ static void *subordinate_parse (const char *line)
|
||||
static char rangebuf[1024];
|
||||
int i;
|
||||
char *cp;
|
||||
char *fields[NFIELDS];
|
||||
char *fields[SUBID_NFIELDS];
|
||||
|
||||
/*
|
||||
* Copy the string to a temporary buffer so the substrings can
|
||||
@@ -93,7 +88,7 @@ static void *subordinate_parse (const char *line)
|
||||
* field. The fields are converted into NUL terminated strings.
|
||||
*/
|
||||
|
||||
for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) {
|
||||
for (cp = rangebuf, i = 0; (i < SUBID_NFIELDS) && (NULL != cp); i++) {
|
||||
fields[i] = cp;
|
||||
while (('\0' != *cp) && (':' != *cp)) {
|
||||
cp++;
|
||||
@@ -108,10 +103,10 @@ static void *subordinate_parse (const char *line)
|
||||
}
|
||||
|
||||
/*
|
||||
* There must be exactly NFIELDS colon separated fields or
|
||||
* There must be exactly SUBID_NFIELDS colon separated fields or
|
||||
* the entry is invalid. Also, fields must be non-blank.
|
||||
*/
|
||||
if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
|
||||
if (i != SUBID_NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
|
||||
return NULL;
|
||||
range.owner = fields[0];
|
||||
if (getulong (fields[1], &range.start) == 0)
|
||||
@@ -152,11 +147,6 @@ static struct commonio_ops subordinate_ops = {
|
||||
NULL, /* close_hook */
|
||||
};
|
||||
|
||||
static /*@observer@*/ /*@null*/const struct subordinate_range *subordinate_next(struct commonio_db *db)
|
||||
{
|
||||
return (const struct subordinate_range *)commonio_next (db);
|
||||
}
|
||||
|
||||
/*
|
||||
* range_exists: Check whether @owner owns any ranges
|
||||
*
|
||||
@@ -319,6 +309,35 @@ static bool have_range(struct commonio_db *db,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool append_range(struct subid_range **ranges, const struct subordinate_range *new, int n)
|
||||
{
|
||||
if (!*ranges) {
|
||||
*ranges = malloc(sizeof(struct subid_range));
|
||||
if (!*ranges)
|
||||
return false;
|
||||
} else {
|
||||
struct subid_range *alloced;
|
||||
alloced = realloc(*ranges, (n + 1) * (sizeof(struct subid_range)));
|
||||
if (!alloced)
|
||||
return false;
|
||||
*ranges = alloced;
|
||||
}
|
||||
(*ranges)[n].start = new->start;
|
||||
(*ranges)[n].count = new->count;
|
||||
return true;
|
||||
}
|
||||
|
||||
void free_subordinate_ranges(struct subordinate_range **ranges, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ranges)
|
||||
return;
|
||||
for (i = 0; i < count; i++)
|
||||
subordinate_free(ranges[i]);
|
||||
free(ranges);
|
||||
}
|
||||
|
||||
/*
|
||||
* subordinate_range_cmp: compare uid ranges
|
||||
*
|
||||
@@ -579,23 +598,37 @@ int sub_uid_open (int mode)
|
||||
return commonio_open (&subordinate_uid_db, mode);
|
||||
}
|
||||
|
||||
bool sub_uid_assigned(const char *owner)
|
||||
bool local_sub_uid_assigned(const char *owner)
|
||||
{
|
||||
return range_exists (&subordinate_uid_db, owner);
|
||||
}
|
||||
|
||||
bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
|
||||
{
|
||||
struct subid_nss_ops *h;
|
||||
bool found;
|
||||
enum subid_status status;
|
||||
h = get_subid_nss_handle();
|
||||
if (h) {
|
||||
status = h->has_range(owner, start, count, ID_TYPE_UID, &found);
|
||||
if (status == SUBID_STATUS_SUCCESS && found)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return have_range (&subordinate_uid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_uid_add (const char *owner, uid_t start, unsigned long count)
|
||||
{
|
||||
if (get_subid_nss_handle())
|
||||
return -EOPNOTSUPP;
|
||||
return add_range (&subordinate_uid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_uid_remove (const char *owner, uid_t start, unsigned long count)
|
||||
{
|
||||
if (get_subid_nss_handle())
|
||||
return -EOPNOTSUPP;
|
||||
return remove_range (&subordinate_uid_db, owner, start, count);
|
||||
}
|
||||
|
||||
@@ -663,21 +696,35 @@ int sub_gid_open (int mode)
|
||||
|
||||
bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
|
||||
{
|
||||
struct subid_nss_ops *h;
|
||||
bool found;
|
||||
enum subid_status status;
|
||||
h = get_subid_nss_handle();
|
||||
if (h) {
|
||||
status = h->has_range(owner, start, count, ID_TYPE_GID, &found);
|
||||
if (status == SUBID_STATUS_SUCCESS && found)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return have_range(&subordinate_gid_db, owner, start, count);
|
||||
}
|
||||
|
||||
bool sub_gid_assigned(const char *owner)
|
||||
bool local_sub_gid_assigned(const char *owner)
|
||||
{
|
||||
return range_exists (&subordinate_gid_db, owner);
|
||||
}
|
||||
|
||||
int sub_gid_add (const char *owner, gid_t start, unsigned long count)
|
||||
{
|
||||
if (get_subid_nss_handle())
|
||||
return -EOPNOTSUPP;
|
||||
return add_range (&subordinate_gid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_gid_remove (const char *owner, gid_t start, unsigned long count)
|
||||
{
|
||||
if (get_subid_nss_handle())
|
||||
return -EOPNOTSUPP;
|
||||
return remove_range (&subordinate_gid_db, owner, start, count);
|
||||
}
|
||||
|
||||
@@ -697,6 +744,308 @@ gid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count)
|
||||
start = find_free_range (&subordinate_gid_db, min, max, count);
|
||||
return start == ULONG_MAX ? (gid_t) -1 : start;
|
||||
}
|
||||
|
||||
/*
|
||||
* int list_owner_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges)
|
||||
*
|
||||
* @owner: username
|
||||
* @id_type: UID or GUID
|
||||
* @ranges: pointer to array of ranges into which results will be placed.
|
||||
*
|
||||
* Fills in the subuid or subgid ranges which are owned by the specified
|
||||
* user. Username may be a username or a string representation of a
|
||||
* UID number. If id_type is UID, then subuids are returned, else
|
||||
* subgids are given.
|
||||
|
||||
* Returns the number of ranges found, or < 0 on error.
|
||||
*
|
||||
* The caller must free the subordinate range list.
|
||||
*/
|
||||
int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_range **in_ranges)
|
||||
{
|
||||
// TODO - need to handle owner being either uid or username
|
||||
struct subid_range *ranges = NULL;
|
||||
const struct subordinate_range *range;
|
||||
struct commonio_db *db;
|
||||
enum subid_status status;
|
||||
int count = 0;
|
||||
struct subid_nss_ops *h;
|
||||
|
||||
*in_ranges = NULL;
|
||||
|
||||
h = get_subid_nss_handle();
|
||||
if (h) {
|
||||
status = h->list_owner_ranges(owner, id_type, in_ranges, &count);
|
||||
if (status == SUBID_STATUS_SUCCESS)
|
||||
return count;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (id_type) {
|
||||
case ID_TYPE_UID:
|
||||
if (!sub_uid_open(O_RDONLY)) {
|
||||
return -1;
|
||||
}
|
||||
db = &subordinate_uid_db;
|
||||
break;
|
||||
case ID_TYPE_GID:
|
||||
if (!sub_gid_open(O_RDONLY)) {
|
||||
return -1;
|
||||
}
|
||||
db = &subordinate_gid_db;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
commonio_rewind(db);
|
||||
while ((range = commonio_next(db)) != NULL) {
|
||||
if (0 == strcmp(range->owner, owner)) {
|
||||
if (!append_range(&ranges, range, count++)) {
|
||||
free(ranges);
|
||||
ranges = NULL;
|
||||
count = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (id_type == ID_TYPE_UID)
|
||||
sub_uid_close();
|
||||
else
|
||||
sub_gid_close();
|
||||
|
||||
*in_ranges = ranges;
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool all_digits(const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; str[i] != '\0'; i++)
|
||||
if (!isdigit(str[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int append_uids(uid_t **uids, const char *owner, int n)
|
||||
{
|
||||
uid_t owner_uid;
|
||||
uid_t *ret;
|
||||
int i;
|
||||
|
||||
if (all_digits(owner)) {
|
||||
i = sscanf(owner, "%d", &owner_uid);
|
||||
if (i != 1) {
|
||||
// should not happen
|
||||
free(*uids);
|
||||
*uids = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
struct passwd *pwd = getpwnam(owner);
|
||||
if (NULL == pwd) {
|
||||
/* Username not defined in /etc/passwd, or error occured during lookup */
|
||||
free(*uids);
|
||||
*uids = NULL;
|
||||
return -1;
|
||||
}
|
||||
owner_uid = pwd->pw_uid;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (owner_uid == (*uids)[i])
|
||||
return n;
|
||||
}
|
||||
|
||||
ret = realloc(*uids, (n + 1) * sizeof(uid_t));
|
||||
if (!ret) {
|
||||
free(*uids);
|
||||
return -1;
|
||||
}
|
||||
ret[n] = owner_uid;
|
||||
*uids = ret;
|
||||
return n+1;
|
||||
}
|
||||
|
||||
int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids)
|
||||
{
|
||||
const struct subordinate_range *range;
|
||||
struct subid_nss_ops *h;
|
||||
enum subid_status status;
|
||||
struct commonio_db *db;
|
||||
int n = 0;
|
||||
|
||||
h = get_subid_nss_handle();
|
||||
if (h) {
|
||||
status = h->find_subid_owners(id, id_type, uids, &n);
|
||||
// Several ways we could handle the error cases here.
|
||||
if (status != SUBID_STATUS_SUCCESS)
|
||||
return -1;
|
||||
return n;
|
||||
}
|
||||
|
||||
switch (id_type) {
|
||||
case ID_TYPE_UID:
|
||||
if (!sub_uid_open(O_RDONLY)) {
|
||||
return -1;
|
||||
}
|
||||
db = &subordinate_uid_db;
|
||||
break;
|
||||
case ID_TYPE_GID:
|
||||
if (!sub_gid_open(O_RDONLY)) {
|
||||
return -1;
|
||||
}
|
||||
db = &subordinate_gid_db;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
*uids = NULL;
|
||||
|
||||
commonio_rewind(db);
|
||||
while ((range = commonio_next(db)) != NULL) {
|
||||
if (id >= range->start && id < range->start + range-> count) {
|
||||
n = append_uids(uids, range->owner, n);
|
||||
if (n < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id_type == ID_TYPE_UID)
|
||||
sub_uid_close();
|
||||
else
|
||||
sub_gid_close();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse)
|
||||
{
|
||||
struct commonio_db *db;
|
||||
const struct subordinate_range *r;
|
||||
bool ret;
|
||||
|
||||
if (get_subid_nss_handle())
|
||||
return false;
|
||||
|
||||
switch (id_type) {
|
||||
case ID_TYPE_UID:
|
||||
if (!sub_uid_lock()) {
|
||||
printf("Failed loging subuids (errno %d)\n", errno);
|
||||
return false;
|
||||
}
|
||||
if (!sub_uid_open(O_CREAT | O_RDWR)) {
|
||||
printf("Failed opening subuids (errno %d)\n", errno);
|
||||
sub_uid_unlock();
|
||||
return false;
|
||||
}
|
||||
db = &subordinate_uid_db;
|
||||
break;
|
||||
case ID_TYPE_GID:
|
||||
if (!sub_gid_lock()) {
|
||||
printf("Failed loging subgids (errno %d)\n", errno);
|
||||
return false;
|
||||
}
|
||||
if (!sub_gid_open(O_CREAT | O_RDWR)) {
|
||||
printf("Failed opening subgids (errno %d)\n", errno);
|
||||
sub_gid_unlock();
|
||||
return false;
|
||||
}
|
||||
db = &subordinate_gid_db;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
commonio_rewind(db);
|
||||
if (reuse) {
|
||||
while ((r = commonio_next(db)) != NULL) {
|
||||
// TODO account for username vs uid_t
|
||||
if (0 != strcmp(r->owner, range->owner))
|
||||
continue;
|
||||
if (r->count >= range->count) {
|
||||
range->count = r->count;
|
||||
range->start = r->start;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
range->start = find_free_range(db, range->start, ULONG_MAX, range->count);
|
||||
|
||||
if (range->start == ULONG_MAX) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = add_range(db, range->owner, range->start, range->count) == 1;
|
||||
|
||||
out:
|
||||
if (id_type == ID_TYPE_UID) {
|
||||
sub_uid_close();
|
||||
sub_uid_unlock();
|
||||
} else {
|
||||
sub_gid_close();
|
||||
sub_gid_unlock();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool release_subid_range(struct subordinate_range *range, enum subid_type id_type)
|
||||
{
|
||||
struct commonio_db *db;
|
||||
bool ret;
|
||||
|
||||
if (get_subid_nss_handle())
|
||||
return false;
|
||||
|
||||
switch (id_type) {
|
||||
case ID_TYPE_UID:
|
||||
if (!sub_uid_lock()) {
|
||||
printf("Failed loging subuids (errno %d)\n", errno);
|
||||
return false;
|
||||
}
|
||||
if (!sub_uid_open(O_CREAT | O_RDWR)) {
|
||||
printf("Failed opening subuids (errno %d)\n", errno);
|
||||
sub_uid_unlock();
|
||||
return false;
|
||||
}
|
||||
db = &subordinate_uid_db;
|
||||
break;
|
||||
case ID_TYPE_GID:
|
||||
if (!sub_gid_lock()) {
|
||||
printf("Failed loging subgids (errno %d)\n", errno);
|
||||
return false;
|
||||
}
|
||||
if (!sub_gid_open(O_CREAT | O_RDWR)) {
|
||||
printf("Failed opening subgids (errno %d)\n", errno);
|
||||
sub_gid_unlock();
|
||||
return false;
|
||||
}
|
||||
db = &subordinate_gid_db;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = remove_range(db, range->owner, range->start, range->count) == 1;
|
||||
|
||||
if (id_type == ID_TYPE_UID) {
|
||||
sub_uid_close();
|
||||
sub_uid_unlock();
|
||||
} else {
|
||||
sub_gid_close();
|
||||
sub_gid_unlock();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* !ENABLE_SUBIDS */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !ENABLE_SUBIDS */
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "../libsubid/subid.h"
|
||||
|
||||
extern int sub_uid_close(void);
|
||||
extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count);
|
||||
extern bool sub_uid_file_present (void);
|
||||
extern bool sub_uid_assigned(const char *owner);
|
||||
extern bool local_sub_uid_assigned(const char *owner);
|
||||
extern int sub_uid_lock (void);
|
||||
extern int sub_uid_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *sub_uid_dbname (void);
|
||||
@@ -23,11 +25,16 @@ extern int sub_uid_unlock (void);
|
||||
extern int sub_uid_add (const char *owner, uid_t start, unsigned long count);
|
||||
extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
|
||||
extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
|
||||
extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges);
|
||||
extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse);
|
||||
extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type);
|
||||
extern int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids);
|
||||
extern void free_subordinate_ranges(struct subordinate_range **ranges, int count);
|
||||
|
||||
extern int sub_gid_close(void);
|
||||
extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
|
||||
extern bool sub_gid_file_present (void);
|
||||
extern bool sub_gid_assigned(const char *owner);
|
||||
extern bool local_sub_gid_assigned(const char *owner);
|
||||
extern int sub_gid_lock (void);
|
||||
extern int sub_gid_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *sub_gid_dbname (void);
|
||||
|
||||
@@ -72,8 +72,8 @@ shadowtcb_status shadowtcb_gain_priv (void)
|
||||
* to exit soon.
|
||||
*/
|
||||
#define OUT_OF_MEMORY do { \
|
||||
fprintf (stderr, _("%s: out of memory\n"), Prog); \
|
||||
(void) fflush (stderr); \
|
||||
fprintf (shadow_logfd, _("%s: out of memory\n"), Prog); \
|
||||
(void) fflush (shadow_logfd); \
|
||||
} while (false)
|
||||
|
||||
/* Returns user's tcb directory path relative to TCB_DIR. */
|
||||
@@ -116,7 +116,7 @@ static /*@null@*/ char *shadowtcb_path_rel_existing (const char *name)
|
||||
return NULL;
|
||||
}
|
||||
if (lstat (path, &st) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, path, strerror (errno));
|
||||
free (path);
|
||||
@@ -132,7 +132,7 @@ static /*@null@*/ char *shadowtcb_path_rel_existing (const char *name)
|
||||
return rval;
|
||||
}
|
||||
if (!S_ISLNK (st.st_mode)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: %s is neither a directory, nor a symlink.\n"),
|
||||
Prog, path);
|
||||
free (path);
|
||||
@@ -140,7 +140,7 @@ static /*@null@*/ char *shadowtcb_path_rel_existing (const char *name)
|
||||
}
|
||||
ret = readlink (path, link, sizeof (link) - 1);
|
||||
if (-1 == ret) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot read symbolic link %s: %s\n"),
|
||||
Prog, path, strerror (errno));
|
||||
free (path);
|
||||
@@ -149,7 +149,7 @@ static /*@null@*/ char *shadowtcb_path_rel_existing (const char *name)
|
||||
free (path);
|
||||
if ((size_t)ret >= sizeof(link) - 1) {
|
||||
link[sizeof(link) - 1] = '\0';
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Suspiciously long symlink: %s\n"),
|
||||
Prog, link);
|
||||
return NULL;
|
||||
@@ -207,7 +207,7 @@ static shadowtcb_status mkdir_leading (const char *name, uid_t uid)
|
||||
}
|
||||
ptr = path;
|
||||
if (stat (TCB_DIR, &st) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, TCB_DIR, strerror (errno));
|
||||
goto out_free_path;
|
||||
@@ -219,19 +219,19 @@ static shadowtcb_status mkdir_leading (const char *name, uid_t uid)
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if ((mkdir (dir, 0700) != 0) && (errno != EEXIST)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot create directory %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free_dir;
|
||||
}
|
||||
if (chown (dir, 0, st.st_gid) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free_dir;
|
||||
}
|
||||
if (chmod (dir, 0711) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free_dir;
|
||||
@@ -261,7 +261,7 @@ static shadowtcb_status unlink_suffs (const char *user)
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if ((unlink (tmp) != 0) && (errno != ENOENT)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: unlink: %s: %s\n"),
|
||||
Prog, tmp, strerror (errno));
|
||||
free (tmp);
|
||||
@@ -286,7 +286,7 @@ static shadowtcb_status rmdir_leading (char *path)
|
||||
}
|
||||
if (rmdir (dir) != 0) {
|
||||
if (errno != ENOTEMPTY) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot remove directory %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
ret = SHADOWTCB_FAILURE;
|
||||
@@ -315,7 +315,7 @@ static shadowtcb_status move_dir (const char *user_newname, uid_t user_newid)
|
||||
goto out_free_nomem;
|
||||
}
|
||||
if (stat (olddir, &oldmode) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, olddir, strerror (errno));
|
||||
goto out_free;
|
||||
@@ -342,7 +342,7 @@ static shadowtcb_status move_dir (const char *user_newname, uid_t user_newid)
|
||||
goto out_free;
|
||||
}
|
||||
if (rename (real_old_dir, real_new_dir) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot rename %s to %s: %s\n"),
|
||||
Prog, real_old_dir, real_new_dir, strerror (errno));
|
||||
goto out_free;
|
||||
@@ -351,7 +351,7 @@ static shadowtcb_status move_dir (const char *user_newname, uid_t user_newid)
|
||||
goto out_free;
|
||||
}
|
||||
if ((unlink (olddir) != 0) && (errno != ENOENT)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot remove %s: %s\n"),
|
||||
Prog, olddir, strerror (errno));
|
||||
goto out_free;
|
||||
@@ -365,7 +365,7 @@ static shadowtcb_status move_dir (const char *user_newname, uid_t user_newid)
|
||||
}
|
||||
if ( (strcmp (real_new_dir, newdir) != 0)
|
||||
&& (symlink (real_new_dir_rel, newdir) != 0)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot create symbolic link %s: %s\n"),
|
||||
Prog, real_new_dir_rel, strerror (errno));
|
||||
goto out_free;
|
||||
@@ -464,37 +464,37 @@ shadowtcb_status shadowtcb_move (/*@NULL@*/const char *user_newname, uid_t user_
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (stat (tcbdir, &dirmode) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (tcbdir, 0, 0) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change owners of %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (tcbdir, 0700) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (lstat (shadow, &filemode) != 0) {
|
||||
if (errno != ENOENT) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot lstat %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Warning, user %s has no tcb shadow file.\n"),
|
||||
Prog, user_newname);
|
||||
} else {
|
||||
if (!S_ISREG (filemode.st_mode) ||
|
||||
filemode.st_nlink != 1) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Emergency: %s's tcb shadow is not a "
|
||||
"regular file with st_nlink=1.\n"
|
||||
"The account is left locked.\n"),
|
||||
@@ -502,13 +502,13 @@ shadowtcb_status shadowtcb_move (/*@NULL@*/const char *user_newname, uid_t user_
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (shadow, user_newid, filemode.st_gid) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (shadow, filemode.st_mode & 07777) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
@@ -518,7 +518,7 @@ shadowtcb_status shadowtcb_move (/*@NULL@*/const char *user_newname, uid_t user_
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (tcbdir, user_newid, dirmode.st_gid) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
@@ -543,7 +543,7 @@ shadowtcb_status shadowtcb_create (const char *name, uid_t uid)
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
if (stat (TCB_DIR, &tcbdir_stat) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, TCB_DIR, strerror (errno));
|
||||
return SHADOWTCB_FAILURE;
|
||||
@@ -563,39 +563,39 @@ shadowtcb_status shadowtcb_create (const char *name, uid_t uid)
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (mkdir (dir, 0700) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: mkdir: %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
fd = open (shadow, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot open %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
close (fd);
|
||||
if (chown (shadow, 0, authgid) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (shadow, (mode_t) ((authgid == shadowgid) ? 0600 : 0640)) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (dir, 0, authgid) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (dir, (mode_t) ((authgid == shadowgid) ? 02700 : 02710)) != 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
EXTRA_DIST = .indent.pro xgetXXbyYY.c
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/lib
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/lib $(ECONF_CPPFLAGS)
|
||||
|
||||
noinst_LIBRARIES = libmisc.a
|
||||
noinst_LTLIBRARIES = libmisc.la
|
||||
|
||||
libmisc_a_SOURCES = \
|
||||
libmisc_la_SOURCES = \
|
||||
addgrps.c \
|
||||
age.c \
|
||||
audit_help.c \
|
||||
@@ -74,6 +74,6 @@ libmisc_a_SOURCES = \
|
||||
yesno.c
|
||||
|
||||
if WITH_BTRFS
|
||||
libmisc_a_SOURCES += btrfs.c
|
||||
libmisc_la_SOURCES += btrfs.c
|
||||
endif
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ int add_groups (const char *list)
|
||||
bool added;
|
||||
char *token;
|
||||
char buf[1024];
|
||||
int ret;
|
||||
|
||||
if (strlen (list) >= sizeof (buf)) {
|
||||
errno = EINVAL;
|
||||
@@ -93,7 +94,7 @@ int add_groups (const char *list)
|
||||
|
||||
grp = getgrnam (token); /* local, no need for xgetgrnam */
|
||||
if (NULL == grp) {
|
||||
fprintf (stderr, _("Warning: unknown group %s\n"),
|
||||
fprintf (shadow_logfd, _("Warning: unknown group %s\n"),
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
@@ -105,7 +106,7 @@ int add_groups (const char *list)
|
||||
}
|
||||
|
||||
if (ngroups >= sysconf (_SC_NGROUPS_MAX)) {
|
||||
fputs (_("Warning: too many groups\n"), stderr);
|
||||
fputs (_("Warning: too many groups\n"), shadow_logfd);
|
||||
break;
|
||||
}
|
||||
tmp = (gid_t *) realloc (grouplist, (size_t)(ngroups + 1) * sizeof (GETGROUPS_T));
|
||||
@@ -120,9 +121,12 @@ int add_groups (const char *list)
|
||||
}
|
||||
|
||||
if (added) {
|
||||
return setgroups ((size_t)ngroups, grouplist);
|
||||
ret = setgroups ((size_t)ngroups, grouplist);
|
||||
free (grouplist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
free (grouplist);
|
||||
return 0;
|
||||
}
|
||||
#else /* HAVE_SETGROUPS && !USE_PAM */
|
||||
|
||||
@@ -59,7 +59,7 @@ void audit_help_open (void)
|
||||
return;
|
||||
}
|
||||
(void) fputs (_("Cannot open audit interface - aborting.\n"),
|
||||
stderr);
|
||||
shadow_logfd);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
static bool path_exists(const char *p)
|
||||
{
|
||||
int ret;
|
||||
struct stat sb;
|
||||
|
||||
return stat(p, &sb) == 0;
|
||||
|
||||
@@ -46,11 +46,18 @@
|
||||
#include "defines.h"
|
||||
#include "chkname.h"
|
||||
|
||||
int allow_bad_names = false;
|
||||
|
||||
static bool is_valid_name (const char *name)
|
||||
{
|
||||
if (allow_bad_names) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* User/group names must match [a-z_][a-z0-9_-]*[$]
|
||||
*/
|
||||
|
||||
if (('\0' == *name) ||
|
||||
!((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) {
|
||||
return false;
|
||||
|
||||
@@ -62,6 +62,7 @@ void chown_tty (const struct passwd *info)
|
||||
grent = getgr_nam_gid (getdef_str ("TTYGROUP"));
|
||||
if (NULL != grent) {
|
||||
gid = grent->gr_gid;
|
||||
gr_free (grent);
|
||||
} else {
|
||||
gid = info->pw_gid;
|
||||
}
|
||||
@@ -75,7 +76,7 @@ void chown_tty (const struct passwd *info)
|
||||
|| (fchmod (STDIN_FILENO, (mode_t)getdef_num ("TTYPERM", 0600)) != 0)) {
|
||||
int err = errno;
|
||||
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Unable to change owner or mode of tty stdin: %s"),
|
||||
strerror (err));
|
||||
SYSLOG ((LOG_WARN,
|
||||
|
||||
@@ -203,7 +203,7 @@ void cleanup_report_del_group_gshadow (void *group_name)
|
||||
void cleanup_unlock_group (unused void *arg)
|
||||
{
|
||||
if (gr_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, gr_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
|
||||
@@ -223,7 +223,7 @@ void cleanup_unlock_group (unused void *arg)
|
||||
void cleanup_unlock_gshadow (unused void *arg)
|
||||
{
|
||||
if (sgr_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, sgr_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
|
||||
|
||||
@@ -120,7 +120,7 @@ void cleanup_report_add_user_shadow (void *user_name)
|
||||
void cleanup_unlock_passwd (unused void *arg)
|
||||
{
|
||||
if (pw_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, pw_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
|
||||
@@ -139,7 +139,7 @@ void cleanup_unlock_passwd (unused void *arg)
|
||||
void cleanup_unlock_shadow (unused void *arg)
|
||||
{
|
||||
if (spw_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, spw_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
|
||||
|
||||
@@ -125,11 +125,11 @@ static void error_acl (struct error_context *ctx, const char *fmt, ...)
|
||||
}
|
||||
|
||||
va_start (ap, fmt);
|
||||
(void) fprintf (stderr, _("%s: "), Prog);
|
||||
if (vfprintf (stderr, fmt, ap) != 0) {
|
||||
(void) fputs (_(": "), stderr);
|
||||
(void) fprintf (shadow_logfd, _("%s: "), Prog);
|
||||
if (vfprintf (shadow_logfd, fmt, ap) != 0) {
|
||||
(void) fputs (_(": "), shadow_logfd);
|
||||
}
|
||||
(void) fprintf (stderr, "%s\n", strerror (errno));
|
||||
(void) fprintf (shadow_logfd, "%s\n", strerror (errno));
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ int copy_tree (const char *src_root, const char *dst_root,
|
||||
}
|
||||
|
||||
if (!S_ISDIR (sb.st_mode)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
"%s: %s is not a directory",
|
||||
Prog, src_root);
|
||||
return -1;
|
||||
@@ -484,7 +484,7 @@ static int copy_dir (const char *src, const char *dst,
|
||||
*/
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
if (set_selinux_file_context (dst, S_IFDIR) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
@@ -605,7 +605,7 @@ static int copy_symlink (const char *src, const char *dst,
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
if (set_selinux_file_context (dst, S_IFLNK) != 0) {
|
||||
free (oldlink);
|
||||
return -1;
|
||||
}
|
||||
@@ -684,7 +684,7 @@ static int copy_special (const char *src, const char *dst,
|
||||
int err = 0;
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
if (set_selinux_file_context (dst, statp->st_mode & S_IFMT) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
@@ -744,7 +744,8 @@ static int copy_file (const char *src, const char *dst,
|
||||
return -1;
|
||||
}
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
if (set_selinux_file_context (dst, S_IFREG) != 0) {
|
||||
(void) close (ifd);
|
||||
return -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
@@ -771,12 +772,16 @@ static int copy_file (const char *src, const char *dst,
|
||||
&& (errno != 0))
|
||||
#endif /* WITH_ATTR */
|
||||
) {
|
||||
if (ofd >= 0) {
|
||||
(void) close (ofd);
|
||||
}
|
||||
(void) close (ifd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
|
||||
if (write (ofd, buf, (size_t)cnt) != cnt) {
|
||||
(void) close (ofd);
|
||||
(void) close (ifd);
|
||||
return -1;
|
||||
}
|
||||
@@ -786,6 +791,7 @@ static int copy_file (const char *src, const char *dst,
|
||||
|
||||
#ifdef HAVE_FUTIMES
|
||||
if (futimes (ofd, mt) != 0) {
|
||||
(void) close (ofd);
|
||||
return -1;
|
||||
}
|
||||
#endif /* HAVE_FUTIMES */
|
||||
|
||||
@@ -171,7 +171,7 @@ void addenv (const char *string, /*@null@*/const char *value)
|
||||
}
|
||||
newenvp = __newenvp;
|
||||
} else {
|
||||
(void) fputs (_("Environment overflow\n"), stderr);
|
||||
(void) fputs (_("Environment overflow\n"), shadow_logfd);
|
||||
newenvc--;
|
||||
free (newenvp[newenvc]);
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ void failure (uid_t uid, const char *tty, struct faillog *fl)
|
||||
fl->fail_cnt++;
|
||||
}
|
||||
|
||||
strncpy (fl->fail_line, tty, sizeof fl->fail_line);
|
||||
strncpy (fl->fail_line, tty, sizeof (fl->fail_line) - 1);
|
||||
(void) time (&fl->fail_time);
|
||||
|
||||
/*
|
||||
|
||||
@@ -74,7 +74,7 @@ static int get_ranges (bool sys_group, gid_t *min_id, gid_t *max_id,
|
||||
|
||||
/* Check that the ranges make sense */
|
||||
if (*max_id < *min_id) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: Invalid configuration: SYS_GID_MIN (%lu), "
|
||||
"GID_MIN (%lu), SYS_GID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) *min_id,
|
||||
@@ -97,7 +97,7 @@ static int get_ranges (bool sys_group, gid_t *min_id, gid_t *max_id,
|
||||
|
||||
/* Check that the ranges make sense */
|
||||
if (*max_id < *min_id) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: Invalid configuration: GID_MIN (%lu), "
|
||||
"GID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) *min_id,
|
||||
@@ -167,7 +167,7 @@ int find_new_gid (bool sys_group,
|
||||
bool *used_gids;
|
||||
const struct group *grp;
|
||||
gid_t gid_min, gid_max, preferred_min;
|
||||
gid_t group_id, id;
|
||||
gid_t id;
|
||||
gid_t lowest_found, highest_found;
|
||||
int result;
|
||||
int nospam = 0;
|
||||
@@ -213,7 +213,7 @@ int find_new_gid (bool sys_group,
|
||||
* more likely to want to stop and address the
|
||||
* issue.
|
||||
*/
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Encountered error attempting to use "
|
||||
"preferred GID: %s\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -243,7 +243,7 @@ int find_new_gid (bool sys_group,
|
||||
/* Create an array to hold all of the discovered GIDs */
|
||||
used_gids = malloc (sizeof (bool) * (gid_max +1));
|
||||
if (NULL == used_gids) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: failed to allocate memory: %s\n"),
|
||||
Prog, strerror (errno));
|
||||
return -1;
|
||||
@@ -323,7 +323,7 @@ int find_new_gid (bool sys_group,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique system GID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -366,7 +366,7 @@ int find_new_gid (bool sys_group,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique system GID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -426,7 +426,7 @@ int find_new_gid (bool sys_group,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique GID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -469,7 +469,7 @@ int find_new_gid (bool sys_group,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique GID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -488,7 +488,7 @@ int find_new_gid (bool sys_group,
|
||||
}
|
||||
|
||||
/* The code reached here and found no available IDs in the range */
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique GID (no more available GIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available GIDs on the system"));
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
*
|
||||
* Return 0 on success, -1 if no unused GIDs are available.
|
||||
*/
|
||||
int find_new_sub_gids (const char *owner,
|
||||
gid_t *range_start, unsigned long *range_count)
|
||||
int find_new_sub_gids (gid_t *range_start, unsigned long *range_count)
|
||||
{
|
||||
unsigned long min, max;
|
||||
unsigned long count;
|
||||
@@ -61,7 +60,7 @@ int find_new_sub_gids (const char *owner,
|
||||
count = getdef_ulong ("SUB_GID_COUNT", 65536);
|
||||
|
||||
if (min > max || count >= max || (min + count - 1) > max) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: Invalid configuration: SUB_GID_MIN (%lu),"
|
||||
" SUB_GID_MAX (%lu), SUB_GID_COUNT (%lu)\n"),
|
||||
Prog, min, max, count);
|
||||
@@ -70,7 +69,7 @@ int find_new_sub_gids (const char *owner,
|
||||
|
||||
start = sub_gid_find_free_range(min, max, count);
|
||||
if (start == (gid_t)-1) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique subordinate GID range\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available subordinate GIDs on the system"));
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
*
|
||||
* Return 0 on success, -1 if no unused UIDs are available.
|
||||
*/
|
||||
int find_new_sub_uids (const char *owner,
|
||||
uid_t *range_start, unsigned long *range_count)
|
||||
int find_new_sub_uids (uid_t *range_start, unsigned long *range_count)
|
||||
{
|
||||
unsigned long min, max;
|
||||
unsigned long count;
|
||||
@@ -61,7 +60,7 @@ int find_new_sub_uids (const char *owner,
|
||||
count = getdef_ulong ("SUB_UID_COUNT", 65536);
|
||||
|
||||
if (min > max || count >= max || (min + count - 1) > max) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: Invalid configuration: SUB_UID_MIN (%lu),"
|
||||
" SUB_UID_MAX (%lu), SUB_UID_COUNT (%lu)\n"),
|
||||
Prog, min, max, count);
|
||||
@@ -70,7 +69,7 @@ int find_new_sub_uids (const char *owner,
|
||||
|
||||
start = sub_uid_find_free_range(min, max, count);
|
||||
if (start == (uid_t)-1) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique subordinate UID range\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available subordinate UIDs on the system"));
|
||||
|
||||
@@ -74,7 +74,7 @@ static int get_ranges (bool sys_user, uid_t *min_id, uid_t *max_id,
|
||||
|
||||
/* Check that the ranges make sense */
|
||||
if (*max_id < *min_id) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: Invalid configuration: SYS_UID_MIN (%lu), "
|
||||
"UID_MIN (%lu), SYS_UID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) *min_id,
|
||||
@@ -97,7 +97,7 @@ static int get_ranges (bool sys_user, uid_t *min_id, uid_t *max_id,
|
||||
|
||||
/* Check that the ranges make sense */
|
||||
if (*max_id < *min_id) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: Invalid configuration: UID_MIN (%lu), "
|
||||
"UID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) *min_id,
|
||||
@@ -167,7 +167,7 @@ int find_new_uid(bool sys_user,
|
||||
bool *used_uids;
|
||||
const struct passwd *pwd;
|
||||
uid_t uid_min, uid_max, preferred_min;
|
||||
uid_t user_id, id;
|
||||
uid_t id;
|
||||
uid_t lowest_found, highest_found;
|
||||
int result;
|
||||
int nospam = 0;
|
||||
@@ -213,7 +213,7 @@ int find_new_uid(bool sys_user,
|
||||
* more likely to want to stop and address the
|
||||
* issue.
|
||||
*/
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Encountered error attempting to use "
|
||||
"preferred UID: %s\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -243,7 +243,7 @@ int find_new_uid(bool sys_user,
|
||||
/* Create an array to hold all of the discovered UIDs */
|
||||
used_uids = malloc (sizeof (bool) * (uid_max +1));
|
||||
if (NULL == used_uids) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: failed to allocate memory: %s\n"),
|
||||
Prog, strerror (errno));
|
||||
return -1;
|
||||
@@ -323,7 +323,7 @@ int find_new_uid(bool sys_user,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique system UID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -366,7 +366,7 @@ int find_new_uid(bool sys_user,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique system UID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -426,7 +426,7 @@ int find_new_uid(bool sys_user,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique UID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -469,7 +469,7 @@ int find_new_uid(bool sys_user,
|
||||
*
|
||||
*/
|
||||
if (!nospam) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique UID (%s). "
|
||||
"Suppressing additional messages.\n"),
|
||||
Prog, strerror (result));
|
||||
@@ -488,7 +488,7 @@ int find_new_uid(bool sys_user,
|
||||
}
|
||||
|
||||
/* The code reached here and found no available IDs in the range */
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: Can't get unique UID (no more available UIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available UIDs on the system"));
|
||||
|
||||
@@ -61,23 +61,23 @@
|
||||
epoch = strtoull (source_date_epoch, &endptr, 10);
|
||||
if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
|
||||
|| (errno != 0 && epoch == 0)) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n"),
|
||||
strerror(errno));
|
||||
} else if (endptr == source_date_epoch) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n"),
|
||||
endptr);
|
||||
} else if (*endptr != '\0') {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n"),
|
||||
endptr);
|
||||
} else if (epoch > ULONG_MAX) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu\n"),
|
||||
ULONG_MAX, epoch);
|
||||
} else if (epoch > fallback) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to the current time (%lu) but was found to be: %llu\n"),
|
||||
fallback, epoch);
|
||||
} else {
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
#include <stdio.h>
|
||||
#include "prototypes.h"
|
||||
#include "idmapping.h"
|
||||
#include <sys/prctl.h>
|
||||
#if HAVE_SYS_CAPABILITY_H
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
@@ -47,19 +47,19 @@ struct map_range *get_map_ranges(int ranges, int argc, char **argv)
|
||||
int idx, argidx;
|
||||
|
||||
if (ranges < 0 || argc < 0) {
|
||||
fprintf(stderr, "%s: error calculating number of arguments\n", Prog);
|
||||
fprintf(shadow_logfd, "%s: error calculating number of arguments\n", Prog);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ranges != ((argc + 2) / 3)) {
|
||||
fprintf(stderr, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc);
|
||||
fprintf(shadow_logfd, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ranges * 3) > argc) {
|
||||
fprintf(stderr, "ranges: %u argc: %d\n",
|
||||
fprintf(shadow_logfd, "ranges: %u argc: %d\n",
|
||||
ranges, argc);
|
||||
fprintf(stderr,
|
||||
fprintf(shadow_logfd,
|
||||
_( "%s: Not enough arguments to form %u mappings\n"),
|
||||
Prog, ranges);
|
||||
return NULL;
|
||||
@@ -67,7 +67,7 @@ struct map_range *get_map_ranges(int ranges, int argc, char **argv)
|
||||
|
||||
mappings = calloc(ranges, sizeof(*mappings));
|
||||
if (!mappings) {
|
||||
fprintf(stderr, _( "%s: Memory allocation failure\n"),
|
||||
fprintf(shadow_logfd, _( "%s: Memory allocation failure\n"),
|
||||
Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -88,24 +88,24 @@ struct map_range *get_map_ranges(int ranges, int argc, char **argv)
|
||||
return NULL;
|
||||
}
|
||||
if (ULONG_MAX - mapping->upper <= mapping->count || ULONG_MAX - mapping->lower <= mapping->count) {
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mapping->upper > UINT_MAX ||
|
||||
mapping->lower > UINT_MAX ||
|
||||
mapping->count > UINT_MAX) {
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mapping->lower + mapping->count > UINT_MAX ||
|
||||
mapping->upper + mapping->count > UINT_MAX) {
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mapping->lower + mapping->count < mapping->lower ||
|
||||
mapping->upper + mapping->count < mapping->upper) {
|
||||
/* this one really shouldn't be possible given previous checks */
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,25 @@ struct map_range *get_map_ranges(int ranges, int argc, char **argv)
|
||||
*/
|
||||
#define ULONG_DIGITS ((((sizeof(unsigned long) * CHAR_BIT) + 9)/10)*3)
|
||||
|
||||
#if HAVE_SYS_CAPABILITY_H
|
||||
static inline bool maps_lower_root(int cap, int ranges, struct map_range *mappings)
|
||||
{
|
||||
int idx;
|
||||
struct map_range *mapping;
|
||||
|
||||
if (cap != CAP_SETUID)
|
||||
return false;
|
||||
|
||||
mapping = mappings;
|
||||
for (idx = 0; idx < ranges; idx++, mapping++) {
|
||||
if (mapping->lower == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The ruid refers to the caller's uid and is used to reset the effective uid
|
||||
* back to the callers real uid.
|
||||
@@ -157,19 +176,19 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
|
||||
} else if (strcmp(map_file, "gid_map") == 0) {
|
||||
cap = CAP_SETGID;
|
||||
} else {
|
||||
fprintf(stderr, _("%s: Invalid map file %s specified\n"), Prog, map_file);
|
||||
fprintf(shadow_logfd, _("%s: Invalid map file %s specified\n"), Prog, map_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Align setuid- and fscaps-based new{g,u}idmap behavior. */
|
||||
if (geteuid() == 0 && geteuid() != ruid) {
|
||||
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
|
||||
fprintf(stderr, _("%s: Could not prctl(PR_SET_KEEPCAPS)\n"), Prog);
|
||||
fprintf(shadow_logfd, _("%s: Could not prctl(PR_SET_KEEPCAPS)\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (seteuid(ruid) < 0) {
|
||||
fprintf(stderr, _("%s: Could not seteuid to %d\n"), Prog, ruid);
|
||||
fprintf(shadow_logfd, _("%s: Could not seteuid to %d\n"), Prog, ruid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -177,9 +196,15 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
|
||||
/* Lockdown new{g,u}idmap by dropping all unneeded capabilities. */
|
||||
memset(data, 0, sizeof(data));
|
||||
data[0].effective = CAP_TO_MASK(cap);
|
||||
/*
|
||||
* When uid 0 from the ancestor userns is supposed to be mapped into
|
||||
* the child userns we need to retain CAP_SETFCAP.
|
||||
*/
|
||||
if (maps_lower_root(cap, ranges, mappings))
|
||||
data[0].effective |= CAP_TO_MASK(CAP_SETFCAP);
|
||||
data[0].permitted = data[0].effective;
|
||||
if (capset(&hdr, data) < 0) {
|
||||
fprintf(stderr, _("%s: Could not set caps\n"), Prog);
|
||||
fprintf(shadow_logfd, _("%s: Could not set caps\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
@@ -197,7 +222,7 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
|
||||
mapping->lower,
|
||||
mapping->count);
|
||||
if ((written <= 0) || (written >= (bufsize - (pos - buf)))) {
|
||||
fprintf(stderr, _("%s: snprintf failed!\n"), Prog);
|
||||
fprintf(shadow_logfd, _("%s: snprintf failed!\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pos += written;
|
||||
@@ -206,14 +231,15 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
|
||||
/* Write the mapping to the mapping file */
|
||||
fd = openat(proc_dir_fd, map_file, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, _("%s: open of %s failed: %s\n"),
|
||||
fprintf(shadow_logfd, _("%s: open of %s failed: %s\n"),
|
||||
Prog, map_file, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (write(fd, buf, pos - buf) != (pos - buf)) {
|
||||
fprintf(stderr, _("%s: write to %s failed: %s\n"),
|
||||
fprintf(shadow_logfd, _("%s: write to %s failed: %s\n"),
|
||||
Prog, map_file, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close(fd);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
@@ -40,5 +40,7 @@ extern struct map_range *get_map_ranges(int ranges, int argc, char **argv);
|
||||
extern void write_mapping(int proc_dir_fd, int ranges,
|
||||
struct map_range *mappings, const char *map_file, uid_t ruid);
|
||||
|
||||
extern void nss_init(char *nsswitch_path);
|
||||
|
||||
#endif /* _ID_MAPPING_H_ */
|
||||
|
||||
|
||||
@@ -548,7 +548,7 @@ void setup_limits (const struct passwd *info)
|
||||
#ifdef LIMITS
|
||||
if (info->pw_uid != 0) {
|
||||
if ((setup_user_limits (info->pw_name) & LOGIN_ERROR_LOGIN) != 0) {
|
||||
(void) fputs (_("Too many logins.\n"), stderr);
|
||||
(void) fputs (_("Too many logins.\n"), shadow_logfd);
|
||||
(void) sleep (2); /* XXX: Should be FAIL_DELAY */
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -241,6 +241,7 @@ bool is_on_list (char *const *list, const char *member)
|
||||
|
||||
if ('\0' == *members) {
|
||||
*array = (char *) 0;
|
||||
free (members);
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,9 +100,9 @@ void dolastlog (
|
||||
ll_time = newlog.ll_time;
|
||||
(void) time (&ll_time);
|
||||
newlog.ll_time = ll_time;
|
||||
strncpy (newlog.ll_line, line, sizeof newlog.ll_line);
|
||||
strncpy (newlog.ll_line, line, sizeof (newlog.ll_line) - 1);
|
||||
#if HAVE_LL_HOST
|
||||
strncpy (newlog.ll_host, host, sizeof newlog.ll_host);
|
||||
strncpy (newlog.ll_host, host, sizeof (newlog.ll_host) - 1);
|
||||
#endif
|
||||
if ( (lseek (fd, offset, SEEK_SET) != offset)
|
||||
|| (write (fd, (const void *) &newlog, sizeof newlog) != (ssize_t) sizeof newlog)
|
||||
|
||||
@@ -62,6 +62,9 @@
|
||||
if ((NULL != pw) && (pw->pw_uid == ruid)) {
|
||||
return pw;
|
||||
}
|
||||
if (NULL != pw) {
|
||||
pw_free (pw);
|
||||
}
|
||||
}
|
||||
|
||||
return xgetpwuid (ruid);
|
||||
|
||||
@@ -268,6 +268,12 @@ static /*@observer@*//*@null@*/const char *obscure_msg (
|
||||
#ifdef USE_SHA_CRYPT
|
||||
|| (strcmp (result, "SHA256") == 0)
|
||||
|| (strcmp (result, "SHA512") == 0)
|
||||
#endif
|
||||
#ifdef USE_BCRYPT
|
||||
|| (strcmp (result, "BCRYPT") == 0)
|
||||
#endif
|
||||
#ifdef USE_YESCRYPT
|
||||
|| (strcmp (result, "YESCRYPT") == 0)
|
||||
#endif
|
||||
) {
|
||||
return NULL;
|
||||
|
||||
@@ -59,20 +59,20 @@ void do_pam_passwd (const char *user, bool silent, bool change_expired)
|
||||
|
||||
ret = pam_start ("passwd", user, &conv, &pamh);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("passwd: pam_start() failed, error %d\n"), ret);
|
||||
exit (10); /* XXX */
|
||||
}
|
||||
|
||||
ret = pam_chauthtok (pamh, flags);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
fprintf (stderr, _("passwd: %s\n"), pam_strerror (pamh, ret));
|
||||
fputs (_("passwd: password unchanged\n"), stderr);
|
||||
fprintf (shadow_logfd, _("passwd: %s\n"), pam_strerror (pamh, ret));
|
||||
fputs (_("passwd: password unchanged\n"), shadow_logfd);
|
||||
pam_end (pamh, ret);
|
||||
exit (10); /* XXX */
|
||||
}
|
||||
|
||||
fputs (_("passwd: password updated successfully\n"), stderr);
|
||||
fputs (_("passwd: password updated successfully\n"), shadow_logfd);
|
||||
(void) pam_end (pamh, PAM_SUCCESS);
|
||||
}
|
||||
#else /* !USE_PAM */
|
||||
|
||||
@@ -76,7 +76,7 @@ static int ni_conv (int num_msg,
|
||||
|
||||
switch (msg[count]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: PAM modules requesting echoing are not supported.\n"),
|
||||
Prog);
|
||||
goto failed_conversation;
|
||||
@@ -88,7 +88,7 @@ static int ni_conv (int num_msg,
|
||||
break;
|
||||
case PAM_ERROR_MSG:
|
||||
if ( (NULL == msg[count]->msg)
|
||||
|| (fprintf (stderr, "%s\n", msg[count]->msg) <0)) {
|
||||
|| (fprintf (shadow_logfd, "%s\n", msg[count]->msg) <0)) {
|
||||
goto failed_conversation;
|
||||
}
|
||||
responses[count].resp = NULL;
|
||||
@@ -101,7 +101,7 @@ static int ni_conv (int num_msg,
|
||||
responses[count].resp = NULL;
|
||||
break;
|
||||
default:
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: conversation type %d not supported.\n"),
|
||||
Prog, msg[count]->msg_style);
|
||||
goto failed_conversation;
|
||||
@@ -143,7 +143,7 @@ int do_pam_passwd_non_interactive (const char *pam_service,
|
||||
|
||||
ret = pam_start (pam_service, username, &non_interactive_pam_conv, &pamh);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: (user %s) pam_start failure %d\n"),
|
||||
Prog, username, ret);
|
||||
return 1;
|
||||
@@ -152,7 +152,7 @@ int do_pam_passwd_non_interactive (const char *pam_service,
|
||||
non_interactive_password = password;
|
||||
ret = pam_chauthtok (pamh, 0);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: (user %s) pam_chauthtok() failed, error:\n"
|
||||
"%s\n"),
|
||||
Prog, username, pam_strerror (pamh, ret));
|
||||
|
||||
@@ -74,35 +74,47 @@ extern const char* process_prefix_flag (const char* short_opt, int argc, char **
|
||||
* Parse the command line options.
|
||||
*/
|
||||
int i;
|
||||
const char *prefix = NULL;
|
||||
const char *prefix = NULL, *val;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
val = NULL;
|
||||
if ( (strcmp (argv[i], "--prefix") == 0)
|
||||
|| ((strncmp (argv[i], "--prefix=", 9) == 0)
|
||||
&& (val = argv[i] + 9))
|
||||
|| (strcmp (argv[i], short_opt) == 0)) {
|
||||
if (NULL != prefix) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: multiple --prefix options\n"),
|
||||
Prog);
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (i + 1 == argc) {
|
||||
fprintf (stderr,
|
||||
if (val) {
|
||||
prefix = val;
|
||||
} else if (i + 1 == argc) {
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: option '%s' requires an argument\n"),
|
||||
Prog, argv[i]);
|
||||
exit (E_BAD_ARG);
|
||||
} else {
|
||||
prefix = argv[++ i];
|
||||
}
|
||||
prefix = argv[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (prefix != NULL) {
|
||||
if ( prefix[0] == '\0' || !strcmp(prefix, "/"))
|
||||
return ""; /* if prefix is "/" then we ignore the flag option */
|
||||
/* should we prevent symbolic link from being used as a prefix? */
|
||||
|
||||
if ( prefix[0] != '/') {
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: prefix must be an absolute path\n"),
|
||||
Prog);
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
size_t len;
|
||||
len = strlen(prefix) + strlen(PASSWD_FILE) + 2;
|
||||
passwd_db_file = xmalloc(len);
|
||||
@@ -113,7 +125,7 @@ extern const char* process_prefix_flag (const char* short_opt, int argc, char **
|
||||
group_db_file = xmalloc(len);
|
||||
snprintf(group_db_file, len, "%s/%s", prefix, GROUP_FILE);
|
||||
gr_setdbname(group_db_file);
|
||||
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
len = strlen(prefix) + strlen(SGROUP_FILE) + 2;
|
||||
sgroup_db_file = xmalloc(len);
|
||||
@@ -128,7 +140,7 @@ extern const char* process_prefix_flag (const char* short_opt, int argc, char **
|
||||
spw_db_file = xmalloc(len);
|
||||
snprintf(spw_db_file, len, "%s/%s", prefix, SHADOW_FILE);
|
||||
spw_setdbname(spw_db_file);
|
||||
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
len = strlen(prefix) + strlen("/etc/subuid") + 2;
|
||||
suid_db_file = xmalloc(len);
|
||||
@@ -141,11 +153,15 @@ extern const char* process_prefix_flag (const char* short_opt, int argc, char **
|
||||
sub_gid_setdbname(sgid_db_file);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ECONF
|
||||
setdef_config_file(prefix);
|
||||
#else
|
||||
len = strlen(prefix) + strlen("/etc/login.defs") + 2;
|
||||
def_conf_file = xmalloc(len);
|
||||
snprintf(def_conf_file, len, "%s/%s", prefix, "/etc/login.defs");
|
||||
setdef_config_file(def_conf_file);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (prefix == NULL)
|
||||
return "";
|
||||
@@ -162,14 +178,14 @@ extern struct group *prefix_getgrnam(const char *name)
|
||||
fg = fopen(group_db_file, "rt");
|
||||
if(!fg)
|
||||
return NULL;
|
||||
while(grp = fgetgrent(fg)) {
|
||||
while((grp = fgetgrent(fg)) != NULL) {
|
||||
if(!strcmp(name, grp->gr_name))
|
||||
break;
|
||||
}
|
||||
fclose(fg);
|
||||
return grp;
|
||||
}
|
||||
|
||||
|
||||
return getgrnam(name);
|
||||
}
|
||||
|
||||
@@ -182,7 +198,7 @@ extern struct group *prefix_getgrgid(gid_t gid)
|
||||
fg = fopen(group_db_file, "rt");
|
||||
if(!fg)
|
||||
return NULL;
|
||||
while(grp = fgetgrent(fg)) {
|
||||
while((grp = fgetgrent(fg)) != NULL) {
|
||||
if(gid == grp->gr_gid)
|
||||
break;
|
||||
}
|
||||
@@ -202,7 +218,7 @@ extern struct passwd *prefix_getpwuid(uid_t uid)
|
||||
fg = fopen(passwd_db_file, "rt");
|
||||
if(!fg)
|
||||
return NULL;
|
||||
while(pwd = fgetpwent(fg)) {
|
||||
while((pwd = fgetpwent(fg)) != NULL) {
|
||||
if(uid == pwd->pw_uid)
|
||||
break;
|
||||
}
|
||||
@@ -222,7 +238,7 @@ extern struct passwd *prefix_getpwnam(const char* name)
|
||||
fg = fopen(passwd_db_file, "rt");
|
||||
if(!fg)
|
||||
return NULL;
|
||||
while(pwd = fgetpwent(fg)) {
|
||||
while((pwd = fgetpwent(fg)) != NULL) {
|
||||
if(!strcmp(name, pwd->pw_name))
|
||||
break;
|
||||
}
|
||||
@@ -242,7 +258,7 @@ extern struct spwd *prefix_getspnam(const char* name)
|
||||
fg = fopen(spw_db_file, "rt");
|
||||
if(!fg)
|
||||
return NULL;
|
||||
while(sp = fgetspent(fg)) {
|
||||
while((sp = fgetspent(fg)) != NULL) {
|
||||
if(!strcmp(name, sp->sp_namp))
|
||||
break;
|
||||
}
|
||||
@@ -262,7 +278,7 @@ extern void prefix_setpwent()
|
||||
}
|
||||
if (fp_pwent)
|
||||
fclose (fp_pwent);
|
||||
|
||||
|
||||
fp_pwent = fopen(passwd_db_file, "rt");
|
||||
if(!fp_pwent)
|
||||
return;
|
||||
@@ -293,7 +309,7 @@ extern void prefix_setgrent()
|
||||
}
|
||||
if (fp_grent)
|
||||
fclose (fp_grent);
|
||||
|
||||
|
||||
fp_grent = fopen(group_db_file, "rt");
|
||||
if(!fp_grent)
|
||||
return;
|
||||
|
||||
@@ -51,7 +51,7 @@ void passwd_check (const char *user, const char *passwd, unused const char *prog
|
||||
if (pw_auth (passwd, user, PW_LOGIN, (char *) 0) != 0) {
|
||||
SYSLOG ((LOG_WARN, "incorrect password for `%s'", user));
|
||||
(void) sleep (1);
|
||||
fprintf (stderr, _("Incorrect password for %s.\n"), user);
|
||||
fprintf (shadow_logfd, _("Incorrect password for %s.\n"), user);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,25 +56,31 @@ extern void process_root_flag (const char* short_opt, int argc, char **argv)
|
||||
* Parse the command line options.
|
||||
*/
|
||||
int i;
|
||||
const char *newroot = NULL;
|
||||
const char *newroot = NULL, *val;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
val = NULL;
|
||||
if ( (strcmp (argv[i], "--root") == 0)
|
||||
|| ((strncmp (argv[i], "--root=", 7) == 0)
|
||||
&& (val = argv[i] + 7))
|
||||
|| (strcmp (argv[i], short_opt) == 0)) {
|
||||
if (NULL != newroot) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: multiple --root options\n"),
|
||||
Prog);
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (i + 1 == argc) {
|
||||
fprintf (stderr,
|
||||
if (val) {
|
||||
newroot = val;
|
||||
} else if (i + 1 == argc) {
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: option '%s' requires an argument\n"),
|
||||
Prog, argv[i]);
|
||||
exit (E_BAD_ARG);
|
||||
} else {
|
||||
newroot = argv[++ i];
|
||||
}
|
||||
newroot = argv[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,34 +94,34 @@ static void change_root (const char* newroot)
|
||||
/* Drop privileges */
|
||||
if ( (setregid (getgid (), getgid ()) != 0)
|
||||
|| (setreuid (getuid (), getuid ()) != 0)) {
|
||||
fprintf (stderr, _("%s: failed to drop privileges (%s)\n"),
|
||||
fprintf (shadow_logfd, _("%s: failed to drop privileges (%s)\n"),
|
||||
Prog, strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ('/' != newroot[0]) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: invalid chroot path '%s'\n"),
|
||||
Prog, newroot);
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (access (newroot, F_OK) != 0) {
|
||||
fprintf(stderr,
|
||||
fprintf(shadow_logfd,
|
||||
_("%s: cannot access chroot directory %s: %s\n"),
|
||||
Prog, newroot, strerror (errno));
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (chdir (newroot) != 0) {
|
||||
fprintf(stderr,
|
||||
fprintf(shadow_logfd,
|
||||
_("%s: cannot chdir to chroot directory %s: %s\n"),
|
||||
Prog, newroot, strerror (errno));
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (chroot (newroot) != 0) {
|
||||
fprintf(stderr,
|
||||
fprintf(shadow_logfd,
|
||||
_("%s: unable to chroot to directory %s: %s\n"),
|
||||
Prog, newroot, strerror (errno));
|
||||
exit (E_BAD_ARG);
|
||||
|
||||
471
libmisc/salt.c
471
libmisc/salt.c
@@ -11,24 +11,100 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if HAVE_SYS_RANDOM_H
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/* local function prototypes */
|
||||
static void seedRNG (void);
|
||||
static /*@observer@*/const char *gensalt (size_t salt_size);
|
||||
#ifdef USE_SHA_CRYPT
|
||||
static long shadow_random (long min, long max);
|
||||
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds);
|
||||
#endif /* USE_SHA_CRYPT */
|
||||
#if (defined CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY && \
|
||||
CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY)
|
||||
#define USE_XCRYPT_GENSALT 1
|
||||
#else
|
||||
#define USE_XCRYPT_GENSALT 0
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_L64A
|
||||
static /*@observer@*/char *l64a(long value)
|
||||
/* Add the salt prefix. */
|
||||
#define MAGNUM(array,ch) (array)[0]=(array)[2]='$',(array)[1]=(ch),(array)[3]='\0'
|
||||
|
||||
#ifdef USE_BCRYPT
|
||||
/* Use $2b$ as prefix for compatibility with OpenBSD's bcrypt. */
|
||||
#define BCRYPTMAGNUM(array) (array)[0]=(array)[3]='$',(array)[1]='2',(array)[2]='b',(array)[4]='\0'
|
||||
#define BCRYPT_SALT_SIZE 22
|
||||
/* Default number of rounds if not explicitly specified. */
|
||||
#define B_ROUNDS_DEFAULT 13
|
||||
/* Minimum number of rounds. */
|
||||
#define B_ROUNDS_MIN 4
|
||||
/* Maximum number of rounds. */
|
||||
#define B_ROUNDS_MAX 31
|
||||
#endif /* USE_BCRYPT */
|
||||
|
||||
#ifdef USE_SHA_CRYPT
|
||||
/* Fixed salt len for sha{256,512}crypt. */
|
||||
#define SHA_CRYPT_SALT_SIZE 16
|
||||
/* Default number of rounds if not explicitly specified. */
|
||||
#define SHA_ROUNDS_DEFAULT 5000
|
||||
/* Minimum number of rounds. */
|
||||
#define SHA_ROUNDS_MIN 1000
|
||||
/* Maximum number of rounds. */
|
||||
#define SHA_ROUNDS_MAX 999999999
|
||||
#endif
|
||||
|
||||
#ifdef USE_YESCRYPT
|
||||
/*
|
||||
* Default number of base64 characters used for the salt.
|
||||
* 24 characters gives a 144 bits (18 bytes) salt. Unlike the more
|
||||
* traditional 128 bits (16 bytes) salt, this 144 bits salt is always
|
||||
* represented by the same number of base64 characters without padding
|
||||
* issue, even with a non-standard base64 encoding scheme.
|
||||
*/
|
||||
#define YESCRYPT_SALT_SIZE 24
|
||||
/* Default cost if not explicitly specified. */
|
||||
#define Y_COST_DEFAULT 5
|
||||
/* Minimum cost. */
|
||||
#define Y_COST_MIN 1
|
||||
/* Maximum cost. */
|
||||
#define Y_COST_MAX 11
|
||||
#endif
|
||||
|
||||
/* Fixed salt len for md5crypt. */
|
||||
#define MD5_CRYPT_SALT_SIZE 8
|
||||
|
||||
/* Generate salt of size salt_size. */
|
||||
#define MAX_SALT_SIZE 44
|
||||
#define MIN_SALT_SIZE 8
|
||||
|
||||
/* Maximum size of the generated salt string. */
|
||||
#define GENSALT_SETTING_SIZE 100
|
||||
|
||||
/* local function prototypes */
|
||||
static long read_random_bytes (void);
|
||||
#if !USE_XCRYPT_GENSALT
|
||||
static /*@observer@*/const char *gensalt (size_t salt_size);
|
||||
#endif /* !USE_XCRYPT_GENSALT */
|
||||
#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
|
||||
static long shadow_random (long min, long max);
|
||||
#endif /* USE_SHA_CRYPT || USE_BCRYPT */
|
||||
#ifdef USE_SHA_CRYPT
|
||||
static /*@observer@*/const unsigned long SHA_get_salt_rounds (/*@null@*/int *prefered_rounds);
|
||||
static /*@observer@*/void SHA_salt_rounds_to_buf (char *buf, unsigned long rounds);
|
||||
#endif /* USE_SHA_CRYPT */
|
||||
#ifdef USE_BCRYPT
|
||||
static /*@observer@*/const unsigned long BCRYPT_get_salt_rounds (/*@null@*/int *prefered_rounds);
|
||||
static /*@observer@*/void BCRYPT_salt_rounds_to_buf (char *buf, unsigned long rounds);
|
||||
#endif /* USE_BCRYPT */
|
||||
#ifdef USE_YESCRYPT
|
||||
static /*@observer@*/const unsigned long YESCRYPT_get_salt_cost (/*@null@*/int *prefered_cost);
|
||||
static /*@observer@*/void YESCRYPT_salt_cost_to_buf (char *buf, unsigned long cost);
|
||||
#endif /* USE_YESCRYPT */
|
||||
|
||||
#if !USE_XCRYPT_GENSALT && !defined(HAVE_L64A)
|
||||
static /*@observer@*/char *l64a (long value)
|
||||
{
|
||||
static char buf[8];
|
||||
char *s = buf;
|
||||
@@ -59,32 +135,58 @@ static /*@observer@*/char *l64a(long value)
|
||||
|
||||
*s = '\0';
|
||||
|
||||
return(buf);
|
||||
return buf;
|
||||
}
|
||||
#endif /* !HAVE_L64A */
|
||||
#endif /* !USE_XCRYPT_GENSALT && !defined(HAVE_L64A) */
|
||||
|
||||
static void seedRNG (void)
|
||||
/* Read sizeof (long) random bytes from /dev/urandom. */
|
||||
static long read_random_bytes (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
static int seeded = 0;
|
||||
long randval = 0;
|
||||
|
||||
if (0 == seeded) {
|
||||
(void) gettimeofday (&tv, NULL);
|
||||
srandom (tv.tv_sec ^ tv.tv_usec ^ getpid ());
|
||||
seeded = 1;
|
||||
#ifdef HAVE_ARC4RANDOM_BUF
|
||||
/* arc4random_buf, if it exists, can never fail. */
|
||||
arc4random_buf (&randval, sizeof (randval));
|
||||
goto end;
|
||||
|
||||
#elif defined(HAVE_GETENTROPY)
|
||||
/* getentropy may exist but lack kernel support. */
|
||||
if (getentropy (&randval, sizeof (randval))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
goto end;
|
||||
|
||||
#elif defined(HAVE_GETRANDOM)
|
||||
/* Likewise getrandom. */
|
||||
if ((size_t) getrandom (&randval, sizeof (randval), 0) != sizeof (randval)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
goto end;
|
||||
|
||||
#else
|
||||
FILE *f = fopen ("/dev/urandom", "r");
|
||||
|
||||
if (fread (&randval, sizeof (randval), 1, f) != 1) {
|
||||
fclose(f);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
goto end;
|
||||
#endif
|
||||
|
||||
fail:
|
||||
fprintf (shadow_logfd,
|
||||
_("Unable to obtain random bytes.\n"));
|
||||
exit (1);
|
||||
|
||||
end:
|
||||
return randval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the salt prefix.
|
||||
*/
|
||||
#define MAGNUM(array,ch) (array)[0]=(array)[2]='$',(array)[1]=(ch),(array)[3]='\0'
|
||||
|
||||
#ifdef USE_SHA_CRYPT
|
||||
/* It is not clear what is the maximum value of random().
|
||||
* We assume 2^31-1.*/
|
||||
#define RANDOM_MAX 0x7FFFFFFF
|
||||
|
||||
#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
|
||||
/*
|
||||
* Return a random number between min and max (both included).
|
||||
*
|
||||
@@ -94,8 +196,9 @@ static long shadow_random (long min, long max)
|
||||
{
|
||||
double drand;
|
||||
long ret;
|
||||
seedRNG ();
|
||||
drand = (double) (max - min + 1) * random () / RANDOM_MAX;
|
||||
|
||||
drand = (double) (read_random_bytes () & RAND_MAX) / (double) RAND_MAX;
|
||||
drand *= (double) (max - min + 1);
|
||||
/* On systems were this is not random() range is lower, we favor
|
||||
* higher numbers of salt. */
|
||||
ret = (long) (max + 1 - drand);
|
||||
@@ -105,28 +208,20 @@ static long shadow_random (long min, long max)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* USE_SHA_CRYPT || USE_BCRYPT */
|
||||
|
||||
/* Default number of rounds if not explicitly specified. */
|
||||
#define ROUNDS_DEFAULT 5000
|
||||
/* Minimum number of rounds. */
|
||||
#define ROUNDS_MIN 1000
|
||||
/* Maximum number of rounds. */
|
||||
#define ROUNDS_MAX 999999999
|
||||
|
||||
/*
|
||||
* Return a salt prefix specifying the rounds number for the SHA crypt methods.
|
||||
*/
|
||||
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds)
|
||||
#ifdef USE_SHA_CRYPT
|
||||
/* Return the the rounds number for the SHA crypt methods. */
|
||||
static /*@observer@*/const unsigned long SHA_get_salt_rounds (/*@null@*/int *prefered_rounds)
|
||||
{
|
||||
static char rounds_prefix[18]; /* Max size: rounds=999999999$ */
|
||||
long rounds;
|
||||
unsigned long rounds;
|
||||
|
||||
if (NULL == prefered_rounds) {
|
||||
long min_rounds = getdef_long ("SHA_CRYPT_MIN_ROUNDS", -1);
|
||||
long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
|
||||
|
||||
if ((-1 == min_rounds) && (-1 == max_rounds)) {
|
||||
return "";
|
||||
rounds = SHA_ROUNDS_DEFAULT;
|
||||
}
|
||||
|
||||
if (-1 == min_rounds) {
|
||||
@@ -141,54 +236,208 @@ static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds
|
||||
max_rounds = min_rounds;
|
||||
}
|
||||
|
||||
rounds = shadow_random (min_rounds, max_rounds);
|
||||
rounds = (unsigned long) shadow_random (min_rounds, max_rounds);
|
||||
} else if (0 == *prefered_rounds) {
|
||||
return "";
|
||||
rounds = SHA_ROUNDS_DEFAULT;
|
||||
} else {
|
||||
rounds = *prefered_rounds;
|
||||
rounds = (unsigned long) *prefered_rounds;
|
||||
}
|
||||
|
||||
/* Sanity checks. The libc should also check this, but this
|
||||
* protects against a rounds_prefix overflow. */
|
||||
if (rounds < ROUNDS_MIN) {
|
||||
rounds = ROUNDS_MIN;
|
||||
if (rounds < SHA_ROUNDS_MIN) {
|
||||
rounds = SHA_ROUNDS_MIN;
|
||||
}
|
||||
|
||||
if (rounds > ROUNDS_MAX) {
|
||||
rounds = ROUNDS_MAX;
|
||||
if (rounds > SHA_ROUNDS_MAX) {
|
||||
rounds = SHA_ROUNDS_MAX;
|
||||
}
|
||||
|
||||
(void) snprintf (rounds_prefix, sizeof rounds_prefix,
|
||||
"rounds=%ld$", rounds);
|
||||
return rounds;
|
||||
}
|
||||
|
||||
return rounds_prefix;
|
||||
/*
|
||||
* Fill a salt prefix specifying the rounds number for the SHA crypt methods
|
||||
* to a buffer.
|
||||
*/
|
||||
static /*@observer@*/void SHA_salt_rounds_to_buf (char *buf, unsigned long rounds)
|
||||
{
|
||||
const size_t buf_begin = strlen (buf);
|
||||
|
||||
/* Nothing to do here if SHA_ROUNDS_DEFAULT is used. */
|
||||
if (rounds == SHA_ROUNDS_DEFAULT) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the result buffer is long enough.
|
||||
* We are going to write a maximum of 17 bytes,
|
||||
* plus one byte for the terminator.
|
||||
* rounds=XXXXXXXXX$
|
||||
* 00000000011111111
|
||||
* 12345678901234567
|
||||
*/
|
||||
assert (GENSALT_SETTING_SIZE > buf_begin + 17);
|
||||
|
||||
(void) snprintf (buf + buf_begin, 18, "rounds=%lu$", rounds);
|
||||
}
|
||||
#endif /* USE_SHA_CRYPT */
|
||||
|
||||
/*
|
||||
* Generate salt of size salt_size.
|
||||
*/
|
||||
#define MAX_SALT_SIZE 16
|
||||
#define MIN_SALT_SIZE 8
|
||||
#ifdef USE_BCRYPT
|
||||
/* Return the the rounds number for the BCRYPT method. */
|
||||
static /*@observer@*/const unsigned long BCRYPT_get_salt_rounds (/*@null@*/int *prefered_rounds)
|
||||
{
|
||||
unsigned long rounds;
|
||||
|
||||
if (NULL == prefered_rounds) {
|
||||
long min_rounds = getdef_long ("BCRYPT_MIN_ROUNDS", -1);
|
||||
long max_rounds = getdef_long ("BCRYPT_MAX_ROUNDS", -1);
|
||||
|
||||
if ((-1 == min_rounds) && (-1 == max_rounds)) {
|
||||
rounds = B_ROUNDS_DEFAULT;
|
||||
} else {
|
||||
if (-1 == min_rounds) {
|
||||
min_rounds = max_rounds;
|
||||
}
|
||||
|
||||
if (-1 == max_rounds) {
|
||||
max_rounds = min_rounds;
|
||||
}
|
||||
|
||||
if (min_rounds > max_rounds) {
|
||||
max_rounds = min_rounds;
|
||||
}
|
||||
|
||||
rounds = (unsigned long) shadow_random (min_rounds, max_rounds);
|
||||
}
|
||||
} else if (0 == *prefered_rounds) {
|
||||
rounds = B_ROUNDS_DEFAULT;
|
||||
} else {
|
||||
rounds = (unsigned long) *prefered_rounds;
|
||||
}
|
||||
|
||||
/* Sanity checks. */
|
||||
if (rounds < B_ROUNDS_MIN) {
|
||||
rounds = B_ROUNDS_MIN;
|
||||
}
|
||||
|
||||
#if USE_XCRYPT_GENSALT
|
||||
if (rounds > B_ROUNDS_MAX) {
|
||||
rounds = B_ROUNDS_MAX;
|
||||
}
|
||||
#else /* USE_XCRYPT_GENSALT */
|
||||
/*
|
||||
* Use 19 as an upper bound for now,
|
||||
* because musl doesn't allow rounds >= 20.
|
||||
*/
|
||||
if (rounds > 19) {
|
||||
/* rounds = B_ROUNDS_MAX; */
|
||||
rounds = 19;
|
||||
}
|
||||
#endif /* USE_XCRYPT_GENSALT */
|
||||
|
||||
return rounds;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a salt prefix specifying the rounds number for the BCRYPT method
|
||||
* to a buffer.
|
||||
*/
|
||||
static /*@observer@*/void BCRYPT_salt_rounds_to_buf (char *buf, unsigned long rounds)
|
||||
{
|
||||
const size_t buf_begin = strlen (buf);
|
||||
|
||||
/*
|
||||
* Check if the result buffer is long enough.
|
||||
* We are going to write three bytes,
|
||||
* plus one byte for the terminator.
|
||||
* XX$
|
||||
* 000
|
||||
* 123
|
||||
*/
|
||||
assert (GENSALT_SETTING_SIZE > buf_begin + 3);
|
||||
|
||||
(void) snprintf (buf + buf_begin, 4, "%2.2lu$", rounds);
|
||||
}
|
||||
#endif /* USE_BCRYPT */
|
||||
|
||||
#ifdef USE_YESCRYPT
|
||||
/* Return the the cost number for the YESCRYPT method. */
|
||||
static /*@observer@*/const unsigned long YESCRYPT_get_salt_cost (/*@null@*/int *prefered_cost)
|
||||
{
|
||||
unsigned long cost;
|
||||
|
||||
if (NULL == prefered_cost) {
|
||||
cost = getdef_num ("YESCRYPT_COST_FACTOR", Y_COST_DEFAULT);
|
||||
} else if (0 == *prefered_cost) {
|
||||
cost = Y_COST_DEFAULT;
|
||||
} else {
|
||||
cost = (unsigned long) *prefered_cost;
|
||||
}
|
||||
|
||||
/* Sanity checks. */
|
||||
if (cost < Y_COST_MIN) {
|
||||
cost = Y_COST_MIN;
|
||||
}
|
||||
|
||||
if (cost > Y_COST_MAX) {
|
||||
cost = Y_COST_MAX;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a salt prefix specifying the cost for the YESCRYPT method
|
||||
* to a buffer.
|
||||
*/
|
||||
static /*@observer@*/void YESCRYPT_salt_cost_to_buf (char *buf, unsigned long cost)
|
||||
{
|
||||
const size_t buf_begin = strlen (buf);
|
||||
|
||||
/*
|
||||
* Check if the result buffer is long enough.
|
||||
* We are going to write four bytes,
|
||||
* plus one byte for the terminator.
|
||||
* jXX$
|
||||
* 0000
|
||||
* 1234
|
||||
*/
|
||||
assert (GENSALT_SETTING_SIZE > buf_begin + 4);
|
||||
|
||||
buf[buf_begin + 0] = 'j';
|
||||
if (cost < 3) {
|
||||
buf[buf_begin + 1] = 0x36 + cost;
|
||||
} else if (cost < 6) {
|
||||
buf[buf_begin + 1] = 0x34 + cost;
|
||||
} else {
|
||||
buf[buf_begin + 1] = 0x3b + cost;
|
||||
}
|
||||
buf[buf_begin + 2] = cost >= 3 ? 'T' : '5';
|
||||
buf[buf_begin + 3] = '$';
|
||||
buf[buf_begin + 4] = '\0';
|
||||
}
|
||||
#endif /* USE_YESCRYPT */
|
||||
|
||||
#if !USE_XCRYPT_GENSALT
|
||||
static /*@observer@*/const char *gensalt (size_t salt_size)
|
||||
{
|
||||
static char salt[32];
|
||||
static char salt[MAX_SALT_SIZE + 6];
|
||||
|
||||
salt[0] = '\0';
|
||||
memset (salt, '\0', MAX_SALT_SIZE + 6);
|
||||
|
||||
assert (salt_size >= MIN_SALT_SIZE &&
|
||||
salt_size <= MAX_SALT_SIZE);
|
||||
seedRNG ();
|
||||
strcat (salt, l64a (random()));
|
||||
strcat (salt, l64a (read_random_bytes ()));
|
||||
do {
|
||||
strcat (salt, l64a (random()));
|
||||
strcat (salt, l64a (read_random_bytes ()));
|
||||
} while (strlen (salt) < salt_size);
|
||||
|
||||
salt[salt_size] = '\0';
|
||||
|
||||
return salt;
|
||||
}
|
||||
#endif /* !USE_XCRYPT_GENSALT */
|
||||
|
||||
/*
|
||||
* Generate 8 base64 ASCII characters of random salt. If MD5_CRYPT_ENAB
|
||||
@@ -198,26 +447,23 @@ static /*@observer@*/const char *gensalt (size_t salt_size)
|
||||
* Other methods can be set with ENCRYPT_METHOD
|
||||
*
|
||||
* The method can be forced with the meth parameter.
|
||||
* If NULL, the method will be defined according to the MD5_CRYPT_ENAB and
|
||||
* ENCRYPT_METHOD login.defs variables.
|
||||
* If NULL, the method will be defined according to the ENCRYPT_METHOD
|
||||
* variable, and if not set according to the MD5_CRYPT_ENAB variable,
|
||||
* which can both be set inside the login.defs file.
|
||||
*
|
||||
* If meth is specified, an additional parameter can be provided.
|
||||
* * For the SHA256 and SHA512 method, this specifies the number of rounds
|
||||
* (if not NULL).
|
||||
* * For the YESCRYPT method, this specifies the cost factor (if not NULL).
|
||||
*/
|
||||
/*@observer@*/const char *crypt_make_salt (/*@null@*//*@observer@*/const char *meth, /*@null@*/void *arg)
|
||||
{
|
||||
/* Max result size for the SHA methods:
|
||||
* +3 $5$
|
||||
* +17 rounds=999999999$
|
||||
* +16 salt
|
||||
* +1 \0
|
||||
*/
|
||||
static char result[40];
|
||||
size_t salt_len = 8;
|
||||
static char result[GENSALT_SETTING_SIZE];
|
||||
size_t salt_len = MAX_SALT_SIZE;
|
||||
const char *method;
|
||||
unsigned long rounds = 0;
|
||||
|
||||
result[0] = '\0';
|
||||
memset (result, '\0', GENSALT_SETTING_SIZE);
|
||||
|
||||
if (NULL != meth)
|
||||
method = meth;
|
||||
@@ -230,31 +476,80 @@ static /*@observer@*/const char *gensalt (size_t salt_size)
|
||||
|
||||
if (0 == strcmp (method, "MD5")) {
|
||||
MAGNUM(result, '1');
|
||||
salt_len = MD5_CRYPT_SALT_SIZE;
|
||||
rounds = 0;
|
||||
#ifdef USE_BCRYPT
|
||||
} else if (0 == strcmp (method, "BCRYPT")) {
|
||||
BCRYPTMAGNUM(result);
|
||||
salt_len = BCRYPT_SALT_SIZE;
|
||||
rounds = BCRYPT_get_salt_rounds ((int *) arg);
|
||||
BCRYPT_salt_rounds_to_buf (result, rounds);
|
||||
#endif /* USE_BCRYPT */
|
||||
#ifdef USE_YESCRYPT
|
||||
} else if (0 == strcmp (method, "YESCRYPT")) {
|
||||
MAGNUM(result, 'y');
|
||||
salt_len = YESCRYPT_SALT_SIZE;
|
||||
rounds = YESCRYPT_get_salt_cost ((int *) arg);
|
||||
YESCRYPT_salt_cost_to_buf (result, rounds);
|
||||
#endif /* USE_YESCRYPT */
|
||||
#ifdef USE_SHA_CRYPT
|
||||
} else if (0 == strcmp (method, "SHA256")) {
|
||||
MAGNUM(result, '5');
|
||||
strcat(result, SHA_salt_rounds((int *)arg));
|
||||
salt_len = (size_t) shadow_random (8, 16);
|
||||
salt_len = SHA_CRYPT_SALT_SIZE;
|
||||
rounds = SHA_get_salt_rounds ((int *) arg);
|
||||
SHA_salt_rounds_to_buf (result, rounds);
|
||||
} else if (0 == strcmp (method, "SHA512")) {
|
||||
MAGNUM(result, '6');
|
||||
strcat(result, SHA_salt_rounds((int *)arg));
|
||||
salt_len = (size_t) shadow_random (8, 16);
|
||||
salt_len = SHA_CRYPT_SALT_SIZE;
|
||||
rounds = SHA_get_salt_rounds ((int *) arg);
|
||||
SHA_salt_rounds_to_buf (result, rounds);
|
||||
#endif /* USE_SHA_CRYPT */
|
||||
} else if (0 != strcmp (method, "DES")) {
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("Invalid ENCRYPT_METHOD value: '%s'.\n"
|
||||
"Defaulting to DES.\n"),
|
||||
method);
|
||||
result[0] = '\0';
|
||||
salt_len = MAX_SALT_SIZE;
|
||||
rounds = 0;
|
||||
memset (result, '\0', GENSALT_SETTING_SIZE);
|
||||
}
|
||||
|
||||
#if USE_XCRYPT_GENSALT
|
||||
/*
|
||||
* Concatenate a pseudo random salt.
|
||||
* Prepare DES setting for crypt_gensalt(), if result
|
||||
* has not been filled with anything previously.
|
||||
*/
|
||||
assert (sizeof (result) > strlen (result) + salt_len);
|
||||
if ('\0' == result[0]) {
|
||||
/* Avoid -Wunused-but-set-variable. */
|
||||
salt_len = GENSALT_SETTING_SIZE - 1;
|
||||
rounds = 0;
|
||||
memset (result, '.', salt_len);
|
||||
result[salt_len] = '\0';
|
||||
}
|
||||
|
||||
char *retval = crypt_gensalt (result, rounds, NULL, 0);
|
||||
|
||||
/* Should not happen, but... */
|
||||
if (NULL == retval) {
|
||||
fprintf (shadow_logfd,
|
||||
_("Unable to generate a salt from setting "
|
||||
"\"%s\", check your settings in "
|
||||
"ENCRYPT_METHOD and the corresponding "
|
||||
"configuration for your selected hash "
|
||||
"method.\n"), result);
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
#else /* USE_XCRYPT_GENSALT */
|
||||
/* Check if the result buffer is long enough. */
|
||||
assert (GENSALT_SETTING_SIZE > strlen (result) + salt_len);
|
||||
|
||||
/* Concatenate a pseudo random salt. */
|
||||
strncat (result, gensalt (salt_len),
|
||||
sizeof (result) - strlen (result) - 1);
|
||||
GENSALT_SETTING_SIZE - strlen (result) - 1);
|
||||
|
||||
return result;
|
||||
#endif /* USE_XCRYPT_GENSALT */
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ void setup_env (struct passwd *info)
|
||||
static char temp_pw_dir[] = "/";
|
||||
|
||||
if (!getdef_bool ("DEFAULT_HOME") || chdir ("/") == -1) {
|
||||
fprintf (stderr, _("Unable to cd to '%s'\n"),
|
||||
fprintf (shadow_logfd, _("Unable to cd to '%s'\n"),
|
||||
info->pw_dir);
|
||||
SYSLOG ((LOG_WARN,
|
||||
"unable to cd to `%s' for user `%s'\n",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#ifdef ENABLE_SUBIDS
|
||||
@@ -95,7 +96,7 @@ static int user_busy_utmp (const char *name)
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: user %s is currently logged in\n"),
|
||||
Prog, name);
|
||||
return 1;
|
||||
@@ -106,6 +107,31 @@ static int user_busy_utmp (const char *name)
|
||||
#endif /* !__linux__ */
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef ENABLE_SUBIDS
|
||||
#define in_parentuid_range(uid) ((uid) >= parentuid && (uid) < parentuid + range)
|
||||
static int different_namespace (const char *sname)
|
||||
{
|
||||
/* 41: /proc/xxxxxxxxxx/task/xxxxxxxxxx/ns/user + \0 */
|
||||
char path[41];
|
||||
char buf[512], buf2[512];
|
||||
ssize_t llen1, llen2;
|
||||
|
||||
snprintf (path, 41, "/proc/%s/ns/user", sname);
|
||||
|
||||
if ((llen1 = readlink (path, buf, sizeof(buf))) == -1)
|
||||
return 0;
|
||||
|
||||
if ((llen2 = readlink ("/proc/self/ns/user", buf2, sizeof(buf2))) == -1)
|
||||
return 0;
|
||||
|
||||
if (llen1 == llen2 && memcmp (buf, buf2, llen1) == 0)
|
||||
return 0; /* same namespace */
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
|
||||
|
||||
static int check_status (const char *name, const char *sname, uid_t uid)
|
||||
{
|
||||
/* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */
|
||||
@@ -114,7 +140,6 @@ static int check_status (const char *name, const char *sname, uid_t uid)
|
||||
FILE *sfile;
|
||||
|
||||
snprintf (status, 40, "/proc/%s/status", sname);
|
||||
status[39] = '\0';
|
||||
|
||||
sfile = fopen (status, "r");
|
||||
if (NULL == sfile) {
|
||||
@@ -123,26 +148,29 @@ static int check_status (const char *name, const char *sname, uid_t uid)
|
||||
while (fgets (line, sizeof (line), sfile) == line) {
|
||||
if (strncmp (line, "Uid:\t", 5) == 0) {
|
||||
unsigned long ruid, euid, suid;
|
||||
|
||||
assert (uid == (unsigned long) uid);
|
||||
(void) fclose (sfile);
|
||||
if (sscanf (line,
|
||||
"Uid:\t%lu\t%lu\t%lu\n",
|
||||
&ruid, &euid, &suid) == 3) {
|
||||
if ( (ruid == (unsigned long) uid)
|
||||
|| (euid == (unsigned long) uid)
|
||||
|| (suid == (unsigned long) uid)
|
||||
#ifdef ENABLE_SUBIDS
|
||||
|| have_sub_uids(name, ruid, 1)
|
||||
|| have_sub_uids(name, euid, 1)
|
||||
|| have_sub_uids(name, suid, 1)
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
) {
|
||||
(void) fclose (sfile);
|
||||
|| (suid == (unsigned long) uid) ) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef ENABLE_SUBIDS
|
||||
if ( different_namespace (sname)
|
||||
&& ( have_sub_uids(name, ruid, 1)
|
||||
|| have_sub_uids(name, euid, 1)
|
||||
|| have_sub_uids(name, suid, 1))
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
} else {
|
||||
/* Ignore errors. This is just a best effort. */
|
||||
}
|
||||
(void) fclose (sfile);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -221,7 +249,7 @@ static int user_busy_processes (const char *name, uid_t uid)
|
||||
#ifdef ENABLE_SUBIDS
|
||||
sub_uid_close();
|
||||
#endif
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: user %s is currently used by process %d\n"),
|
||||
Prog, name, pid);
|
||||
return 1;
|
||||
@@ -241,10 +269,11 @@ static int user_busy_processes (const char *name, uid_t uid)
|
||||
}
|
||||
if (check_status (name, task_path+6, uid) != 0) {
|
||||
(void) closedir (proc);
|
||||
(void) closedir (task_dir);
|
||||
#ifdef ENABLE_SUBIDS
|
||||
sub_uid_close();
|
||||
#endif
|
||||
fprintf (stderr,
|
||||
fprintf (shadow_logfd,
|
||||
_("%s: user %s is currently used by process %d\n"),
|
||||
Prog, name, pid);
|
||||
return 1;
|
||||
|
||||
@@ -257,25 +257,25 @@ static void updwtmpx (const char *filename, const struct utmpx *utx)
|
||||
utent->ut_type = USER_PROCESS;
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_TYPE */
|
||||
utent->ut_pid = getpid ();
|
||||
strncpy (utent->ut_line, line, sizeof (utent->ut_line));
|
||||
strncpy (utent->ut_line, line, sizeof (utent->ut_line) - 1);
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_ID
|
||||
if (NULL != ut) {
|
||||
strncpy (utent->ut_id, ut->ut_id, sizeof (utent->ut_id));
|
||||
} else {
|
||||
/* XXX - assumes /dev/tty?? */
|
||||
strncpy (utent->ut_id, line + 3, sizeof (utent->ut_id));
|
||||
strncpy (utent->ut_id, line + 3, sizeof (utent->ut_id) - 1);
|
||||
}
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ID */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_NAME
|
||||
strncpy (utent->ut_name, name, sizeof (utent->ut_name));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_NAME */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_USER
|
||||
strncpy (utent->ut_user, name, sizeof (utent->ut_user));
|
||||
strncpy (utent->ut_user, name, sizeof (utent->ut_user) - 1);
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_USER */
|
||||
if (NULL != hostname) {
|
||||
struct addrinfo *info = NULL;
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
strncpy (utent->ut_host, hostname, sizeof (utent->ut_host));
|
||||
strncpy (utent->ut_host, hostname, sizeof (utent->ut_host) - 1);
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_HOST */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
|
||||
utent->ut_syslen = MIN (strlen (hostname),
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
result = malloc(sizeof(LOOKUP_TYPE));
|
||||
if (NULL == result) {
|
||||
fprintf (stderr, _("%s: out of memory\n"),
|
||||
fprintf (shadow_logfd, _("%s: out of memory\n"),
|
||||
"x" STRINGIZE(FUNCTION_NAME));
|
||||
exit (13);
|
||||
}
|
||||
@@ -84,7 +84,7 @@
|
||||
LOOKUP_TYPE *resbuf = NULL;
|
||||
buffer = (char *)realloc (buffer, length);
|
||||
if (NULL == buffer) {
|
||||
fprintf (stderr, _("%s: out of memory\n"),
|
||||
fprintf (shadow_logfd, _("%s: out of memory\n"),
|
||||
"x" STRINGIZE(FUNCTION_NAME));
|
||||
exit (13);
|
||||
}
|
||||
@@ -132,7 +132,7 @@
|
||||
if (result) {
|
||||
result = DUP_FUNCTION(result);
|
||||
if (NULL == result) {
|
||||
fprintf (stderr, _("%s: out of memory\n"),
|
||||
fprintf (shadow_logfd, _("%s: out of memory\n"),
|
||||
"x" STRINGIZE(FUNCTION_NAME));
|
||||
exit (13);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
ptr = (char *) malloc (size);
|
||||
if (NULL == ptr) {
|
||||
(void) fprintf (stderr,
|
||||
(void) fprintf (shadow_logfd,
|
||||
_("%s: failed to allocate memory: %s\n"),
|
||||
Prog, strerror (errno));
|
||||
exit (13);
|
||||
@@ -66,3 +66,10 @@
|
||||
{
|
||||
return strcpy (xmalloc (strlen (str) + 1), str);
|
||||
}
|
||||
|
||||
void xfree(void *ap)
|
||||
{
|
||||
if (ap) {
|
||||
free(ap);
|
||||
}
|
||||
}
|
||||
|
||||
29
libsubid/Makefile.am
Normal file
29
libsubid/Makefile.am
Normal file
@@ -0,0 +1,29 @@
|
||||
lib_LTLIBRARIES = libsubid.la
|
||||
libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \
|
||||
-shared -version-info @LIBSUBID_ABI_MAJOR@
|
||||
libsubid_la_SOURCES = api.c
|
||||
|
||||
pkginclude_HEADERS = subid.h
|
||||
|
||||
MISCLIBS = \
|
||||
$(LIBAUDIT) \
|
||||
$(LIBSELINUX) \
|
||||
$(LIBSEMANAGE) \
|
||||
$(LIBCRYPT_NOPAM) \
|
||||
$(LIBSKEY) \
|
||||
$(LIBMD) \
|
||||
$(LIBECONF) \
|
||||
$(LIBCRYPT) \
|
||||
$(LIBACL) \
|
||||
$(LIBATTR) \
|
||||
$(LIBTCB)
|
||||
|
||||
libsubid_la_LIBADD = \
|
||||
$(top_srcdir)/lib/libshadow.la \
|
||||
$(top_srcdir)/libmisc/libmisc.la \
|
||||
$(MISCLIBS) -ldl
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/lib \
|
||||
-I${top_srcdir}/libmisc \
|
||||
-DLOCALEDIR=\"$(datadir)/locale\"
|
||||
130
libsubid/api.c
Normal file
130
libsubid/api.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Serge Hallyn
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <stdbool.h>
|
||||
#include "subordinateio.h"
|
||||
#include "idmapping.h"
|
||||
#include "subid.h"
|
||||
|
||||
const char *Prog = "(libsubid)";
|
||||
FILE *shadow_logfd;
|
||||
|
||||
bool libsubid_init(const char *progname, FILE * logfd)
|
||||
{
|
||||
if (progname) {
|
||||
progname = strdup(progname);
|
||||
if (progname)
|
||||
Prog = progname;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (logfd) {
|
||||
shadow_logfd = logfd;
|
||||
return true;
|
||||
}
|
||||
shadow_logfd = fopen("/dev/null", "w");
|
||||
if (!shadow_logfd) {
|
||||
shadow_logfd = stderr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
int get_subid_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges)
|
||||
{
|
||||
return list_owner_ranges(owner, id_type, ranges);
|
||||
}
|
||||
|
||||
int get_subuid_ranges(const char *owner, struct subid_range **ranges)
|
||||
{
|
||||
return get_subid_ranges(owner, ID_TYPE_UID, ranges);
|
||||
}
|
||||
|
||||
int get_subgid_ranges(const char *owner, struct subid_range **ranges)
|
||||
{
|
||||
return get_subid_ranges(owner, ID_TYPE_GID, ranges);
|
||||
}
|
||||
|
||||
static
|
||||
int get_subid_owner(unsigned long id, enum subid_type id_type, uid_t **owner)
|
||||
{
|
||||
return find_subid_owners(id, id_type, owner);
|
||||
}
|
||||
|
||||
int get_subuid_owners(uid_t uid, uid_t **owner)
|
||||
{
|
||||
return get_subid_owner((unsigned long)uid, ID_TYPE_UID, owner);
|
||||
}
|
||||
|
||||
int get_subgid_owners(gid_t gid, uid_t **owner)
|
||||
{
|
||||
return get_subid_owner((unsigned long)gid, ID_TYPE_GID, owner);
|
||||
}
|
||||
|
||||
static
|
||||
bool grant_subid_range(struct subordinate_range *range, bool reuse,
|
||||
enum subid_type id_type)
|
||||
{
|
||||
return new_subid_range(range, id_type, reuse);
|
||||
}
|
||||
|
||||
bool grant_subuid_range(struct subordinate_range *range, bool reuse)
|
||||
{
|
||||
return grant_subid_range(range, reuse, ID_TYPE_UID);
|
||||
}
|
||||
|
||||
bool grant_subgid_range(struct subordinate_range *range, bool reuse)
|
||||
{
|
||||
return grant_subid_range(range, reuse, ID_TYPE_GID);
|
||||
}
|
||||
|
||||
static
|
||||
bool ungrant_subid_range(struct subordinate_range *range, enum subid_type id_type)
|
||||
{
|
||||
return release_subid_range(range, id_type);
|
||||
}
|
||||
|
||||
bool ungrant_subuid_range(struct subordinate_range *range)
|
||||
{
|
||||
return ungrant_subid_range(range, ID_TYPE_UID);
|
||||
}
|
||||
|
||||
bool ungrant_subgid_range(struct subordinate_range *range)
|
||||
{
|
||||
return ungrant_subid_range(range, ID_TYPE_GID);
|
||||
}
|
||||
151
libsubid/subid.h
Normal file
151
libsubid/subid.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef SUBID_RANGE_DEFINED
|
||||
#define SUBID_RANGE_DEFINED 1
|
||||
|
||||
/* subid_range is just a starting point and size of a range */
|
||||
struct subid_range {
|
||||
unsigned long start;
|
||||
unsigned long count;
|
||||
};
|
||||
|
||||
/* subordinage_range is a subid_range plus an owner, representing
|
||||
* a range in /etc/subuid or /etc/subgid */
|
||||
struct subordinate_range {
|
||||
const char *owner;
|
||||
unsigned long start;
|
||||
unsigned long count;
|
||||
};
|
||||
|
||||
enum subid_type {
|
||||
ID_TYPE_UID = 1,
|
||||
ID_TYPE_GID = 2
|
||||
};
|
||||
|
||||
enum subid_status {
|
||||
SUBID_STATUS_SUCCESS = 0,
|
||||
SUBID_STATUS_UNKNOWN_USER = 1,
|
||||
SUBID_STATUS_ERROR_CONN = 2,
|
||||
SUBID_STATUS_ERROR = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
* libsubid_init: initialize libsubid
|
||||
*
|
||||
* @progname: Name to display as program. If NULL, then "(libsubid)" will be
|
||||
* shown in error messages.
|
||||
* @logfd: Open file pointer to pass error messages to. If NULL, then
|
||||
* /dev/null will be opened and messages will be sent there. The
|
||||
* default if libsubid_init() is not called is stderr (2).
|
||||
*
|
||||
* This function does not need to be called. If not called, then the defaults
|
||||
* will be used.
|
||||
*
|
||||
* Returns false if an error occurred.
|
||||
*/
|
||||
bool libsubid_init(const char *progname, FILE *logfd);
|
||||
|
||||
/*
|
||||
* get_subuid_ranges: return a list of UID ranges for a user
|
||||
*
|
||||
* @owner: username being queried
|
||||
* @ranges: a pointer to an array of subid_range structs in which the result
|
||||
* will be returned.
|
||||
*
|
||||
* The caller must free(ranges) when done.
|
||||
*
|
||||
* returns: number of ranges found, ir < 0 on error.
|
||||
*/
|
||||
int get_subuid_ranges(const char *owner, struct subid_range **ranges);
|
||||
|
||||
/*
|
||||
* get_subgid_ranges: return a list of GID ranges for a user
|
||||
*
|
||||
* @owner: username being queried
|
||||
* @ranges: a pointer to an array of subid_range structs in which the result
|
||||
* will be returned.
|
||||
*
|
||||
* The caller must free(ranges) when done.
|
||||
*
|
||||
* returns: number of ranges found, ir < 0 on error.
|
||||
*/
|
||||
int get_subgid_ranges(const char *owner, struct subid_range **ranges);
|
||||
|
||||
/*
|
||||
* get_subuid_owners: return a list of uids to which the given uid has been
|
||||
* delegated.
|
||||
*
|
||||
* @uid: The subuid being queried
|
||||
* @owners: a pointer to an array of uids into which the results are placed.
|
||||
* The returned array must be freed by the caller.
|
||||
*
|
||||
* Returns the number of uids returned, or < 0 on error.
|
||||
*/
|
||||
int get_subuid_owners(uid_t uid, uid_t **owner);
|
||||
|
||||
/*
|
||||
* get_subgid_owners: return a list of uids to which the given gid has been
|
||||
* delegated.
|
||||
*
|
||||
* @uid: The subgid being queried
|
||||
* @owners: a pointer to an array of uids into which the results are placed.
|
||||
* The returned array must be freed by the caller.
|
||||
*
|
||||
* Returns the number of uids returned, or < 0 on error.
|
||||
*/
|
||||
int get_subgid_owners(gid_t gid, uid_t **owner);
|
||||
|
||||
/*
|
||||
* grant_subuid_range: assign a subuid range to a user
|
||||
*
|
||||
* @range: pointer to a struct subordinate_range detailing the UID range
|
||||
* to allocate. ->owner must be the username, and ->count must be
|
||||
* filled in. ->start is ignored, and will contain the start
|
||||
* of the newly allocated range, upon success.
|
||||
*
|
||||
* Returns true if the delegation succeeded, false otherwise. If true,
|
||||
* then the range from (range->start, range->start + range->count) will
|
||||
* be delegated to range->owner.
|
||||
*/
|
||||
bool grant_subuid_range(struct subordinate_range *range, bool reuse);
|
||||
|
||||
/*
|
||||
* grant_subsid_range: assign a subgid range to a user
|
||||
*
|
||||
* @range: pointer to a struct subordinate_range detailing the GID range
|
||||
* to allocate. ->owner must be the username, and ->count must be
|
||||
* filled in. ->start is ignored, and will contain the start
|
||||
* of the newly allocated range, upon success.
|
||||
*
|
||||
* Returns true if the delegation succeeded, false otherwise. If true,
|
||||
* then the range from (range->start, range->start + range->count) will
|
||||
* be delegated to range->owner.
|
||||
*/
|
||||
bool grant_subgid_range(struct subordinate_range *range, bool reuse);
|
||||
|
||||
/*
|
||||
* ungrant_subuid_range: remove a subuid allocation.
|
||||
*
|
||||
* @range: pointer to a struct subordinate_range detailing the UID allocation
|
||||
* to remove.
|
||||
*
|
||||
* Returns true if successful, false if it failed, for instance if the
|
||||
* delegation did not exist.
|
||||
*/
|
||||
bool ungrant_subuid_range(struct subordinate_range *range);
|
||||
|
||||
/*
|
||||
* ungrant_subuid_range: remove a subgid allocation.
|
||||
*
|
||||
* @range: pointer to a struct subordinate_range detailing the GID allocation
|
||||
* to remove.
|
||||
*
|
||||
* Returns true if successful, false if it failed, for instance if the
|
||||
* delegation did not exist.
|
||||
*/
|
||||
bool ungrant_subgid_range(struct subordinate_range *range);
|
||||
|
||||
#define SUBID_NFIELDS 3
|
||||
#endif
|
||||
@@ -41,7 +41,6 @@ man_MANS = \
|
||||
man1/sg.1 \
|
||||
man3/shadow.3 \
|
||||
man5/shadow.5 \
|
||||
man1/su.1 \
|
||||
man5/suauth.5 \
|
||||
man8/useradd.8 \
|
||||
man8/userdel.8 \
|
||||
@@ -54,6 +53,10 @@ man_nopam = \
|
||||
man5/login.access.5 \
|
||||
man5/porttime.5
|
||||
|
||||
if WITH_SU
|
||||
man_MANS += man1/su.1
|
||||
endif
|
||||
|
||||
if !USE_PAM
|
||||
man_MANS += $(man_nopam)
|
||||
endif
|
||||
@@ -133,6 +136,8 @@ login_defs_v = \
|
||||
FAKE_SHELL.xml \
|
||||
FTMP_FILE.xml \
|
||||
GID_MAX.xml \
|
||||
HMAC_CRYPTO_ALGO.xml \
|
||||
HOME_MODE.xml \
|
||||
HUSHLOGIN_FILE.xml \
|
||||
ISSUE_FILE.xml \
|
||||
KILLCHAR.xml \
|
||||
@@ -149,6 +154,7 @@ login_defs_v = \
|
||||
MD5_CRYPT_ENAB.xml \
|
||||
MOTD_FILE.xml \
|
||||
NOLOGINS_FILE.xml \
|
||||
NONEXISTENT.xml \
|
||||
OBSCURE_CHECKS_ENAB.xml \
|
||||
PASS_ALWAYS_WARN.xml \
|
||||
PASS_CHANGE_TRIES.xml \
|
||||
|
||||
@@ -7,4 +7,4 @@ pre-built ones might not fit your version of shadow. To build them yourself use
|
||||
- xsltproc
|
||||
- docbook 4
|
||||
- docbook stylesheets
|
||||
- xml2po
|
||||
- itstool
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
Set the number of days since January 1st, 1970 when the password
|
||||
was last changed. The date may also be expressed in the format
|
||||
YYYY-MM-DD (or the format more commonly used in your area).
|
||||
If the <replaceable>LAST_DAY</replaceable> is set to
|
||||
<emphasis>0</emphasis> the user is forced to change his password
|
||||
on the next log on.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -118,6 +121,13 @@
|
||||
contact the system administrator before being able to use the
|
||||
system again.
|
||||
</para>
|
||||
<para>
|
||||
For example the following can be used to set an account to expire
|
||||
in 180 days:
|
||||
</para>
|
||||
<programlisting>
|
||||
chage -E $(date -d +180days +%Y-%m-%d)
|
||||
</programlisting>
|
||||
<para>
|
||||
Passing the number <emphasis remap='I'>-1</emphasis> as the
|
||||
<replaceable>EXPIRE_DATE</replaceable> will remove an account
|
||||
@@ -131,6 +141,12 @@
|
||||
<para>Display help message and exit.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-i</option>, <option>--iso8601</option></term>
|
||||
<listitem>
|
||||
<para>When printing dates, use YYYY-MM-DD format.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-I</option>, <option>--inactive</option> <replaceable>INACTIVE</replaceable>
|
||||
@@ -233,6 +249,18 @@
|
||||
The <command>chage</command> program requires a shadow password file to
|
||||
be available.
|
||||
</para>
|
||||
<para>
|
||||
The chage program will report only the information from the shadow
|
||||
password file. This implies that configuration from other sources
|
||||
(e.g. LDAP or empty password hash field from the passwd file) that
|
||||
affect the user's login will not be shown in the chage output.
|
||||
</para>
|
||||
<para>
|
||||
The <command>chage</command> program will also not report any
|
||||
inconsistency between the shadow and passwd files (e.g. missing x in
|
||||
the passwd file). The <command>pwck</command> can be used to check
|
||||
for this kind of inconsistencies.
|
||||
</para>
|
||||
<para>The <command>chage</command> command is restricted to the root
|
||||
user, except for the <option>-l</option> option, which may be used by
|
||||
an unprivileged user to determine when their password or account is due
|
||||
|
||||
@@ -46,7 +46,7 @@ Vypíše seznam členů skupiny.
|
||||
Příkaz
|
||||
\fBgroupmems\fR
|
||||
by měl mít nastavena práva
|
||||
2770
|
||||
2710
|
||||
a měl by jej vlastnit uživatel
|
||||
\fIroot\fR
|
||||
a skupina
|
||||
@@ -58,7 +58,7 @@ spravovat členství ve skupinách.
|
||||
.sp
|
||||
.nf
|
||||
$ groupadd \-r groups
|
||||
$ chmod 2770 groupmems
|
||||
$ chmod 2710 groupmems
|
||||
$ chown root.groups groupmems
|
||||
$ groupmems \-g groups \-a gk4
|
||||
|
||||
|
||||
@@ -5,8 +5,19 @@ config.xml: ../config.xml.in
|
||||
$(MAKE) -C .. config.xml
|
||||
cp ../config.xml $@
|
||||
|
||||
%.xml: ../%.xml ../po/$(LANG).po
|
||||
xml2po --expand-all-entities -l $(LANG) -p ../po/$(LANG).po -o $@ ../$@
|
||||
messages.mo: ../po/$(LANG).po
|
||||
msgfmt ../po/$(LANG).po -o messages.mo
|
||||
|
||||
login.defs.d:
|
||||
ln -sf ../login.defs.d login.defs.d
|
||||
|
||||
%.xml: ../%.xml messages.mo login.defs.d
|
||||
if grep -q SHADOW-CONFIG-HERE $< ; then \
|
||||
sed -e 's/^<!-- SHADOW-CONFIG-HERE -->/<!ENTITY % config SYSTEM "config.xml">%config;/' $< > $@; \
|
||||
else \
|
||||
sed -e 's/^\(<!DOCTYPE .*docbookx.dtd"\)>/\1 [<!ENTITY % config SYSTEM "config.xml">%config;]>/' $< > $@; \
|
||||
fi
|
||||
itstool -d -l $(LANG) -m messages.mo -o . $@
|
||||
sed -i 's:\(^<refentry .*\)>:\1 lang="$(LANG)">:' $@
|
||||
|
||||
include ../generate_mans.mak
|
||||
@@ -16,4 +27,4 @@ $(man_MANS):
|
||||
@echo you need to run configure with --enable-man to generate man pages
|
||||
endif
|
||||
|
||||
CLEANFILES = .xml2po.mo $(EXTRA_DIST) $(addsuffix .xml,$(EXTRA_DIST)) config.xml
|
||||
CLEANFILES = messages.mo login.defs.d $(EXTRA_DIST) $(addsuffix .xml,$(EXTRA_DIST)) config.xml
|
||||
|
||||
@@ -229,6 +229,22 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-U</option>, <option>--users</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A list of usernames to add as members of the group.
|
||||
</para>
|
||||
<para>
|
||||
The default behavior (if the <option>-g</option>,
|
||||
<option>-N</option>, and <option>-U</option> options are not
|
||||
specified) is defined by the <option>USERGROUPS_ENAB</option>
|
||||
variable in <filename>/etc/login.defs</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
@@ -318,13 +334,13 @@
|
||||
<varlistentry>
|
||||
<term><replaceable>4</replaceable></term>
|
||||
<listitem>
|
||||
<para>GID not unique (when <option>-o</option> not used)</para>
|
||||
<para>GID is already used (when called without <option>-o</option>)</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><replaceable>9</replaceable></term>
|
||||
<listitem>
|
||||
<para>group name not unique</para>
|
||||
<para>group name is already used</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
||||
@@ -91,6 +91,17 @@
|
||||
are:
|
||||
</para>
|
||||
<variablelist remap='IP'>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-f</option>, <option>--force</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This option forces the removal of the group, even if there's some user
|
||||
having the group as the primary one.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option>, <option>--help</option></term>
|
||||
<listitem>
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
<title>SETUP</title>
|
||||
<para>
|
||||
The <command>groupmems</command> executable should be in mode
|
||||
<literal>2770</literal> as user <emphasis>root</emphasis> and in group
|
||||
<literal>2710</literal> as user <emphasis>root</emphasis> and in group
|
||||
<emphasis>groups</emphasis>. The system administrator can add users to
|
||||
group <emphasis>groups</emphasis> to allow or disallow them using the
|
||||
<command>groupmems</command> utility to manage their own group
|
||||
@@ -189,7 +189,7 @@
|
||||
|
||||
<programlisting>
|
||||
$ groupadd -r groups
|
||||
$ chmod 2770 groupmems
|
||||
$ chmod 2710 groupmems
|
||||
$ chown root.groups groupmems
|
||||
$ groupmems -g groups -a gk4
|
||||
</programlisting>
|
||||
|
||||
@@ -93,6 +93,15 @@
|
||||
</para>
|
||||
<variablelist remap='IP'>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-a</option>, <option>--append</option> <replaceable>GID</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>If group members are specified with -U, append them to the existing
|
||||
member list, rather than replacing it.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-g</option>, <option>--gid</option> <replaceable>GID</replaceable>
|
||||
</term>
|
||||
@@ -203,6 +212,22 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-U</option>, <option>--users</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A list of usernames to add as members of the group.
|
||||
</para>
|
||||
<para>
|
||||
The default behavior (if the <option>-g</option>,
|
||||
<option>-N</option>, and <option>-U</option> options are not
|
||||
specified) is defined by the <option>USERGROUPS_ENAB</option>
|
||||
variable in <filename>/etc/login.defs</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
@@ -274,7 +299,7 @@
|
||||
<varlistentry>
|
||||
<term><replaceable>4</replaceable></term>
|
||||
<listitem>
|
||||
<para>E_GID_IN_USE: specified group doesn't exist</para>
|
||||
<para>E_GID_IN_USE: group id already in use</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
<!-- SHADOW-CONFIG-HERE -->
|
||||
]>
|
||||
<refentry id='grpck.8'>
|
||||
<!-- $Id$ -->
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Julianne Frances</firstname>
|
||||
@@ -192,6 +191,17 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-S</option>, <option>--silence-warnings</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Suppress more controversial warnings, in particular warnings about
|
||||
inconsistency between group members listed in
|
||||
<filename>/etc/group</filename> and
|
||||
<filename>/etc/ghadow</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
By default, <command>grpck</command> operates on
|
||||
|
||||
@@ -233,5 +233,12 @@
|
||||
is no entries for users with UID between 170 and 800 lastlog will appear
|
||||
to hang as it processes entries with UIDs 171-799).
|
||||
</para>
|
||||
<para>
|
||||
Having high UIDs can create problems when handling the <term><filename>
|
||||
/var/log/lastlog</filename></term> with external tools. Although the
|
||||
actual file is sparse and does not use too much space, certain
|
||||
applications are not designed to identify sparse files by default and may
|
||||
require a specific option to handle them.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
<!ENTITY FAKE_SHELL SYSTEM "login.defs.d/FAKE_SHELL.xml">
|
||||
<!ENTITY FTMP_FILE SYSTEM "login.defs.d/FTMP_FILE.xml">
|
||||
<!ENTITY GID_MAX SYSTEM "login.defs.d/GID_MAX.xml">
|
||||
<!ENTITY HMAC_CRYPTO_ALGO SYSTEM "login.defs.d/HMAC_CRYPTO_ALGO.xml">
|
||||
<!ENTITY HOME_MODE SYSTEM "login.defs.d/HOME_MODE.xml">
|
||||
<!ENTITY HUSHLOGIN_FILE SYSTEM "login.defs.d/HUSHLOGIN_FILE.xml">
|
||||
<!ENTITY ISSUE_FILE SYSTEM "login.defs.d/ISSUE_FILE.xml">
|
||||
<!ENTITY KILLCHAR SYSTEM "login.defs.d/KILLCHAR.xml">
|
||||
@@ -66,6 +68,7 @@
|
||||
<!ENTITY MD5_CRYPT_ENAB SYSTEM "login.defs.d/MD5_CRYPT_ENAB.xml">
|
||||
<!ENTITY MOTD_FILE SYSTEM "login.defs.d/MOTD_FILE.xml">
|
||||
<!ENTITY NOLOGINS_FILE SYSTEM "login.defs.d/NOLOGINS_FILE.xml">
|
||||
<!ENTITY NONEXISTENT SYSTEM "login.defs.d/NONEXISTENT.xml">
|
||||
<!ENTITY OBSCURE_CHECKS_ENAB SYSTEM "login.defs.d/OBSCURE_CHECKS_ENAB.xml">
|
||||
<!ENTITY PASS_ALWAYS_WARN SYSTEM "login.defs.d/PASS_ALWAYS_WARN.xml">
|
||||
<!ENTITY PASS_CHANGE_TRIES SYSTEM "login.defs.d/PASS_CHANGE_TRIES.xml">
|
||||
@@ -185,6 +188,8 @@
|
||||
&FAKE_SHELL;
|
||||
&FTMP_FILE;
|
||||
&GID_MAX; <!-- documents also GID_MIN -->
|
||||
&HMAC_CRYPTO_ALGO;
|
||||
&HOME_MODE;
|
||||
&HUSHLOGIN_FILE;
|
||||
&ISSUE_FILE;
|
||||
&KILLCHAR;
|
||||
@@ -201,6 +206,7 @@
|
||||
&MD5_CRYPT_ENAB;
|
||||
&MOTD_FILE;
|
||||
&NOLOGINS_FILE;
|
||||
&NONEXISTENT;
|
||||
&OBSCURE_CHECKS_ENAB;
|
||||
&PASS_ALWAYS_WARN;
|
||||
&PASS_CHANGE_TRIES;
|
||||
@@ -401,6 +407,7 @@
|
||||
ENCRYPT_METHOD
|
||||
GID_MAX GID_MIN
|
||||
MAX_MEMBERS_PER_GROUP MD5_CRYPT_ENAB
|
||||
HOME_MODE
|
||||
PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
|
||||
<phrase condition="sha_crypt">SHA_CRYPT_MAX_ROUNDS
|
||||
SHA_CRYPT_MIN_ROUNDS</phrase>
|
||||
@@ -481,6 +488,7 @@
|
||||
<para>
|
||||
CREATE_HOME
|
||||
GID_MAX GID_MIN
|
||||
HOME_MODE
|
||||
LASTLOG_UID_MAX
|
||||
MAIL_DIR MAX_MEMBERS_PER_GROUP
|
||||
PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
<replaceable>MD5</replaceable><phrase condition="sha_crypt">,
|
||||
<replaceable>SHA256</replaceable>,
|
||||
<replaceable>SHA512</replaceable></phrase>.
|
||||
MD5 and DES should not be used for new hashes, see
|
||||
<refentrytitle>crypt</refentrytitle><manvolnum>5</manvolnum>
|
||||
for recommendations.
|
||||
</para>
|
||||
<para>
|
||||
Note: this parameter overrides the <option>MD5_CRYPT_ENAB</option>
|
||||
|
||||
44
man/login.defs.d/HMAC_CRYPTO_ALGO.xml
Normal file
44
man/login.defs.d/HMAC_CRYPTO_ALGO.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<!--
|
||||
Copyright (c) 1991 - 1993, Julianne Frances Haugh
|
||||
Copyright (c) 1991 - 1993, Chip Rosenthal
|
||||
Copyright (c) 2007 - 2008, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the copyright holders or contributors may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<varlistentry condition="no_pam">
|
||||
<term><option>HMAC_CRYPTO_ALGO</option> (string)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Used to select the HMAC cryptography algorithm that the pam_timestamp
|
||||
module is going to use to calculate the keyed-hash message authentication
|
||||
code.
|
||||
</para>
|
||||
<para>
|
||||
Note: Check <refentrytitle>hmac</refentrytitle><manvolnum>3</manvolnum>
|
||||
to see the possible algorithms that are available in your system.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
43
man/login.defs.d/HOME_MODE.xml
Normal file
43
man/login.defs.d/HOME_MODE.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<!--
|
||||
Copyright (c) 1991 - 1993, Julianne Frances Haugh
|
||||
Copyright (c) 1991 - 1993, Chip Rosenthal
|
||||
Copyright (c) 2007 - 2009, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the copyright holders or contributors may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<varlistentry>
|
||||
<term><option>HOME_MODE</option> (number)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The mode for new home directories. If not specified,
|
||||
the <option>UMASK</option> is used to create the mode.
|
||||
</para>
|
||||
<para>
|
||||
<command>useradd</command> and <command>newusers</command> use this
|
||||
to set the mode of the home directory they create.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
41
man/login.defs.d/NONEXISTENT.xml
Normal file
41
man/login.defs.d/NONEXISTENT.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<!--
|
||||
Copyright (c) 1991 - 1993, Julianne Frances Haugh
|
||||
Copyright (c) 1991 - 1993, Chip Rosenthal
|
||||
Copyright (c) 2007 - 2009, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the copyright holders or contributors may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<varlistentry>
|
||||
<term><option>NONEXISTENT</option> (string)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If a system account intentionally does not have a home directory
|
||||
that exists, this string can be provided in the /etc/passwd
|
||||
entry for the account to indicate this. The result is that pwck
|
||||
will not emit a spurious warning for this account.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -34,7 +34,7 @@
|
||||
<para>
|
||||
The minimum number of days allowed between password changes. Any
|
||||
password changes attempted sooner than this will be rejected. If not
|
||||
specified, -1 will be assumed (which disables the restriction).
|
||||
specified, 0 will be assumed (which disables the restriction).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</para>
|
||||
<para>
|
||||
If not specified, the libc will choose the default number of rounds
|
||||
(5000).
|
||||
(5000), which is orders of magnitude too low for modern hardware.
|
||||
</para>
|
||||
<para>
|
||||
The values must be inside the 1000-999,999,999 range.
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
</para>
|
||||
<para>
|
||||
<command>useradd</command> and <command>newusers</command> use this
|
||||
mask to set the mode of the home directory they create
|
||||
mask to set the mode of the home directory they create if
|
||||
<option>HOME_MODE</option> is not set.
|
||||
</para>
|
||||
<para condition="no_pam">
|
||||
It is also used by <command>login</command> to define users' initial
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
]>
|
||||
|
||||
<refentry id='newgidmap.1'>
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Eric</firstname>
|
||||
<surname>Biederman</surname>
|
||||
<contrib>Creation, 2013</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>newgidmap</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
@@ -80,9 +87,15 @@
|
||||
<refsect1 id='description'>
|
||||
<title>DESCRIPTION</title>
|
||||
<para>
|
||||
The <command>newgidmap</command> sets <filename>/proc/[pid]/gid_map</filename> based on its
|
||||
command line arguments and the gids allowed in <filename>/etc/subgid</filename>.
|
||||
Note that the root user is not exempted from the requirement for a valid
|
||||
The <command>newgidmap</command> sets <filename>/proc/[pid]/gid_map</filename>
|
||||
based on its command line arguments and the gids allowed. Subgid
|
||||
delegation can either be managed via <filename>/etc/subgid</filename>
|
||||
or through the configured NSS subid module. These options are mutually
|
||||
exclusive.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that the root group is not exempted from the requirement for a valid
|
||||
<filename>/etc/subgid</filename> entry.
|
||||
</para>
|
||||
|
||||
@@ -120,7 +133,7 @@
|
||||
<command>newgidmap</command> verifies that the caller is the owner
|
||||
of the process indicated by <option>pid</option> and that for each
|
||||
of the above sets, each of the GIDs in the range [lowergid,
|
||||
lowergid+count] is allowed to the caller according to
|
||||
lowergid+count) is allowed to the caller according to
|
||||
<filename>/etc/subgid</filename> before setting
|
||||
<filename>/proc/[pid]/gid_map</filename>.
|
||||
</para>
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
]>
|
||||
|
||||
<refentry id='newuidmap.1'>
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Eric</firstname>
|
||||
<surname>Biederman</surname>
|
||||
<contrib>Creation, 2013</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>newuidmap</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
@@ -80,8 +87,14 @@
|
||||
<refsect1 id='description'>
|
||||
<title>DESCRIPTION</title>
|
||||
<para>
|
||||
The <command>newuidmap</command> sets <filename>/proc/[pid]/uid_map</filename> based on its
|
||||
command line arguments and the uids allowed in <filename>/etc/subuid</filename>.
|
||||
The <command>newuidmap</command> sets <filename>/proc/[pid]/uid_map</filename>
|
||||
based on its command line arguments and the uids allowed. Subuid
|
||||
delegation can either be managed via <filename>/etc/subuid</filename> or
|
||||
through the configured NSS subid module. These options are mutually
|
||||
exclusive.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that the root user is not exempted from the requirement for a valid
|
||||
<filename>/etc/subuid</filename> entry.
|
||||
</para>
|
||||
@@ -120,7 +133,7 @@
|
||||
<command>newuidmap</command> verifies that the caller is the owner
|
||||
of the process indicated by <option>pid</option> and that for each
|
||||
of the above sets, each of the UIDs in the range [loweruid,
|
||||
loweruid+count] is allowed to the caller according to
|
||||
loweruid+count) is allowed to the caller according to
|
||||
<filename>/etc/subuid</filename> before setting
|
||||
<filename>/proc/[pid]/uid_map</filename>.
|
||||
</para>
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY ENCRYPT_METHOD SYSTEM "login.defs.d/ENCRYPT_METHOD.xml">
|
||||
<!ENTITY GID_MAX SYSTEM "login.defs.d/GID_MAX.xml">
|
||||
<!ENTITY HOME_MODE SYSTEM "login.defs.d/HOME_MODE.xml">
|
||||
<!ENTITY MAX_MEMBERS_PER_GROUP SYSTEM "login.defs.d/MAX_MEMBERS_PER_GROUP.xml">
|
||||
<!ENTITY MD5_CRYPT_ENAB SYSTEM "login.defs.d/MD5_CRYPT_ENAB.xml">
|
||||
<!ENTITY PASS_MAX_DAYS SYSTEM "login.defs.d/PASS_MAX_DAYS.xml">
|
||||
@@ -218,7 +219,15 @@
|
||||
<para>
|
||||
If this field does not specify an existing directory, the
|
||||
specified directory is created, with ownership set to the
|
||||
user being created or updated and its primary group.
|
||||
user being created or updated and its primary group. Note
|
||||
that <emphasis>newusers does not create parent directories
|
||||
</emphasis> of the new user's home directory. The newusers
|
||||
command will fail to create the home directory if the parent
|
||||
directories do not exist, and will send a message to stderr
|
||||
informing the user of the failure. The newusers command will
|
||||
not halt or return a failure to the calling shell if it fails
|
||||
to create the home directory, it will continue to process the
|
||||
batch of new users specified.
|
||||
</para>
|
||||
<para>
|
||||
If the home directory of an existing user is changed,
|
||||
@@ -266,6 +275,18 @@
|
||||
<para>
|
||||
The options which apply to the <command>newusers</command> command are:
|
||||
</para>
|
||||
<variablelist remap='IP'>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>--badname</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Allow names that do not conform to standards.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<variablelist remap='IP' condition="no_pam">
|
||||
<varlistentry>
|
||||
<term><option>-c</option>, <option>--crypt-method</option></term>
|
||||
@@ -370,6 +391,7 @@
|
||||
</variablelist>
|
||||
<variablelist>
|
||||
&GID_MAX; <!-- documents also GID_MIN -->
|
||||
&HOME_MODE;
|
||||
&MAX_MEMBERS_PER_GROUP;
|
||||
</variablelist>
|
||||
<variablelist condition="no_pam">
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
<citerefentry><refentrytitle>nologin</refentrytitle><manvolnum>5</manvolnum>
|
||||
</citerefentry>.
|
||||
</para>
|
||||
<para>
|
||||
If <command>SSH_ORIGINAL_COMMAND</command> is populated it will be logged.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id='see_also'>
|
||||
|
||||
@@ -98,28 +98,50 @@
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
The encrypted password field may be blank, in which case no password
|
||||
is required to authenticate as the specified login name. However,
|
||||
some applications which read the <filename>/etc/passwd</filename> file
|
||||
may decide not to permit <emphasis>any</emphasis> access at all if the
|
||||
<emphasis>password</emphasis> field is blank. If the
|
||||
<emphasis>password</emphasis> field is a lower-case <quote>x</quote>,
|
||||
then the encrypted password is actually stored in the
|
||||
If the <emphasis>password</emphasis> field is a lower-case
|
||||
<quote>x</quote>, then the encrypted password is actually stored in the
|
||||
<citerefentry><refentrytitle>shadow</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> file instead; there
|
||||
<emphasis>must</emphasis> be a corresponding line in the
|
||||
<filename>/etc/shadow</filename> file, or else the user account is invalid.
|
||||
If the <emphasis>password</emphasis> field is any other string, then
|
||||
it will be treated as an encrypted password, as specified by
|
||||
<citerefentry><refentrytitle>crypt</refentrytitle>
|
||||
<manvolnum>3</manvolnum></citerefentry>.
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The comment field is used by various system utilities, such as
|
||||
The encrypted <emphasis>password</emphasis> field may be empty,
|
||||
in which case no password is required to authenticate as the
|
||||
specified login name. However, some applications which read the
|
||||
<filename>/etc/passwd</filename> file may decide not to permit
|
||||
<emphasis>any</emphasis> access at all if the
|
||||
<emphasis>password</emphasis> field is blank.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A <emphasis>password</emphasis> field which starts with an
|
||||
exclamation mark means that the password is locked. The
|
||||
remaining characters on the line represent the
|
||||
<emphasis>password</emphasis> field before the password was
|
||||
locked.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Refer to <citerefentry><refentrytitle>crypt</refentrytitle>
|
||||
<manvolnum>3</manvolnum></citerefentry> for details on how
|
||||
this string is interpreted.
|
||||
</para>
|
||||
<para>
|
||||
If the password field contains some string that is not a valid
|
||||
result of <citerefentry><refentrytitle>crypt</refentrytitle>
|
||||
<manvolnum>3</manvolnum></citerefentry>, for instance ! or *,
|
||||
the user will not be able to use a unix password to log in
|
||||
(but the user may log in the system by other means).
|
||||
</para>
|
||||
<para>
|
||||
The comment field, also known as the gecos field, is used by
|
||||
various system utilities, such as
|
||||
<citerefentry><refentrytitle>finger</refentrytitle>
|
||||
<manvolnum>1</manvolnum></citerefentry>.
|
||||
<manvolnum>1</manvolnum></citerefentry>. The use of an ampersand
|
||||
here will be replaced by the capitalised login name when the field
|
||||
is used or displayed by such system utilities.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -6980,7 +6980,7 @@ msgstr ""
|
||||
|
||||
#: groupmems.8.xml:181(para)
|
||||
msgid ""
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2770</"
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2710</"
|
||||
"literal> as user <emphasis>root</emphasis> and in group <emphasis>groups</"
|
||||
"emphasis>. The system administrator can add users to group <emphasis>groups</"
|
||||
"emphasis> to allow or disallow them using the <command>groupmems</command> "
|
||||
@@ -6992,7 +6992,7 @@ msgstr ""
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
|
||||
12
man/po/de.po
12
man/po/de.po
@@ -1005,10 +1005,10 @@ msgstr ""
|
||||
|
||||
#: usermod.8.xml:327(para) chsh.1.xml:123(para)
|
||||
msgid ""
|
||||
"The name of the user's new login shell. Setting this field to blank causes "
|
||||
"The path of the user's new login shell. Setting this field to blank causes "
|
||||
"the system to select the default login shell."
|
||||
msgstr ""
|
||||
"Der Name der neuen Anmelde-Shell des Benutzers. Falls dieses Feld leer "
|
||||
"Der Pfad der neuen Anmelde-Shell des Benutzers. Falls dieses Feld leer "
|
||||
"gelassen wird, verwendet das System die Standard-Anmelde-Shell."
|
||||
|
||||
#: usermod.8.xml:334(term) useradd.8.xml:471(term)
|
||||
@@ -8878,14 +8878,14 @@ msgstr "EINRICHTUNG"
|
||||
|
||||
#: groupmems.8.xml:181(para)
|
||||
msgid ""
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2770</"
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2710</"
|
||||
"literal> as user <emphasis>root</emphasis> and in group <emphasis>groups</"
|
||||
"emphasis>. The system administrator can add users to group <emphasis>groups</"
|
||||
"emphasis> to allow or disallow them using the <command>groupmems</command> "
|
||||
"utility to manage their own group membership list."
|
||||
msgstr ""
|
||||
"Die ausführbare Datei <command>groupmems</command> sollte die Rechte "
|
||||
"<literal>2770</literal> haben und dem Benutzer <emphasis>root</emphasis> und "
|
||||
"<literal>2710</literal> haben und dem Benutzer <emphasis>root</emphasis> und "
|
||||
"der Gruppe <emphasis>groups</emphasis> gehören. Der Systemadministrator kann "
|
||||
"Benutzer der Gruppe <emphasis>groups</emphasis> hinzufügen, um ihnen zu "
|
||||
"ermöglichen, mit <command>groupmems</command> die Mitgliederliste ihrer "
|
||||
@@ -8896,14 +8896,14 @@ msgstr ""
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
|
||||
@@ -8701,14 +8701,14 @@ msgstr "CONFIGURATION"
|
||||
|
||||
#: groupmems.8.xml:181(para)
|
||||
msgid ""
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2770</"
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2710</"
|
||||
"literal> as user <emphasis>root</emphasis> and in group <emphasis>groups</"
|
||||
"emphasis>. The system administrator can add users to group <emphasis>groups</"
|
||||
"emphasis> to allow or disallow them using the <command>groupmems</command> "
|
||||
"utility to manage their own group membership list."
|
||||
msgstr ""
|
||||
"L'exécutable <command>groupmems</command> doit être installé en mode "
|
||||
"<literal>2770</literal> avec pour utilisateur <emphasis>root</emphasis> et "
|
||||
"<literal>2710</literal> avec pour utilisateur <emphasis>root</emphasis> et "
|
||||
"pour groupe <emphasis>groups</emphasis>. L'administrateur système peut "
|
||||
"ajouter des utilisateurs au groupe <emphasis>groups</emphasis> pour leur "
|
||||
"permettre ou leur interdire d'utiliser <command>groupmems</command> pour "
|
||||
@@ -8719,14 +8719,14 @@ msgstr ""
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
|
||||
@@ -9254,14 +9254,14 @@ msgstr "CONFIGURAZIONE"
|
||||
|
||||
#: groupmems.8.xml:181(para)
|
||||
msgid ""
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2770</"
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2710</"
|
||||
"literal> as user <emphasis>root</emphasis> and in group <emphasis>groups</"
|
||||
"emphasis>. The system administrator can add users to group <emphasis>groups</"
|
||||
"emphasis> to allow or disallow them using the <command>groupmems</command> "
|
||||
"utility to manage their own group membership list."
|
||||
msgstr ""
|
||||
"L'eseguibile <command>groupmems</command> dovrebbe avere i permessi "
|
||||
"<literal>2770</literal> ed essere di proprietà di <emphasis>root</emphasis> "
|
||||
"<literal>2710</literal> ed essere di proprietà di <emphasis>root</emphasis> "
|
||||
"e del gruppo <emphasis>groups</emphasis>. L'amministratore di sistema può "
|
||||
"aggiungere utenti al gruppo <emphasis>groups</emphasis> per permettere loro "
|
||||
"di poter gestire l'elenco di membri del proprio gruppo tramite il comando "
|
||||
@@ -9272,14 +9272,14 @@ msgstr ""
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" $ groupadd -r groups\n"
|
||||
" $ chmod 2770 groupmems\n"
|
||||
" $ chmod 2710 groupmems\n"
|
||||
" $ chown root.groups groupmems\n"
|
||||
" $ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
|
||||
@@ -7558,7 +7558,7 @@ msgstr ""
|
||||
|
||||
#: groupmems.8.xml:181(para)
|
||||
msgid ""
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2770</"
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2710</"
|
||||
"literal> as user <emphasis>root</emphasis> and in group <emphasis>groups</"
|
||||
"emphasis>. The system administrator can add users to group <emphasis>groups</"
|
||||
"emphasis> to allow or disallow them using the <command>groupmems</command> "
|
||||
@@ -7570,14 +7570,14 @@ msgstr ""
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
|
||||
@@ -9292,14 +9292,14 @@ msgstr "НАСТРОЙКА"
|
||||
|
||||
#: groupmems.8.xml:181(para)
|
||||
msgid ""
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2770</"
|
||||
"The <command>groupmems</command> executable should be in mode <literal>2710</"
|
||||
"literal> as user <emphasis>root</emphasis> and in group <emphasis>groups</"
|
||||
"emphasis>. The system administrator can add users to group <emphasis>groups</"
|
||||
"emphasis> to allow or disallow them using the <command>groupmems</command> "
|
||||
"utility to manage their own group membership list."
|
||||
msgstr ""
|
||||
"Исполняемый файл программы <command>groupmems</command> должен иметь права "
|
||||
"<literal>2770</literal>, принадлежать пользователю <emphasis>root</emphasis> "
|
||||
"<literal>2710</literal>, принадлежать пользователю <emphasis>root</emphasis> "
|
||||
"и группе <emphasis>groups</emphasis>. Системный администратор может "
|
||||
"добавлять пользователей в группу <emphasis>groups</emphasis>, разрешая или "
|
||||
"запрещая им запускать программу <command>groupmems</command> для управления "
|
||||
@@ -9311,14 +9311,14 @@ msgstr ""
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t$ groupadd -r groups\n"
|
||||
"\t$ chmod 2770 groupmems\n"
|
||||
"\t$ chmod 2710 groupmems\n"
|
||||
"\t$ chown root.groups groupmems\n"
|
||||
"\t$ groupmems -g groups -a gk4\n"
|
||||
" "
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user