Compare commits
781 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
499c6f7938 | ||
|
|
e568b9e435 | ||
|
|
36ef489fe1 | ||
|
|
65741533ca | ||
|
|
93ce5304fe | ||
|
|
355e31d19d | ||
|
|
24cfe44b07 | ||
|
|
db38a728d1 | ||
|
|
4ad827768e | ||
|
|
b04c2d7e99 | ||
|
|
cb550dae17 | ||
|
|
56c7096000 | ||
|
|
b0bcb01888 | ||
|
|
f7257fafe1 | ||
|
|
616ed68b48 | ||
|
|
7e96d749e4 | ||
|
|
885692e3c5 | ||
|
|
bbb2a1522f | ||
|
|
ae00a3579c | ||
|
|
fa69d08d13 | ||
|
|
7d5d9c1841 | ||
|
|
80907f451b | ||
|
|
f4f6300499 | ||
|
|
d6f18c207e | ||
|
|
35c0b2cb47 | ||
|
|
d07e4b8e32 | ||
|
|
0762426c4d | ||
|
|
5cd975acbf | ||
|
|
ae69e6da5a | ||
|
|
647c22c85a | ||
|
|
1edc2153bb | ||
|
|
bf56a7097e | ||
|
|
a6418fb0df | ||
|
|
401d72d609 | ||
|
|
a1352582df | ||
|
|
2e239f44cf | ||
|
|
5b22b11454 | ||
|
|
91d5c24f58 | ||
|
|
e9a8ffbb51 | ||
|
|
1b9b5ec306 | ||
|
|
f596cd113c | ||
|
|
2e075ad91b | ||
|
|
fd55bd5d4a | ||
|
|
604c7d72d9 | ||
|
|
738ebc04b9 | ||
|
|
8dfd253b9c | ||
|
|
2a08642cdc | ||
|
|
3aa2765d59 | ||
|
|
12235612b5 | ||
|
|
39b17ee5d5 | ||
|
|
37bda83dfc | ||
|
|
16ea6678ef | ||
|
|
a7118480af | ||
|
|
41705d4532 | ||
|
|
b98658bd11 | ||
|
|
50916c195b | ||
|
|
a61ecc3177 | ||
|
|
627ebe09ed | ||
|
|
2adab29e61 | ||
|
|
fb41fb8c46 | ||
|
|
738eac8669 | ||
|
|
82afbc40ce | ||
|
|
00694672cd | ||
|
|
fa2afc96ac | ||
|
|
42cb56a3a0 | ||
|
|
b5e7ede8b7 | ||
|
|
c859ad91c4 | ||
|
|
5dead2b296 | ||
|
|
6573e0175f | ||
|
|
96816f495e | ||
|
|
9f13b4fdaa | ||
|
|
5f143879df | ||
|
|
785231657c | ||
|
|
b9ecd1cf42 | ||
|
|
4a4549c49b | ||
|
|
3e85eafb4c | ||
|
|
e3343c1d9b | ||
|
|
297141c6c4 | ||
|
|
589a773f7e | ||
|
|
f634cd3e2c | ||
|
|
8eaa6f8b4c | ||
|
|
9ee294ba70 | ||
|
|
d945d61e42 | ||
|
|
f8f0886248 | ||
|
|
87bb724151 | ||
|
|
205e8b5137 | ||
|
|
a9b8fdc3c9 | ||
|
|
321e3ed02c | ||
|
|
63e6dc6b11 | ||
|
|
a96a8861dd | ||
|
|
24875bb422 | ||
|
|
74073db5db | ||
|
|
fe0a5b6ee3 | ||
|
|
12875d2687 | ||
|
|
489432d742 | ||
|
|
750093a3ed | ||
|
|
a01499179f | ||
|
|
6ba7fd7d13 | ||
|
|
1737e6e0ec | ||
|
|
3f649c5504 | ||
|
|
9bdcf8fa15 | ||
|
|
7f9e196903 | ||
|
|
8bcb2c1e71 | ||
|
|
79db09da98 | ||
|
|
8f64190223 | ||
|
|
ce684e236c | ||
|
|
d1534c53f7 | ||
|
|
19b672c3a4 | ||
|
|
a979e7d14d | ||
|
|
4654150518 | ||
|
|
0921785ca2 | ||
|
|
b60e8b6b45 | ||
|
|
538336a332 | ||
|
|
5c1279d803 | ||
|
|
61939960cc | ||
|
|
ee7af4d7e2 | ||
|
|
b8355dba15 | ||
|
|
5d661e366b | ||
|
|
787fbd3fab | ||
|
|
c671c3a738 | ||
|
|
69fe59a632 | ||
|
|
ba65b06b4a | ||
|
|
4da0573bf7 | ||
|
|
4e75bb57bb | ||
|
|
c527c0196b | ||
|
|
a326ffa435 | ||
|
|
0f448edf19 | ||
|
|
9b6b06cd03 | ||
|
|
d7d0b06a41 | ||
|
|
72fa8afa07 | ||
|
|
1e75786616 | ||
|
|
1db4402dbb | ||
|
|
59e1947950 | ||
|
|
f8b8aaf5e4 | ||
|
|
613dc54ac5 | ||
|
|
a1591f77e8 | ||
|
|
102253834a | ||
|
|
dd85562fac | ||
|
|
90cc7f0f1d | ||
|
|
bb00d1630a | ||
|
|
a5188d2f05 | ||
|
|
6547cbda6f | ||
|
|
79919f184c | ||
|
|
e6b23e1431 | ||
|
|
b0c0a94c66 | ||
|
|
76b51939aa | ||
|
|
91fc51387c | ||
|
|
009125484e | ||
|
|
8112a12521 | ||
|
|
69307a1f2b | ||
|
|
e68e07d095 | ||
|
|
851245107d | ||
|
|
e88d1f5803 | ||
|
|
988f7334ad | ||
|
|
80fd2969c9 | ||
|
|
13b74243a6 | ||
|
|
c7035dbe9c | ||
|
|
8f78169a52 | ||
|
|
5766499b85 | ||
|
|
4fd672c5b9 | ||
|
|
fca3b5cdc9 | ||
|
|
8fa9bedcf7 | ||
|
|
44869516d3 | ||
|
|
06d5369fdb | ||
|
|
71f7f777ec | ||
|
|
3a37388d43 | ||
|
|
4c1d96e8e0 | ||
|
|
f9bd143012 | ||
|
|
98e42fa944 | ||
|
|
ab6c366668 | ||
|
|
fc656ad7bd | ||
|
|
1353c71054 | ||
|
|
566fbac1ef | ||
|
|
496002abc9 | ||
|
|
e8dd48ac09 | ||
|
|
08b4253001 | ||
|
|
1a87c69854 | ||
|
|
861773bf77 | ||
|
|
01e88bda16 | ||
|
|
5e45ac1688 | ||
|
|
10396f9536 | ||
|
|
0c571784a3 | ||
|
|
7646230de2 | ||
|
|
42e72c418d | ||
|
|
37eec13774 | ||
|
|
f28f5f3af4 | ||
|
|
6e357e14fc | ||
|
|
d0d01ffb00 | ||
|
|
916977c5bb | ||
|
|
af8ff8c1ca | ||
|
|
3d2f164dca | ||
|
|
c357e94283 | ||
|
|
7f165aab7f | ||
|
|
956d68c870 | ||
|
|
61ebff6d97 | ||
|
|
0b1397b33b | ||
|
|
a121b9b659 | ||
|
|
43033b65ad | ||
|
|
0c6159650d | ||
|
|
7b562d96b3 | ||
|
|
988ec76cf8 | ||
|
|
87e15d7b82 | ||
|
|
77c1b2a369 | ||
|
|
b0db85bc04 | ||
|
|
cbd90eed74 | ||
|
|
35f0a2e951 | ||
|
|
614c79defc | ||
|
|
fef6f9379a | ||
|
|
fe29344b33 | ||
|
|
2c0f3ef707 | ||
|
|
aebddca35d | ||
|
|
620ee81b7e | ||
|
|
e76a5df932 | ||
|
|
7fb1063ccd | ||
|
|
811288df64 | ||
|
|
31906409c8 | ||
|
|
b05783da32 | ||
|
|
54302f6006 | ||
|
|
2a32262725 | ||
|
|
e35a7fbd89 | ||
|
|
c55311aa6d | ||
|
|
3704745289 | ||
|
|
eae8b63d4f | ||
|
|
349efcb0a6 | ||
|
|
46d697cded | ||
|
|
53e0ff91d3 | ||
|
|
a362a68f53 | ||
|
|
332a50c273 | ||
|
|
790dbb07fc | ||
|
|
f59a69f4b6 | ||
|
|
efcbbc3d74 | ||
|
|
a0503bc3a1 | ||
|
|
82c1a583f8 | ||
|
|
fcfa81283e | ||
|
|
fba5cad820 | ||
|
|
5bdf239a66 | ||
|
|
408a30f0ba | ||
|
|
c8f45eda53 | ||
|
|
2ba18ea4a9 | ||
|
|
a45b272a2f | ||
|
|
5ad0d896f1 | ||
|
|
9efd6a53d2 | ||
|
|
18fdfee274 | ||
|
|
a6ac4dda75 | ||
|
|
29c3763f9c | ||
|
|
c694843da5 | ||
|
|
432faba3e1 | ||
|
|
70e1a5c9b6 | ||
|
|
61c1d100dc | ||
|
|
3508f7dccc | ||
|
|
d4158bdf77 | ||
|
|
1bcf2ffb59 | ||
|
|
87ac185752 | ||
|
|
22fbd774dc | ||
|
|
a87e747049 | ||
|
|
f3bea401e9 | ||
|
|
2ce68e8aec | ||
|
|
bf66861e3f | ||
|
|
131e95ffaf | ||
|
|
ca10b825c7 | ||
|
|
2ed05e548b | ||
|
|
8156c3b0be | ||
|
|
d2a822fe39 | ||
|
|
5298ac3dd9 | ||
|
|
c49371e423 | ||
|
|
76f7ae8d7d | ||
|
|
e312f007b8 | ||
|
|
239bb04b18 | ||
|
|
4d2bee2e23 | ||
|
|
a24058d660 | ||
|
|
70d9bc6233 | ||
|
|
5fa86c2b42 | ||
|
|
a8586cbce7 | ||
|
|
acc3423c96 | ||
|
|
ceddfa340d | ||
|
|
8675b74bf4 | ||
|
|
b4a3ab4082 | ||
|
|
0b4b3d63da | ||
|
|
774f8a073a | ||
|
|
6b46161f2d | ||
|
|
08a212ccae | ||
|
|
64a9f33ffa | ||
|
|
bc0f4fa509 | ||
|
|
681c1d12b5 | ||
|
|
ce156b578f | ||
|
|
4e32b9fea9 | ||
|
|
fb631fa4eb | ||
|
|
ac305b82a4 | ||
|
|
5a56996eef | ||
|
|
af7b9b8b62 | ||
|
|
554d4f6b95 | ||
|
|
80a30dfe6f | ||
|
|
cab74eddef | ||
|
|
42590e062f | ||
|
|
3fdefd3e40 | ||
|
|
192fa18195 | ||
|
|
60a7cc9d7c | ||
|
|
e27f4a91b9 | ||
|
|
ca1bb50c24 | ||
|
|
8d136297c4 | ||
|
|
2c400eff94 | ||
|
|
5d9c298e9d | ||
|
|
689a7197a0 | ||
|
|
413bb19543 | ||
|
|
db337babbc | ||
|
|
46861e6bd8 | ||
|
|
84f5ca951c | ||
|
|
1c97cf5c83 | ||
|
|
9a7f5c6b16 | ||
|
|
b5200cf753 | ||
|
|
686ac847aa | ||
|
|
e075442345 | ||
|
|
c7258f22d8 | ||
|
|
304b0ec202 | ||
|
|
52238dd6a7 | ||
|
|
66e39884e2 | ||
|
|
d548bf4742 | ||
|
|
1675ca3378 | ||
|
|
77459dc27d | ||
|
|
ffd3e43ad8 | ||
|
|
95bc6eb7b2 | ||
|
|
06c81b67c2 | ||
|
|
c3f109556a | ||
|
|
f481938cc5 | ||
|
|
4b15eefd3c | ||
|
|
b9df8b5817 | ||
|
|
ac52639b77 | ||
|
|
a51954203e | ||
|
|
021066a980 | ||
|
|
a1cac18ac3 | ||
|
|
2a3b84b888 | ||
|
|
f703b686da | ||
|
|
682eedb167 | ||
|
|
3511b1de80 | ||
|
|
2f85113366 | ||
|
|
b23443630c | ||
|
|
7585fa0fe9 | ||
|
|
1ba2139d5c | ||
|
|
f67403ba01 | ||
|
|
996e842149 | ||
|
|
c2bb947c14 | ||
|
|
d4fc74e43c | ||
|
|
a1dd26d2d6 | ||
|
|
503976fc6a | ||
|
|
dab1523df5 | ||
|
|
a65c2c9b18 | ||
|
|
5331930716 | ||
|
|
96c7b12bc4 | ||
|
|
5dd5f51700 | ||
|
|
df7abc5447 | ||
|
|
db7370d242 | ||
|
|
a8e9fc86eb | ||
|
|
a402c4db3b | ||
|
|
780af2653a | ||
|
|
9372111aaa | ||
|
|
9fda9f5c28 | ||
|
|
80135cdc17 | ||
|
|
6aa874a0a0 | ||
|
|
d1dac25379 | ||
|
|
526e7ac972 | ||
|
|
fa7bae1210 | ||
|
|
d60f0a1a10 | ||
|
|
78230efd01 | ||
|
|
8411a8e8b4 | ||
|
|
295106b6a8 | ||
|
|
29381bf9d6 | ||
|
|
5a5cf15430 | ||
|
|
884a2de437 | ||
|
|
5349c79d12 | ||
|
|
9ee627fe02 | ||
|
|
1def19ecea | ||
|
|
dc857372ed | ||
|
|
730fc8fc33 | ||
|
|
fafe281d31 | ||
|
|
f98b47eb55 | ||
|
|
e3e64317e8 | ||
|
|
f2c8017df4 | ||
|
|
bf9036d27a | ||
|
|
87da822c7f | ||
|
|
47a57bced1 | ||
|
|
1dc04372df | ||
|
|
27153ae92b | ||
|
|
28d7f83c87 | ||
|
|
c1052e2df2 | ||
|
|
c9121d025f | ||
|
|
0e2a3979f4 | ||
|
|
186ea0e203 | ||
|
|
f47d9eba94 | ||
|
|
7368452e49 | ||
|
|
635ef3bbf8 | ||
|
|
b46fd9a2b4 | ||
|
|
a62e781248 | ||
|
|
32ef9c2135 | ||
|
|
f2d6449374 | ||
|
|
7b532f0b44 | ||
|
|
af96cba0cc | ||
|
|
a684cadbb6 | ||
|
|
6c85ca9661 | ||
|
|
de60b7b2de | ||
|
|
d8c9236a18 | ||
|
|
2bb7007fcb | ||
|
|
4c7d798307 | ||
|
|
3cb730bcfe | ||
|
|
1b0a32d71c | ||
|
|
915ec6531a | ||
|
|
1df7433e44 | ||
|
|
0bd396011a | ||
|
|
6405b58a98 | ||
|
|
9d977dba8e | ||
|
|
ad7a108d60 | ||
|
|
fca6aeeea2 | ||
|
|
5b8ff14caf | ||
|
|
a438c2f184 | ||
|
|
66cb5b33ad | ||
|
|
c28c443d8f | ||
|
|
93358ac3de | ||
|
|
0667aee3cc | ||
|
|
2297508f13 | ||
|
|
1a04bbb044 | ||
|
|
cf31f05cfb | ||
|
|
2b290e7abb | ||
|
|
a324a7f13f | ||
|
|
eb4097180b | ||
|
|
8d7e1faebf | ||
|
|
c0311206c8 | ||
|
|
4b2f537795 | ||
|
|
4d49f543dd | ||
|
|
d400af51fa | ||
|
|
c8d2175981 | ||
|
|
11c7543c76 | ||
|
|
29d4533047 | ||
|
|
c813e692a2 | ||
|
|
65e32d850c | ||
|
|
9f2ce12b28 | ||
|
|
f4860274be | ||
|
|
6b17118e72 | ||
|
|
54a0762bbb | ||
|
|
1e3f19ad89 | ||
|
|
5b73a0492d | ||
|
|
9fa519c983 | ||
|
|
c71e7861ed | ||
|
|
f3df48ab4f | ||
|
|
5df1f2f683 | ||
|
|
0833bc3cc0 | ||
|
|
b18d46e68d | ||
|
|
d1f92a2225 | ||
|
|
a279244709 | ||
|
|
b12db09e31 | ||
|
|
4d6385633f | ||
|
|
8c060833c8 | ||
|
|
70c9eeff05 | ||
|
|
f91b828708 | ||
|
|
828e9d095e | ||
|
|
bab84a13ff | ||
|
|
49f0d8b680 | ||
|
|
4976708c00 | ||
|
|
761cdf5dfc | ||
|
|
2fb1dbfcd1 | ||
|
|
8b3029e430 | ||
|
|
f8aef607ae | ||
|
|
bbae92e76f | ||
|
|
c89eb6d7eb | ||
|
|
70cf08329b | ||
|
|
a7b3bcb43c | ||
|
|
18b7c8d188 | ||
|
|
f34a638b38 | ||
|
|
e48fb58753 | ||
|
|
18fc4505d3 | ||
|
|
ee4e367ea8 | ||
|
|
7034a913fd | ||
|
|
e3ebd2c736 | ||
|
|
25d67da1da | ||
|
|
7e17182e4c | ||
|
|
7e0008a2d7 | ||
|
|
a21809cdae | ||
|
|
3dcaaf87e7 | ||
|
|
f3c7ca59c5 | ||
|
|
ba98ffe152 | ||
|
|
abddd42aa0 | ||
|
|
118303b9da | ||
|
|
f74d7a9fd0 | ||
|
|
12a9942732 | ||
|
|
a109ff1d85 | ||
|
|
3766b78eba | ||
|
|
614e95af39 | ||
|
|
05e4cf9aae | ||
|
|
d2c11f8bee | ||
|
|
c04189bfb6 | ||
|
|
6c5e97e745 | ||
|
|
687ae4f4a8 | ||
|
|
87b56b19fb | ||
|
|
190a6e7687 | ||
|
|
046fe0cfe0 | ||
|
|
81e1dbc90e | ||
|
|
281721cd15 | ||
|
|
0fcae007a0 | ||
|
|
6b3266f228 | ||
|
|
ce4152c817 | ||
|
|
73877b22c4 | ||
|
|
bf3e8f290c | ||
|
|
81a4edb776 | ||
|
|
399f453b4d | ||
|
|
8e6c4b2e07 | ||
|
|
4507bd32af | ||
|
|
e9a14b2409 | ||
|
|
cd6a300222 | ||
|
|
978b3ef881 | ||
|
|
da693710f6 | ||
|
|
71656e3cba | ||
|
|
72d75d50d9 | ||
|
|
cdf963b2b3 | ||
|
|
6598f82111 | ||
|
|
de11907053 | ||
|
|
8075d27e32 | ||
|
|
7109072b8f | ||
|
|
cf4aea18b4 | ||
|
|
7bbaec8fed | ||
|
|
68b7aad535 | ||
|
|
f86b2704d5 | ||
|
|
c59126a817 | ||
|
|
b4899946ef | ||
|
|
76ea48bb64 | ||
|
|
0802405344 | ||
|
|
0c7df2f9a0 | ||
|
|
77f81fa0b6 | ||
|
|
8851893412 | ||
|
|
aa2fee4969 | ||
|
|
d7b55ce2bb | ||
|
|
38a50366bc | ||
|
|
307f703b99 | ||
|
|
306f19b805 | ||
|
|
421085672b | ||
|
|
b6dc6082ab | ||
|
|
a3be8ff055 | ||
|
|
c9119dc6bb | ||
|
|
cfeacc4d67 | ||
|
|
7cc0389757 | ||
|
|
2bdcb9c33d | ||
|
|
7ae6b8fc34 | ||
|
|
82779cd336 | ||
|
|
82ed690817 | ||
|
|
130553a578 | ||
|
|
1355d5d3eb | ||
|
|
fa33bb9d0e | ||
|
|
0ebc407246 | ||
|
|
2c950c5cb5 | ||
|
|
2722e6bb68 | ||
|
|
ce4e0b78bc | ||
|
|
5d1795062f | ||
|
|
b6cc69cd8f | ||
|
|
10e78fbd8e | ||
|
|
e3e99974f8 | ||
|
|
e069125a2c | ||
|
|
0528803da6 | ||
|
|
e5e00ce9d6 | ||
|
|
69b276a712 | ||
|
|
5c04fe9b61 | ||
|
|
9c050c54ef | ||
|
|
3a07026740 | ||
|
|
538db04950 | ||
|
|
e2b778a38e | ||
|
|
85bc9c1d1a | ||
|
|
501ae11f51 | ||
|
|
eb6cb5311b | ||
|
|
e3a5f66059 | ||
|
|
fd4b6cc52a | ||
|
|
93ccc35ff0 | ||
|
|
ccc49e8841 | ||
|
|
7fc596fb8a | ||
|
|
b0fe7d3a0b | ||
|
|
6461841ccd | ||
|
|
75e65f72c2 | ||
|
|
2cba7fdfcd | ||
|
|
9ddc88dd9d | ||
|
|
bc8456425d | ||
|
|
7eab6d9958 | ||
|
|
2bf3f0c03c | ||
|
|
9eea2344fc | ||
|
|
538600ef48 | ||
|
|
2ebd2a08ff | ||
|
|
6713942f83 | ||
|
|
c6f5ce280f | ||
|
|
9aad7a3783 | ||
|
|
a22551d56b | ||
|
|
d6f96fa07e | ||
|
|
5a0715fd6c | ||
|
|
717110d355 | ||
|
|
d5c6257ac2 | ||
|
|
88fce52fbf | ||
|
|
8f3ee46325 | ||
|
|
aa035f9853 | ||
|
|
b2f5629de8 | ||
|
|
db98798134 | ||
|
|
d4227e75cd | ||
|
|
e6c015e0d0 | ||
|
|
44db9db053 | ||
|
|
4c2ed7b52e | ||
|
|
6f571dbfc6 | ||
|
|
a363e1c51f | ||
|
|
b684ea837d | ||
|
|
d4eced9b84 | ||
|
|
a674a2e6fd | ||
|
|
276e406c0f | ||
|
|
7ac0323c7b | ||
|
|
95c78ce92b | ||
|
|
21c692d23f | ||
|
|
5b194e290c | ||
|
|
22fb4fe019 | ||
|
|
62c8e79676 | ||
|
|
e4e3bd5175 | ||
|
|
eb18ee624f | ||
|
|
6298ca94cb | ||
|
|
7c9270d7a5 | ||
|
|
5f9226b14b | ||
|
|
9320075030 | ||
|
|
ca032792bd | ||
|
|
abb95d5aab | ||
|
|
dcd480ffd9 | ||
|
|
68cdac68cb | ||
|
|
e1307ea789 | ||
|
|
52fe9f62f6 | ||
|
|
f42160862a | ||
|
|
1b631c42ef | ||
|
|
0afd6a8312 | ||
|
|
4ac21ca652 | ||
|
|
dbbae8dcd3 | ||
|
|
eed5fc7179 | ||
|
|
b8c5483b85 | ||
|
|
4f12c31e3b | ||
|
|
53543b9b6a | ||
|
|
afafd0f683 | ||
|
|
d65354efcf | ||
|
|
d3abd86df5 | ||
|
|
838f39d0fd | ||
|
|
4589ba350f | ||
|
|
92143eb7b9 | ||
|
|
c9679b7954 | ||
|
|
5fc99a117b | ||
|
|
87ba782106 | ||
|
|
dd8a09ce8d | ||
|
|
ba7dde0168 | ||
|
|
3a03794bb6 | ||
|
|
fe753e24a3 | ||
|
|
42a4604461 | ||
|
|
a70898fc28 | ||
|
|
186eef69dc | ||
|
|
c3a380ade8 | ||
|
|
936bd6a191 | ||
|
|
73d36f5ece | ||
|
|
00431d772e | ||
|
|
a22c7e731a | ||
|
|
398cf8ee6f | ||
|
|
e50ff5c7b5 | ||
|
|
906e8c0001 | ||
|
|
2fa4cedb1e | ||
|
|
47210d9a1a | ||
|
|
d1881d1b56 | ||
|
|
6713a2ce67 | ||
|
|
f626317e90 | ||
|
|
56327f6298 | ||
|
|
7d05c4a2b0 | ||
|
|
232bcafd7c | ||
|
|
c82cfebd5e | ||
|
|
07a6bcaa77 | ||
|
|
fe0e4f635e | ||
|
|
815ffb7d3e | ||
|
|
7f8c48834f | ||
|
|
0a6ce91369 | ||
|
|
71dda8b648 | ||
|
|
2296db3db6 | ||
|
|
1e798b640d | ||
|
|
e91899c0da | ||
|
|
6099bda088 | ||
|
|
43e4d608ae | ||
|
|
ef32209fd7 | ||
|
|
55b2e44814 | ||
|
|
6bb86709ee | ||
|
|
ce6dca81bc | ||
|
|
d7ffaf94b1 | ||
|
|
c573f432fe | ||
|
|
7cb33ba636 | ||
|
|
182731d6eb | ||
|
|
f79fd32208 | ||
|
|
b3c68f1692 | ||
|
|
ef1a2a82dd | ||
|
|
269d4c55dd | ||
|
|
91c8e1bf0d | ||
|
|
c8626c09af | ||
|
|
cac7d1a495 | ||
|
|
3cbda4157b | ||
|
|
46ce06791a | ||
|
|
462e8a3d90 | ||
|
|
cd9e4d1b2b | ||
|
|
e31af5f255 | ||
|
|
a0dae7557c | ||
|
|
836bf643b0 | ||
|
|
f9e4c7ca02 | ||
|
|
a31782497c | ||
|
|
47f937ac13 | ||
|
|
be8d08fda6 | ||
|
|
7dea133b55 | ||
|
|
63f0e5e2c0 | ||
|
|
fdb577e0a0 | ||
|
|
45544f42b9 | ||
|
|
0452fa2458 | ||
|
|
2b92b0f305 | ||
|
|
e43c3aed67 | ||
|
|
6aa98c17bd | ||
|
|
a9f1ce0db1 | ||
|
|
d48973bbc8 | ||
|
|
3879f07fa8 | ||
|
|
3ea7f76c17 | ||
|
|
827f8882bc | ||
|
|
24a7015f64 | ||
|
|
2a267ca05f | ||
|
|
e41460cae5 | ||
|
|
5e2b49dad4 | ||
|
|
5038f6687b | ||
|
|
8b98a2e829 | ||
|
|
46466a8fcc | ||
|
|
4e0d734598 | ||
|
|
8cfe8db1fb | ||
|
|
5ae74603da | ||
|
|
747664ad4f | ||
|
|
9e31065b5e | ||
|
|
004fb5f9c2 | ||
|
|
da62edb4e0 | ||
|
|
adc4729ffa | ||
|
|
64d0313c5b | ||
|
|
94b414861d | ||
|
|
9305161183 | ||
|
|
297fa24b90 | ||
|
|
3ca3362283 | ||
|
|
4f38c8d201 | ||
|
|
964f68630a | ||
|
|
caed1add3a | ||
|
|
77020623ed | ||
|
|
d264017684 | ||
|
|
383ea561f8 | ||
|
|
ef5e803875 | ||
|
|
22de221c21 | ||
|
|
6f88bcf581 | ||
|
|
6ce26e12f5 | ||
|
|
09869159f7 | ||
|
|
14839257ac | ||
|
|
f16c6bd7dd | ||
|
|
a24aff2148 | ||
|
|
fc6d8e933b | ||
|
|
c6364944d4 | ||
|
|
70ef747a56 | ||
|
|
3d7aa44c8e | ||
|
|
c249832df1 | ||
|
|
3169455653 | ||
|
|
f7122499a6 | ||
|
|
cc7ac94641 | ||
|
|
7f9dfde0dc | ||
|
|
2533c87bd6 | ||
|
|
6fef9f5178 | ||
|
|
f9ac07f455 | ||
|
|
175e361a4d | ||
|
|
53bedaa4c1 | ||
|
|
1ebf7842f5 | ||
|
|
f14452ec3c | ||
|
|
78c0edb7c1 | ||
|
|
f2b4efff20 | ||
|
|
11003f5842 | ||
|
|
c638c3cc3d | ||
|
|
a2982f0d4e | ||
|
|
639b2bd8e5 | ||
|
|
7069324a20 | ||
|
|
9d331bb32b | ||
|
|
bc0657d13c | ||
|
|
712ed48a62 | ||
|
|
66afec21d1 | ||
|
|
b94825bbad | ||
|
|
06d2a32a3e | ||
|
|
623d9e2ab3 | ||
|
|
cb8d416b37 | ||
|
|
de9bee0354 | ||
|
|
ae75a8c0c1 | ||
|
|
8098f63998 |
47
.gitignore
vendored
Normal file
47
.gitignore
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
*~
|
||||
lib*.a
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.gmo
|
||||
.deps
|
||||
.libs
|
||||
|
||||
*.patch
|
||||
*.rej
|
||||
*.orig
|
||||
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
/ABOUT-NLS
|
||||
/aclocal.m4
|
||||
/autom4te.cache
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.log
|
||||
/config.rpath
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/m4
|
||||
/missing
|
||||
/stamp-h1
|
||||
/ylwrap
|
||||
|
||||
/po/*.header
|
||||
/po/*.sed
|
||||
/po/*.sin
|
||||
/po/Makefile.in.in
|
||||
/po/Makevars.template
|
||||
/po/POTFILES
|
||||
/po/Rules-quot
|
||||
/po/stamp-po
|
||||
|
||||
/shadow.spec
|
||||
/libmisc/getdate.c
|
||||
244
NEWS
244
NEWS
@@ -1,5 +1,249 @@
|
||||
$Id$
|
||||
|
||||
shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24
|
||||
|
||||
- general
|
||||
* Improved support for large groups (impacts most user/group management
|
||||
tools).
|
||||
|
||||
- addition of system users or groups
|
||||
* Speed improvement. This should be noticeable in case of LDAP configured
|
||||
systems. This should impact useradd, groupadd, and newusers
|
||||
* Since system accounts are allocated from SYS_?ID_MIN to SYS_?ID_MAX in
|
||||
reverse order, accounts are packed close to SYS_?ID_MAX if SYS_?ID_MIN
|
||||
is already used but there are still dome gaps.
|
||||
|
||||
- login
|
||||
* Add support for shells being a shell script without a shebang.
|
||||
- su
|
||||
* Preserve the DISPLAY and XAUTHORITY environment variables. This was
|
||||
only the case in the non PAM enabled versions.
|
||||
* Add support for shells being a shell script without a shebang.
|
||||
|
||||
*** translation
|
||||
* The Finnish translation of passwd(1) was outdated and is no more
|
||||
distributed.
|
||||
|
||||
shadow-4.1.4 -> shadow-4.1.4.1 2009-05-22
|
||||
|
||||
- login
|
||||
* Fix failures with empty usernames on non PAM versions.
|
||||
* Fix CONSOLE (securetty) support on non PAM versions.
|
||||
- newgrp
|
||||
* Return the exit status of the child.
|
||||
- userdel
|
||||
* On Linux, do not check if an user is logged in with utmp, but check if
|
||||
the user is running some processes.
|
||||
* If not on Linux, continue to search for an utmp record, but make sure
|
||||
the process recorded in the utmp entry is still running.
|
||||
* Report failures to remove the user's mailbox
|
||||
* When USERGROUPS_ENAB is enabled, remove the user's group when the
|
||||
user was the only member.
|
||||
* Do not fail when -r is used and the home directory does not exist.
|
||||
- usermod
|
||||
* Check if the user is busy when the user's UID, name or home directory
|
||||
is changed.
|
||||
|
||||
shadow-4.1.3.1 -> shadow-4.1.4 2009-05-10
|
||||
|
||||
- packaging
|
||||
* Enable --enable-account-tools-setuid by default for PAM builds.
|
||||
* Add configure option --enable-utmpx, disabled by default to mimic
|
||||
the previous behavior on Linux (where utmp and utmpx are identical).
|
||||
* Fix build failure on non-PAM systems when --without-pam is not
|
||||
specified.
|
||||
|
||||
- chpasswd
|
||||
* Change the passwords using PAM. This permits to define the password
|
||||
policy in a central place. The -c/--crypt-method, -e/--encrypted,
|
||||
-m/--md5 and -s/--sha-rounds options are no more supported on PAM
|
||||
enabled systems.
|
||||
- grpck
|
||||
* Warn if a group has an entry in group and gshadow, and the password
|
||||
field in group is not 'x'.
|
||||
- login
|
||||
* Do not trust the current utmp entry's ut_line to set PAM_TTY. This could
|
||||
lead to DOS attacks.
|
||||
* (PAM) Even if the user was already authenticated (-f flag), ask the
|
||||
user to update his authentication token if needed.
|
||||
- lastlog
|
||||
* Fix regression causing empty reports.
|
||||
- newusers
|
||||
* Change the passwords using PAM. This permits to define the password
|
||||
policy in a central place. The -c/--crypt-method and -s/--sha-rounds
|
||||
options are no more supported on PAM enabled systems.
|
||||
- pwck
|
||||
* Warn if an user has an entry in passwd and shadow, and the password
|
||||
field in passwd is not 'x'.
|
||||
|
||||
*** translation
|
||||
- Updated Czech translation
|
||||
- Updated French translation
|
||||
- Updated German translation
|
||||
- Updated Japanese translation
|
||||
- Updated Korean translation
|
||||
- Updated Portuguese translation
|
||||
- Updated Russian translation
|
||||
|
||||
shadow-4.1.3 -> shadow-4.1.3.1 2009-04-15
|
||||
|
||||
*** security:
|
||||
- Due to bad parsing of octal permissions, the permissions on tty (login)
|
||||
but also UMASK were set wrongly (and weirdly). Only shadow-4.1.3 was
|
||||
affected.
|
||||
|
||||
*** general
|
||||
- login
|
||||
* Fix regression when no user is specified on the command line.
|
||||
- userdel
|
||||
* Fixed SE Linux support
|
||||
- vipw
|
||||
* SE Linux: Set the default context to the context of the file being
|
||||
edited. This ensures that the backup file inherit from the file's
|
||||
context.
|
||||
|
||||
*** translation
|
||||
- Updated Norwegian Bokmål translation
|
||||
|
||||
shadow-4.1.2.2 -> shadow-4.1.3 2009-04-12
|
||||
|
||||
*** general:
|
||||
- packaging
|
||||
* Fixed support for OpenPAM.
|
||||
* Fixed support for uclibc.
|
||||
* Added configure --enable-account-tools-setuid (default) /
|
||||
--disable-account-tools-setuid options. This permits to disable the
|
||||
PAM authentication of the caller for chage, chgpasswd, chpasswd,
|
||||
groupadd, groupdel, groupmod, newusers, useradd, userdel, and usermod.
|
||||
This authentication is not necessary when these tools are not
|
||||
installed setuid root.
|
||||
* Added configure --with-group-name-max-length (default) /
|
||||
--without-group-name-max-length options. This permits to configure the maximum length allowed for group names:
|
||||
<no option> -> default of 16 (like today)
|
||||
--with-group-name-max-length -> default of 16
|
||||
--without-group-name-max-length -> no max length
|
||||
--with-group-name-max-length=n > max is set to n
|
||||
No sanity checking is performed on n so people could do
|
||||
something neat like --with-group-name-max-length=MAX_INT
|
||||
- addition of users or groups
|
||||
* Speed improvement in case UID_MAX/SYS_UID_MAX/GID_MAX/SYS_GID_MAX is
|
||||
used for an user/group. This should be noticeable in case of LDAP
|
||||
configured systems. This should impact useradd, groupadd, and newusers
|
||||
- error handling improvement
|
||||
* Make sure errors and incomplete changes are reported to syslog and
|
||||
audit in case of unexpected failures.
|
||||
* Report system inconsistencies to syslog and audit.
|
||||
* Only report success to syslog and audit if the changes are really
|
||||
performed in the system databases.
|
||||
This is still not complete.
|
||||
- /etc/login.defs
|
||||
* New CREATE_HOME variable to tell useradd to create a home directory by
|
||||
default.
|
||||
- Translations
|
||||
* New Kazakh translation.
|
||||
* Spanish manpages are no more distributed. They are outdated. Please
|
||||
contact pkg-shadow-devel@lists.alioth.debian.org if you wish to
|
||||
provide updates.
|
||||
|
||||
- faillog
|
||||
* Accept users specified as a numerical UID, or ranges of users (-user,
|
||||
user-, user1-user2).
|
||||
* -l, -m, and -r now apply not only to existing users, but to all the
|
||||
specified UIDs.
|
||||
* Options can be specified in any order.
|
||||
- gpasswd
|
||||
* Added support for long options --add (-a), --delete (-d),
|
||||
--remove-password (-r), --restrict (-R), --administrators (-A), and
|
||||
--members (-M).
|
||||
* Added support for usernames with arbitrary length.
|
||||
* audit logging improvements.
|
||||
* error handling improvement (see above).
|
||||
* Log permission denied to syslog and audit.
|
||||
- groupadd
|
||||
* audit logging improvements.
|
||||
* error handling improvement (see above).
|
||||
* Speedup (see "addition of users or groups" above).
|
||||
* do not create groups with GID set to (gid_t)-1.
|
||||
* Allocate system group GIDs in reverse order. This could be useful
|
||||
later to increase the static IDs range.
|
||||
- groupdel
|
||||
* audit logging improvements.
|
||||
* error handling improvement (see above).
|
||||
- groupmems
|
||||
* Check if user exist before they are added to groups.
|
||||
* Avoid segfault in case the specified group does not exist in /etc/group.
|
||||
* Everybody is allowed to list the users of a group.
|
||||
* /etc/group is open readonly when one just wants to list the users of a
|
||||
group.
|
||||
* Added syslog support.
|
||||
* Use the groupmems PAM service name instead of groupmod.
|
||||
* Fix segmentation faults when adding or removing users from a group.
|
||||
* Added support for shadow groups.
|
||||
* Added support long options --add (-a), --delete (-d), --purge (-p),
|
||||
--list (-l), --group (-g).
|
||||
- groupmod
|
||||
* audit logging improvements.
|
||||
* error handling improvement (see above).
|
||||
* do not create groups with GID set to (gid_t)-1.
|
||||
- grpck
|
||||
* warn for groups with GID set to (gid_t)-1.
|
||||
- login
|
||||
* Restore the echoctl, echoke, onclr flags to the terminal termio flags.
|
||||
Reset echoprt, noflsh, tostop. This behavior seems to have change by
|
||||
mistake in earlier releases (4.0.8, for no obvious reason).
|
||||
- newusers
|
||||
* Implement the -r, --system option.
|
||||
* Speedup (see "addition of users or groups" above).
|
||||
* do not create users with UID set to (gid_t)-1.
|
||||
* do not create groups with GID set to (gid_t)-1.
|
||||
* Allocate system account UIDs/GIDs in reverse order. This could be useful
|
||||
later to increase the static IDs range.
|
||||
- passwd
|
||||
* For compatibility with other passwd version, the --lock an --unlock
|
||||
options do not lock or unlock the user account anymore. They only
|
||||
lock or unlock the user's password.
|
||||
- pwck
|
||||
* warn for users with UID set to (uid_t)-1.
|
||||
- su
|
||||
* Preserve COLORTERM in addition to TERM when su is called with the -l
|
||||
option.
|
||||
- useradd
|
||||
* audit logging improvements.
|
||||
* Speedup (see "addition of users or groups" above).
|
||||
* See CREATE_HOME above.
|
||||
* New -M/--no-create-home option to disable CREATE_HOME.
|
||||
* do not create users with UID set to (gid_t)-1.
|
||||
* Added -Z option to map SELinux user for user's login.
|
||||
* Allocate system user UIDs in reverse order. This could be useful
|
||||
later to increase the static IDs range.
|
||||
- userdel
|
||||
* audit logging improvements.
|
||||
* Do not fail if the removed user is not in the shadow database.
|
||||
* When the user's group shall be removed, do not fail if this group is
|
||||
not in the gshadow file.
|
||||
* Delete the SELinux user mapping for user's login.
|
||||
- usermod
|
||||
* Allow adding LDAP users (or any user not present in the local passwd
|
||||
file) to local groups
|
||||
* do not create users with UID set to (gid_t)-1.
|
||||
* Added -Z option to map SELinux user for user's login.
|
||||
|
||||
shadow-4.1.2.1 -> shadow-4.1.2.2 23-11-2008
|
||||
|
||||
*** security
|
||||
- Fix a race condition in login that could lead to gaining ownership or
|
||||
changing mode of arbitrary files.
|
||||
- Fix a possible login DOS, which could be caused by injecting forged
|
||||
entries in utmp.
|
||||
|
||||
shadow-4.1.2 -> shadow-4.1.2.1 26-06-2008
|
||||
|
||||
*** security
|
||||
- Fix an "audit log injection" vulnerability in login.
|
||||
This vulnerability makes it easier for attackers to hide activities by
|
||||
modifying portions of log events, e.g. by appending an addr= statement
|
||||
to the login name.
|
||||
|
||||
shadow-4.1.1 -> shadow-4.1.2 25-05-2008
|
||||
|
||||
*** security:
|
||||
|
||||
17
README
17
README
@@ -1,14 +1,19 @@
|
||||
Shadow SITES
|
||||
============
|
||||
|
||||
Homepage
|
||||
http://pkg-shadow.alioth.debian.org/
|
||||
|
||||
FTP site
|
||||
ftp://pkg-shadow.alioth.debian.org/pub/pkg-shadow
|
||||
|
||||
SVN repository
|
||||
anonymous read only access: svn://svn.debian.org/pkg-shadow/
|
||||
anonymous read only access: svn://svn.debian.org/pkg-shadow/upstream
|
||||
|
||||
SVN web interface
|
||||
http://svn.debian.org/wsvn/pkg-shadow
|
||||
http://svn.debian.org/wsvn/pkg-shadow/upstream
|
||||
or
|
||||
http://svn.debian.org/viewsvn/pkg-shadow/upstream
|
||||
|
||||
Mailing lists
|
||||
for general discuss: pkg-shadow-devel@lists.alioth.debian.org
|
||||
@@ -51,6 +56,7 @@ Calle Karlsson <ckn@kash.se>
|
||||
Chip Rosenthal <chip@unicom.com>
|
||||
Chris Evans <lady0110@sable.ox.ac.uk>
|
||||
Cristian Gafton <gafton@sorosis.ro>
|
||||
Dan Walsh <dwalsh@redhat.com>
|
||||
Darcy Boese <possum@chardonnay.niagara.com>
|
||||
Dave Hagewood <admin@arrowweb.com>
|
||||
David A. Holland <dholland@hcs.harvard.edu>
|
||||
@@ -77,12 +83,14 @@ Juha Virtanen <jiivee@iki.fi>
|
||||
Julianne Frances Haugh <jockgrrl@ix.netcom.com>
|
||||
Leonard N. Zubkoff <lnz@dandelion.com>
|
||||
Luca Berra <bluca@www.polimi.it>
|
||||
Lukáš Kuklínek <lkukline@redhat.com>
|
||||
Lutz Schwalowsky <schwalow@mineralogie.uni-hamburg.de>
|
||||
Marc Ewing <marc@redhat.com>
|
||||
Martin Bene <mb@sime.com>
|
||||
Martin Mares <mj@gts.cz>
|
||||
Michael Meskes <meskes@topsystem.de>
|
||||
Michael Talbot-Wilson <mike@calypso.bns.com.au>
|
||||
Mike Frysinger <vapier@gentoo.org>
|
||||
Mike Pakovic <mpakovic@users.southeast.net>
|
||||
Nicolas François <nicolas.francois@centraliens.net>
|
||||
Nikos Mavroyanopoulos <nmav@i-net.paiko.gr>
|
||||
@@ -91,6 +99,8 @@ Phillip Street
|
||||
Rafał Maszkowski <rzm@icm.edu.pl>
|
||||
Rani Chouha <ranibey@smartec.com>
|
||||
Sami Kerola <kerolasa@rocketmail.com>
|
||||
Sebastian Rick Rijkers <srrijkers@gmail.com>
|
||||
Seraphim Mellos <mellos@ceid.upatras.gr>
|
||||
Shane Watts <shane@nexus.mlckew.edu.au>
|
||||
Steve M. Robbins <steve@nyongwa.montreal.qc.ca>
|
||||
Thorsten Kukuk <kukuk@suse.de>
|
||||
@@ -102,5 +112,6 @@ Werner Fink <werner@suse.de>
|
||||
Maintainers
|
||||
===========
|
||||
|
||||
Tomasz Kłoczko <kloczek@pld.org.pl> (2000-2006)
|
||||
Tomasz Kłoczko <kloczek@pld.org.pl> (2000-2007)
|
||||
Nicolas François <nicolas.francois@centraliens.net> (2007-now)
|
||||
|
||||
|
||||
110
TODO
110
TODO
@@ -1,11 +1,38 @@
|
||||
passwd -l should lock the password, not the account.
|
||||
/etc/default/useradd
|
||||
* GROUP=1000 should accept a group name.
|
||||
|
||||
vipw: Test SHADOWGRP support before using gshadow features.
|
||||
Check when RLOGIN is enabled if ruserok() exists
|
||||
|
||||
PAM: add support for customization of the PAM support (i.e. support the
|
||||
Debian PAM configuration)
|
||||
Move selinux_file_context out of libmisc/copydir.c
|
||||
|
||||
PAM: check if a non-interactive conversation function could be used to
|
||||
Review hardcoded root account?
|
||||
|
||||
review all call to strto
|
||||
|
||||
libmisc/cleanup_user.c
|
||||
cleanup needed (cleanup_report_add_user* not used)
|
||||
|
||||
|
||||
libxcrypt support
|
||||
* http://wiki.linuxfromscratch.org/patches/browser/trunk/shadow/shadow-4.0.18.1-owl_blowfish-1.patch
|
||||
|
||||
implement getlong, getulong.
|
||||
avoid atoi, atol, atoul, strtol, strtoul, ...
|
||||
|
||||
manpages: comment the RLOGIN parts
|
||||
|
||||
Replace build_list (in lib/gshadow.c) and list (in lib/sgetgrent.c) by
|
||||
comma_to_list()
|
||||
|
||||
Revert the modified files if all files could not be changed.
|
||||
* or warn and indicate which files were modified and which were not.
|
||||
* check the order the files are modified.
|
||||
|
||||
report nscd_flush_cache failures?
|
||||
call nscd from the programs or from lib (commonio?)
|
||||
|
||||
PAM: check if a non-interactive conversation function could be used to set
|
||||
the password in chpasswd and newusers
|
||||
|
||||
WITH_SELINUX
|
||||
- review all tools to check that the strategies are consistent
|
||||
@@ -13,33 +40,20 @@ WITH_SELINUX
|
||||
chage, chfn, chsh: same change needed as in passwd.
|
||||
- probably need moving check_selinux_access to a separate file.
|
||||
|
||||
man useradd
|
||||
document default behavior for GROUP
|
||||
remove "The default group number is 1 or whatever is..."
|
||||
|
||||
useradd manpage
|
||||
- add -k option
|
||||
- mention that -o require -u
|
||||
|
||||
testsuite
|
||||
- newgrp
|
||||
- test with unknown user's GID
|
||||
|
||||
newusers
|
||||
- add logging to SYSLOG & AUDIT
|
||||
|
||||
faillog
|
||||
- accept numerical user and range of users
|
||||
- use CREATE_HOME
|
||||
- Add a -Z option (see useradd / usermod)
|
||||
|
||||
Document when/where option appeared, document whether an option is standard
|
||||
or not.
|
||||
|
||||
depends rules for the manpages
|
||||
|
||||
Check all the expiry semantics
|
||||
|
||||
Add options --crypt-method and --sha-rounds to gpasswd
|
||||
|
||||
ALL:
|
||||
- move base passwd/shadow/group/gshadow operation to module for allow write
|
||||
different backend modules for db, NIS, LDAP and others. Default backend it
|
||||
@@ -49,38 +63,52 @@ ALL:
|
||||
passwd have old piece of code with handling -r option and it will be good
|
||||
finish this and propagate on other shadow tools for allow operate on other
|
||||
user databases by well known tools.
|
||||
- Protect against signals. Register do_cleanups in a signal handler.
|
||||
|
||||
- login.defs
|
||||
- generate depending on configuration
|
||||
|
||||
- useradd:
|
||||
- add handle create user mail spool in maildir format.
|
||||
|
||||
- add handle -n switch in groups and id command for allow query is
|
||||
group/user with specified id/gid exist - this will be very usable
|
||||
on automation in packages for query/check is group/user exist in system
|
||||
or not,
|
||||
|
||||
- groupmems:
|
||||
- need some work on add PAM and i18n support.
|
||||
- Add support for -k in -D mode
|
||||
- Add support for -K in -D mode
|
||||
- Add option to create or not the mail spool (and set the default in -D
|
||||
mode)
|
||||
- Change -l to reset the entry if an entry was already there
|
||||
- set the mask in mkdir?
|
||||
|
||||
- userdel:
|
||||
- add backup option for the removal of user resources,
|
||||
- add lookop and remove per user group.
|
||||
- user_busy: check that the user is not running any processes.
|
||||
- missing "deleting group" FAILED
|
||||
- home dir removed, but userdel may fail and may leave the user
|
||||
=> warning needed
|
||||
|
||||
- usermod
|
||||
- add an option equivalent to useradd's -l (only when uid is changed)
|
||||
- the mode of new home directories should be set according to the
|
||||
original mode. Does copy_tree does this?
|
||||
- user renamed, order is not kept in /etc/group (see
|
||||
47_usermod-l_no_shadow_file). This is a problem when the first user is
|
||||
considered as the admin.
|
||||
- see mail "user ID change" on April, 15
|
||||
+ fix call to chown (combination of -m and -u/-g)
|
||||
+ add tests
|
||||
|
||||
- passwd:
|
||||
- check combination of options (e.g. -u/-l)
|
||||
- when -u refuse to unlock because it would create an empty password, it
|
||||
should not display "Password changed."
|
||||
exit instead?
|
||||
|
||||
- newgrp: check the USE_PAM section.
|
||||
|
||||
- groupmems: check reason for isgroup
|
||||
- pwck
|
||||
- Add check to move passwd passwords to shadow if there is a shadow
|
||||
entry (with a password).
|
||||
- Add check to move passwd passwords to shadow if there is a shadow
|
||||
file.
|
||||
|
||||
- newusers: doc for pw_gid not clear. Differentiate
|
||||
pw_gid specified and exist
|
||||
pw_gid specified but does not exist
|
||||
* name
|
||||
* number
|
||||
pw_gid not specified.
|
||||
- newusers: document what happens when no uid is specified.
|
||||
- newusers: add option --system?
|
||||
|
||||
-Documentation:
|
||||
* document when options were added.
|
||||
- su
|
||||
- add a login.defs configuration parameter to add variables to keep in
|
||||
the environment with "su -l" (TERM/TERMCOLOR/...
|
||||
|
||||
206
configure.in
206
configure.in
@@ -1,6 +1,6 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT
|
||||
AM_INIT_AUTOMAKE(shadow, 4.1.2)
|
||||
AM_INIT_AUTOMAKE(shadow, 4.1.4.2)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
dnl Some hacks...
|
||||
@@ -28,6 +28,7 @@ dnl Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
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 \
|
||||
utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h paths.h \
|
||||
@@ -37,10 +38,10 @@ AC_CHECK_HEADERS(errno.h fcntl.h limits.h unistd.h sys/time.h utmp.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 getgroups gethostname getspnam \
|
||||
AC_CHECK_FUNCS(l64a fchmod fchown fsync futimes getgroups gethostname getspnam \
|
||||
gettimeofday getusershell getutent initgroups lchown lckpwdf lstat \
|
||||
memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
|
||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r)
|
||||
lutimes memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
|
||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo)
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
@@ -51,41 +52,39 @@ AC_TYPE_PID_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_HEADER_STAT
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
AC_CHECK_MEMBERS([struct stat.st_atim])
|
||||
AC_CHECK_MEMBERS([struct stat.st_atimensec])
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtim])
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtimensec])
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
|
||||
if test "$ac_cv_header_utmp_h" = "yes"; then
|
||||
AC_CACHE_CHECK(for ut_host in struct utmp,
|
||||
ac_cv_struct_utmp_ut_host,
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <utmp.h>],
|
||||
[struct utmp ut; char *cp = ut.ut_host;]
|
||||
)],
|
||||
[ac_cv_struct_utmp_ut_host=yes],
|
||||
[ac_cv_struct_utmp_ut_host=no]
|
||||
)
|
||||
)
|
||||
|
||||
if test "$ac_cv_struct_utmp_ut_host" = "yes"; then
|
||||
AC_DEFINE(UT_HOST, 1, [Define if you have ut_host in struct utmp.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(for ut_user in struct utmp,
|
||||
ac_cv_struct_utmp_ut_user,
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <utmp.h>],
|
||||
[struct utmp ut; char *cp = ut.ut_user;]
|
||||
)],
|
||||
[ac_cv_struct_utmp_ut_user=yes],
|
||||
[ac_cv_struct_utmp_ut_user=no]
|
||||
)
|
||||
)
|
||||
|
||||
if test "$ac_cv_struct_utmp_ut_user" = "no"; then
|
||||
AC_DEFINE(ut_user, ut_name,
|
||||
[Define to ut_name if struct utmp has ut_name (not ut_user).])
|
||||
fi
|
||||
AC_CHECK_MEMBERS([struct utmp.ut_type,
|
||||
struct utmp.ut_id,
|
||||
struct utmp.ut_name,
|
||||
struct utmp.ut_user,
|
||||
struct utmp.ut_host,
|
||||
struct utmp.ut_syslen,
|
||||
struct utmp.ut_addr,
|
||||
struct utmp.ut_addr_v6,
|
||||
struct utmp.ut_time,
|
||||
struct utmp.ut_xtime,
|
||||
struct utmp.ut_tv],,,[[#include <utmp.h>]])
|
||||
dnl There are dependencies:
|
||||
dnl If UTMPX has to be used, the utmp structure shall have a ut_id field.
|
||||
if test "$ac_cv_header_utmpx_h" = "yes" &&
|
||||
test "$ac_cv_member_struct_utmp_ut_id" != "yes"; then
|
||||
AC_MSG_ERROR(Systems with UTMPX and no ut_id field in the utmp structure are not supported)
|
||||
fi
|
||||
|
||||
AC_CHECK_MEMBERS([struct utmpx.ut_name,
|
||||
struct utmpx.ut_host,
|
||||
struct utmpx.ut_syslen,
|
||||
struct utmpx.ut_addr,
|
||||
struct utmpx.ut_addr_v6,
|
||||
struct utmpx.ut_time,
|
||||
struct utmpx.ut_xtime],,,[[#include <utmpx.h>]])
|
||||
|
||||
if test "$ac_cv_header_lastlog_h" = "yes"; then
|
||||
AC_CACHE_CHECK(for ll_host in struct lastlog,
|
||||
ac_cv_struct_lastlog_ll_host,
|
||||
@@ -212,8 +211,31 @@ AC_ARG_ENABLE(shadowgrp,
|
||||
AC_ARG_ENABLE(man,
|
||||
[AC_HELP_STRING([--enable-man],
|
||||
[regenerate roff man pages from Docbook @<:@default=no@:>@])],
|
||||
[enable_man=yes],
|
||||
[enable_man=no]
|
||||
[enable_man="${enableval}"],
|
||||
[enable_man="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(account-tools-setuid,
|
||||
[AC_HELP_STRING([--enable-account-tools-setuid],
|
||||
[Install the user and group management tools setuid and authenticate the callers. This requires --with-pam.])],
|
||||
[case "${enableval}" in
|
||||
yes) enable_acct_tools_setuid="yes" ;;
|
||||
no) enable_acct_tools_setuid="no" ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-account-tools-setuid)
|
||||
;;
|
||||
esac],
|
||||
[enable_acct_tools_setuid="maybe"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(utmpx,
|
||||
[AC_HELP_STRING([--enable-utmpx],
|
||||
[enable loggin in utmpx / wtmpx @<:@default=no@:>@])],
|
||||
[case "${enableval}" in
|
||||
yes) enable_utmpx="yes" ;;
|
||||
no) enable_utmpx="no" ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-utmpx) ;;
|
||||
esac],
|
||||
[enable_utmpx="no"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(audit,
|
||||
@@ -234,10 +256,31 @@ 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(nscd,
|
||||
[AC_HELP_STRING([--with-nscd], [enable support for nscd @<:@default=yes@:>@])],
|
||||
[with_nscd=$withval], [with_nscd=yes])
|
||||
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])
|
||||
|
||||
if test "$with_group_name_max_length" = "no" ; then
|
||||
with_group_name_max_length=0
|
||||
elif test "$with_group_name_max_length" = "yes" ; then
|
||||
with_group_name_max_length=16
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(GROUP_NAME_MAX_LENGTH, $with_group_name_max_length, [max group name length])
|
||||
AC_SUBST(GROUP_NAME_MAX_LENGTH)
|
||||
GROUP_NAME_MAX_LENGTH="$with_group_name_max_length"
|
||||
|
||||
AM_CONDITIONAL(USE_SHA_CRYPT, test "x$with_sha_crypt" = "xyes")
|
||||
if test "$with_sha_crypt" = "yes"; then
|
||||
AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms])
|
||||
AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms])
|
||||
fi
|
||||
|
||||
if test "$with_nscd" = "yes"; then
|
||||
AC_CHECK_FUNC(posix_spawn,
|
||||
[AC_DEFINE(USE_NSCD, 1, [Define to support flushing of nscd caches])],
|
||||
[AC_MSG_ERROR([posix_spawn is needed for nscd support])])
|
||||
fi
|
||||
|
||||
dnl Check for some functions in libc first, only if not found check for
|
||||
@@ -268,7 +311,7 @@ if test "$enable_man" = "yes"; then
|
||||
JH_CHECK_XML_CATALOG([http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl],
|
||||
[DocBook XSL Stylesheets >= 1.70.1], [], enable_man=no)
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_REGENERATE_MAN, test x$enable_man != xno)
|
||||
AM_CONDITIONAL(ENABLE_REGENERATE_MAN, test "x$enable_man" != "xno")
|
||||
|
||||
AC_SUBST(LIBCRYPT)
|
||||
AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
|
||||
@@ -280,6 +323,15 @@ if test "$with_audit" != "no"; then
|
||||
if test "$audit_header$with_audit" = "noyes" ; then
|
||||
AC_MSG_ERROR([libaudit.h is missing])
|
||||
elif test "$audit_header" = "yes"; then
|
||||
AC_CHECK_DECL(AUDIT_ADD_USER,,[audit_header="no"],[#include <libaudit.h>])
|
||||
AC_CHECK_DECL(AUDIT_DEL_USER,,[audit_header="no"],[#include <libaudit.h>])
|
||||
AC_CHECK_DECL(AUDIT_ADD_GROUP,,[audit_header="no"],[#include <libaudit.h>])
|
||||
AC_CHECK_DECL(AUDIT_DEL_GROUP,,[audit_header="no"],[#include <libaudit.h>])
|
||||
if test "$audit_header$with_audit" = "noyes" ; then
|
||||
AC_MSG_ERROR([AUDIT_ADD_USER AUDIT_DEL_USER AUDIT_ADD_GROUP or AUDIT_DEL_GROUP missing from libaudit.h])
|
||||
fi
|
||||
fi
|
||||
if test "$audit_header" = "yes"; then
|
||||
AC_CHECK_LIB(audit, audit_log_acct_message,
|
||||
[audit_lib="yes"], [audit_lib="no"])
|
||||
if test "$audit_lib$with_audit" = "noyes" ; then
|
||||
@@ -339,23 +391,55 @@ if test "$with_libpam" != "no"; then
|
||||
AC_MSG_ERROR(libpam not found)
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB(pam_misc, main,
|
||||
[pam_misc_lib="yes"], [pam_misc_lib="no"])
|
||||
if test "$pam_misc_lib$with_libpam" = "noyes" ; then
|
||||
AC_MSG_ERROR(libpam_misc not found)
|
||||
LIBPAM="-lpam"
|
||||
pam_conv_function="no"
|
||||
|
||||
AC_CHECK_LIB(pam, openpam_ttyconv,
|
||||
[pam_conv_function="openpam_ttyconv"],
|
||||
AC_CHECK_LIB(pam_misc, misc_conv,
|
||||
[pam_conv_function="misc_conv"; LIBPAM="$LIBPAM -lpam_misc"])
|
||||
)
|
||||
|
||||
if test "$pam_conv_function$with_libpam" = "noyes" ; then
|
||||
AC_MSG_ERROR(PAM conversation function not found)
|
||||
fi
|
||||
|
||||
if test "$pam_lib$pam_misc_lib" = "yesyes" ; then
|
||||
pam_headers_found=no
|
||||
AC_CHECK_HEADERS( [security/openpam.h security/pam_misc.h],
|
||||
[ pam_headers_found=yes ; break ], [],
|
||||
[ #include <security/pam_appl.h> ] )
|
||||
if test "$pam_headers_found$with_libpam" = "noyes" ; then
|
||||
AC_MSG_ERROR(PAM headers not found)
|
||||
fi
|
||||
|
||||
|
||||
if test "$pam_lib$pam_headers_found" = "yesyes" -a "$pam_conv_function" != "no" ; then
|
||||
with_libpam="yes"
|
||||
else
|
||||
with_libpam="no"
|
||||
unset LIBPAM
|
||||
fi
|
||||
fi
|
||||
dnl Now with_libpam is either yes or no
|
||||
if test "$with_libpam" = "yes"; then
|
||||
AC_CHECK_DECLS([PAM_ESTABLISH_CRED,
|
||||
PAM_DELETE_CRED,
|
||||
PAM_NEW_AUTHTOK_REQD,
|
||||
PAM_DATA_SILENT],
|
||||
[], [], [#include <security/pam_appl.h>])
|
||||
|
||||
|
||||
save_libs=$LIBS
|
||||
LIBS="$LIBS $LIBPAM"
|
||||
# We do not use AC_CHECK_FUNCS to avoid duplicated definition with
|
||||
# Linux PAM.
|
||||
AC_CHECK_FUNC(pam_fail_delay, [AC_DEFINE(HAS_PAM_FAIL_DELAY, 1, [Define to 1 if you have the declaration of 'pam_fail_delay'])])
|
||||
LIBS=$save_libs
|
||||
|
||||
AC_DEFINE(USE_PAM, 1, [Define to support Pluggable Authentication Modules])
|
||||
AC_DEFINE_UNQUOTED(SHADOW_PAM_CONVERSATION, [$pam_conv_function],[PAM converstation to use])
|
||||
AM_CONDITIONAL(USE_PAM, [true])
|
||||
LIBPAM="-lpam -lpam_misc"
|
||||
|
||||
AC_MSG_CHECKING(use login and su access checking if PAM not used)
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
@@ -365,6 +449,24 @@ else
|
||||
AC_MSG_RESULT(yes)
|
||||
fi
|
||||
|
||||
if test "$enable_acct_tools_setuid" != "no"; then
|
||||
if test "$with_libpam" != "yes"; then
|
||||
if test "$enable_acct_tools_setuid" = "yes"; then
|
||||
AC_MSG_ERROR(PAM support is required for --enable-account-tools-setuid)
|
||||
else
|
||||
enable_acct_tools_setuid="no"
|
||||
fi
|
||||
else
|
||||
enable_acct_tools_setuid="yes"
|
||||
fi
|
||||
if test "$enable_acct_tools_setuid" = "yes"; then
|
||||
AC_DEFINE(ACCT_TOOLS_SETUID,
|
||||
1,
|
||||
[Define if account management tools should be installed setuid and authenticate the callers])
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(ACCT_TOOLS_SETUID, test "x$enable_acct_tools_setuid" = "xyes")
|
||||
|
||||
AC_SUBST(LIBSKEY)
|
||||
AC_SUBST(LIBMD)
|
||||
if test "$with_skey" = "yes"; then
|
||||
@@ -380,6 +482,17 @@ if test "$with_skey" = "yes"; then
|
||||
],[AC_DEFINE(SKEY_BSD_STYLE, 1, [Define to support newer BSD S/Key API])])
|
||||
fi
|
||||
|
||||
if test "$enable_utmpx" = "yes"; then
|
||||
if test "$ac_cv_header_utmpx_h" != "yes"; then
|
||||
AC_MSG_ERROR([The utmpx.h header file is required for utmpx support.])
|
||||
fi
|
||||
AC_DEFINE(USE_UTMPX,
|
||||
1,
|
||||
[Define if utmpx should be used])
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED(SHELL, ["$SHELL"], [The default shell.])
|
||||
|
||||
AM_GNU_GETTEXT_VERSION(0.16)
|
||||
AM_GNU_GETTEXT([external], [need-ngettext])
|
||||
AM_CONDITIONAL(USE_NLS, test "x$USE_NLS" = "xyes")
|
||||
@@ -389,6 +502,7 @@ AC_CONFIG_FILES([
|
||||
po/Makefile.in
|
||||
doc/Makefile
|
||||
man/Makefile
|
||||
man/config.xml
|
||||
man/po/Makefile.in
|
||||
man/cs/Makefile
|
||||
man/de/Makefile
|
||||
@@ -423,8 +537,12 @@ echo
|
||||
echo " auditing support: $with_audit"
|
||||
echo " CrackLib support: $with_libcrack"
|
||||
echo " PAM support: $with_libpam"
|
||||
if test "$with_libpam" = "yes"; then
|
||||
echo " suid account management tools: $enable_acct_tools_setuid"
|
||||
fi
|
||||
echo " SELinux support: $with_selinux"
|
||||
echo " shadow group support: $enable_shadowgrp"
|
||||
echo " S/Key support: $with_skey"
|
||||
echo " SHA passwords encryption: $with_sha_crypt"
|
||||
echo " nscd support: $with_nscd"
|
||||
echo
|
||||
|
||||
@@ -230,7 +230,7 @@ void main()
|
||||
fflush(stdin);
|
||||
} else
|
||||
if (dir[strlen(dir)-1]=='/')
|
||||
sprintf(dir,"%s%s",dir,uname);
|
||||
sprintf(dir+strlen(dir),"%s",uname);
|
||||
|
||||
printf("\nShell [%s]: ",DEFAULT_SHELL);
|
||||
fflush(stdout);
|
||||
|
||||
@@ -296,7 +296,7 @@ main (void)
|
||||
sprintf (dir, "%s/%s", DEFAULT_HOME, usrname);
|
||||
}
|
||||
else if (dir[strlen (dir) - 1] == '/')
|
||||
sprintf (dir, "%s%s", dir, usrname);
|
||||
sprintf (dir+strlen(dir), "%s", usrname);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -31,8 +31,6 @@ New ideas to add to this list are welcome, too. --marekm
|
||||
- new option for /etc/suauth: don't load user's environment (force "su -")
|
||||
suggested by Ulisses Alonso Camaro
|
||||
- find out why recent releases won't compile on Solaris
|
||||
- newusers UID/GID selection algorithm should be the same as useradd
|
||||
(and use UID_MIN, UID_MAX from login.defs)
|
||||
- newusers should be able to copy /etc/skel to the new home directory
|
||||
(like useradd)
|
||||
- add directories where other packages can add hooks for package-specific
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#
|
||||
# Delay in seconds before being allowed another attempt after a login failure
|
||||
# Note: When PAM is used, some modules may enfore a minimal delay (e.g.
|
||||
# pam_unix enforces a 2s delay)
|
||||
#
|
||||
FAIL_DELAY 3
|
||||
|
||||
@@ -169,7 +171,6 @@ TTYPERM 0600
|
||||
#
|
||||
# ERASECHAR Terminal ERASE character ('\010' = backspace).
|
||||
# KILLCHAR Terminal KILL character ('\025' = CTRL/U).
|
||||
# UMASK Default "umask" value.
|
||||
# ULIMIT Default "ulimit" value.
|
||||
#
|
||||
# The ERASECHAR and KILLCHAR are used only on System V machines.
|
||||
@@ -180,9 +181,16 @@ TTYPERM 0600
|
||||
#
|
||||
ERASECHAR 0177
|
||||
KILLCHAR 025
|
||||
UMASK 022
|
||||
#ULIMIT 2097152
|
||||
|
||||
# Default initial "umask" value for non-PAM enabled systems.
|
||||
# UMASK is also used by useradd and newusers to set the mode of new home
|
||||
# directories.
|
||||
# 022 is the default value, but 027, or even 077, could be considered
|
||||
# better for privacy. There is no One True Answer here: each sysadmin
|
||||
# must make up her mind.
|
||||
UMASK 022
|
||||
|
||||
#
|
||||
# Password aging controls:
|
||||
#
|
||||
@@ -215,7 +223,7 @@ CRACKLIB_DICTPATH /var/cache/cracklib/cracklib_dict
|
||||
UID_MIN 1000
|
||||
UID_MAX 60000
|
||||
# System accounts
|
||||
SYS_UID_MIN 100
|
||||
SYS_UID_MIN 101
|
||||
SYS_UID_MAX 999
|
||||
|
||||
#
|
||||
@@ -224,7 +232,7 @@ SYS_UID_MAX 999
|
||||
GID_MIN 1000
|
||||
GID_MAX 60000
|
||||
# System accounts
|
||||
SYS_GID_MIN 100
|
||||
SYS_GID_MIN 101
|
||||
SYS_GID_MAX 999
|
||||
|
||||
#
|
||||
@@ -367,3 +375,12 @@ USERGROUPS_ENAB yes
|
||||
# 0 is the default value and disables this feature.
|
||||
#
|
||||
#MAX_MEMBERS_PER_GROUP 0
|
||||
|
||||
#
|
||||
# If useradd should create home directories for users by default (non
|
||||
# system users only)
|
||||
# This option is overridden with the -M or -m flags on the useradd command
|
||||
# line.
|
||||
#
|
||||
#CREATE_HOME yes
|
||||
|
||||
|
||||
@@ -2,19 +2,21 @@
|
||||
# and also cooperate to make a distribution for `make dist'
|
||||
|
||||
pamd_files = \
|
||||
chage \
|
||||
chfn \
|
||||
chsh \
|
||||
groupmems \
|
||||
login \
|
||||
passwd \
|
||||
su
|
||||
|
||||
pamd_acct_tools_files = \
|
||||
chage \
|
||||
chgpasswd \
|
||||
chpasswd \
|
||||
chsh \
|
||||
groupadd \
|
||||
groupdel \
|
||||
groupmems \
|
||||
groupmod \
|
||||
login \
|
||||
newusers \
|
||||
passwd \
|
||||
su \
|
||||
useradd \
|
||||
userdel \
|
||||
usermod
|
||||
@@ -22,6 +24,9 @@ pamd_files = \
|
||||
if USE_PAM
|
||||
pamddir = $(sysconfdir)/pam.d
|
||||
pamd_DATA = $(pamd_files)
|
||||
if ACCT_TOOLS_SETUID
|
||||
pamd_DATA += $(pamd_acct_tools_files)
|
||||
endif
|
||||
endif
|
||||
|
||||
EXTRA_DIST = $(pamd_files)
|
||||
EXTRA_DIST = $(pamd_files) $(pamd_acct_tools_files)
|
||||
|
||||
@@ -17,6 +17,11 @@ libshadow_la_SOURCES = \
|
||||
fputsx.c \
|
||||
getdef.c \
|
||||
getdef.h \
|
||||
get_gid.c \
|
||||
getlong.c \
|
||||
get_pid.c \
|
||||
get_uid.c \
|
||||
getulong.c \
|
||||
groupio.c \
|
||||
groupmem.c \
|
||||
groupio.h \
|
||||
@@ -35,6 +40,7 @@ libshadow_la_SOURCES = \
|
||||
pwmem.c \
|
||||
sgetgrent.c \
|
||||
sgetpwent.c \
|
||||
sgetspent.c \
|
||||
sgroupio.c \
|
||||
sgroupio.h\
|
||||
shadow.c \
|
||||
|
||||
498
lib/commonio.c
498
lib/commonio.c
File diff suppressed because it is too large
Load Diff
@@ -37,14 +37,18 @@
|
||||
#ifdef WITH_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "defines.h" /* bool */
|
||||
|
||||
/*
|
||||
* Linked list entry.
|
||||
*/
|
||||
struct commonio_entry {
|
||||
char *line;
|
||||
void *eptr; /* struct passwd, struct spwd, ... */
|
||||
struct commonio_entry *prev, *next;
|
||||
unsigned int changed:1;
|
||||
/*@null@*/char *line;
|
||||
/*@null@*/void *eptr; /* struct passwd, struct spwd, ... */
|
||||
/*@dependent@*/ /*@null@*/struct commonio_entry *prev;
|
||||
/*@owned@*/ /*@null@*/struct commonio_entry *next;
|
||||
bool changed:1;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -55,12 +59,12 @@ struct commonio_ops {
|
||||
* Make a copy of the object (for example, struct passwd)
|
||||
* and all strings pointed by it, in malloced memory.
|
||||
*/
|
||||
void *(*dup) (const void *);
|
||||
/*@null@*/ /*@only@*/void *(*dup) (const void *);
|
||||
|
||||
/*
|
||||
* free() the object including any strings pointed by it.
|
||||
*/
|
||||
void (*free) (void *);
|
||||
void (*free) (/*@out@*/ /*@only@*/void *);
|
||||
|
||||
/*
|
||||
* Return the name of the object (for example, pw_name
|
||||
@@ -84,7 +88,7 @@ struct commonio_ops {
|
||||
* fgets and fputs (can be replaced by versions that
|
||||
* understand line continuation conventions).
|
||||
*/
|
||||
char *(*fgets) (char *, int, FILE *);
|
||||
/*@null@*/char *(*fgets) (/*@returned@*/ /*@out@*/char *s, int n, FILE *stream);
|
||||
int (*fputs) (const char *, FILE *);
|
||||
|
||||
/*
|
||||
@@ -93,8 +97,8 @@ struct commonio_ops {
|
||||
* is open or before it is closed.
|
||||
* They return 0 on failure and 1 on success.
|
||||
*/
|
||||
int (*open_hook) (void);
|
||||
int (*close_hook) (void);
|
||||
/*@null@*/int (*open_hook) (void);
|
||||
/*@null@*/int (*close_hook) (void);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -109,40 +113,41 @@ struct commonio_db {
|
||||
/*
|
||||
* Operations from above.
|
||||
*/
|
||||
struct commonio_ops *ops;
|
||||
/*@observer@*/const struct commonio_ops *ops;
|
||||
|
||||
/*
|
||||
* Currently open file stream.
|
||||
*/
|
||||
FILE *fp;
|
||||
/*@dependent@*/ /*@null@*/FILE *fp;
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
security_context_t scontext;
|
||||
/*@null@*/security_context_t scontext;
|
||||
#endif
|
||||
/*
|
||||
* Head, tail, current position in linked list.
|
||||
*/
|
||||
struct commonio_entry *head, *tail, *cursor;
|
||||
/*@owned@*/ /*@null@*/struct commonio_entry *head, *tail;
|
||||
/*@dependent@*/ /*@null@*/struct commonio_entry *cursor;
|
||||
|
||||
/*
|
||||
* Various flags.
|
||||
*/
|
||||
unsigned int changed:1;
|
||||
unsigned int isopen:1;
|
||||
unsigned int locked:1;
|
||||
unsigned int readonly:1;
|
||||
bool changed:1;
|
||||
bool isopen:1;
|
||||
bool locked:1;
|
||||
bool readonly:1;
|
||||
};
|
||||
|
||||
extern int commonio_setname (struct commonio_db *, const char *);
|
||||
extern int commonio_present (const struct commonio_db *);
|
||||
extern bool commonio_present (const struct commonio_db *db);
|
||||
extern int commonio_lock (struct commonio_db *);
|
||||
extern int commonio_lock_nowait (struct commonio_db *);
|
||||
extern int commonio_open (struct commonio_db *, int);
|
||||
extern const void *commonio_locate (struct commonio_db *, const char *);
|
||||
extern /*@observer@*/ /*@null@*/const void *commonio_locate (struct commonio_db *, const char *);
|
||||
extern int commonio_update (struct commonio_db *, const void *);
|
||||
extern int commonio_remove (struct commonio_db *, const char *);
|
||||
extern int commonio_rewind (struct commonio_db *);
|
||||
extern const void *commonio_next (struct commonio_db *);
|
||||
extern /*@observer@*/ /*@null@*/const void *commonio_next (struct commonio_db *);
|
||||
extern int commonio_close (struct commonio_db *);
|
||||
extern int commonio_unlock (struct commonio_db *);
|
||||
extern void commonio_del_entry (struct commonio_db *,
|
||||
|
||||
@@ -4,29 +4,60 @@
|
||||
#ifndef _DEFINES_H_
|
||||
#define _DEFINES_H_
|
||||
|
||||
#if HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# if ! HAVE__BOOL
|
||||
# ifdef __cplusplus
|
||||
typedef bool _Bool;
|
||||
# else
|
||||
typedef unsigned char _Bool;
|
||||
# endif
|
||||
# endif
|
||||
# define bool _Bool
|
||||
# define false (0)
|
||||
# define true (1)
|
||||
# define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
|
||||
|
||||
/* Take care of NLS matters. */
|
||||
|
||||
#if HAVE_LOCALE_H
|
||||
#ifdef S_SPLINT_S
|
||||
extern char *setlocale(int categorie, const char *locale);
|
||||
# define LC_ALL (6)
|
||||
extern char * bindtextdomain (const char * domainname, const char * dirname);
|
||||
extern char * textdomain (const char * domainname);
|
||||
# define _(Text) Text
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
|
||||
#else
|
||||
#ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#else
|
||||
# undef setlocale
|
||||
# define setlocale(category, locale) (NULL)
|
||||
# ifndef LC_ALL
|
||||
# define LC_ALL 6
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define gettext_noop(String) (String)
|
||||
/* #define gettext_def(String) "#define String" */
|
||||
|
||||
#if ENABLE_NLS
|
||||
#ifdef ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(Text) gettext (Text)
|
||||
#else
|
||||
# undef bindtextdomain
|
||||
# define bindtextdomain(Domain, Directory) /* empty */
|
||||
# define bindtextdomain(Domain, Directory) (NULL)
|
||||
# undef textdomain
|
||||
# define textdomain(Domain) /* empty */
|
||||
# define textdomain(Domain) (NULL)
|
||||
# define _(Text) Text
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
@@ -136,7 +167,7 @@ char *strchr (), *strrchr (), *strtok ();
|
||||
|
||||
/* cleaner than lots of #ifdefs everywhere - use this as follows:
|
||||
SYSLOG((LOG_CRIT, "user %s cracked root", user)); */
|
||||
#if ENABLE_NLS
|
||||
#ifdef ENABLE_NLS
|
||||
/* Temporarily set LC_TIME to "C" to avoid strange dates in syslog.
|
||||
This is a workaround for a more general syslog(d) design problem -
|
||||
syslogd should log the current system time for each event, and not
|
||||
@@ -146,17 +177,20 @@ char *strchr (), *strrchr (), *strtok ();
|
||||
* --Nekral */
|
||||
#define SYSLOG(x) \
|
||||
do { \
|
||||
char *saved_locale = setlocale(LC_ALL, NULL); \
|
||||
if (saved_locale) \
|
||||
saved_locale = strdup(saved_locale); \
|
||||
if (saved_locale) \
|
||||
setlocale(LC_ALL, "C"); \
|
||||
syslog x ; \
|
||||
if (saved_locale) { \
|
||||
setlocale(LC_ALL, saved_locale); \
|
||||
free(saved_locale); \
|
||||
char *old_locale = setlocale(LC_ALL, NULL); \
|
||||
char *saved_locale = NULL; \
|
||||
if (NULL != old_locale) { \
|
||||
saved_locale = strdup (old_locale); \
|
||||
} \
|
||||
} while (0)
|
||||
if (NULL != saved_locale) { \
|
||||
(void) setlocale (LC_ALL, "C"); \
|
||||
} \
|
||||
syslog x ; \
|
||||
if (NULL != saved_locale) { \
|
||||
(void) setlocale (LC_ALL, saved_locale); \
|
||||
free (saved_locale); \
|
||||
} \
|
||||
} while (false)
|
||||
#else /* !ENABLE_NLS */
|
||||
#define SYSLOG(x) syslog x
|
||||
#endif /* !ENABLE_NLS */
|
||||
@@ -303,6 +337,8 @@ extern char *strerror ();
|
||||
#define SHADOW_PASSWD_STRING "x"
|
||||
#endif
|
||||
|
||||
#define SHADOW_SP_FLAG_UNSET ((unsigned long int)-1)
|
||||
|
||||
#ifdef WITH_AUDIT
|
||||
#ifdef __u8 /* in case we use pam < 0.80 */
|
||||
#undef __u8
|
||||
@@ -321,4 +357,29 @@ extern char *strerror ();
|
||||
# define unused
|
||||
#endif
|
||||
|
||||
/* ! Arguments evaluated twice ! */
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
/* Maximum length of usernames */
|
||||
#ifdef HAVE_UTMPX_H
|
||||
# include <utmpx.h>
|
||||
# define USER_NAME_MAX_LENGTH (sizeof (((struct utmpx *)NULL)->ut_user))
|
||||
#else
|
||||
# include <utmp.h>
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_USER
|
||||
# define USER_NAME_MAX_LENGTH (sizeof (((struct utmp *)NULL)->ut_user))
|
||||
# else
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_NAME
|
||||
# define USER_NAME_MAX_LENGTH (sizeof (((struct utmp *)NULL)->ut_name))
|
||||
# else
|
||||
# define USER_NAME_MAX_LENGTH 32
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _DEFINES_H_ */
|
||||
|
||||
@@ -53,12 +53,12 @@ char *pw_encrypt (const char *clear, const char *salt)
|
||||
* expect us to return NULL, so...
|
||||
*/
|
||||
perror ("crypt");
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* The GNU crypt does not return NULL if the algorithm is not
|
||||
* supported, and return a DES encrypted password. */
|
||||
if (salt && salt[0] == '$' && strlen (cp) <= 13)
|
||||
if ((NULL != salt) && (salt[0] == '$') && (strlen (cp) <= 13))
|
||||
{
|
||||
const char *method;
|
||||
switch (salt[1])
|
||||
@@ -82,12 +82,15 @@ char *pw_encrypt (const char *clear, const char *salt)
|
||||
fprintf (stderr,
|
||||
_("crypt method not supported by libcrypt? (%s)\n"),
|
||||
method);
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strlen (cp) != 13)
|
||||
if (strlen (cp) != 13) {
|
||||
return cp; /* nonstandard crypt() in libc, better bail out */
|
||||
}
|
||||
|
||||
strcpy (cipher, cp);
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,12 @@
|
||||
/*
|
||||
* Exit codes used by shadow programs
|
||||
*/
|
||||
#define E_SUCCESS 0 /* success */
|
||||
#define E_SUCCESS EXIT_SUCCESS /* success */
|
||||
/*
|
||||
* FIXME: other values should differ from EXIT_FAILURE (and EXIT_SUCCESS).
|
||||
*
|
||||
* FIXME: reserve EXIT_FAILURE for internal failures.
|
||||
*/
|
||||
#define E_NOPERM 1 /* permission denied */
|
||||
#define E_USAGE 2 /* invalid command syntax */
|
||||
#define E_BAD_ARG 3 /* invalid argument to option */
|
||||
|
||||
28
lib/fputsx.c
28
lib/fputsx.c
@@ -39,23 +39,29 @@
|
||||
#ident "$Id$"
|
||||
|
||||
|
||||
char *fgetsx (char *buf, int cnt, FILE * f)
|
||||
/*@null@*/char *fgetsx (/*@returned@*/ /*@out@*/char *buf, int cnt, FILE * f)
|
||||
{
|
||||
char *cp = buf;
|
||||
char *ep;
|
||||
|
||||
while (cnt > 0) {
|
||||
if (fgets (cp, cnt, f) == 0) {
|
||||
if (cp == buf)
|
||||
if (fgets (cp, cnt, f) != cp) {
|
||||
if (cp == buf) {
|
||||
return 0;
|
||||
else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((ep = strrchr (cp, '\\')) && *(ep + 1) == '\n') {
|
||||
if ((cnt -= ep - cp) > 0)
|
||||
*(cp = ep) = '\0';
|
||||
} else
|
||||
ep = strrchr (cp, '\\');
|
||||
if ((NULL != ep) && (*(ep + 1) == '\n')) {
|
||||
cnt -= ep - cp;
|
||||
if (cnt > 0) {
|
||||
cp = ep;
|
||||
*cp = '\0';
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
@@ -64,9 +70,10 @@ int fputsx (const char *s, FILE * stream)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; *s; i++, s++) {
|
||||
if (putc (*s, stream) == EOF)
|
||||
for (i = 0; '\0' != *s; i++, s++) {
|
||||
if (putc (*s, stream) == EOF) {
|
||||
return EOF;
|
||||
}
|
||||
|
||||
#if 0 /* The standard getgr*() can't handle that. --marekm */
|
||||
if (i > (BUFSIZ / 2)) {
|
||||
@@ -80,3 +87,4 @@ int fputsx (const char *s, FILE * stream)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
54
lib/get_gid.c
Normal file
54
lib/get_gid.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
int get_gid (const char *gidstr, gid_t *gid)
|
||||
{
|
||||
long long int val;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
val = strtoll (gidstr, &endptr, 10);
|
||||
if ( ('\0' == *gidstr)
|
||||
|| ('\0' != *endptr)
|
||||
|| (ERANGE == errno)
|
||||
|| (/*@+longintegral@*/val != (gid_t)val)/*@=longintegral@*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*gid = (gid_t)val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
54
lib/get_pid.c
Normal file
54
lib/get_pid.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
int get_pid (const char *pidstr, pid_t *pid)
|
||||
{
|
||||
long long int val;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
val = strtoll (pidstr, &endptr, 10);
|
||||
if ( ('\0' == *pidstr)
|
||||
|| ('\0' != *endptr)
|
||||
|| (ERANGE == errno)
|
||||
|| (/*@+longintegral@*/val != (pid_t)val)/*@=longintegral@*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pid = (pid_t)val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
54
lib/get_uid.c
Normal file
54
lib/get_uid.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
int get_uid (const char *uidstr, uid_t *uid)
|
||||
{
|
||||
long long int val;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
val = strtoll (uidstr, &endptr, 10);
|
||||
if ( ('\0' == *uidstr)
|
||||
|| ('\0' != *endptr)
|
||||
|| (ERANGE == errno)
|
||||
|| (/*@+longintegral@*/val != (uid_t)val)/*@=longintegral@*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*uid = (uid_t)val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
198
lib/getdef.c
198
lib/getdef.c
@@ -39,13 +39,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include "getdef.h"
|
||||
/*
|
||||
* A configuration item definition.
|
||||
*/
|
||||
struct itemdef {
|
||||
const char *name; /* name of the item */
|
||||
char *value; /* value given, or NULL if no value */
|
||||
/*@null@*/const char *name; /* name of the item */
|
||||
/*@null@*/char *value; /* value given, or NULL if no value */
|
||||
};
|
||||
|
||||
#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
|
||||
@@ -131,10 +132,10 @@ static struct itemdef def_table[] = {
|
||||
#endif
|
||||
|
||||
static char def_fname[] = LOGINDEFS; /* login config defs file */
|
||||
static int def_loaded = 0; /* are defs already loaded? */
|
||||
static bool def_loaded = false; /* are defs already loaded? */
|
||||
|
||||
/* local function prototypes */
|
||||
static struct itemdef *def_find (const char *);
|
||||
static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *);
|
||||
static void def_load (void);
|
||||
|
||||
|
||||
@@ -145,14 +146,16 @@ static void def_load (void);
|
||||
* defined. First time invoked, will load definitions from the file.
|
||||
*/
|
||||
|
||||
char *getdef_str (const char *item)
|
||||
/*@observer@*/ /*@null@*/const char *getdef_str (const char *item)
|
||||
{
|
||||
struct itemdef *d;
|
||||
|
||||
if (!def_loaded)
|
||||
if (!def_loaded) {
|
||||
def_load ();
|
||||
}
|
||||
|
||||
return ((d = def_find (item)) == NULL ? (char *) NULL : d->value);
|
||||
d = def_find (item);
|
||||
return ((NULL == d)? (const char *) NULL : d->value);
|
||||
}
|
||||
|
||||
|
||||
@@ -162,15 +165,18 @@ char *getdef_str (const char *item)
|
||||
* Return TRUE if specified item is defined as "yes", else FALSE.
|
||||
*/
|
||||
|
||||
int getdef_bool (const char *item)
|
||||
bool getdef_bool (const char *item)
|
||||
{
|
||||
struct itemdef *d;
|
||||
|
||||
if (!def_loaded)
|
||||
if (!def_loaded) {
|
||||
def_load ();
|
||||
}
|
||||
|
||||
if ((d = def_find (item)) == NULL || d->value == NULL)
|
||||
return 0;
|
||||
d = def_find (item);
|
||||
if ((NULL == d) || (NULL == d->value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (strcasecmp (d->value, "yes") == 0);
|
||||
}
|
||||
@@ -187,14 +193,27 @@ int getdef_bool (const char *item)
|
||||
int getdef_num (const char *item, int dflt)
|
||||
{
|
||||
struct itemdef *d;
|
||||
long val;
|
||||
|
||||
if (!def_loaded)
|
||||
if (!def_loaded) {
|
||||
def_load ();
|
||||
}
|
||||
|
||||
if ((d = def_find (item)) == NULL || d->value == NULL)
|
||||
d = def_find (item);
|
||||
if ((NULL == d) || (NULL == d->value)) {
|
||||
return dflt;
|
||||
}
|
||||
|
||||
return (int) strtol (d->value, (char **) NULL, 0);
|
||||
if ( (getlong (d->value, &val) == 0)
|
||||
|| (val > INT_MAX)
|
||||
|| (val < INT_MIN)) {
|
||||
fprintf (stderr,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
}
|
||||
|
||||
return (int) val;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,14 +228,27 @@ int getdef_num (const char *item, int dflt)
|
||||
unsigned int getdef_unum (const char *item, unsigned int dflt)
|
||||
{
|
||||
struct itemdef *d;
|
||||
long val;
|
||||
|
||||
if (!def_loaded)
|
||||
if (!def_loaded) {
|
||||
def_load ();
|
||||
}
|
||||
|
||||
if ((d = def_find (item)) == NULL || d->value == NULL)
|
||||
d = def_find (item);
|
||||
if ((NULL == d) || (NULL == d->value)) {
|
||||
return dflt;
|
||||
}
|
||||
|
||||
return (unsigned int) strtoul (d->value, (char **) NULL, 0);
|
||||
if ( (getlong (d->value, &val) == 0)
|
||||
|| (val < 0)
|
||||
|| (val > INT_MAX)) {
|
||||
fprintf (stderr,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
}
|
||||
|
||||
return (unsigned int) val;
|
||||
}
|
||||
|
||||
|
||||
@@ -231,16 +263,59 @@ unsigned int getdef_unum (const char *item, unsigned int dflt)
|
||||
long getdef_long (const char *item, long dflt)
|
||||
{
|
||||
struct itemdef *d;
|
||||
long val;
|
||||
|
||||
if (!def_loaded)
|
||||
if (!def_loaded) {
|
||||
def_load ();
|
||||
}
|
||||
|
||||
if ((d = def_find (item)) == NULL || d->value == NULL)
|
||||
d = def_find (item);
|
||||
if ((NULL == d) || (NULL == d->value)) {
|
||||
return dflt;
|
||||
}
|
||||
|
||||
return strtol (d->value, (char **) NULL, 0);
|
||||
if (getlong (d->value, &val) == 0) {
|
||||
fprintf (stderr,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* getdef_ulong - get unsigned long numerical value from table of definitions
|
||||
*
|
||||
* Returns numeric value of specified item, else the "dflt" value if
|
||||
* the item is not defined. Octal (leading "0") and hex (leading "0x")
|
||||
* values are handled.
|
||||
*/
|
||||
|
||||
unsigned long getdef_ulong (const char *item, unsigned long dflt)
|
||||
{
|
||||
struct itemdef *d;
|
||||
unsigned long val;
|
||||
|
||||
if (!def_loaded) {
|
||||
def_load ();
|
||||
}
|
||||
|
||||
d = def_find (item);
|
||||
if ((NULL == d) || (NULL == d->value)) {
|
||||
return dflt;
|
||||
}
|
||||
|
||||
if (getulong (d->value, &val) == 0) {
|
||||
/* FIXME: we should have a getulong */
|
||||
fprintf (stderr,
|
||||
_("configuration error - cannot parse %s value: '%s'"),
|
||||
item, d->value);
|
||||
return dflt;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* putdef_str - override the value read from /etc/login.defs
|
||||
@@ -252,28 +327,33 @@ int putdef_str (const char *name, const char *value)
|
||||
struct itemdef *d;
|
||||
char *cp;
|
||||
|
||||
if (!def_loaded)
|
||||
if (!def_loaded) {
|
||||
def_load ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the slot to save the value. If this parameter
|
||||
* is unknown then "def_find" will print an err message.
|
||||
*/
|
||||
if ((d = def_find (name)) == NULL)
|
||||
d = def_find (name);
|
||||
if (NULL == d) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save off the value.
|
||||
*/
|
||||
if ((cp = strdup (value)) == NULL) {
|
||||
fputs (_("Could not allocate space for config info.\n"),
|
||||
stderr);
|
||||
cp = strdup (value);
|
||||
if (NULL == cp) {
|
||||
(void) fputs (_("Could not allocate space for config info.\n"),
|
||||
stderr);
|
||||
SYSLOG ((LOG_ERR, "could not allocate space for config info"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (d->value)
|
||||
if (NULL != d->value) {
|
||||
free (d->value);
|
||||
}
|
||||
|
||||
d->value = cp;
|
||||
return 0;
|
||||
@@ -287,9 +367,8 @@ int putdef_str (const char *name, const char *value)
|
||||
* specified configuration option.
|
||||
*/
|
||||
|
||||
static struct itemdef *def_find (const char *name)
|
||||
static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
|
||||
{
|
||||
int n;
|
||||
struct itemdef *ptr;
|
||||
|
||||
|
||||
@@ -297,9 +376,10 @@ static struct itemdef *def_find (const char *name)
|
||||
* Search into the table.
|
||||
*/
|
||||
|
||||
for (ptr = def_table; ptr->name; ptr++) {
|
||||
if (!(n = strcmp (ptr->name, name)))
|
||||
for (ptr = def_table; NULL != ptr->name; ptr++) {
|
||||
if (strcmp (ptr->name, name) == 0) {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -307,9 +387,8 @@ static struct itemdef *def_find (const char *name)
|
||||
*/
|
||||
|
||||
fprintf (stderr,
|
||||
_
|
||||
("configuration error - unknown item '%s' (notify administrator)\n"),
|
||||
name);
|
||||
_("configuration error - unknown item '%s' (notify administrator)\n"),
|
||||
name);
|
||||
SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name));
|
||||
return (struct itemdef *) NULL;
|
||||
}
|
||||
@@ -329,31 +408,35 @@ static void def_load (void)
|
||||
/*
|
||||
* Open the configuration definitions file.
|
||||
*/
|
||||
if ((fp = fopen (def_fname, "r")) == NULL) {
|
||||
SYSLOG ((LOG_CRIT, "cannot open login definitions %s [%m]",
|
||||
def_fname));
|
||||
exit (1);
|
||||
fp = fopen (def_fname, "r");
|
||||
if (NULL == fp) {
|
||||
int err = errno;
|
||||
SYSLOG ((LOG_CRIT, "cannot open login definitions %s [%s]",
|
||||
def_fname, strerror (err)));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the initialized flag.
|
||||
* (do it early to prevent recursion in putdef_str())
|
||||
*/
|
||||
++def_loaded;
|
||||
def_loaded = true;
|
||||
|
||||
/*
|
||||
* Go through all of the lines in the file.
|
||||
*/
|
||||
while (fgets (buf, sizeof (buf), fp) != NULL) {
|
||||
while (fgets (buf, (int) sizeof (buf), fp) != NULL) {
|
||||
|
||||
/*
|
||||
* Trim trailing whitespace.
|
||||
*/
|
||||
for (i = strlen (buf) - 1; i >= 0; --i) {
|
||||
if (!isspace (buf[i]))
|
||||
for (i = (int) strlen (buf) - 1; i >= 0; --i) {
|
||||
if (!isspace (buf[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[++i] = '\0';
|
||||
i++;
|
||||
buf[i] = '\0';
|
||||
|
||||
/*
|
||||
* Break the line into two fields.
|
||||
@@ -372,14 +455,19 @@ static void def_load (void)
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
putdef_str (name, value);
|
||||
(void)putdef_str (name, value);
|
||||
}
|
||||
|
||||
if (ferror (fp)) {
|
||||
SYSLOG ((LOG_CRIT, "cannot read login definitions %s [%m]",
|
||||
def_fname));
|
||||
exit (1);
|
||||
if (ferror (fp) != 0) {
|
||||
int err = errno;
|
||||
SYSLOG ((LOG_CRIT, "cannot read login definitions %s [%s]",
|
||||
def_fname, strerror (err)));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
(void) fclose (fp);
|
||||
@@ -396,18 +484,22 @@ int main (int argc, char **argv)
|
||||
def_load ();
|
||||
|
||||
for (i = 0; i < NUMDEFS; ++i) {
|
||||
if ((d = def_find (def_table[i].name)) == NULL)
|
||||
d = def_find (def_table[i].name);
|
||||
if (NULL == d) {
|
||||
printf ("error - lookup '%s' failed\n",
|
||||
def_table[i].name);
|
||||
else
|
||||
def_table[i].name);
|
||||
} else {
|
||||
printf ("%4d %-24s %s\n", i + 1, d->name, d->value);
|
||||
}
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if ((cp = getdef_str (argv[1])) != NULL)
|
||||
cp = getdef_str (argv[1]);
|
||||
if (NULL != cp) {
|
||||
printf ("%s `%s'\n", argv[1], cp);
|
||||
else
|
||||
} else {
|
||||
printf ("%s not found\n", argv[1]);
|
||||
}
|
||||
}
|
||||
exit (0);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2002 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,11 +33,12 @@
|
||||
#define _GETDEF_H
|
||||
|
||||
/* getdef.c */
|
||||
extern int getdef_bool (const char *);
|
||||
extern bool getdef_bool (const char *);
|
||||
extern long getdef_long (const char *, long);
|
||||
extern int getdef_num (const char *, int);
|
||||
extern unsigned long getdef_ulong (const char *, unsigned long);
|
||||
extern unsigned int getdef_unum (const char *, unsigned int);
|
||||
extern char *getdef_str (const char *);
|
||||
extern /*@observer@*/ /*@null@*/const char *getdef_str (const char *);
|
||||
extern int putdef_str (const char *, const char *);
|
||||
|
||||
/* default UMASK value if not specified in /etc/login.defs */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -31,17 +31,27 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
int getlong(const char *numstr, long int *result)
|
||||
/*
|
||||
* getlong - extract a long integer provided by the numstr string in *result
|
||||
*
|
||||
* It supports decimal, hexadecimal or octal representations.
|
||||
*
|
||||
* Returns 0 on failure, 1 on success.
|
||||
*/
|
||||
int getlong (const char *numstr, /*@out@*/long int *result)
|
||||
{
|
||||
long val;
|
||||
char *endptr;
|
||||
|
||||
val = strtol (numstr, &endptr, 10);
|
||||
if (*endptr || errno == ERANGE)
|
||||
errno = 0;
|
||||
val = strtol (numstr, &endptr, 0);
|
||||
if (('\0' == *numstr) || ('\0' != *endptr) || (ERANGE == errno)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*result = val;
|
||||
return 1;
|
||||
65
lib/getulong.c
Normal file
65
lib/getulong.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id: getlong.c 2763 2009-04-23 09:57:03Z nekral-guest $"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
/*
|
||||
* getulong - extract an unsigned long integer provided by the numstr string in *result
|
||||
*
|
||||
* It supports decimal, hexadecimal or octal representations.
|
||||
*
|
||||
* Returns 0 on failure, 1 on success.
|
||||
*/
|
||||
int getulong (const char *numstr, /*@out@*/unsigned long int *result)
|
||||
{
|
||||
long long int val;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
val = strtoll (numstr, &endptr, 0);
|
||||
if ( ('\0' == *numstr)
|
||||
|| ('\0' != *endptr)
|
||||
|| (ERANGE == errno)
|
||||
/*@+ignoresigns@*/
|
||||
|| (val != (unsigned long int)val)
|
||||
/*@=ignoresigns@*/
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*result = (unsigned long int)val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
108
lib/groupio.c
108
lib/groupio.c
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
@@ -43,29 +44,24 @@
|
||||
#include "getdef.h"
|
||||
#include "groupio.h"
|
||||
|
||||
static struct commonio_entry *merge_group_entries (struct commonio_entry *gr1,
|
||||
struct commonio_entry *gr2);
|
||||
static /*@null@*/struct commonio_entry *merge_group_entries (
|
||||
/*@null@*/ /*@returned@*/struct commonio_entry *gr1,
|
||||
/*@null@*/struct commonio_entry *gr2);
|
||||
static int split_groups (unsigned int max_members);
|
||||
static int group_open_hook (void);
|
||||
|
||||
static void *group_dup (const void *ent)
|
||||
static /*@null@*/ /*@only@*/void *group_dup (const void *ent)
|
||||
{
|
||||
const struct group *gr = ent;
|
||||
|
||||
return __gr_dup (gr);
|
||||
}
|
||||
|
||||
static void group_free (void *ent)
|
||||
static void group_free (/*@out@*/ /*@only@*/void *ent)
|
||||
{
|
||||
struct group *gr = ent;
|
||||
|
||||
free (gr->gr_name);
|
||||
free (gr->gr_passwd);
|
||||
while (*(gr->gr_mem)) {
|
||||
free (*(gr->gr_mem));
|
||||
gr->gr_mem++;
|
||||
}
|
||||
free (gr);
|
||||
gr_free (gr);
|
||||
}
|
||||
|
||||
static const char *group_getname (const void *ent)
|
||||
@@ -91,8 +87,9 @@ static int group_close_hook (void)
|
||||
{
|
||||
unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
|
||||
|
||||
if (0 == max_members)
|
||||
if (0 == max_members) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return split_groups (max_members);
|
||||
}
|
||||
@@ -109,7 +106,7 @@ static struct commonio_ops group_ops = {
|
||||
group_close_hook
|
||||
};
|
||||
|
||||
static struct commonio_db group_db = {
|
||||
static /*@owned@*/struct commonio_db group_db = {
|
||||
GROUP_FILE, /* filename */
|
||||
&group_ops, /* ops */
|
||||
NULL, /* fp */
|
||||
@@ -119,17 +116,22 @@ static struct commonio_db group_db = {
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
0, /* changed */
|
||||
0, /* isopen */
|
||||
0, /* locked */
|
||||
0 /* readonly */
|
||||
false, /* changed */
|
||||
false, /* isopen */
|
||||
false, /* locked */
|
||||
false /* readonly */
|
||||
};
|
||||
|
||||
int gr_name (const char *filename)
|
||||
int gr_setdbname (const char *filename)
|
||||
{
|
||||
return commonio_setname (&group_db, filename);
|
||||
}
|
||||
|
||||
/*@observer@*/const char *gr_dbname (void)
|
||||
{
|
||||
return group_db.filename;
|
||||
}
|
||||
|
||||
int gr_lock (void)
|
||||
{
|
||||
return commonio_lock (&group_db);
|
||||
@@ -140,12 +142,12 @@ int gr_open (int mode)
|
||||
return commonio_open (&group_db, mode);
|
||||
}
|
||||
|
||||
const struct group *gr_locate (const char *name)
|
||||
/*@observer@*/ /*@null@*/const struct group *gr_locate (const char *name)
|
||||
{
|
||||
return commonio_locate (&group_db, name);
|
||||
}
|
||||
|
||||
const struct group *gr_locate_gid (gid_t gid)
|
||||
/*@observer@*/ /*@null@*/const struct group *gr_locate_gid (gid_t gid)
|
||||
{
|
||||
const struct group *grp;
|
||||
|
||||
@@ -172,7 +174,7 @@ int gr_rewind (void)
|
||||
return commonio_rewind (&group_db);
|
||||
}
|
||||
|
||||
const struct group *gr_next (void)
|
||||
/*@observer@*/ /*@null@*/const struct group *gr_next (void)
|
||||
{
|
||||
return commonio_next (&group_db);
|
||||
}
|
||||
@@ -189,15 +191,15 @@ int gr_unlock (void)
|
||||
|
||||
void __gr_set_changed (void)
|
||||
{
|
||||
group_db.changed = 1;
|
||||
group_db.changed = true;
|
||||
}
|
||||
|
||||
struct commonio_entry *__gr_get_head (void)
|
||||
/*@dependent@*/ /*@null@*/struct commonio_entry *__gr_get_head (void)
|
||||
{
|
||||
return group_db.head;
|
||||
}
|
||||
|
||||
struct commonio_db *__gr_get_db (void)
|
||||
/*@observer@*/const struct commonio_db *__gr_get_db (void)
|
||||
{
|
||||
return &group_db;
|
||||
}
|
||||
@@ -211,20 +213,23 @@ static int gr_cmp (const void *p1, const void *p2)
|
||||
{
|
||||
gid_t u1, u2;
|
||||
|
||||
if ((*(struct commonio_entry **) p1)->eptr == NULL)
|
||||
if ((*(struct commonio_entry **) p1)->eptr == NULL) {
|
||||
return 1;
|
||||
if ((*(struct commonio_entry **) p2)->eptr == NULL)
|
||||
}
|
||||
if ((*(struct commonio_entry **) p2)->eptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
u1 = ((struct group *) (*(struct commonio_entry **) p1)->eptr)->gr_gid;
|
||||
u2 = ((struct group *) (*(struct commonio_entry **) p2)->eptr)->gr_gid;
|
||||
|
||||
if (u1 < u2)
|
||||
if (u1 < u2) {
|
||||
return -1;
|
||||
else if (u1 > u2)
|
||||
} else if (u1 > u2) {
|
||||
return 1;
|
||||
else
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort entries by GID */
|
||||
@@ -238,11 +243,12 @@ static int group_open_hook (void)
|
||||
unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
|
||||
struct commonio_entry *gr1, *gr2;
|
||||
|
||||
if (0 == max_members)
|
||||
if (0 == max_members) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (gr1 = group_db.head; gr1; gr1 = gr1->next) {
|
||||
for (gr2 = gr1->next; gr2; gr2 = gr2->next) {
|
||||
for (gr1 = group_db.head; NULL != gr1; gr1 = gr1->next) {
|
||||
for (gr2 = gr1->next; NULL != gr2; gr2 = gr2->next) {
|
||||
struct group *g1 = (struct group *)gr1->eptr;
|
||||
struct group *g2 = (struct group *)gr2->eptr;
|
||||
if (NULL != g1 &&
|
||||
@@ -257,11 +263,15 @@ static int group_open_hook (void)
|
||||
if (NULL == gr1)
|
||||
return 0;
|
||||
/* Unlink gr2 */
|
||||
if (NULL != gr2->next)
|
||||
if (NULL != gr2->next) {
|
||||
gr2->next->prev = gr2->prev;
|
||||
}
|
||||
/* gr2 does not start with head */
|
||||
assert (NULL != gr2->prev);
|
||||
gr2->prev->next = gr2->next;
|
||||
}
|
||||
}
|
||||
assert (NULL != gr1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -279,15 +289,16 @@ static int group_open_hook (void)
|
||||
* the modified first entry on success, or NULL on failure (with errno
|
||||
* set).
|
||||
*/
|
||||
static struct commonio_entry *merge_group_entries (struct commonio_entry *gr1,
|
||||
struct commonio_entry *gr2)
|
||||
static /*@null@*/struct commonio_entry *merge_group_entries (
|
||||
/*@null@*/ /*@returned@*/struct commonio_entry *gr1,
|
||||
/*@null@*/struct commonio_entry *gr2)
|
||||
{
|
||||
struct group *gptr1;
|
||||
struct group *gptr2;
|
||||
char **new_members;
|
||||
int members = 0;
|
||||
size_t members = 0;
|
||||
char *new_line;
|
||||
int new_line_len, i;
|
||||
size_t new_line_len, i;
|
||||
if (NULL == gr2 || NULL == gr1) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
@@ -316,30 +327,36 @@ static struct commonio_entry *merge_group_entries (struct commonio_entry *gr1,
|
||||
for (i=0; NULL != gptr2->gr_mem[i]; i++) {
|
||||
char **pmember = gptr1->gr_mem;
|
||||
while (NULL != *pmember) {
|
||||
if (0 == strcmp(*pmember, gptr2->gr_mem[i]))
|
||||
if (0 == strcmp(*pmember, gptr2->gr_mem[i])) {
|
||||
break;
|
||||
}
|
||||
pmember++;
|
||||
}
|
||||
if (NULL == *pmember)
|
||||
if (NULL == *pmember) {
|
||||
members++;
|
||||
}
|
||||
}
|
||||
new_members = (char **)malloc ( (members+1) * sizeof(char*) );
|
||||
if (NULL == new_members) {
|
||||
free (new_line);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
for (i=0; NULL != gptr1->gr_mem[i]; i++)
|
||||
for (i=0; NULL != gptr1->gr_mem[i]; i++) {
|
||||
new_members[i] = gptr1->gr_mem[i];
|
||||
}
|
||||
members = i;
|
||||
for (i=0; NULL != gptr2->gr_mem[i]; i++) {
|
||||
char **pmember = new_members;
|
||||
while (NULL != *pmember) {
|
||||
if (0 == strcmp(*pmember, gptr2->gr_mem[i]))
|
||||
if (0 == strcmp(*pmember, gptr2->gr_mem[i])) {
|
||||
break;
|
||||
}
|
||||
pmember++;
|
||||
}
|
||||
if (NULL == *pmember) {
|
||||
new_members[members++] = gptr2->gr_mem[i];
|
||||
new_members[members] = gptr2->gr_mem[i];
|
||||
members++;
|
||||
new_members[members] = NULL;
|
||||
}
|
||||
}
|
||||
@@ -360,7 +377,7 @@ static int split_groups (unsigned int max_members)
|
||||
{
|
||||
struct commonio_entry *gr;
|
||||
|
||||
for (gr = group_db.head; gr; gr = gr->next) {
|
||||
for (gr = group_db.head; NULL != gr; gr = gr->next) {
|
||||
struct group *gptr = (struct group *)gr->eptr;
|
||||
struct commonio_entry *new;
|
||||
struct group *new_gptr;
|
||||
@@ -382,12 +399,13 @@ static int split_groups (unsigned int max_members)
|
||||
}
|
||||
new->eptr = group_dup(gr->eptr);
|
||||
if (NULL == new->eptr) {
|
||||
free (new);
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
new_gptr = (struct group *)new->eptr;
|
||||
new->line = NULL;
|
||||
new->changed = 1;
|
||||
new->changed = true;
|
||||
|
||||
/* Enforce the maximum number of members on gptr */
|
||||
gptr->gr_mem[max_members] = NULL;
|
||||
|
||||
@@ -31,17 +31,25 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
#ifndef _GROUPIO_H
|
||||
#define _GROUPIO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <grp.h>
|
||||
|
||||
extern int gr_close (void);
|
||||
extern const struct group *gr_locate (const char *);
|
||||
extern const struct group *gr_locate_gid (gid_t gid);
|
||||
extern /*@observer@*/ /*@null@*/const struct group *gr_locate (const char *name);
|
||||
extern /*@observer@*/ /*@null@*/const struct group *gr_locate_gid (gid_t gid);
|
||||
extern int gr_lock (void);
|
||||
extern int gr_name (const char *);
|
||||
extern const struct group *gr_next (void);
|
||||
extern int gr_open (int);
|
||||
extern int gr_remove (const char *);
|
||||
extern int gr_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *gr_dbname (void);
|
||||
extern /*@observer@*/ /*@null@*/const struct group *gr_next (void);
|
||||
extern int gr_open (int mode);
|
||||
extern int gr_remove (const char *name);
|
||||
extern int gr_rewind (void);
|
||||
extern int gr_unlock (void);
|
||||
extern int gr_update (const struct group *);
|
||||
extern int gr_update (const struct group *gr);
|
||||
extern int gr_sort (void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -39,29 +39,51 @@
|
||||
#include "defines.h"
|
||||
#include "groupio.h"
|
||||
|
||||
struct group *__gr_dup (const struct group *grent)
|
||||
/*@null@*/ /*@only@*/struct group *__gr_dup (const struct group *grent)
|
||||
{
|
||||
struct group *gr;
|
||||
int i;
|
||||
|
||||
if (!(gr = (struct group *) malloc (sizeof *gr)))
|
||||
gr = (struct group *) malloc (sizeof *gr);
|
||||
if (NULL == gr) {
|
||||
return NULL;
|
||||
}
|
||||
*gr = *grent;
|
||||
if (!(gr->gr_name = strdup (grent->gr_name)))
|
||||
gr->gr_name = strdup (grent->gr_name);
|
||||
if (NULL == gr->gr_name) {
|
||||
return NULL;
|
||||
if (!(gr->gr_passwd = strdup (grent->gr_passwd)))
|
||||
}
|
||||
gr->gr_passwd = strdup (grent->gr_passwd);
|
||||
if (NULL == gr->gr_passwd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; grent->gr_mem[i]; i++);
|
||||
|
||||
gr->gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
||||
if (!gr->gr_mem)
|
||||
if (NULL == gr->gr_mem) {
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; grent->gr_mem[i]; i++) {
|
||||
gr->gr_mem[i] = strdup (grent->gr_mem[i]);
|
||||
if (!gr->gr_mem[i])
|
||||
if (NULL == gr->gr_mem[i]) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
gr->gr_mem[i] = NULL;
|
||||
|
||||
return gr;
|
||||
}
|
||||
|
||||
void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
||||
{
|
||||
free (grent->gr_name);
|
||||
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
||||
free (grent->gr_passwd);
|
||||
while (*(grent->gr_mem)) {
|
||||
free (*(grent->gr_mem));
|
||||
grent->gr_mem++;
|
||||
}
|
||||
free (grent);
|
||||
}
|
||||
|
||||
|
||||
237
lib/gshadow.c
237
lib/gshadow.c
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -40,21 +40,20 @@
|
||||
#include <stdio.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
static FILE *shadow;
|
||||
static char sgrbuf[BUFSIZ * 4];
|
||||
static char **members = NULL;
|
||||
static /*@null@*/FILE *shadow;
|
||||
static /*@null@*//*@only@*/char **members = NULL;
|
||||
static size_t nmembers = 0;
|
||||
static char **admins = NULL;
|
||||
static /*@null@*//*@only@*/char **admins = NULL;
|
||||
static size_t nadmins = 0;
|
||||
static struct sgrp sgroup;
|
||||
|
||||
#define FIELDS 4
|
||||
|
||||
#ifdef USE_NIS
|
||||
static int nis_used;
|
||||
static int nis_ignore;
|
||||
static bool nis_used;
|
||||
static bool nis_ignore;
|
||||
static enum { native, start, middle, native2 } nis_state;
|
||||
static int nis_bound;
|
||||
static bool nis_bound;
|
||||
static char *nis_domain;
|
||||
static char *nis_key;
|
||||
static int nis_keylen;
|
||||
@@ -65,19 +64,6 @@ static int nis_vallen;
|
||||
#endif
|
||||
|
||||
#ifdef USE_NIS
|
||||
|
||||
/*
|
||||
* __setsgNIS - turn on or off NIS searches
|
||||
*/
|
||||
|
||||
void __setsgNIS (int flag)
|
||||
{
|
||||
nis_ignore = !flag;
|
||||
|
||||
if (nis_ignore)
|
||||
nis_used = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* bind_nis - bind to NIS server
|
||||
*/
|
||||
@@ -87,29 +73,35 @@ static int bind_nis (void)
|
||||
if (yp_get_default_domain (&nis_domain))
|
||||
return -1;
|
||||
|
||||
nis_bound = 1;
|
||||
nis_bound = true;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char **build_list (char *s, char **list[], size_t * nlist)
|
||||
static /*@null@*/char **build_list (char *s, char **list[], size_t * nlist)
|
||||
{
|
||||
char **ptr = *list;
|
||||
size_t nelem = *nlist, size;
|
||||
|
||||
while (s != NULL && *s != '\0') {
|
||||
size = (nelem + 1) * sizeof (ptr);
|
||||
if ((ptr = realloc (*list, size)) != NULL) {
|
||||
ptr[nelem++] = s;
|
||||
ptr = realloc (*list, size);
|
||||
if (NULL != ptr) {
|
||||
ptr[nelem] = s;
|
||||
nelem++;
|
||||
*list = ptr;
|
||||
*nlist = nelem;
|
||||
if ((s = strchr (s, ',')))
|
||||
*s++ = '\0';
|
||||
s = strchr (s, ',');
|
||||
if (NULL != s) {
|
||||
*s = '\0';
|
||||
s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
size = (nelem + 1) * sizeof (ptr);
|
||||
if ((ptr = realloc (*list, size)) != NULL) {
|
||||
ptr[nelem] = '\0';
|
||||
ptr = realloc (*list, size);
|
||||
if (NULL != ptr) {
|
||||
ptr[nelem] = NULL;
|
||||
*list = ptr;
|
||||
}
|
||||
return ptr;
|
||||
@@ -120,41 +112,60 @@ void setsgent (void)
|
||||
#ifdef USE_NIS
|
||||
nis_state = native;
|
||||
#endif
|
||||
if (shadow)
|
||||
if (NULL != shadow) {
|
||||
rewind (shadow);
|
||||
else
|
||||
} else {
|
||||
shadow = fopen (SGROUP_FILE, "r");
|
||||
}
|
||||
}
|
||||
|
||||
void endsgent (void)
|
||||
{
|
||||
if (shadow)
|
||||
if (NULL != shadow) {
|
||||
(void) fclose (shadow);
|
||||
}
|
||||
|
||||
shadow = (FILE *) 0;
|
||||
}
|
||||
|
||||
struct sgrp *sgetsgent (const char *string)
|
||||
/*@observer@*//*@null@*/struct sgrp *sgetsgent (const char *string)
|
||||
{
|
||||
static char *sgrbuf = NULL;
|
||||
static size_t sgrbuflen = 0;
|
||||
|
||||
char *fields[FIELDS];
|
||||
char *cp;
|
||||
int i;
|
||||
size_t len = strlen (string) + 1;
|
||||
|
||||
strncpy (sgrbuf, string, (int) sizeof sgrbuf - 1);
|
||||
sgrbuf[sizeof sgrbuf - 1] = '\0';
|
||||
if (len > sgrbuflen) {
|
||||
char *buf = (char *) realloc (sgrbuf, sizeof (char) * len);
|
||||
if (NULL == buf) {
|
||||
return NULL;
|
||||
}
|
||||
sgrbuf = buf;
|
||||
sgrbuflen = len;
|
||||
}
|
||||
|
||||
if ((cp = strrchr (sgrbuf, '\n')))
|
||||
strncpy (sgrbuf, string, len);
|
||||
sgrbuf[len-1] = '\0';
|
||||
|
||||
cp = strrchr (sgrbuf, '\n');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* There should be exactly 4 colon separated fields. Find
|
||||
* all 4 of them and save the starting addresses in fields[].
|
||||
*/
|
||||
|
||||
for (cp = sgrbuf, i = 0; i < FIELDS && cp; i++) {
|
||||
for (cp = sgrbuf, i = 0; (i < FIELDS) && (NULL != cp); i++) {
|
||||
fields[i] = cp;
|
||||
if ((cp = strchr (cp, ':')))
|
||||
cp = strchr (cp, ':');
|
||||
if (NULL != cp) {
|
||||
*cp++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -162,24 +173,26 @@ struct sgrp *sgetsgent (const char *string)
|
||||
* the line is invalid.
|
||||
*/
|
||||
|
||||
if (cp || i != FIELDS)
|
||||
if ((NULL != cp) || (i != FIELDS)) {
|
||||
#ifdef USE_NIS
|
||||
if (!IS_NISCHAR (fields[0][0]))
|
||||
if (!IS_NISCHAR (fields[0][0])) {
|
||||
return 0;
|
||||
else
|
||||
nis_used = 1;
|
||||
} else {
|
||||
nis_used = true;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
sgroup.sg_name = fields[0];
|
||||
sgroup.sg_passwd = fields[1];
|
||||
if (nadmins) {
|
||||
if (0 != nadmins) {
|
||||
nadmins = 0;
|
||||
free (admins);
|
||||
admins = NULL;
|
||||
}
|
||||
if (nmembers) {
|
||||
if (0 != nmembers) {
|
||||
nmembers = 0;
|
||||
free (members);
|
||||
members = NULL;
|
||||
@@ -197,44 +210,76 @@ struct sgrp *sgetsgent (const char *string)
|
||||
* converts it to a (struct sgrp). NULL is returned on EOF.
|
||||
*/
|
||||
|
||||
struct sgrp *fgetsgent (FILE * fp)
|
||||
/*@observer@*//*@null@*/struct sgrp *fgetsgent (/*@null@*/FILE * fp)
|
||||
{
|
||||
char buf[sizeof sgrbuf];
|
||||
char *cp;
|
||||
static size_t buflen = 0;
|
||||
static char *buf = NULL;
|
||||
|
||||
if (!fp)
|
||||
return (0);
|
||||
char *cp;
|
||||
struct sgrp *ret;
|
||||
|
||||
if (0 == buflen) {
|
||||
buf = (char *) malloc (BUFSIZ);
|
||||
if (NULL == buf) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == fp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
while (fgetsx (buf, sizeof buf, fp) != (char *) 0)
|
||||
while (fgetsx (buf, (int) sizeof buf, fp) == buf)
|
||||
#else
|
||||
if (fgetsx (buf, sizeof buf, fp) != (char *) 0)
|
||||
if (fgetsx (buf, (int) sizeof buf, fp) == buf)
|
||||
#endif
|
||||
{
|
||||
if ((cp = strchr (buf, '\n')))
|
||||
while ( ((cp = strrchr (buf, '\n')) == NULL)
|
||||
&& (feof (fp) == 0)) {
|
||||
size_t len;
|
||||
|
||||
cp = (char *) realloc (buf, buflen*2);
|
||||
if (NULL == cp) {
|
||||
return NULL;
|
||||
}
|
||||
buf = cp;
|
||||
buflen *= 2;
|
||||
|
||||
len = strlen (buf);
|
||||
if (fgetsx (&buf[len],
|
||||
(int) (buflen - len),
|
||||
fp) != &buf[len]) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
cp = strrchr (buf, '\n');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
}
|
||||
#ifdef USE_NIS
|
||||
if (nis_ignore && IS_NISCHAR (buf[0]))
|
||||
if (nis_ignore && IS_NISCHAR (buf[0])) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
return (sgetsgent (buf));
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* getsgent - get a single shadow group entry
|
||||
*/
|
||||
|
||||
struct sgrp *getsgent (void)
|
||||
/*@observer@*//*@null@*/struct sgrp *getsgent (void)
|
||||
{
|
||||
#ifdef USE_NIS
|
||||
int nis_1_group = 0;
|
||||
bool nis_1_group = false;
|
||||
struct sgrp *val;
|
||||
char buf[BUFSIZ];
|
||||
#endif
|
||||
if (!shadow)
|
||||
if (NULL == shadow) {
|
||||
setsgent ();
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
again:
|
||||
@@ -249,8 +294,10 @@ struct sgrp *getsgent (void)
|
||||
* NULL right away if there is none.
|
||||
*/
|
||||
|
||||
if (!(val = fgetsgent (shadow)))
|
||||
val = fgetsgent (shadow);
|
||||
if (NULL == val) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this entry began with a NIS escape character, we have
|
||||
@@ -259,10 +306,11 @@ struct sgrp *getsgent (void)
|
||||
*/
|
||||
|
||||
if (IS_NISCHAR (val->sg_name[0])) {
|
||||
if (val->sg_name[1])
|
||||
nis_1_group = 1;
|
||||
else
|
||||
if ('\0' != val->sg_name[1]) {
|
||||
nis_1_group = true;
|
||||
} else {
|
||||
nis_state = start;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -270,16 +318,18 @@ struct sgrp *getsgent (void)
|
||||
* use a NIS map, it must be a regular local group.
|
||||
*/
|
||||
|
||||
if (nis_1_group == 0 && nis_state != start)
|
||||
if (!nis_1_group && (nis_state != start)) {
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is an escape to use an NIS map, switch over to
|
||||
* that bunch of code.
|
||||
*/
|
||||
|
||||
if (nis_state == start)
|
||||
if (nis_state == start) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
/*
|
||||
* NEEDSWORK. Here we substitute pieces-parts of this entry.
|
||||
@@ -287,7 +337,7 @@ struct sgrp *getsgent (void)
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (nis_bound == 0) {
|
||||
if (!nis_bound) {
|
||||
if (bind_nis ()) {
|
||||
nis_state = native2;
|
||||
goto again;
|
||||
@@ -319,12 +369,11 @@ struct sgrp *getsgent (void)
|
||||
* getsgnam - get a shadow group entry by name
|
||||
*/
|
||||
|
||||
struct sgrp *getsgnam (const char *name)
|
||||
/*@observer@*//*@null@*/struct sgrp *getsgnam (const char *name)
|
||||
{
|
||||
struct sgrp *sgrp;
|
||||
|
||||
#ifdef USE_NIS
|
||||
char buf[BUFSIZ];
|
||||
static char save_name[16];
|
||||
int nis_disabled = 0;
|
||||
#endif
|
||||
@@ -339,8 +388,9 @@ struct sgrp *getsgnam (const char *name)
|
||||
* Search the gshadow.byname map for this group.
|
||||
*/
|
||||
|
||||
if (!nis_bound)
|
||||
if (!nis_bound) {
|
||||
bind_nis ();
|
||||
}
|
||||
|
||||
if (nis_bound) {
|
||||
char *cp;
|
||||
@@ -348,11 +398,14 @@ struct sgrp *getsgnam (const char *name)
|
||||
if (yp_match (nis_domain, "gshadow.byname", name,
|
||||
strlen (name), &nis_val,
|
||||
&nis_vallen) == 0) {
|
||||
if (cp = strchr (nis_val, '\n'))
|
||||
cp = strchr (nis_val, '\n');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
nis_state = middle;
|
||||
if (sgrp = sgetsgent (nis_val)) {
|
||||
sgrp = sgetsgent (nis_val);
|
||||
if (NULL != sgrp) {
|
||||
strcpy (save_name, sgrp->sg_name);
|
||||
nis_key = save_name;
|
||||
nis_keylen = strlen (save_name);
|
||||
@@ -365,20 +418,19 @@ struct sgrp *getsgnam (const char *name)
|
||||
#endif
|
||||
#ifdef USE_NIS
|
||||
if (nis_used) {
|
||||
nis_ignore++;
|
||||
nis_disabled++;
|
||||
nis_ignore = true;
|
||||
nis_disabled = true;
|
||||
}
|
||||
#endif
|
||||
while ((sgrp = getsgent ()) != (struct sgrp *) 0) {
|
||||
if (strcmp (name, sgrp->sg_name) == 0)
|
||||
if (strcmp (name, sgrp->sg_name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef USE_NIS
|
||||
nis_ignore--;
|
||||
nis_ignore = false;
|
||||
#endif
|
||||
if (sgrp)
|
||||
return sgrp;
|
||||
return (0);
|
||||
return sgrp;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -395,19 +447,23 @@ int putsgent (const struct sgrp *sgrp, FILE * fp)
|
||||
int i;
|
||||
size_t size;
|
||||
|
||||
if (!fp || !sgrp)
|
||||
if ((NULL == fp) || (NULL == sgrp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* calculate the required buffer size */
|
||||
size = strlen (sgrp->sg_name) + strlen (sgrp->sg_passwd) + 10;
|
||||
for (i = 0; sgrp->sg_adm && sgrp->sg_adm[i]; i++)
|
||||
for (i = 0; (NULL != sgrp->sg_adm) && (NULL != sgrp->sg_adm[i]); i++) {
|
||||
size += strlen (sgrp->sg_adm[i]) + 1;
|
||||
for (i = 0; sgrp->sg_mem && sgrp->sg_mem[i]; i++)
|
||||
}
|
||||
for (i = 0; (NULL != sgrp->sg_mem) && (NULL != sgrp->sg_mem[i]); i++) {
|
||||
size += strlen (sgrp->sg_mem[i]) + 1;
|
||||
}
|
||||
|
||||
buf = malloc (size);
|
||||
if (!buf)
|
||||
if (NULL == buf) {
|
||||
return -1;
|
||||
}
|
||||
cp = buf;
|
||||
|
||||
/*
|
||||
@@ -427,27 +483,32 @@ int putsgent (const struct sgrp *sgrp, FILE * fp)
|
||||
* with a ",".
|
||||
*/
|
||||
|
||||
for (i = 0; sgrp->sg_adm[i]; i++) {
|
||||
if (i > 0)
|
||||
for (i = 0; NULL != sgrp->sg_adm[i]; i++) {
|
||||
if (i > 0) {
|
||||
*cp++ = ',';
|
||||
}
|
||||
|
||||
strcpy (cp, sgrp->sg_adm[i]);
|
||||
cp += strlen (cp);
|
||||
}
|
||||
*cp++ = ':';
|
||||
*cp = ':';
|
||||
cp++;
|
||||
|
||||
/*
|
||||
* Now do likewise with the group members.
|
||||
*/
|
||||
|
||||
for (i = 0; sgrp->sg_mem[i]; i++) {
|
||||
if (i > 0)
|
||||
*cp++ = ',';
|
||||
for (i = 0; NULL != sgrp->sg_mem[i]; i++) {
|
||||
if (i > 0) {
|
||||
*cp = ',';
|
||||
cp++;
|
||||
}
|
||||
|
||||
strcpy (cp, sgrp->sg_mem[i]);
|
||||
cp += strlen (cp);
|
||||
}
|
||||
*cp++ = '\n';
|
||||
*cp = '\n';
|
||||
cp++;
|
||||
*cp = '\0';
|
||||
|
||||
/*
|
||||
|
||||
@@ -54,18 +54,18 @@ struct sgrp {
|
||||
#include <stdio.h> /* for FILE */
|
||||
|
||||
#if __STDC__
|
||||
struct sgrp *getsgent (void);
|
||||
struct sgrp *getsgnam (const char *);
|
||||
struct sgrp *sgetsgent (const char *);
|
||||
struct sgrp *fgetsgent (FILE *);
|
||||
/*@observer@*//*@null@*/struct sgrp *getsgent (void);
|
||||
/*@observer@*//*@null@*/struct sgrp *getsgnam (const char *);
|
||||
/*@observer@*//*@null@*/struct sgrp *sgetsgent (const char *);
|
||||
/*@observer@*//*@null@*/struct sgrp *fgetsgent (/*@null@*/FILE *);
|
||||
void setsgent (void);
|
||||
void endsgent (void);
|
||||
int putsgent (const struct sgrp *, FILE *);
|
||||
#else
|
||||
struct sgrp *getsgent ();
|
||||
struct sgrp *getsgnam ();
|
||||
struct sgrp *sgetsgent ();
|
||||
struct sgrp *fgetsgent ();
|
||||
/*@observer@*//*@null@*/struct sgrp *getsgent ();
|
||||
/*@observer@*//*@null@*/struct sgrp *getsgnam ();
|
||||
/*@observer@*//*@null@*/struct sgrp *sgetsgent ();
|
||||
/*@observer@*//*@null@*/struct sgrp *fgetsgent ();
|
||||
void setsgent ();
|
||||
void endsgent ();
|
||||
int putsgent ();
|
||||
|
||||
29
lib/nscd.c
29
lib/nscd.c
@@ -1,7 +1,12 @@
|
||||
/* Author: Peter Vrabec <pvrabec@redhat.com> */
|
||||
|
||||
#include <config.h>
|
||||
#ifdef USE_NSCD
|
||||
|
||||
/* because of TEMP_FAILURE_RETRY */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <features.h>
|
||||
#include <stdio.h>
|
||||
@@ -11,8 +16,11 @@
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include "defines.h"
|
||||
#include "nscd.h"
|
||||
|
||||
#define MSG_NSCD_FLUSH_CACHE_FAILED "Failed to flush the nscd cache.\n"
|
||||
|
||||
/*
|
||||
* nscd_flush_cache - flush specified service buffer in nscd cache
|
||||
*/
|
||||
@@ -24,27 +32,34 @@ int nscd_flush_cache (const char *service)
|
||||
char *spawnedEnv[] = {NULL};
|
||||
|
||||
/* spawn process */
|
||||
if( (err=posix_spawn(&pid, spawnedArgs[0], NULL, NULL,
|
||||
spawnedArgs, spawnedEnv)) !=0 )
|
||||
err = posix_spawn (&pid, spawnedArgs[0], NULL, NULL,
|
||||
spawnedArgs, spawnedEnv);
|
||||
if(0 != err)
|
||||
{
|
||||
fprintf(stderr, "posix_spawn() error=%d\n", err);
|
||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
||||
(void) fprintf (stderr, "posix_spawn() error=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wait for the spawned process to exit */
|
||||
/* Wait for the spawned process to exit */
|
||||
termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
|
||||
if (termpid == -1)
|
||||
if (-1 == termpid)
|
||||
{
|
||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
||||
perror("waitpid");
|
||||
return -1;
|
||||
}
|
||||
else if (termpid != pid)
|
||||
{
|
||||
fprintf(stderr, "waitpid returned %ld != %ld\n",
|
||||
(long int) termpid, (long int) pid);
|
||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
||||
(void) fprintf (stderr, "waitpid returned %ld != %ld\n",
|
||||
(long int) termpid, (long int) pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* USE_NSCD */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* USE_NSCD */
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
/*
|
||||
* nscd_flush_cache - flush specified service buffer in nscd cache
|
||||
*/
|
||||
#ifdef USE_NSCD
|
||||
extern int nscd_flush_cache (const char *service);
|
||||
#else
|
||||
#define nscd_flush_cache(service) (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,24 +28,31 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_misc.h>
|
||||
#ifdef HAVE_SECURITY_PAM_MISC_H
|
||||
# include <security/pam_misc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SECURITY_OPENPAM_H
|
||||
# include <security/openpam.h>
|
||||
#endif
|
||||
|
||||
|
||||
static struct pam_conv conv = {
|
||||
misc_conv,
|
||||
SHADOW_PAM_CONVERSATION,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* compatibility with different versions of Linux-PAM */
|
||||
#ifndef PAM_ESTABLISH_CRED
|
||||
#if !HAVE_DECL_PAM_ESTABLISH_CRED
|
||||
#define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
|
||||
#endif
|
||||
#ifndef PAM_DELETE_CRED
|
||||
#if !HAVE_DECL_PAM_DELETE_CRED
|
||||
#define PAM_DELETE_CRED PAM_CRED_DELETE
|
||||
#endif
|
||||
#ifndef PAM_NEW_AUTHTOK_REQD
|
||||
#if !HAVE_DECL_PAM_NEW_AUTHTOK_REQD
|
||||
#define PAM_NEW_AUTHTOK_REQD PAM_AUTHTOKEN_REQD
|
||||
#endif
|
||||
#ifndef PAM_DATA_SILENT
|
||||
#if !HAVE_DECL_PAM_DATA_SILENT
|
||||
#define PAM_DATA_SILENT 0
|
||||
#endif
|
||||
|
||||
162
lib/port.c
162
lib/port.c
@@ -57,15 +57,19 @@ static int portcmp (const char *pattern, const char *port)
|
||||
{
|
||||
const char *orig = port;
|
||||
|
||||
while (*pattern && *pattern == *port)
|
||||
pattern++, port++;
|
||||
while (('\0' != *pattern) && (*pattern == *port)) {
|
||||
pattern++;
|
||||
port++;
|
||||
}
|
||||
|
||||
if (*pattern == 0 && *port == 0)
|
||||
if (('\0' == *pattern) && ('\0' == *port)) {
|
||||
return 0;
|
||||
if (orig[0] == 'S' && orig[1] == 'U' && orig[2] == '\0')
|
||||
}
|
||||
if (('S' == orig[0]) && ('U' == orig[1]) && ('\0' == orig[2])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return *pattern == '*' ? 0 : 1;
|
||||
return (*pattern == '*') ? 0 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -77,10 +81,11 @@ static int portcmp (const char *pattern, const char *port)
|
||||
|
||||
static void setportent (void)
|
||||
{
|
||||
if (ports)
|
||||
if (NULL != ports) {
|
||||
rewind (ports);
|
||||
else
|
||||
} else {
|
||||
ports = fopen (PORTS, "r");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -93,8 +98,9 @@ static void setportent (void)
|
||||
|
||||
static void endportent (void)
|
||||
{
|
||||
if (ports)
|
||||
fclose (ports);
|
||||
if (NULL != ports) {
|
||||
(void) fclose (ports);
|
||||
}
|
||||
|
||||
ports = (FILE *) 0;
|
||||
}
|
||||
@@ -125,10 +131,11 @@ static struct port *getportent (void)
|
||||
* since we want to search from the beginning each time.
|
||||
*/
|
||||
|
||||
if (!ports)
|
||||
if (NULL == ports) {
|
||||
setportent ();
|
||||
}
|
||||
|
||||
if (!ports) {
|
||||
if (NULL == ports) {
|
||||
errno = saveerr;
|
||||
return 0;
|
||||
}
|
||||
@@ -150,12 +157,13 @@ static struct port *getportent (void)
|
||||
* is a '\n'. Lines which begin with '#' are all ignored.
|
||||
*/
|
||||
|
||||
if (fgets (buf, sizeof buf, ports) == 0) {
|
||||
if (fgets (buf, (int) sizeof buf, ports) == 0) {
|
||||
errno = saveerr;
|
||||
return 0;
|
||||
}
|
||||
if (buf[0] == '#')
|
||||
if ('#' == buf[0]) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the name of the TTY device. It is the first colon
|
||||
@@ -169,19 +177,24 @@ static struct port *getportent (void)
|
||||
port.pt_names = ttys;
|
||||
for (cp = buf, j = 0; j < PORT_TTY; j++) {
|
||||
port.pt_names[j] = cp;
|
||||
while (*cp && *cp != ':' && *cp != ',')
|
||||
while (('\0' != *cp) && (':' != *cp) && (',' != *cp)) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (!*cp)
|
||||
if ('\0' == *cp) {
|
||||
goto again; /* line format error */
|
||||
}
|
||||
|
||||
if (*cp == ':') /* end of tty name list */
|
||||
if (':' == *cp) { /* end of tty name list */
|
||||
break;
|
||||
}
|
||||
|
||||
if (*cp == ',') /* end of current tty name */
|
||||
if (',' == *cp) { /* end of current tty name */
|
||||
*cp++ = '\0';
|
||||
}
|
||||
}
|
||||
*cp++ = 0;
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
port.pt_names[j + 1] = (char *) 0;
|
||||
|
||||
/*
|
||||
@@ -191,24 +204,29 @@ static struct port *getportent (void)
|
||||
* The last entry in the list is a (char *) 0 pointer.
|
||||
*/
|
||||
|
||||
if (*cp != ':') {
|
||||
if (':' != *cp) {
|
||||
port.pt_users = users;
|
||||
port.pt_users[0] = cp;
|
||||
|
||||
for (j = 1; *cp != ':'; cp++) {
|
||||
if (*cp == ',' && j < PORT_IDS) {
|
||||
*cp++ = 0;
|
||||
port.pt_users[j++] = cp;
|
||||
for (j = 1; ':' != *cp; cp++) {
|
||||
if ((',' == *cp) && (j < PORT_IDS)) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
port.pt_users[j] = cp;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
port.pt_users[j] = 0;
|
||||
} else
|
||||
} else {
|
||||
port.pt_users = 0;
|
||||
}
|
||||
|
||||
if (*cp != ':')
|
||||
if (':' != *cp) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
*cp++ = 0;
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
|
||||
/*
|
||||
* Get the list of valid times. The times field is the third
|
||||
@@ -223,7 +241,7 @@ static struct port *getportent (void)
|
||||
* the starting time. Days are presumed to wrap at 0000.
|
||||
*/
|
||||
|
||||
if (*cp == '\0') {
|
||||
if ('\0' == *cp) {
|
||||
port.pt_times = 0;
|
||||
return &port;
|
||||
}
|
||||
@@ -234,7 +252,7 @@ static struct port *getportent (void)
|
||||
* Get the next comma separated entry
|
||||
*/
|
||||
|
||||
for (j = 0; *cp && j < PORT_TIMES; j++) {
|
||||
for (j = 0; ('\0' != *cp) && (j < PORT_TIMES); j++) {
|
||||
|
||||
/*
|
||||
* Start off with no days of the week
|
||||
@@ -248,7 +266,9 @@ static struct port *getportent (void)
|
||||
* week or the other two values.
|
||||
*/
|
||||
|
||||
for (i = 0; cp[i] && cp[i + 1] && isalpha (cp[i]); i += 2) {
|
||||
for (i = 0;
|
||||
('\0' != cp[i]) && ('\0' != cp[i + 1]) && isalpha (cp[i]);
|
||||
i += 2) {
|
||||
switch ((cp[i] << 8) | (cp[i + 1])) {
|
||||
case ('S' << 8) | 'u':
|
||||
port.pt_times[j].t_days |= 01;
|
||||
@@ -287,8 +307,9 @@ static struct port *getportent (void)
|
||||
* The default is 'Al' if no days were seen.
|
||||
*/
|
||||
|
||||
if (i == 0)
|
||||
if (0 == i) {
|
||||
port.pt_times[j].t_days = 0177;
|
||||
}
|
||||
|
||||
/*
|
||||
* The start and end times are separated from each
|
||||
@@ -296,19 +317,27 @@ static struct port *getportent (void)
|
||||
* representing the times of day.
|
||||
*/
|
||||
|
||||
for (dtime = 0; cp[i] && isdigit (cp[i]); i++)
|
||||
for (dtime = 0; ('\0' != cp[i]) && isdigit (cp[i]); i++) {
|
||||
dtime = dtime * 10 + cp[i] - '0';
|
||||
}
|
||||
|
||||
if (cp[i] != '-' || dtime > 2400 || dtime % 100 > 59)
|
||||
if (('-' != cp[i]) || (dtime > 2400) || ((dtime % 100) > 59)) {
|
||||
goto again;
|
||||
}
|
||||
port.pt_times[j].t_start = dtime;
|
||||
cp = cp + i + 1;
|
||||
|
||||
for (dtime = i = 0; cp[i] && isdigit (cp[i]); i++)
|
||||
for (dtime = 0, i = 0;
|
||||
('\0' != cp[i]) && isdigit (cp[i]);
|
||||
i++) {
|
||||
dtime = dtime * 10 + cp[i] - '0';
|
||||
}
|
||||
|
||||
if ((cp[i] != ',' && cp[i]) || dtime > 2400 || dtime % 100 > 59)
|
||||
if ( ((',' != cp[i]) && ('\0' != cp[i]))
|
||||
|| (dtime > 2400)
|
||||
|| ((dtime % 100) > 59)) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
port.pt_times[j].t_end = dtime;
|
||||
cp = cp + i + 1;
|
||||
@@ -340,24 +369,32 @@ static struct port *getttyuser (const char *tty, const char *user)
|
||||
|
||||
setportent ();
|
||||
|
||||
while ((port = getportent ())) {
|
||||
if (port->pt_names == 0 || port->pt_users == 0)
|
||||
while ((port = getportent ()) != NULL) {
|
||||
if ( (0 == port->pt_names)
|
||||
|| (0 == port->pt_users)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; port->pt_names[i]; i++)
|
||||
if (portcmp (port->pt_names[i], tty) == 0)
|
||||
for (i = 0; NULL != port->pt_names[i]; i++) {
|
||||
if (portcmp (port->pt_names[i], tty) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port->pt_names[i] == 0)
|
||||
if (port->pt_names[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; port->pt_users[j]; j++)
|
||||
if (strcmp (user, port->pt_users[j]) == 0 ||
|
||||
strcmp (port->pt_users[j], "*") == 0)
|
||||
for (j = 0; NULL != port->pt_users[j]; j++) {
|
||||
if ( (strcmp (user, port->pt_users[j]) == 0)
|
||||
|| (strcmp (port->pt_users[j], "*") == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port->pt_users[j] != 0)
|
||||
if (port->pt_users[j] != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
endportent ();
|
||||
return port;
|
||||
@@ -370,7 +407,7 @@ static struct port *getttyuser (const char *tty, const char *user)
|
||||
* the user name and TTY given.
|
||||
*/
|
||||
|
||||
int isttytime (const char *id, const char *port, time_t when)
|
||||
bool isttytime (const char *id, const char *port, time_t when)
|
||||
{
|
||||
int i;
|
||||
int dtime;
|
||||
@@ -379,24 +416,27 @@ int isttytime (const char *id, const char *port, time_t when)
|
||||
|
||||
/*
|
||||
* Try to find a matching entry for this user. Default to
|
||||
* letting the user in - there are pleny of ways to have an
|
||||
* letting the user in - there are plenty of ways to have an
|
||||
* entry to match all users.
|
||||
*/
|
||||
|
||||
if (!(pp = getttyuser (port, id)))
|
||||
return 1;
|
||||
pp = getttyuser (port, id);
|
||||
if (NULL == pp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The entry is there, but has no time entries - don't
|
||||
* ever let them login.
|
||||
*/
|
||||
|
||||
if (pp->pt_times == 0)
|
||||
return 0;
|
||||
if (0 == pp->pt_times) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current time is converted to HHMM format for
|
||||
* comparision against the time values in the TTY entry.
|
||||
* comparison against the time values in the TTY entry.
|
||||
*/
|
||||
|
||||
tm = localtime (&when);
|
||||
@@ -405,22 +445,25 @@ int isttytime (const char *id, const char *port, time_t when)
|
||||
/*
|
||||
* Each time entry is compared against the current
|
||||
* time. For entries with the start after the end time,
|
||||
* the comparision is made so that the time is between
|
||||
* the comparison is made so that the time is between
|
||||
* midnight and either the start or end time.
|
||||
*/
|
||||
|
||||
for (i = 0; pp->pt_times[i].t_start != -1; i++) {
|
||||
if (!(pp->pt_times[i].t_days & PORT_DAY (tm->tm_wday)))
|
||||
if (!(pp->pt_times[i].t_days & PORT_DAY (tm->tm_wday))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
|
||||
if (dtime >= pp->pt_times[i].t_start &&
|
||||
dtime <= pp->pt_times[i].t_end)
|
||||
return 1;
|
||||
if ( (dtime >= pp->pt_times[i].t_start)
|
||||
&& (dtime <= pp->pt_times[i].t_end)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (dtime >= pp->pt_times[i].t_start ||
|
||||
dtime <= pp->pt_times[i].t_end)
|
||||
return 1;
|
||||
if ( (dtime >= pp->pt_times[i].t_start)
|
||||
|| (dtime <= pp->pt_times[i].t_end)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,5 +472,6 @@ int isttytime (const char *id, const char *port, time_t when)
|
||||
* be let in right now.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
243
lib/prototypes.h
243
lib/prototypes.h
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -43,11 +43,12 @@
|
||||
#define _PROTOTYPES_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_UTMPX_H
|
||||
#ifdef USE_UTMPX
|
||||
#include <utmpx.h>
|
||||
#else
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <shadow.h>
|
||||
@@ -56,14 +57,18 @@
|
||||
#include "defines.h"
|
||||
#include "commonio.h"
|
||||
|
||||
extern char *Prog;
|
||||
|
||||
/* addgrps.c */
|
||||
#if defined (HAVE_SETGROUPS) && ! defined (USE_PAM)
|
||||
extern int add_groups (const char *);
|
||||
extern void add_cons_grps (void);
|
||||
#endif
|
||||
|
||||
/* age.c */
|
||||
extern void agecheck (const struct passwd *, const struct spwd *);
|
||||
extern int expire (const struct passwd *, const struct spwd *);
|
||||
extern int isexpired (const struct passwd *, const struct spwd *);
|
||||
extern void agecheck (/*@null@*/const struct spwd *);
|
||||
extern int expire (const struct passwd *, /*@null@*/const struct spwd *);
|
||||
/* isexpired.c */
|
||||
extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *);
|
||||
|
||||
/* basename() renamed to Basename() to avoid libc name space confusion */
|
||||
/* basename.c */
|
||||
@@ -73,16 +78,51 @@ extern char *Basename (char *str);
|
||||
extern int chown_tree (const char *, uid_t, uid_t, gid_t, gid_t);
|
||||
|
||||
/* chowntty.c */
|
||||
extern void chown_tty (const char *, const struct passwd *);
|
||||
extern void chown_tty (const struct passwd *);
|
||||
|
||||
/* cleanup.c */
|
||||
typedef void (*cleanup_function) (/*@null@*/void *arg);
|
||||
void add_cleanup (cleanup_function pcf, /*@null@*/void *arg);
|
||||
void del_cleanup (cleanup_function pcf);
|
||||
void do_cleanups (void);
|
||||
|
||||
/* cleanup_group.c */
|
||||
struct cleanup_info_mod {
|
||||
char *audit_msg;
|
||||
char *action;
|
||||
char *name;
|
||||
};
|
||||
void cleanup_report_add_group (void *group_name);
|
||||
void cleanup_report_add_group_group (void *group_name);
|
||||
#ifdef SHADOWGRP
|
||||
void cleanup_report_add_group_gshadow (void *group_name);
|
||||
#endif
|
||||
void cleanup_report_del_group (void *group_name);
|
||||
void cleanup_report_del_group_group (void *group_name);
|
||||
#ifdef SHADOWGRP
|
||||
void cleanup_report_del_group_gshadow (void *group_name);
|
||||
#endif
|
||||
void cleanup_report_mod_passwd (void *cleanup_info);
|
||||
void cleanup_report_mod_group (void *cleanup_info);
|
||||
void cleanup_report_mod_gshadow (void *cleanup_info);
|
||||
void cleanup_unlock_group (/*@null@*/void *unused);
|
||||
#ifdef SHADOWGRP
|
||||
void cleanup_unlock_gshadow (/*@null@*/void *unused);
|
||||
#endif
|
||||
void cleanup_unlock_passwd (/*@null@*/void *unused);
|
||||
|
||||
/* console.c */
|
||||
extern int console (const char *);
|
||||
extern bool console (const char *);
|
||||
|
||||
/* copydir.c */
|
||||
extern int copy_tree (const char *src_root, const char *dst_root,
|
||||
long int uid, long int gid);
|
||||
extern int remove_tree (const char *root);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
extern int selinux_file_context (const char *dst_name);
|
||||
#endif
|
||||
|
||||
/* encrypt.c */
|
||||
extern char *pw_encrypt (const char *, const char *);
|
||||
|
||||
@@ -90,7 +130,7 @@ extern char *pw_encrypt (const char *, const char *);
|
||||
extern void pw_entry (const char *, struct passwd *);
|
||||
|
||||
/* env.c */
|
||||
extern void addenv (const char *, const char *);
|
||||
extern void addenv (const char *, /*@null@*/const char *);
|
||||
extern void initenv (void);
|
||||
extern void set_env (int, char *const *);
|
||||
extern void sanitize_env (void);
|
||||
@@ -99,52 +139,89 @@ extern void sanitize_env (void);
|
||||
extern void change_field (char *, size_t, const char *);
|
||||
extern int valid_field (const char *, const char *);
|
||||
|
||||
/* find_new_ids.c */
|
||||
extern int find_new_uid (int sys_user, uid_t *uid, uid_t const *preferred_uid);
|
||||
extern int find_new_gid (int sys_group, gid_t *gid, gid_t const *preferred_gid);
|
||||
/* find_new_gid.c */
|
||||
extern int find_new_gid (bool sys_group,
|
||||
gid_t *gid,
|
||||
/*@null@*/gid_t const *preferred_gid);
|
||||
|
||||
/* find_new_uid.c */
|
||||
extern int find_new_uid (bool sys_user,
|
||||
uid_t *uid,
|
||||
/*@null@*/uid_t const *preferred_uid);
|
||||
|
||||
/* get_gid.c */
|
||||
extern int get_gid (const char *gidstr, gid_t *gid);
|
||||
|
||||
/* getgr_nam_gid.c */
|
||||
extern /*@null@*/struct group *getgr_nam_gid (const char *grname);
|
||||
|
||||
/* getlong.c */
|
||||
extern int getlong(const char *numstr, long int *result);
|
||||
extern int getlong (const char *numstr, /*@out@*/long int *result);
|
||||
|
||||
/* get_pid.c */
|
||||
extern int get_pid (const char *pidstr, pid_t *pid);
|
||||
|
||||
/* getrange */
|
||||
extern int getrange (char *range,
|
||||
unsigned long *min, bool *has_min,
|
||||
unsigned long *max, bool *has_max);
|
||||
|
||||
/* get_uid.c */
|
||||
extern int get_uid (const char *uidstr, uid_t *uid);
|
||||
|
||||
/* getulong.c */
|
||||
extern int getulong (const char *numstr, /*@out@*/unsigned long int *result);
|
||||
|
||||
/* fputsx.c */
|
||||
extern char *fgetsx (char *, int, FILE *);
|
||||
extern /*@null@*/char *fgetsx (/*@returned@*/ /*@out@*/char *, int, FILE *);
|
||||
extern int fputsx (const char *, FILE *);
|
||||
|
||||
/* groupio.c */
|
||||
extern void __gr_del_entry (const struct commonio_entry *ent);
|
||||
extern struct commonio_db *__gr_get_db (void);
|
||||
extern struct commonio_entry *__gr_get_head (void);
|
||||
extern /*@observer@*/const struct commonio_db *__gr_get_db (void);
|
||||
extern /*@dependent@*/ /*@null@*/struct commonio_entry *__gr_get_head (void);
|
||||
extern void __gr_set_changed (void);
|
||||
|
||||
/* groupmem.c */
|
||||
extern struct group *__gr_dup (const struct group *grent);
|
||||
extern /*@null@*/ /*@only@*/struct group *__gr_dup (const struct group *grent);
|
||||
extern void gr_free (/*@out@*/ /*@only@*/struct group *grent);
|
||||
|
||||
/* hushed.c */
|
||||
extern int hushed (const struct passwd *);
|
||||
extern bool hushed (const char *username);
|
||||
|
||||
/* audit_help.c */
|
||||
#ifdef WITH_AUDIT
|
||||
extern int audit_fd;
|
||||
extern void audit_help_open (void);
|
||||
/* Use AUDIT_NO_ID when a name is provided to audit_logger instead of an ID */
|
||||
#define AUDIT_NO_ID ((unsigned int) -1)
|
||||
typedef enum {
|
||||
SHADOW_AUDIT_FAILURE = 0,
|
||||
SHADOW_AUDIT_SUCCESS = 1} shadow_audit_result;
|
||||
extern void audit_logger (int type, const char *pgname, const char *op,
|
||||
const char *name, unsigned int id, int result);
|
||||
const char *name, unsigned int id,
|
||||
shadow_audit_result result);
|
||||
void audit_logger_message (const char *message, shadow_audit_result result);
|
||||
#endif
|
||||
|
||||
/* limits.c */
|
||||
#ifndef USE_PAM
|
||||
extern void setup_limits (const struct passwd *);
|
||||
#endif
|
||||
|
||||
/* list.c */
|
||||
extern char **add_list (char **, const char *);
|
||||
extern char **del_list (char **, const char *);
|
||||
extern char **dup_list (char *const *);
|
||||
extern int is_on_list (char *const *, const char *);
|
||||
extern char **comma_to_list (const char *);
|
||||
extern /*@only@*/ /*@out@*/char **add_list (/*@returned@*/ /*@only@*/char **, const char *);
|
||||
extern /*@only@*/ /*@out@*/char **del_list (/*@returned@*/ /*@only@*/char **, const char *);
|
||||
extern /*@only@*/ /*@out@*/char **dup_list (char *const *);
|
||||
extern bool is_on_list (char *const *list, const char *member);
|
||||
extern /*@only@*/char **comma_to_list (const char *);
|
||||
|
||||
/* log.c */
|
||||
extern void dolastlog (struct lastlog *ll,
|
||||
const struct passwd *pw,
|
||||
const char *line,
|
||||
const char *host);
|
||||
extern void dolastlog (
|
||||
struct lastlog *ll,
|
||||
const struct passwd *pw,
|
||||
/*@unique@*/const char *line,
|
||||
/*@unique@*/const char *host);
|
||||
|
||||
/* login_nopam.c */
|
||||
extern int login_access (const char *user, const char *from);
|
||||
@@ -159,22 +236,37 @@ extern void mailcheck (void);
|
||||
extern void motd (void);
|
||||
|
||||
/* myname.c */
|
||||
extern struct passwd *get_my_pwent (void);
|
||||
extern /*@null@*/struct passwd *get_my_pwent (void);
|
||||
|
||||
/* pam_pass_non_interractive.c */
|
||||
#ifdef USE_PAM
|
||||
extern int do_pam_passwd_non_interractive (const char *pam_service,
|
||||
const char *username,
|
||||
const char* password);
|
||||
#endif /* USE_PAM */
|
||||
|
||||
/* obscure.c */
|
||||
#ifndef USE_PAM
|
||||
extern int obscure (const char *, const char *, const struct passwd *);
|
||||
#endif
|
||||
|
||||
/* pam_pass.c */
|
||||
extern void do_pam_passwd (const char *, int, int);
|
||||
#ifdef USE_PAM
|
||||
extern void do_pam_passwd (const char *user, bool silent, bool change_expired);
|
||||
#endif
|
||||
|
||||
/* port.c */
|
||||
extern int isttytime (const char *, const char *, time_t);
|
||||
extern bool isttytime (const char *, const char *, time_t);
|
||||
|
||||
/* pwd2spwd.c */
|
||||
#ifndef USE_PAM
|
||||
extern struct spwd *pwd_to_spwd (const struct passwd *);
|
||||
#endif
|
||||
|
||||
/* pwdcheck.c */
|
||||
#ifndef USE_PAM
|
||||
extern void passwd_check (const char *, const char *, const char *);
|
||||
#endif
|
||||
|
||||
/* pwd_init.c */
|
||||
extern void pwd_init (void);
|
||||
@@ -182,21 +274,27 @@ extern void pwd_init (void);
|
||||
/* pwio.c */
|
||||
extern void __pw_del_entry (const struct commonio_entry *ent);
|
||||
extern struct commonio_db *__pw_get_db (void);
|
||||
extern struct commonio_entry *__pw_get_head (void);
|
||||
extern /*@dependent@*/ /*@null@*/struct commonio_entry *__pw_get_head (void);
|
||||
|
||||
/* pwmem.c */
|
||||
extern struct passwd *__pw_dup (const struct passwd *pwent);
|
||||
extern /*@null@*/ /*@only@*/struct passwd *__pw_dup (const struct passwd *pwent);
|
||||
extern void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent);
|
||||
|
||||
/* rlogin.c */
|
||||
extern int do_rlogin (const char *, char *, int, char *, int);
|
||||
extern int do_rlogin (const char *remote_host, char *name, size_t namelen,
|
||||
char *term, size_t termlen);
|
||||
|
||||
/* salt.c */
|
||||
extern char *crypt_make_salt (const char *meth, void *arg);
|
||||
extern /*@observer@*/const char *crypt_make_salt (/*@null@*/const char *meth, /*@null@*/void *arg);
|
||||
|
||||
/* setugid.c */
|
||||
extern int setup_groups (const struct passwd *);
|
||||
extern int change_uid (const struct passwd *);
|
||||
extern int setup_uid_gid (const struct passwd *, int);
|
||||
extern int setup_groups (const struct passwd *info);
|
||||
extern int change_uid (const struct passwd *info);
|
||||
#if (defined HAVE_INITGROUPS) && (! defined USE_PAM)
|
||||
extern int setup_uid_gid (const struct passwd *info, bool is_console);
|
||||
#else
|
||||
extern int setup_uid_gid (const struct passwd *info);
|
||||
#endif
|
||||
|
||||
/* setup.c */
|
||||
extern void setup (struct passwd *);
|
||||
@@ -210,21 +308,34 @@ extern struct group *sgetgrent (const char *buf);
|
||||
/* sgetpwent.c */
|
||||
extern struct passwd *sgetpwent (const char *buf);
|
||||
|
||||
/* sgetspent.c */
|
||||
#ifndef HAVE_SGETSPENT
|
||||
extern struct spwd *sgetspent (const char *string);
|
||||
#endif
|
||||
|
||||
/* sgroupio.c */
|
||||
extern void __sgr_del_entry (const struct commonio_entry *ent);
|
||||
extern struct sgrp *__sgr_dup (const struct sgrp *sgent);
|
||||
extern struct commonio_entry *__sgr_get_head (void);
|
||||
extern /*@null@*/ /*@only@*/struct sgrp *__sgr_dup (const struct sgrp *sgent);
|
||||
extern void sgr_free (/*@out@*/ /*@only@*/struct sgrp *sgent);
|
||||
extern /*@dependent@*/ /*@null@*/struct commonio_entry *__sgr_get_head (void);
|
||||
extern void __sgr_set_changed (void);
|
||||
|
||||
/* shadowio.c */
|
||||
extern struct commonio_entry *__spw_get_head (void);
|
||||
extern /*@dependent@*/ /*@null@*/struct commonio_entry *__spw_get_head (void);
|
||||
extern void __spw_del_entry (const struct commonio_entry *ent);
|
||||
|
||||
/* shadowmem.c */
|
||||
extern struct spwd *__spw_dup (const struct spwd *spent);
|
||||
extern /*@null@*/ /*@only@*/struct spwd *__spw_dup (const struct spwd *spent);
|
||||
extern void spw_free (/*@out@*/ /*@only@*/struct spwd *spent);
|
||||
|
||||
/* shell.c */
|
||||
extern int shell (const char *, const char *, char *const *);
|
||||
extern int shell (const char *file, /*@null@*/const char *arg, char *const envp[]);
|
||||
|
||||
/* system.c */
|
||||
extern int safe_system (const char *command,
|
||||
const char *argv[],
|
||||
const char *env[],
|
||||
int ignore_stderr);
|
||||
|
||||
/* strtoday.c */
|
||||
extern long strtoday (const char *);
|
||||
@@ -233,7 +344,10 @@ extern long strtoday (const char *);
|
||||
extern int check_su_auth (const char *actual_id, const char *wanted_id);
|
||||
|
||||
/* sulog.c */
|
||||
extern void sulog (const char *, int, const char *, const char *);
|
||||
extern void sulog (const char *tty,
|
||||
bool success,
|
||||
const char *oldname,
|
||||
const char *name);
|
||||
|
||||
/* sub.c */
|
||||
extern void subsystem (const struct passwd *);
|
||||
@@ -242,34 +356,51 @@ extern void subsystem (const struct passwd *);
|
||||
extern void ttytype (const char *);
|
||||
|
||||
/* tz.c */
|
||||
#ifndef USE_PAM
|
||||
extern char *tz (const char *);
|
||||
#endif
|
||||
|
||||
/* ulimit.c */
|
||||
extern void set_filesize_limit (int);
|
||||
extern int set_filesize_limit (int blocks);
|
||||
|
||||
/* user_busy.c */
|
||||
extern int user_busy (const char *name, uid_t uid);
|
||||
|
||||
/* utmp.c */
|
||||
extern void checkutmp (int);
|
||||
extern void setutmp (const char *, const char *, const char *);
|
||||
extern /*@null@*/struct utmp *get_current_utmp (void);
|
||||
extern struct utmp *prepare_utmp (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
/*@null@*/const struct utmp *ut);
|
||||
extern int setutmp (struct utmp *ut);
|
||||
#ifdef USE_UTMPX
|
||||
extern struct utmpx *prepare_utmpx (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
/*@null@*/const struct utmp *ut);
|
||||
extern int setutmpx (struct utmpx *utx);
|
||||
#endif /* USE_UTMPX */
|
||||
|
||||
/* valid.c */
|
||||
extern int valid (const char *, const struct passwd *);
|
||||
extern bool valid (const char *, const struct passwd *);
|
||||
|
||||
/* xmalloc.c */
|
||||
extern char *xmalloc (size_t);
|
||||
extern char *xstrdup (const char *);
|
||||
extern /*@maynotreturn@*/ /*@out@*//*@only@*/char *xmalloc (size_t size)
|
||||
/*@ensures MaxSet(result) == (size - 1); @*/;
|
||||
extern /*@maynotreturn@*/ /*@only@*/char *xstrdup (const char *);
|
||||
|
||||
/* xgetpwnam.c */
|
||||
extern struct passwd *xgetpwnam (const char *);
|
||||
extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *);
|
||||
/* xgetpwuid.c */
|
||||
extern struct passwd *xgetpwuid (uid_t);
|
||||
extern /*@null@*/ /*@only@*/struct passwd *xgetpwuid (uid_t);
|
||||
/* xgetgrnam.c */
|
||||
extern struct group *xgetgrnam (const char *);
|
||||
extern /*@null@*/ /*@only@*/struct group *xgetgrnam (const char *);
|
||||
/* xgetgrgid.c */
|
||||
extern struct group *xgetgrgid (gid_t);
|
||||
extern /*@null@*/ /*@only@*/struct group *xgetgrgid (gid_t);
|
||||
/* xgetspnam.c */
|
||||
extern struct spwd *xgetspnam(const char *);
|
||||
extern /*@null@*/ /*@only@*/struct spwd *xgetspnam(const char *);
|
||||
|
||||
/* yesno.c */
|
||||
extern int yes_or_no (int read_only);
|
||||
extern bool yes_or_no (bool read_only);
|
||||
|
||||
#endif /* _PROTOTYPES_H */
|
||||
|
||||
57
lib/pwauth.c
57
lib/pwauth.c
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1992 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -54,8 +54,8 @@ static const char *PROMPT = gettext_noop ("Password: ");
|
||||
static const char *PROMPT = gettext_noop ("%s's Password: ");
|
||||
#endif
|
||||
|
||||
int wipe_clear_pass = 1;
|
||||
char *clear_pass = NULL;
|
||||
bool wipe_clear_pass = true;
|
||||
/*@null@*/char *clear_pass = NULL;
|
||||
|
||||
/*
|
||||
* pw_auth - perform getpass/crypt authentication
|
||||
@@ -65,8 +65,10 @@ char *clear_pass = NULL;
|
||||
* compared.
|
||||
*/
|
||||
|
||||
int
|
||||
pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
int pw_auth (const char *cipher,
|
||||
const char *user,
|
||||
int reason,
|
||||
/*@null@*/const char *input)
|
||||
{
|
||||
char prompt[1024];
|
||||
char *clear = NULL;
|
||||
@@ -74,7 +76,7 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
int retval;
|
||||
|
||||
#ifdef SKEY
|
||||
int use_skey = 0;
|
||||
bool use_skey = false;
|
||||
char challenge_info[40];
|
||||
struct skey skey;
|
||||
#endif
|
||||
@@ -83,15 +85,17 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
* There are programs for adding and deleting authentication data.
|
||||
*/
|
||||
|
||||
if (reason == PW_ADD || reason == PW_DELETE)
|
||||
if ((PW_ADD == reason) || (PW_DELETE == reason)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are even programs for changing the user name ...
|
||||
*/
|
||||
|
||||
if (reason == PW_CHANGE && input != (char *) 0)
|
||||
if ((PW_CHANGE == reason) && (NULL != input)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
@@ -102,8 +106,9 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
* revisited.
|
||||
*/
|
||||
|
||||
if (reason == PW_CHANGE && getuid () == 0)
|
||||
if ((PW_CHANGE == reason) && (getuid () == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
@@ -114,8 +119,9 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
* matter.
|
||||
*/
|
||||
|
||||
if (cipher == (char *) 0 || *cipher == '\0')
|
||||
if ((NULL == cipher) || ('\0' == *cipher)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SKEY
|
||||
/*
|
||||
@@ -132,8 +138,9 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
# define skeychallenge(s,u,c) skeychallenge(s,u,c,sizeof(c))
|
||||
# endif
|
||||
|
||||
if (skeychallenge (&skey, user, challenge_info) == 0)
|
||||
use_skey = 1;
|
||||
if (skeychallenge (&skey, user, challenge_info) == 0) {
|
||||
use_skey = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -141,17 +148,20 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
* get the cleartext password for us.
|
||||
*/
|
||||
|
||||
if (reason != PW_FTP && reason != PW_REXEC && !input) {
|
||||
if (!(cp = getdef_str ("LOGIN_STRING")))
|
||||
if ((PW_FTP != reason) && (PW_REXEC != reason) && (NULL == input)) {
|
||||
cp = getdef_str ("LOGIN_STRING");
|
||||
if (NULL == cp) {
|
||||
cp = _(PROMPT);
|
||||
}
|
||||
#ifdef SKEY
|
||||
if (use_skey)
|
||||
if (use_skey) {
|
||||
printf ("[%s]\n", challenge_info);
|
||||
}
|
||||
#endif
|
||||
|
||||
snprintf (prompt, sizeof prompt, cp, user);
|
||||
clear = getpass (prompt);
|
||||
if (!clear) {
|
||||
if (NULL == clear) {
|
||||
static char c[1];
|
||||
|
||||
c[0] = '\0';
|
||||
@@ -177,9 +187,9 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
* ...Re-prompt, with echo on.
|
||||
* -- AR 8/22/1999
|
||||
*/
|
||||
if (retval && !input[0] && (use_skey)) {
|
||||
if ((0 != retval) && ('\0' == input[0]) && use_skey) {
|
||||
clear = getpass (prompt);
|
||||
if (!clear) {
|
||||
if (NULL == clear) {
|
||||
static char c[1];
|
||||
|
||||
c[0] = '\0';
|
||||
@@ -188,13 +198,15 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
input = clear;
|
||||
}
|
||||
|
||||
if (retval && use_skey) {
|
||||
if ((0 != retval) && use_skey) {
|
||||
int passcheck = -1;
|
||||
|
||||
if (skeyverify (&skey, input) == 0)
|
||||
if (skeyverify (&skey, input) == 0) {
|
||||
passcheck = skey.n;
|
||||
if (passcheck > 0)
|
||||
}
|
||||
if (passcheck > 0) {
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -206,8 +218,9 @@ pw_auth (const char *cipher, const char *user, int reason, const char *input)
|
||||
*/
|
||||
|
||||
clear_pass = clear;
|
||||
if (wipe_clear_pass && clear && *clear)
|
||||
if (wipe_clear_pass && (NULL != clear) && ('\0' != *clear)) {
|
||||
strzero (clear);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#else /* !USE_PAM */
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1992 - 1993, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1997, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2009 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,7 +35,10 @@
|
||||
*/
|
||||
|
||||
#ifndef USE_PAM
|
||||
int pw_auth (const char *cipher, const char *user, int flag, const char *input);
|
||||
int pw_auth (const char *cipher,
|
||||
const char *user,
|
||||
int flag,
|
||||
/*@null@*/const char *input);
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
/*
|
||||
|
||||
36
lib/pwio.c
36
lib/pwio.c
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -42,23 +42,18 @@
|
||||
#include "commonio.h"
|
||||
#include "pwio.h"
|
||||
|
||||
static void *passwd_dup (const void *ent)
|
||||
static /*@null@*/ /*@only@*/void *passwd_dup (const void *ent)
|
||||
{
|
||||
const struct passwd *pw = ent;
|
||||
|
||||
return __pw_dup (pw);
|
||||
}
|
||||
|
||||
static void passwd_free (void *ent)
|
||||
static void passwd_free (/*@out@*/ /*@only@*/void *ent)
|
||||
{
|
||||
struct passwd *pw = ent;
|
||||
|
||||
free (pw->pw_name);
|
||||
free (pw->pw_passwd);
|
||||
free (pw->pw_gecos);
|
||||
free (pw->pw_dir);
|
||||
free (pw->pw_shell);
|
||||
free (pw);
|
||||
pw_free (pw);
|
||||
}
|
||||
|
||||
static const char *passwd_getname (const void *ent)
|
||||
@@ -102,17 +97,22 @@ static struct commonio_db passwd_db = {
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
0, /* changed */
|
||||
0, /* isopen */
|
||||
0, /* locked */
|
||||
0 /* readonly */
|
||||
false, /* changed */
|
||||
false, /* isopen */
|
||||
false, /* locked */
|
||||
false /* readonly */
|
||||
};
|
||||
|
||||
int pw_name (const char *filename)
|
||||
int pw_setdbname (const char *filename)
|
||||
{
|
||||
return commonio_setname (&passwd_db, filename);
|
||||
}
|
||||
|
||||
/*@observer@*/const char *pw_dbname (void)
|
||||
{
|
||||
return passwd_db.filename;
|
||||
}
|
||||
|
||||
int pw_lock (void)
|
||||
{
|
||||
return commonio_lock (&passwd_db);
|
||||
@@ -123,12 +123,12 @@ int pw_open (int mode)
|
||||
return commonio_open (&passwd_db, mode);
|
||||
}
|
||||
|
||||
const struct passwd *pw_locate (const char *name)
|
||||
/*@observer@*/ /*@null@*/const struct passwd *pw_locate (const char *name)
|
||||
{
|
||||
return commonio_locate (&passwd_db, name);
|
||||
}
|
||||
|
||||
const struct passwd *pw_locate_uid (uid_t uid)
|
||||
/*@observer@*/ /*@null@*/const struct passwd *pw_locate_uid (uid_t uid)
|
||||
{
|
||||
const struct passwd *pwd;
|
||||
|
||||
@@ -155,7 +155,7 @@ int pw_rewind (void)
|
||||
return commonio_rewind (&passwd_db);
|
||||
}
|
||||
|
||||
const struct passwd *pw_next (void)
|
||||
/*@observer@*/ /*@null@*/const struct passwd *pw_next (void)
|
||||
{
|
||||
return commonio_next (&passwd_db);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ int pw_unlock (void)
|
||||
return commonio_unlock (&passwd_db);
|
||||
}
|
||||
|
||||
struct commonio_entry *__pw_get_head (void)
|
||||
/*@null@*/struct commonio_entry *__pw_get_head (void)
|
||||
{
|
||||
return passwd_db.head;
|
||||
}
|
||||
|
||||
22
lib/pwio.h
22
lib/pwio.h
@@ -31,17 +31,25 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
#ifndef _PWIO_H
|
||||
#define _PWIO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
extern int pw_close (void);
|
||||
extern const struct passwd *pw_locate (const char *);
|
||||
extern const struct passwd *pw_locate_uid (uid_t uid);
|
||||
extern /*@observer@*/ /*@null@*/const struct passwd *pw_locate (const char *name);
|
||||
extern /*@observer@*/ /*@null@*/const struct passwd *pw_locate_uid (uid_t uid);
|
||||
extern int pw_lock (void);
|
||||
extern int pw_name (const char *);
|
||||
extern const struct passwd *pw_next (void);
|
||||
extern int pw_open (int);
|
||||
extern int pw_remove (const char *);
|
||||
extern int pw_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *pw_dbname (void);
|
||||
extern /*@observer@*/ /*@null@*/const struct passwd *pw_next (void);
|
||||
extern int pw_open (int mode);
|
||||
extern int pw_remove (const char *name);
|
||||
extern int pw_rewind (void);
|
||||
extern int pw_unlock (void);
|
||||
extern int pw_update (const struct passwd *);
|
||||
extern int pw_update (const struct passwd *pw);
|
||||
extern int pw_sort (void);
|
||||
|
||||
#endif
|
||||
|
||||
45
lib/pwmem.c
45
lib/pwmem.c
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,29 +35,52 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#include "pwio.h"
|
||||
|
||||
struct passwd *__pw_dup (const struct passwd *pwent)
|
||||
/*@null@*/ /*@only@*/struct passwd *__pw_dup (const struct passwd *pwent)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
if (!(pw = (struct passwd *) malloc (sizeof *pw)))
|
||||
pw = (struct passwd *) malloc (sizeof *pw);
|
||||
if (NULL == pw) {
|
||||
return NULL;
|
||||
}
|
||||
*pw = *pwent;
|
||||
if (!(pw->pw_name = strdup (pwent->pw_name)))
|
||||
pw->pw_name = strdup (pwent->pw_name);
|
||||
if (NULL == pw->pw_name) {
|
||||
return NULL;
|
||||
if (!(pw->pw_passwd = strdup (pwent->pw_passwd)))
|
||||
}
|
||||
pw->pw_passwd = strdup (pwent->pw_passwd);
|
||||
if (NULL == pw->pw_passwd) {
|
||||
return NULL;
|
||||
if (!(pw->pw_gecos = strdup (pwent->pw_gecos)))
|
||||
}
|
||||
pw->pw_gecos = strdup (pwent->pw_gecos);
|
||||
if (NULL == pw->pw_gecos) {
|
||||
return NULL;
|
||||
if (!(pw->pw_dir = strdup (pwent->pw_dir)))
|
||||
}
|
||||
pw->pw_dir = strdup (pwent->pw_dir);
|
||||
if (NULL == pw->pw_dir) {
|
||||
return NULL;
|
||||
if (!(pw->pw_shell = strdup (pwent->pw_shell)))
|
||||
}
|
||||
pw->pw_shell = strdup (pwent->pw_shell);
|
||||
if (NULL == pw->pw_shell) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent)
|
||||
{
|
||||
free (pwent->pw_name);
|
||||
memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
|
||||
free (pwent->pw_passwd);
|
||||
free (pwent->pw_gecos);
|
||||
free (pwent->pw_dir);
|
||||
free (pwent->pw_shell);
|
||||
free (pwent);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <grp.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
@@ -87,10 +88,12 @@ static char **list (char *s)
|
||||
if (!s || s[0] == '\0')
|
||||
break;
|
||||
members[i++] = s;
|
||||
while (*s && *s != ',')
|
||||
while (('\0' != *s) && (',' != *s)) {
|
||||
s++;
|
||||
if (*s)
|
||||
}
|
||||
if ('\0' != *s) {
|
||||
*s++ = '\0';
|
||||
}
|
||||
}
|
||||
members[i] = (char *) 0;
|
||||
return members;
|
||||
@@ -120,22 +123,32 @@ struct group *sgetgrent (const char *buf)
|
||||
}
|
||||
strcpy (grpbuf, buf);
|
||||
|
||||
if ((cp = strrchr (grpbuf, '\n')))
|
||||
cp = strrchr (grpbuf, '\n');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
|
||||
for (cp = grpbuf, i = 0; i < NFIELDS && cp; i++) {
|
||||
grpfields[i] = cp;
|
||||
if ((cp = strchr (cp, ':')))
|
||||
*cp++ = 0;
|
||||
}
|
||||
if (i < (NFIELDS - 1) || *grpfields[2] == '\0')
|
||||
return 0;
|
||||
|
||||
for (cp = grpbuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) {
|
||||
grpfields[i] = cp;
|
||||
cp = strchr (cp, ':');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
if (i < (NFIELDS - 1) || *grpfields[2] == '\0') {
|
||||
return (struct group *) 0;
|
||||
}
|
||||
grent.gr_name = grpfields[0];
|
||||
grent.gr_passwd = grpfields[1];
|
||||
grent.gr_gid = atoi (grpfields[2]);
|
||||
if (get_gid (grpfields[2], &grent.gr_gid) == 0) {
|
||||
return (struct group *) 0;
|
||||
}
|
||||
grent.gr_mem = list (grpfields[3]);
|
||||
if (!grent.gr_mem)
|
||||
if (NULL == grent.gr_mem) {
|
||||
return (struct group *) 0; /* out of memory */
|
||||
}
|
||||
|
||||
return &grent;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ struct passwd *sgetpwent (const char *buf)
|
||||
static char pwdbuf[1024];
|
||||
register int i;
|
||||
register char *cp;
|
||||
char *ep;
|
||||
char *fields[NFIELDS];
|
||||
|
||||
/*
|
||||
@@ -77,15 +76,18 @@ struct passwd *sgetpwent (const char *buf)
|
||||
* field. The fields are converted into NUL terminated strings.
|
||||
*/
|
||||
|
||||
for (cp = pwdbuf, i = 0; i < NFIELDS && cp; i++) {
|
||||
for (cp = pwdbuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) {
|
||||
fields[i] = cp;
|
||||
while (*cp && *cp != ':')
|
||||
++cp;
|
||||
while (('\0' != *cp) && (':' != *cp)) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (*cp)
|
||||
*cp++ = '\0';
|
||||
else
|
||||
cp = 0;
|
||||
if ('\0' != *cp) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
} else {
|
||||
cp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,7 +96,7 @@ struct passwd *sgetpwent (const char *buf)
|
||||
*/
|
||||
|
||||
if (i != NFIELDS || *fields[2] == '\0' || *fields[3] == '\0')
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Each of the fields is converted the appropriate data type
|
||||
@@ -105,13 +107,11 @@ struct passwd *sgetpwent (const char *buf)
|
||||
|
||||
pwent.pw_name = fields[0];
|
||||
pwent.pw_passwd = fields[1];
|
||||
if (fields[2][0] == '\0' ||
|
||||
((pwent.pw_uid = strtol (fields[2], &ep, 10)) == 0 && *ep)) {
|
||||
return 0;
|
||||
if (get_uid (fields[2], &pwent.pw_uid) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (fields[3][0] == '\0' ||
|
||||
((pwent.pw_gid = strtol (fields[3], &ep, 10)) == 0 && *ep)) {
|
||||
return 0;
|
||||
if (get_gid (fields[3], &pwent.pw_gid) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
pwent.pw_gecos = fields[4];
|
||||
pwent.pw_dir = fields[5];
|
||||
@@ -119,3 +119,4 @@ struct passwd *sgetpwent (const char *buf)
|
||||
|
||||
return &pwent;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2009 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -31,6 +32,9 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Newer versions of Linux libc already have shadow support. */
|
||||
#ifndef HAVE_SGETSPENT
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -56,32 +60,41 @@ struct spwd *sgetspent (const char *string)
|
||||
* have to do that to our private copy.
|
||||
*/
|
||||
|
||||
if (strlen (string) >= sizeof spwbuf)
|
||||
if (strlen (string) >= sizeof spwbuf) {
|
||||
return 0; /* fail if too long */
|
||||
}
|
||||
strcpy (spwbuf, string);
|
||||
|
||||
if ((cp = strrchr (spwbuf, '\n')))
|
||||
cp = strrchr (spwbuf, '\n');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Tokenize the string into colon separated fields. Allow up to
|
||||
* FIELDS different fields.
|
||||
*/
|
||||
|
||||
for (cp = spwbuf, i = 0; *cp && i < FIELDS; i++) {
|
||||
for (cp = spwbuf, i = 0; ('\0' != *cp) && (i < FIELDS); i++) {
|
||||
fields[i] = cp;
|
||||
while (*cp && *cp != ':')
|
||||
while (('\0' != *cp) && (':' != *cp)) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (*cp)
|
||||
*cp++ = '\0';
|
||||
if ('\0' != *cp) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == (FIELDS - 1))
|
||||
if (i == (FIELDS - 1)) {
|
||||
fields[i++] = cp;
|
||||
}
|
||||
|
||||
if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
|
||||
if ( ((NULL != cp) && ('\0' != *cp)) ||
|
||||
((i != FIELDS) && (i != OFIELDS)) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start populating the structure. The fields are all in
|
||||
@@ -97,28 +110,34 @@ struct spwd *sgetspent (const char *string)
|
||||
* incorrectly formatted number.
|
||||
*/
|
||||
|
||||
if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp) {
|
||||
return 0;
|
||||
} else if (fields[2][0] == '\0')
|
||||
if (fields[2][0] == '\0') {
|
||||
spwd.sp_lstchg = -1;
|
||||
} else if ( (getlong (fields[2], &spwd.sp_lstchg) == 0)
|
||||
|| (spwd.sp_lstchg < 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the minimum period between password changes.
|
||||
*/
|
||||
|
||||
if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp) {
|
||||
return 0;
|
||||
} else if (fields[3][0] == '\0')
|
||||
if (fields[3][0] == '\0') {
|
||||
spwd.sp_min = -1;
|
||||
} else if ( (getlong (fields[3], &spwd.sp_min) == 0)
|
||||
|| (spwd.sp_min < 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the maximum number of days a password is valid.
|
||||
*/
|
||||
|
||||
if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp) {
|
||||
return 0;
|
||||
} else if (fields[4][0] == '\0')
|
||||
if (fields[4][0] == '\0') {
|
||||
spwd.sp_max = -1;
|
||||
} else if ( (getlong (fields[4], &spwd.sp_max) == 0)
|
||||
|| (spwd.sp_max < 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
|
||||
@@ -126,8 +145,10 @@ struct spwd *sgetspent (const char *string)
|
||||
*/
|
||||
|
||||
if (i == OFIELDS) {
|
||||
spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
|
||||
spwd.sp_flag = -1;
|
||||
spwd.sp_warn = -1;
|
||||
spwd.sp_inact = -1;
|
||||
spwd.sp_expire = -1;
|
||||
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||
|
||||
return &spwd;
|
||||
}
|
||||
@@ -136,40 +157,52 @@ struct spwd *sgetspent (const char *string)
|
||||
* Get the number of days of password expiry warning.
|
||||
*/
|
||||
|
||||
if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp) {
|
||||
return 0;
|
||||
} else if (fields[5][0] == '\0')
|
||||
if (fields[5][0] == '\0') {
|
||||
spwd.sp_warn = -1;
|
||||
} else if ( (getlong (fields[5], &spwd.sp_warn) == 0)
|
||||
|| (spwd.sp_warn < 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of days of inactivity before an account is
|
||||
* disabled.
|
||||
*/
|
||||
|
||||
if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp) {
|
||||
return 0;
|
||||
} else if (fields[6][0] == '\0')
|
||||
if (fields[6][0] == '\0') {
|
||||
spwd.sp_inact = -1;
|
||||
} else if ( (getlong (fields[6], &spwd.sp_inact) == 0)
|
||||
|| (spwd.sp_inact < 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of days after the epoch before the account is
|
||||
* set to expire.
|
||||
*/
|
||||
|
||||
if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp) {
|
||||
return 0;
|
||||
} else if (fields[7][0] == '\0')
|
||||
if (fields[7][0] == '\0') {
|
||||
spwd.sp_expire = -1;
|
||||
} else if ( (getlong (fields[7], &spwd.sp_expire) == 0)
|
||||
|| (spwd.sp_expire < 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This field is reserved for future use. But it isn't supposed
|
||||
* to have anything other than a valid integer in it.
|
||||
*/
|
||||
|
||||
if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp) {
|
||||
if (fields[8][0] == '\0') {
|
||||
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||
} else if (getlong (fields[8], &spwd.sp_flag) == 0) {
|
||||
/* FIXME: add a getulong function */
|
||||
return 0;
|
||||
} else if (fields[8][0] == '\0')
|
||||
spwd.sp_flag = -1;
|
||||
}
|
||||
|
||||
return (&spwd);
|
||||
}
|
||||
#else
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif
|
||||
|
||||
|
||||
118
lib/sgroupio.c
118
lib/sgroupio.c
@@ -42,66 +42,113 @@
|
||||
#include "commonio.h"
|
||||
#include "sgroupio.h"
|
||||
|
||||
struct sgrp *__sgr_dup (const struct sgrp *sgent)
|
||||
/*@null@*/ /*@only@*/struct sgrp *__sgr_dup (const struct sgrp *sgent)
|
||||
{
|
||||
struct sgrp *sg;
|
||||
int i;
|
||||
|
||||
if (!(sg = (struct sgrp *) malloc (sizeof *sg)))
|
||||
sg = (struct sgrp *) malloc (sizeof *sg);
|
||||
if (NULL == sg) {
|
||||
return NULL;
|
||||
}
|
||||
*sg = *sgent;
|
||||
if (!(sg->sg_name = strdup (sgent->sg_name)))
|
||||
sg->sg_name = strdup (sgent->sg_name);
|
||||
if (NULL == sg->sg_name) {
|
||||
free (sg);
|
||||
return NULL;
|
||||
if (!(sg->sg_passwd = strdup (sgent->sg_passwd)))
|
||||
}
|
||||
sg->sg_passwd = strdup (sgent->sg_passwd);
|
||||
if (NULL == sg->sg_passwd) {
|
||||
free (sg->sg_name);
|
||||
free (sg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; sgent->sg_adm[i]; i++);
|
||||
for (i = 0; NULL != sgent->sg_adm[i]; i++);
|
||||
sg->sg_adm = (char **) malloc ((i + 1) * sizeof (char *));
|
||||
if (!sg->sg_adm)
|
||||
if (NULL == sg->sg_adm) {
|
||||
free (sg->sg_passwd);
|
||||
free (sg->sg_name);
|
||||
free (sg);
|
||||
return NULL;
|
||||
for (i = 0; sgent->sg_adm[i]; i++) {
|
||||
}
|
||||
for (i = 0; NULL != sgent->sg_adm[i]; i++) {
|
||||
sg->sg_adm[i] = strdup (sgent->sg_adm[i]);
|
||||
if (!sg->sg_adm[i])
|
||||
if (NULL == sg->sg_adm[i]) {
|
||||
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
||||
free (sg->sg_adm[i]);
|
||||
}
|
||||
free (sg->sg_adm);
|
||||
free (sg->sg_passwd);
|
||||
free (sg->sg_name);
|
||||
free (sg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
sg->sg_adm[i] = NULL;
|
||||
|
||||
for (i = 0; sgent->sg_mem[i]; i++);
|
||||
for (i = 0; NULL != sgent->sg_mem[i]; i++);
|
||||
sg->sg_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
||||
if (!sg->sg_mem)
|
||||
if (NULL == sg->sg_mem) {
|
||||
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
||||
free (sg->sg_adm[i]);
|
||||
}
|
||||
free (sg->sg_adm);
|
||||
free (sg->sg_passwd);
|
||||
free (sg->sg_name);
|
||||
free (sg);
|
||||
return NULL;
|
||||
for (i = 0; sgent->sg_mem[i]; i++) {
|
||||
}
|
||||
for (i = 0; NULL != sgent->sg_mem[i]; i++) {
|
||||
sg->sg_mem[i] = strdup (sgent->sg_mem[i]);
|
||||
if (!sg->sg_mem[i])
|
||||
if (NULL == sg->sg_mem[i]) {
|
||||
for (i = 0; NULL != sg->sg_mem[i]; i++) {
|
||||
free (sg->sg_mem[i]);
|
||||
}
|
||||
free (sg->sg_mem);
|
||||
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
||||
free (sg->sg_adm[i]);
|
||||
}
|
||||
free (sg->sg_adm);
|
||||
free (sg->sg_passwd);
|
||||
free (sg->sg_name);
|
||||
free (sg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
sg->sg_mem[i] = NULL;
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
static void *gshadow_dup (const void *ent)
|
||||
static /*@null@*/ /*@only@*/void *gshadow_dup (const void *ent)
|
||||
{
|
||||
const struct sgrp *sg = ent;
|
||||
|
||||
return __sgr_dup (sg);
|
||||
}
|
||||
|
||||
static void gshadow_free (void *ent)
|
||||
static void gshadow_free (/*@out@*/ /*@only@*/void *ent)
|
||||
{
|
||||
struct sgrp *sg = ent;
|
||||
|
||||
free (sg->sg_name);
|
||||
free (sg->sg_passwd);
|
||||
while (*(sg->sg_adm)) {
|
||||
free (*(sg->sg_adm));
|
||||
sg->sg_adm++;
|
||||
sgr_free (sg);
|
||||
}
|
||||
|
||||
void sgr_free (/*@out@*/ /*@only@*/struct sgrp *sgent)
|
||||
{
|
||||
free (sgent->sg_name);
|
||||
memzero (sgent->sg_passwd, strlen (sgent->sg_passwd));
|
||||
free (sgent->sg_passwd);
|
||||
while (NULL != *(sgent->sg_adm)) {
|
||||
free (*(sgent->sg_adm));
|
||||
sgent->sg_adm++;
|
||||
}
|
||||
while (*(sg->sg_mem)) {
|
||||
free (*(sg->sg_mem));
|
||||
sg->sg_mem++;
|
||||
while (NULL != *(sgent->sg_mem)) {
|
||||
free (*(sgent->sg_mem));
|
||||
sgent->sg_mem++;
|
||||
}
|
||||
free (sg);
|
||||
free (sgent);
|
||||
}
|
||||
|
||||
static const char *gshadow_getname (const void *ent)
|
||||
@@ -145,18 +192,23 @@ static struct commonio_db gshadow_db = {
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
0, /* changed */
|
||||
0, /* isopen */
|
||||
0, /* locked */
|
||||
0 /* readonly */
|
||||
false, /* changed */
|
||||
false, /* isopen */
|
||||
false, /* locked */
|
||||
false /* readonly */
|
||||
};
|
||||
|
||||
int sgr_name (const char *filename)
|
||||
int sgr_setdbname (const char *filename)
|
||||
{
|
||||
return commonio_setname (&gshadow_db, filename);
|
||||
}
|
||||
|
||||
int sgr_file_present (void)
|
||||
/*@observer@*/const char *sgr_dbname (void)
|
||||
{
|
||||
return gshadow_db.filename;
|
||||
}
|
||||
|
||||
bool sgr_file_present (void)
|
||||
{
|
||||
return commonio_present (&gshadow_db);
|
||||
}
|
||||
@@ -171,7 +223,7 @@ int sgr_open (int mode)
|
||||
return commonio_open (&gshadow_db, mode);
|
||||
}
|
||||
|
||||
const struct sgrp *sgr_locate (const char *name)
|
||||
/*@observer@*/ /*@null@*/const struct sgrp *sgr_locate (const char *name)
|
||||
{
|
||||
return commonio_locate (&gshadow_db, name);
|
||||
}
|
||||
@@ -191,7 +243,7 @@ int sgr_rewind (void)
|
||||
return commonio_rewind (&gshadow_db);
|
||||
}
|
||||
|
||||
const struct sgrp *sgr_next (void)
|
||||
/*@null@*/const struct sgrp *sgr_next (void)
|
||||
{
|
||||
return commonio_next (&gshadow_db);
|
||||
}
|
||||
@@ -208,10 +260,10 @@ int sgr_unlock (void)
|
||||
|
||||
void __sgr_set_changed (void)
|
||||
{
|
||||
gshadow_db.changed = 1;
|
||||
gshadow_db.changed = true;
|
||||
}
|
||||
|
||||
struct commonio_entry *__sgr_get_head (void)
|
||||
/*@dependent@*/ /*@null@*/struct commonio_entry *__sgr_get_head (void)
|
||||
{
|
||||
return gshadow_db.head;
|
||||
}
|
||||
|
||||
@@ -31,16 +31,22 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
#ifndef _SGROUPIO_H
|
||||
#define _SGROUPIO_H
|
||||
|
||||
extern int sgr_close (void);
|
||||
extern int sgr_file_present (void);
|
||||
extern const struct sgrp *sgr_locate (const char *);
|
||||
extern bool sgr_file_present (void);
|
||||
extern /*@null@*/const struct sgrp *sgr_locate (const char *name);
|
||||
extern int sgr_lock (void);
|
||||
extern int sgr_name (const char *);
|
||||
extern const struct sgrp *sgr_next (void);
|
||||
extern int sgr_open (int);
|
||||
extern int sgr_remove (const char *);
|
||||
extern int sgr_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *sgr_dbname (void);
|
||||
extern /*@null@*/const struct sgrp *sgr_next (void);
|
||||
extern int sgr_open (int mode);
|
||||
extern int sgr_remove (const char *name);
|
||||
extern int sgr_rewind (void);
|
||||
extern int sgr_unlock (void);
|
||||
extern int sgr_update (const struct sgrp *);
|
||||
extern int sgr_update (const struct sgrp *sg);
|
||||
extern int sgr_sort (void);
|
||||
|
||||
#endif
|
||||
|
||||
196
lib/shadow.c
196
lib/shadow.c
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2009 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -56,8 +56,6 @@ static int nis_vallen;
|
||||
#endif
|
||||
|
||||
static FILE *shadow;
|
||||
static char spwbuf[BUFSIZ];
|
||||
static struct spwd spwd;
|
||||
|
||||
#define FIELDS 9
|
||||
#define OFIELDS 5
|
||||
@@ -72,8 +70,9 @@ void __setspNIS (int flag)
|
||||
{
|
||||
nis_ignore = !flag;
|
||||
|
||||
if (nis_ignore)
|
||||
if (nis_ignore) {
|
||||
nis_used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -124,6 +123,8 @@ void endspent (void)
|
||||
|
||||
static struct spwd *my_sgetspent (const char *string)
|
||||
{
|
||||
static char spwbuf[BUFSIZ];
|
||||
static struct spwd spwd;
|
||||
char *fields[FIELDS];
|
||||
char *cp;
|
||||
char *cpp;
|
||||
@@ -182,52 +183,58 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
* incorrectly formatted number, unless we are using NIS.
|
||||
*/
|
||||
|
||||
spwd.sp_lstchg = strtol (fields[2], &cpp, 10);
|
||||
if ((spwd.sp_lstchg == 0) && *cpp) {
|
||||
#ifdef USE_NIS
|
||||
if (!nis_used)
|
||||
return 0;
|
||||
else
|
||||
spwd.sp_lstchg = -1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if (fields[2][0] == '\0')
|
||||
if (fields[2][0] == '\0') {
|
||||
spwd.sp_lstchg = -1;
|
||||
} else {
|
||||
if (getlong (fields[2], &spwd.sp_lstchg) == 0) {
|
||||
#ifdef USE_NIS
|
||||
if (nis_used) {
|
||||
spwd.sp_lstchg = -1;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
} else if (spwd.sp_lstchg < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the minimum period between password changes.
|
||||
*/
|
||||
|
||||
spwd.sp_min = strtol (fields[3], &cpp, 10);
|
||||
if ((spwd.sp_min == 0) && *cpp) {
|
||||
#ifdef USE_NIS
|
||||
if (!nis_used)
|
||||
return 0;
|
||||
else
|
||||
spwd.sp_min = -1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if (fields[3][0] == '\0')
|
||||
if (fields[3][0] == '\0') {
|
||||
spwd.sp_min = -1;
|
||||
} else {
|
||||
if (getlong (fields[3], &spwd.sp_min) == 0) {
|
||||
#ifdef USE_NIS
|
||||
if (nis_used) {
|
||||
spwd.sp_min = -1;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
} else if (spwd.sp_min < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the maximum number of days a password is valid.
|
||||
*/
|
||||
|
||||
spwd.sp_max = strtol (fields[4], &cpp, 10);
|
||||
if ((spwd.sp_max == 0) && *cpp) {
|
||||
#ifdef USE_NIS
|
||||
if (!nis_used)
|
||||
return 0;
|
||||
else
|
||||
spwd.sp_max = -1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if (fields[4][0] == '\0')
|
||||
if (fields[4][0] == '\0') {
|
||||
spwd.sp_max = -1;
|
||||
} else {
|
||||
if (getlong (fields[4], &spwd.sp_max) == 0) {
|
||||
#ifdef USE_NIS
|
||||
if (nis_used) {
|
||||
spwd.sp_max = -1;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
} else if (spwd.sp_max < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
|
||||
@@ -235,8 +242,10 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
*/
|
||||
|
||||
if (i == OFIELDS) {
|
||||
spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
|
||||
spwd.sp_flag = -1;
|
||||
spwd.sp_warn = -1;
|
||||
spwd.sp_inact = -1;
|
||||
spwd.sp_expire = -1;
|
||||
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||
|
||||
return &spwd;
|
||||
}
|
||||
@@ -245,72 +254,81 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
* Get the number of days of password expiry warning.
|
||||
*/
|
||||
|
||||
spwd.sp_warn = strtol (fields[5], &cpp, 10);
|
||||
if ((spwd.sp_warn == 0) && *cpp) {
|
||||
#ifdef USE_NIS
|
||||
if (!nis_used)
|
||||
return 0;
|
||||
else
|
||||
spwd.sp_warn = -1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if (fields[5][0] == '\0')
|
||||
if (fields[5][0] == '\0') {
|
||||
spwd.sp_warn = -1;
|
||||
} else {
|
||||
if (getlong (fields[5], &spwd.sp_warn) == 0) {
|
||||
#ifdef USE_NIS
|
||||
if (nis_used) {
|
||||
spwd.sp_warn = -1;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
} else if (spwd.sp_warn < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of days of inactivity before an account is
|
||||
* disabled.
|
||||
*/
|
||||
|
||||
spwd.sp_inact = strtol (fields[6], &cpp, 10);
|
||||
if ((spwd.sp_inact == 0) && *cpp) {
|
||||
#ifdef USE_NIS
|
||||
if (!nis_used)
|
||||
return 0;
|
||||
else
|
||||
spwd.sp_inact = -1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if (fields[6][0] == '\0')
|
||||
if (fields[6][0] == '\0') {
|
||||
spwd.sp_inact = -1;
|
||||
} else {
|
||||
if (getlong (fields[6], &spwd.sp_inact) == 0) {
|
||||
#ifdef USE_NIS
|
||||
if (nis_used) {
|
||||
spwd.sp_inact = -1;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
} else if (spwd.sp_inact < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of days after the epoch before the account is
|
||||
* set to expire.
|
||||
*/
|
||||
|
||||
spwd.sp_expire = strtol (fields[7], &cpp, 10);
|
||||
if ((spwd.sp_expire == 0) && *cpp) {
|
||||
#ifdef USE_NIS
|
||||
if (!nis_used)
|
||||
return 0;
|
||||
else
|
||||
spwd.sp_expire = -1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if (fields[7][0] == '\0')
|
||||
if (fields[7][0] == '\0') {
|
||||
spwd.sp_expire = -1;
|
||||
} else {
|
||||
if (getlong (fields[7], &spwd.sp_expire) == 0) {
|
||||
#ifdef USE_NIS
|
||||
if (nis_used) {
|
||||
spwd.sp_expire = -1;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
} else if (spwd.sp_expire < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This field is reserved for future use. But it isn't supposed
|
||||
* to have anything other than a valid integer in it.
|
||||
*/
|
||||
|
||||
spwd.sp_flag = strtol (fields[8], &cpp, 10);
|
||||
if ((spwd.sp_flag == 0) && *cpp) {
|
||||
if (fields[8][0] == '\0') {
|
||||
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||
} else {
|
||||
if (getlong (fields[8], &spwd.sp_flag) == 0) {
|
||||
/* FIXME: add a getulong function */
|
||||
#ifdef USE_NIS
|
||||
if (!nis_used)
|
||||
return 0;
|
||||
else
|
||||
spwd.sp_flag = -1;
|
||||
#else
|
||||
return 0;
|
||||
if (nis_used) {
|
||||
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||
} else
|
||||
#endif
|
||||
} else if (fields[8][0] == '\0')
|
||||
spwd.sp_flag = -1;
|
||||
return 0;
|
||||
} else if (spwd.sp_flag < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (&spwd);
|
||||
}
|
||||
@@ -324,21 +342,24 @@ struct spwd *fgetspent (FILE * fp)
|
||||
char buf[BUFSIZ];
|
||||
char *cp;
|
||||
|
||||
if (!fp)
|
||||
if (NULL == fp) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
while (fgets (buf, sizeof buf, fp) != (char *) 0)
|
||||
while (fgets (buf, (int) sizeof buf, fp) != (char *) 0)
|
||||
#else
|
||||
if (fgets (buf, sizeof buf, fp) != (char *) 0)
|
||||
if (fgets (buf, (int) sizeof buf, fp) != (char *) 0)
|
||||
#endif
|
||||
{
|
||||
cp = strchr (buf, '\n');
|
||||
if (NULL != cp)
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
}
|
||||
#ifdef USE_NIS
|
||||
if (nis_ignore && IS_NISCHAR (buf[0]))
|
||||
if (nis_ignore && IS_NISCHAR (buf[0])) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
return my_sgetspent (buf);
|
||||
}
|
||||
@@ -513,3 +534,4 @@ struct spwd *getspnam (const char *name)
|
||||
#else
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -42,20 +42,18 @@
|
||||
#include "commonio.h"
|
||||
#include "shadowio.h"
|
||||
|
||||
static void *shadow_dup (const void *ent)
|
||||
static /*@null@*/ /*@only@*/void *shadow_dup (const void *ent)
|
||||
{
|
||||
const struct spwd *sp = ent;
|
||||
|
||||
return __spw_dup (sp);
|
||||
}
|
||||
|
||||
static void shadow_free (void *ent)
|
||||
static void shadow_free (/*@out@*//*@only@*/void *ent)
|
||||
{
|
||||
struct spwd *sp = ent;
|
||||
|
||||
free (sp->sp_namp);
|
||||
free (sp->sp_pwdp);
|
||||
free (sp);
|
||||
spw_free (sp);
|
||||
}
|
||||
|
||||
static const char *shadow_getname (const void *ent)
|
||||
@@ -99,18 +97,23 @@ static struct commonio_db shadow_db = {
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
0, /* changed */
|
||||
0, /* isopen */
|
||||
0, /* locked */
|
||||
0 /* readonly */
|
||||
false, /* changed */
|
||||
false, /* isopen */
|
||||
false, /* locked */
|
||||
false /* readonly */
|
||||
};
|
||||
|
||||
int spw_name (const char *filename)
|
||||
int spw_setdbname (const char *filename)
|
||||
{
|
||||
return commonio_setname (&shadow_db, filename);
|
||||
}
|
||||
|
||||
int spw_file_present (void)
|
||||
/*@observer@*/const char *spw_dbname (void)
|
||||
{
|
||||
return shadow_db.filename;
|
||||
}
|
||||
|
||||
bool spw_file_present (void)
|
||||
{
|
||||
return commonio_present (&shadow_db);
|
||||
}
|
||||
@@ -125,7 +128,7 @@ int spw_open (int mode)
|
||||
return commonio_open (&shadow_db, mode);
|
||||
}
|
||||
|
||||
const struct spwd *spw_locate (const char *name)
|
||||
/*@observer@*/ /*@null@*/const struct spwd *spw_locate (const char *name)
|
||||
{
|
||||
return commonio_locate (&shadow_db, name);
|
||||
}
|
||||
@@ -145,7 +148,7 @@ int spw_rewind (void)
|
||||
return commonio_rewind (&shadow_db);
|
||||
}
|
||||
|
||||
const struct spwd *spw_next (void)
|
||||
/*@observer@*/ /*@null@*/const struct spwd *spw_next (void)
|
||||
{
|
||||
return commonio_next (&shadow_db);
|
||||
}
|
||||
|
||||
@@ -30,16 +30,24 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
#ifndef _SHADOWIO_H
|
||||
#define _SHADOWIO_H
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
extern int spw_close (void);
|
||||
extern int spw_file_present (void);
|
||||
extern const struct spwd *spw_locate (const char *);
|
||||
extern bool spw_file_present (void);
|
||||
extern /*@observer@*/ /*@null@*/const struct spwd *spw_locate (const char *name);
|
||||
extern int spw_lock (void);
|
||||
extern int spw_name (const char *);
|
||||
extern const struct spwd *spw_next (void);
|
||||
extern int spw_open (int);
|
||||
extern int spw_remove (const char *);
|
||||
extern int spw_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *spw_dbname (void);
|
||||
extern /*@observer@*/ /*@null@*/const struct spwd *spw_next (void);
|
||||
extern int spw_open (int mode);
|
||||
extern int spw_remove (const char *name);
|
||||
extern int spw_rewind (void);
|
||||
extern int spw_unlock (void);
|
||||
extern int spw_update (const struct spwd *);
|
||||
extern int spw_update (const struct spwd *sp);
|
||||
extern int spw_sort (void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -41,17 +41,32 @@
|
||||
#include <stdio.h>
|
||||
#include "shadowio.h"
|
||||
|
||||
struct spwd *__spw_dup (const struct spwd *spent)
|
||||
/*@null@*/ /*@only@*/struct spwd *__spw_dup (const struct spwd *spent)
|
||||
{
|
||||
struct spwd *sp;
|
||||
|
||||
if (!(sp = (struct spwd *) malloc (sizeof *sp)))
|
||||
sp = (struct spwd *) malloc (sizeof *sp);
|
||||
if (NULL == sp) {
|
||||
return NULL;
|
||||
}
|
||||
*sp = *spent;
|
||||
if (!(sp->sp_namp = strdup (spent->sp_namp)))
|
||||
sp->sp_namp = strdup (spent->sp_namp);
|
||||
if (NULL == sp->sp_namp) {
|
||||
return NULL;
|
||||
if (!(sp->sp_pwdp = strdup (spent->sp_pwdp)))
|
||||
}
|
||||
sp->sp_pwdp = strdup (spent->sp_pwdp);
|
||||
if (NULL == sp->sp_pwdp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
void spw_free (/*@out@*/ /*@only@*/struct spwd *spent)
|
||||
{
|
||||
free (spent->sp_namp);
|
||||
memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
|
||||
free (spent->sp_pwdp);
|
||||
free (spent);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ libmisc_a_SOURCES = \
|
||||
chkname.h \
|
||||
chowndir.c \
|
||||
chowntty.c \
|
||||
cleanup.c \
|
||||
cleanup_group.c \
|
||||
cleanup_user.c \
|
||||
console.c \
|
||||
copydir.c \
|
||||
entry.c \
|
||||
@@ -21,10 +24,12 @@ libmisc_a_SOURCES = \
|
||||
failure.c \
|
||||
failure.h \
|
||||
fields.c \
|
||||
find_new_ids.c \
|
||||
find_new_gid.c \
|
||||
find_new_uid.c \
|
||||
getdate.h \
|
||||
getdate.y \
|
||||
getlong.c \
|
||||
getgr_nam_gid.c \
|
||||
getrange.c \
|
||||
hushed.c \
|
||||
isexpired.c \
|
||||
limits.c \
|
||||
@@ -35,6 +40,7 @@ libmisc_a_SOURCES = \
|
||||
myname.c \
|
||||
obscure.c \
|
||||
pam_pass.c \
|
||||
pam_pass_non_interractive.c \
|
||||
pwd2spwd.c \
|
||||
pwdcheck.c \
|
||||
pwd_init.c \
|
||||
@@ -43,12 +49,14 @@ libmisc_a_SOURCES = \
|
||||
setugid.c \
|
||||
setupenv.c \
|
||||
shell.c \
|
||||
system.c \
|
||||
strtoday.c \
|
||||
sub.c \
|
||||
sulog.c \
|
||||
ttytype.c \
|
||||
tz.c \
|
||||
ulimit.c \
|
||||
user_busy.c \
|
||||
utmp.c \
|
||||
valid.c \
|
||||
xgetpwnam.c \
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_SETGROUPS
|
||||
#if defined (HAVE_SETGROUPS) && ! defined (USE_PAM)
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
@@ -52,7 +52,9 @@
|
||||
int add_groups (const char *list)
|
||||
{
|
||||
GETGROUPS_T *grouplist, *tmp;
|
||||
int i, ngroups, added;
|
||||
size_t i;
|
||||
int ngroups;
|
||||
bool added;
|
||||
char *token;
|
||||
char buf[1024];
|
||||
|
||||
@@ -65,11 +67,13 @@ int add_groups (const char *list)
|
||||
i = 16;
|
||||
for (;;) {
|
||||
grouplist = (gid_t *) malloc (i * sizeof (GETGROUPS_T));
|
||||
if (!grouplist)
|
||||
if (NULL == grouplist) {
|
||||
return -1;
|
||||
}
|
||||
ngroups = getgroups (i, grouplist);
|
||||
if (i > ngroups)
|
||||
if ((-1 == ngroups) || (i > (size_t)ngroups)) {
|
||||
break;
|
||||
}
|
||||
/* not enough room, so try allocating a larger buffer */
|
||||
free (grouplist);
|
||||
i *= 2;
|
||||
@@ -79,40 +83,45 @@ int add_groups (const char *list)
|
||||
return -1;
|
||||
}
|
||||
|
||||
added = 0;
|
||||
for (token = strtok (buf, SEP); token; token = strtok (NULL, SEP)) {
|
||||
added = false;
|
||||
for (token = strtok (buf, SEP); NULL != token; token = strtok (NULL, SEP)) {
|
||||
struct group *grp;
|
||||
|
||||
grp = getgrnam (token); /* local, no need for xgetgrnam */
|
||||
if (!grp) {
|
||||
if (NULL == grp) {
|
||||
fprintf (stderr, _("Warning: unknown group %s\n"),
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < ngroups && grouplist[i] != grp->gr_gid; i++);
|
||||
for (i = 0; i < (size_t)ngroups && grouplist[i] != grp->gr_gid; i++);
|
||||
|
||||
if (i < ngroups)
|
||||
if (i < (size_t)ngroups) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngroups >= sysconf (_SC_NGROUPS_MAX)) {
|
||||
fputs (_("Warning: too many groups\n"), stderr);
|
||||
break;
|
||||
}
|
||||
tmp = (gid_t *) realloc (grouplist, (ngroups + 1) * sizeof (GETGROUPS_T));
|
||||
if (!tmp) {
|
||||
tmp = (gid_t *) realloc (grouplist, (size_t)(ngroups + 1) * sizeof (GETGROUPS_T));
|
||||
if (NULL == tmp) {
|
||||
free (grouplist);
|
||||
return -1;
|
||||
}
|
||||
tmp[ngroups++] = grp->gr_gid;
|
||||
tmp[ngroups] = grp->gr_gid;
|
||||
ngroups++;
|
||||
grouplist = tmp;
|
||||
added++;
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (added)
|
||||
return setgroups (ngroups, grouplist);
|
||||
if (added) {
|
||||
return setgroups ((size_t)ngroups, grouplist);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#else /* HAVE_SETGROUPS && !USE_PAM */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* HAVE_SETGROUPS && !USE_PAM */
|
||||
|
||||
|
||||
101
libmisc/age.c
101
libmisc/age.c
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -53,31 +53,33 @@
|
||||
* expire() calls /bin/passwd to change the user's password
|
||||
* if it has expired.
|
||||
*/
|
||||
int expire (const struct passwd *pw, const struct spwd *sp)
|
||||
int expire (const struct passwd *pw, /*@null@*/const struct spwd *sp)
|
||||
{
|
||||
int status;
|
||||
int child;
|
||||
int pid;
|
||||
pid_t child;
|
||||
pid_t pid;
|
||||
|
||||
if (!sp)
|
||||
sp = pwd_to_spwd (pw);
|
||||
if (NULL == sp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the user's password has expired, and if so
|
||||
* force them to change their password.
|
||||
*/
|
||||
|
||||
switch (status = isexpired (pw, sp)) {
|
||||
status = isexpired (pw, sp);
|
||||
switch (status) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
fputs (_("Your password has expired."), stdout);
|
||||
(void) fputs (_("Your password has expired."), stdout);
|
||||
break;
|
||||
case 2:
|
||||
fputs (_("Your password is inactive."), stdout);
|
||||
(void) fputs (_("Your password is inactive."), stdout);
|
||||
break;
|
||||
case 3:
|
||||
fputs (_("Your login has expired."), stdout);
|
||||
(void) fputs (_("Your login has expired."), stdout);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -88,12 +90,12 @@ int expire (const struct passwd *pw, const struct spwd *sp)
|
||||
* change that password.
|
||||
*/
|
||||
|
||||
if (status > 1 || sp->sp_max < sp->sp_min) {
|
||||
puts (_(" Contact the system administrator."));
|
||||
exit (1);
|
||||
if ((status > 1) || (sp->sp_max < sp->sp_min)) {
|
||||
(void) puts (_(" Contact the system administrator."));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
puts (_(" Choose a new password."));
|
||||
fflush (stdout);
|
||||
(void) puts (_(" Choose a new password."));
|
||||
(void) fflush (stdout);
|
||||
|
||||
/*
|
||||
* Close all the files so that unauthorized access won't
|
||||
@@ -115,7 +117,8 @@ int expire (const struct passwd *pw, const struct spwd *sp)
|
||||
* change their password before being able to use the account.
|
||||
*/
|
||||
|
||||
if ((pid = fork ()) == 0) {
|
||||
pid = fork ();
|
||||
if (0 == pid) {
|
||||
int err;
|
||||
|
||||
/*
|
||||
@@ -123,24 +126,32 @@ int expire (const struct passwd *pw, const struct spwd *sp)
|
||||
* passwd to work just like it would had they executed
|
||||
* it from the command line while logged in.
|
||||
*/
|
||||
if (setup_uid_gid (pw, 0))
|
||||
#if defined(HAVE_INITGROUPS) && ! defined(USE_PAM)
|
||||
if (setup_uid_gid (pw, false) != 0)
|
||||
#else
|
||||
if (setup_uid_gid (pw) != 0)
|
||||
#endif
|
||||
{
|
||||
_exit (126);
|
||||
}
|
||||
|
||||
execl (PASSWD_PROGRAM, PASSWD_PROGRAM, pw->pw_name, (char *) 0);
|
||||
(void) execl (PASSWD_PROGRAM, PASSWD_PROGRAM, pw->pw_name, (char *) 0);
|
||||
err = errno;
|
||||
perror ("Can't execute " PASSWD_PROGRAM);
|
||||
_exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
|
||||
} else if (pid == -1) {
|
||||
_exit ((ENOENT == err) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
|
||||
} else if ((pid_t) -1 == pid) {
|
||||
perror ("fork");
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
while ((child = wait (&status)) != pid && child != -1);
|
||||
|
||||
if (child == pid && status == 0)
|
||||
while (((child = wait (&status)) != pid) && (child != (pid_t)-1));
|
||||
|
||||
if ((child == pid) && (0 == status)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
exit (1);
|
||||
/*NOTREACHED*/}
|
||||
exit (EXIT_FAILURE);
|
||||
/*@notreached@*/}
|
||||
|
||||
/*
|
||||
* agecheck - see if warning is needed for password expiration
|
||||
@@ -149,30 +160,42 @@ int expire (const struct passwd *pw, const struct spwd *sp)
|
||||
* to expire and warns the user of the pending password expiration.
|
||||
*/
|
||||
|
||||
void agecheck (const struct passwd *pw, const struct spwd *sp)
|
||||
void agecheck (/*@null@*/const struct spwd *sp)
|
||||
{
|
||||
long now = time ((long *) 0) / SCALE;
|
||||
long now = (long) time ((time_t *) 0) / SCALE;
|
||||
long remain;
|
||||
|
||||
if (!sp)
|
||||
sp = pwd_to_spwd (pw);
|
||||
if (NULL == sp) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The last, max, and warn fields must be supported or the
|
||||
* warning period cannot be calculated.
|
||||
*/
|
||||
|
||||
if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1)
|
||||
if ( (-1 == sp->sp_lstchg)
|
||||
|| (-1 == sp->sp_max)
|
||||
|| (-1 == sp->sp_warn)) {
|
||||
return;
|
||||
if ((remain = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn) {
|
||||
}
|
||||
|
||||
if (0 == sp->sp_lstchg) {
|
||||
(void) puts (_("You must change your password."));
|
||||
return;
|
||||
}
|
||||
|
||||
remain = sp->sp_lstchg + sp->sp_max - now;
|
||||
if (remain <= sp->sp_warn) {
|
||||
remain /= DAY / SCALE;
|
||||
if (remain > 1)
|
||||
printf (_
|
||||
("Your password will expire in %ld days.\n"),
|
||||
remain);
|
||||
else if (remain == 1)
|
||||
puts (_("Your password will expire tomorrow."));
|
||||
else if (remain == 0)
|
||||
puts (_("Your password will expire today."));
|
||||
if (remain > 1) {
|
||||
(void) printf (_("Your password will expire in %ld days.\n"),
|
||||
remain);
|
||||
} else if (1 == remain) {
|
||||
(void) puts (_("Your password will expire tomorrow."));
|
||||
} else if (remain == 0) {
|
||||
(void) puts (_("Your password will expire today."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,11 +53,14 @@ void audit_help_open (void)
|
||||
if (audit_fd < 0) {
|
||||
/* You get these only when the kernel doesn't have
|
||||
* audit compiled in. */
|
||||
if (errno == EINVAL || errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT)
|
||||
if ( (errno == EINVAL)
|
||||
|| (errno == EPROTONOSUPPORT)
|
||||
|| (errno == EAFNOSUPPORT)) {
|
||||
return;
|
||||
fprintf (stderr, "Cannot open audit interface - aborting.\n");
|
||||
exit (1);
|
||||
}
|
||||
(void) fputs (_("Cannot open audit interface - aborting.\n"),
|
||||
stderr);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,16 +75,32 @@ void audit_help_open (void)
|
||||
* name - user's account or group name. If not available use NULL.
|
||||
* id - uid or gid that the operation is being performed on. This is used
|
||||
* only when user is NULL.
|
||||
* result - 1 is "success" and 0 is "failed"
|
||||
*/
|
||||
void audit_logger (int type, const char *pgname, const char *op,
|
||||
const char *name, unsigned int id, int result)
|
||||
const char *name, unsigned int id,
|
||||
shadow_audit_result result)
|
||||
{
|
||||
if (audit_fd < 0)
|
||||
if (audit_fd < 0) {
|
||||
return;
|
||||
else
|
||||
} else {
|
||||
audit_log_acct_message (audit_fd, type, NULL, op, name, id,
|
||||
NULL, NULL, NULL, result);
|
||||
NULL, NULL, NULL, (int) result);
|
||||
}
|
||||
}
|
||||
|
||||
void audit_logger_message (const char *message, shadow_audit_result result)
|
||||
{
|
||||
if (audit_fd < 0) {
|
||||
return;
|
||||
} else {
|
||||
audit_log_user_message (audit_fd,
|
||||
AUDIT_USYS_CONFIG,
|
||||
message,
|
||||
NULL, /* hostname */
|
||||
NULL, /* addr */
|
||||
NULL, /* tty */
|
||||
(int) result);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* WITH_AUDIT */
|
||||
|
||||
@@ -31,8 +31,11 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* check_user_name(), check_group_name() - check the new user/group
|
||||
* name for validity; return value: 1 - OK, 0 - bad name
|
||||
* is_valid_user_name(), is_valid_group_name() - check the new user/group
|
||||
* name for validity;
|
||||
* return values:
|
||||
* true - OK
|
||||
* false - bad name
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@@ -42,57 +45,55 @@
|
||||
#include <ctype.h>
|
||||
#include "defines.h"
|
||||
#include "chkname.h"
|
||||
#if HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#else
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
static int good_name (const char *name)
|
||||
|
||||
static bool is_valid_name (const char *name)
|
||||
{
|
||||
/*
|
||||
* User/group names must match [a-z_][a-z0-9_-]*[$]
|
||||
*/
|
||||
if (!*name || !((*name >= 'a' && *name <= 'z') || *name == '_'))
|
||||
return 0;
|
||||
|
||||
while (*++name) {
|
||||
if (!((*name >= 'a' && *name <= 'z') ||
|
||||
(*name >= '0' && *name <= '9') ||
|
||||
*name == '_' || *name == '-' ||
|
||||
(*name == '$' && *(name + 1) == '\0')))
|
||||
return 0;
|
||||
if (('\0' == *name) ||
|
||||
!((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
while ('\0' != *++name) {
|
||||
if (!(( ('a' <= *name) && ('z' >= *name) ) ||
|
||||
( ('0' <= *name) && ('9' >= *name) ) ||
|
||||
('_' == *name) ||
|
||||
('-' == *name) ||
|
||||
( ('$' == *name) && ('\0' == *(name + 1)) )
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int check_user_name (const char *name)
|
||||
bool is_valid_user_name (const char *name)
|
||||
{
|
||||
#if HAVE_UTMPX_H
|
||||
struct utmpx ut;
|
||||
#else
|
||||
struct utmp ut;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* User names are limited by whatever utmp can
|
||||
* handle (usually max 8 characters).
|
||||
* handle.
|
||||
*/
|
||||
if (strlen (name) > sizeof (ut.ut_user))
|
||||
return 0;
|
||||
if (strlen (name) > USER_NAME_MAX_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return good_name (name);
|
||||
return is_valid_name (name);
|
||||
}
|
||||
|
||||
int check_group_name (const char *name)
|
||||
bool is_valid_group_name (const char *name)
|
||||
{
|
||||
/*
|
||||
* Arbitrary limit for group names - max 16
|
||||
* characters (same as on HP-UX 10).
|
||||
* Arbitrary limit for group names.
|
||||
* HP-UX 10 limits to 16 characters
|
||||
*/
|
||||
if (strlen (name) > 16)
|
||||
return 0;
|
||||
if ( (GROUP_NAME_MAX_LENGTH > 0)
|
||||
&& (strlen (name) > GROUP_NAME_MAX_LENGTH)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return good_name (name);
|
||||
return is_valid_name (name);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1997 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,13 +35,16 @@
|
||||
#define _CHKNAME_H_
|
||||
|
||||
/*
|
||||
* check_user_name(), check_group_name() - check the new user/group
|
||||
* name for validity; return value: 1 - OK, 0 - bad name
|
||||
* is_valid_user_name(), is_valid_group_name() - check the new user/group
|
||||
* name for validity;
|
||||
* return values:
|
||||
* true - OK
|
||||
* false - bad name
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
extern int check_user_name (const char *);
|
||||
extern int check_group_name (const char *name);
|
||||
extern bool is_valid_user_name (const char *name);
|
||||
extern bool is_valid_group_name (const char *name);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -104,9 +104,11 @@ chown_tree (const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid,
|
||||
* Do the entire subdirectory.
|
||||
*/
|
||||
|
||||
if ((rc = chown_tree (new_name, old_uid, new_uid,
|
||||
old_gid, new_gid)))
|
||||
rc = chown_tree (new_name, old_uid, new_uid,
|
||||
old_gid, new_gid);
|
||||
if (0 != rc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef HAVE_LCHOWN
|
||||
/* don't use chown (follows symbolic links!) */
|
||||
@@ -117,16 +119,18 @@ chown_tree (const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid,
|
||||
LCHOWN (new_name, new_uid,
|
||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
||||
}
|
||||
closedir (dir);
|
||||
(void) closedir (dir);
|
||||
|
||||
/*
|
||||
* Now do the root of the tree
|
||||
*/
|
||||
|
||||
if (!stat (root, &sb)) {
|
||||
if (sb.st_uid == old_uid)
|
||||
if (stat (root, &sb) == 0) {
|
||||
if (sb.st_uid == old_uid) {
|
||||
LCHOWN (root, new_uid,
|
||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -43,31 +43,14 @@
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
#include "getdef.h"
|
||||
/*
|
||||
* is_my_tty -- determine if "tty" is the same as TTY stdin is using
|
||||
*/
|
||||
static int is_my_tty (const char *tty)
|
||||
{
|
||||
struct stat by_name, by_fd;
|
||||
|
||||
if (stat (tty, &by_name) || fstat (0, &by_fd))
|
||||
return 0;
|
||||
|
||||
if (by_name.st_rdev != by_fd.st_rdev)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* chown_tty() sets the login tty to be owned by the new user ID
|
||||
* with TTYPERM modes
|
||||
*/
|
||||
|
||||
void chown_tty (const char *tty, const struct passwd *info)
|
||||
void chown_tty (const struct passwd *info)
|
||||
{
|
||||
char buf[200], full_tty[200];
|
||||
char *group; /* TTY group name or number */
|
||||
struct group *grent;
|
||||
gid_t gid;
|
||||
|
||||
@@ -76,45 +59,32 @@ void chown_tty (const char *tty, const struct passwd *info)
|
||||
* ID. Otherwise, use the user's primary group ID.
|
||||
*/
|
||||
|
||||
if (!(group = getdef_str ("TTYGROUP")))
|
||||
gid = info->pw_gid;
|
||||
else if (group[0] >= '0' && group[0] <= '9')
|
||||
gid = atoi (group);
|
||||
else if ((grent = getgrnam (group))) /* local, no need for xgetgrnam */
|
||||
grent = getgr_nam_gid (getdef_str ("TTYGROUP"));
|
||||
if (NULL != grent) {
|
||||
gid = grent->gr_gid;
|
||||
else
|
||||
} else {
|
||||
gid = info->pw_gid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the permissions on the TTY to be owned by the user with
|
||||
* the group as determined above.
|
||||
*/
|
||||
|
||||
if (*tty != '/') {
|
||||
snprintf (full_tty, sizeof full_tty, "/dev/%s", tty);
|
||||
tty = full_tty;
|
||||
}
|
||||
|
||||
if (!is_my_tty (tty)) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"unable to determine TTY name, got %s\n", tty));
|
||||
closelog ();
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (chown (tty, info->pw_uid, gid) ||
|
||||
chmod (tty, getdef_num ("TTYPERM", 0600))) {
|
||||
if ( (fchown (STDIN_FILENO, info->pw_uid, gid) != 0)
|
||||
|| (fchmod (STDIN_FILENO, getdef_num ("TTYPERM", 0600)) != 0)) {
|
||||
int err = errno;
|
||||
|
||||
snprintf (buf, sizeof buf, _("Unable to change tty %s"), tty);
|
||||
perror (buf);
|
||||
fprintf (stderr,
|
||||
_("Unable to change owner or mode of tty stdin: %s"),
|
||||
strerror (err));
|
||||
SYSLOG ((LOG_WARN,
|
||||
"unable to change tty `%s' for user `%s'\n", tty,
|
||||
info->pw_name));
|
||||
closelog ();
|
||||
|
||||
if (err != EROFS)
|
||||
exit (1);
|
||||
"unable to change owner or mode of tty stdin for user `%s': %s\n",
|
||||
info->pw_name, strerror (err)));
|
||||
if (EROFS != err) {
|
||||
closelog ();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#ifdef __linux__
|
||||
/*
|
||||
|
||||
128
libmisc/cleanup.c
Normal file
128
libmisc/cleanup.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
|
||||
/*
|
||||
* The cleanup_functions stack.
|
||||
*/
|
||||
#define CLEANUP_FUNCTIONS 10
|
||||
static cleanup_function cleanup_functions[CLEANUP_FUNCTIONS];
|
||||
static void * cleanup_function_args[CLEANUP_FUNCTIONS];
|
||||
|
||||
/*
|
||||
* - Cleanup functions shall not fail.
|
||||
* - You should register do_cleanups with atexit.
|
||||
* - You should add cleanup functions to the stack with add_cleanup when
|
||||
* an operation is expected to be executed later, and remove it from the
|
||||
* stack with del_cleanup when it has been executed.
|
||||
*
|
||||
**/
|
||||
|
||||
/*
|
||||
* do_cleanups - perform the actions stored in the cleanup_functions stack.
|
||||
*
|
||||
* It is intended to be used as:
|
||||
* atexit (do_cleanups);
|
||||
*/
|
||||
void do_cleanups (void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Make sure there were no overflow */
|
||||
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-1]);
|
||||
|
||||
i = CLEANUP_FUNCTIONS;
|
||||
do {
|
||||
i--;
|
||||
if (cleanup_functions[i] != NULL) {
|
||||
cleanup_functions[i] (cleanup_function_args[i]);
|
||||
}
|
||||
} while (i>0);
|
||||
}
|
||||
|
||||
/*
|
||||
* add_cleanup - Add a cleanup_function to the cleanup_functions stack.
|
||||
*/
|
||||
void add_cleanup (cleanup_function pcf, /*@null@*/void *arg)
|
||||
{
|
||||
unsigned int i;
|
||||
assert (NULL != pcf);
|
||||
|
||||
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-2]);
|
||||
|
||||
/* Add the cleanup_function at the end of the stack */
|
||||
for (i=0; NULL != cleanup_functions[i]; i++);
|
||||
cleanup_functions[i] = pcf;
|
||||
cleanup_function_args[i] = arg;
|
||||
}
|
||||
|
||||
/*
|
||||
* del_cleanup - Remove a cleanup_function from the cleanup_functions stack.
|
||||
*/
|
||||
void del_cleanup (cleanup_function pcf)
|
||||
{
|
||||
unsigned int i;
|
||||
assert (NULL != pcf);
|
||||
|
||||
/* Find the pcf cleanup function */
|
||||
for (i=0; i<CLEANUP_FUNCTIONS; i++) {
|
||||
if (cleanup_functions[i] == pcf) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the cleanup function was found */
|
||||
assert (i<CLEANUP_FUNCTIONS);
|
||||
|
||||
/* Move the rest of the cleanup functions */
|
||||
for (; i<CLEANUP_FUNCTIONS; i++) {
|
||||
/* Make sure the cleanup function was specified only once */
|
||||
assert (cleanup_functions[i+1] != pcf);
|
||||
|
||||
if (i == (CLEANUP_FUNCTIONS -1)) {
|
||||
cleanup_functions[i] = NULL;
|
||||
cleanup_function_args[i] = NULL;
|
||||
} else {
|
||||
cleanup_functions[i] = cleanup_functions[i+1];
|
||||
cleanup_function_args[i] = cleanup_function_args[i+1];
|
||||
}
|
||||
|
||||
/* A NULL indicates the end of the stack */
|
||||
if (NULL == cleanup_functions[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
237
libmisc/cleanup_group.c
Normal file
237
libmisc/cleanup_group.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "groupio.h"
|
||||
#include "sgroupio.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
/*
|
||||
* cleanup_report_add_group - Report failure to add a group to the system
|
||||
*
|
||||
* It should be registered when it is decided to add a group to the system.
|
||||
*/
|
||||
void cleanup_report_add_group (void *group_name)
|
||||
{
|
||||
const char *name = (const char *)group_name;
|
||||
|
||||
SYSLOG ((LOG_ERR, "failed to add group %s", name));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_GROUP, Prog,
|
||||
"",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup_report_del_group - Report failure to remove a group from the system
|
||||
*
|
||||
* It should be registered when it is decided to remove a group from the system.
|
||||
*/
|
||||
void cleanup_report_del_group (void *group_name)
|
||||
{
|
||||
const char *name = (const char *)group_name;
|
||||
|
||||
SYSLOG ((LOG_ERR, "failed to remove group %s", name));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_DEL_GROUP, Prog,
|
||||
"",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cleanup_report_mod_group (void *cleanup_info)
|
||||
{
|
||||
const struct cleanup_info_mod *info;
|
||||
info = (const struct cleanup_info_mod *)cleanup_info;
|
||||
|
||||
SYSLOG ((LOG_ERR,
|
||||
"failed to change %s (%s)",
|
||||
gr_dbname (),
|
||||
info->action));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_USER_ACCT, Prog,
|
||||
info->audit_msg,
|
||||
info->name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
void cleanup_report_mod_gshadow (void *cleanup_info)
|
||||
{
|
||||
const struct cleanup_info_mod *info;
|
||||
info = (const struct cleanup_info_mod *)cleanup_info;
|
||||
|
||||
SYSLOG ((LOG_ERR,
|
||||
"failed to change %s (%s)",
|
||||
sgr_dbname (),
|
||||
info->action));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_USER_ACCT, Prog,
|
||||
info->audit_msg,
|
||||
info->name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cleanup_report_add_group_group - Report failure to add a group to group
|
||||
*
|
||||
* It should be registered when it is decided to add a group to the
|
||||
* group database.
|
||||
*/
|
||||
void cleanup_report_add_group_group (void *group_name)
|
||||
{
|
||||
const char *name = (const char *)group_name;
|
||||
|
||||
SYSLOG ((LOG_ERR, "failed to add group %s to %s", name, gr_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_GROUP, Prog,
|
||||
"adding group to /etc/group",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
/*
|
||||
* cleanup_report_add_group_gshadow - Report failure to add a group to gshadow
|
||||
*
|
||||
* It should be registered when it is decided to add a group to the
|
||||
* gshadow database.
|
||||
*/
|
||||
void cleanup_report_add_group_gshadow (void *group_name)
|
||||
{
|
||||
const char *name = (const char *)group_name;
|
||||
|
||||
SYSLOG ((LOG_ERR, "failed to add group %s to %s", name, sgr_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_GROUP, Prog,
|
||||
"adding group to /etc/gshadow",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cleanup_report_del_group_group - Report failure to remove a group from the
|
||||
* regular group database
|
||||
*
|
||||
* It should be registered when it is decided to remove a group from the
|
||||
* regular group database.
|
||||
*/
|
||||
void cleanup_report_del_group_group (void *group_name)
|
||||
{
|
||||
const char *name = (const char *)group_name;
|
||||
|
||||
SYSLOG ((LOG_ERR,
|
||||
"failed to remove group %s from %s",
|
||||
name, gr_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_GROUP, Prog,
|
||||
"removing group from /etc/group",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
/*
|
||||
* cleanup_report_del_group_gshadow - Report failure to remove a group from
|
||||
* gshadow
|
||||
*
|
||||
* It should be registered when it is decided to remove a group from the
|
||||
* gshadow database.
|
||||
*/
|
||||
void cleanup_report_del_group_gshadow (void *group_name)
|
||||
{
|
||||
const char *name = (const char *)group_name;
|
||||
|
||||
SYSLOG ((LOG_ERR,
|
||||
"failed to remove group %s from %s",
|
||||
name, sgr_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_GROUP, Prog,
|
||||
"removing group from /etc/gshadow",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cleanup_unlock_group - Unlock the group file
|
||||
*
|
||||
* It should be registered after the group file is successfully locked.
|
||||
*/
|
||||
void cleanup_unlock_group (unused void *arg)
|
||||
{
|
||||
if (gr_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, gr_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger_message ("unlocking group file",
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
/*
|
||||
* cleanup_unlock_gshadow - Unlock the gshadow file
|
||||
*
|
||||
* It should be registered after the gshadow file is successfully locked.
|
||||
*/
|
||||
void cleanup_unlock_gshadow (unused void *arg)
|
||||
{
|
||||
if (sgr_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, sgr_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger_message ("unlocking gshadow file",
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
152
libmisc/cleanup_user.c
Normal file
152
libmisc/cleanup_user.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "pwio.h"
|
||||
#include "shadowio.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
/*
|
||||
* cleanup_report_add_user - Report failure to add an user to the system
|
||||
*
|
||||
* It should be registered when it is decided to add an user to the system.
|
||||
*/
|
||||
void cleanup_report_add_user (void *user_name)
|
||||
{
|
||||
const char *name = (const char *)user_name;
|
||||
|
||||
SYSLOG ((LOG_ERR, "failed to add user %s", name));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_USER, Prog,
|
||||
"",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cleanup_report_mod_passwd (void *cleanup_info)
|
||||
{
|
||||
const struct cleanup_info_mod *info;
|
||||
info = (const struct cleanup_info_mod *)cleanup_info;
|
||||
|
||||
SYSLOG ((LOG_ERR,
|
||||
"failed to change %s (%s)",
|
||||
pw_dbname (),
|
||||
info->action));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_USER_ACCT, Prog,
|
||||
info->audit_msg,
|
||||
info->name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup_report_add_user_passwd - Report failure to add an user to
|
||||
* /etc/passwd
|
||||
*
|
||||
* It should be registered when it is decided to add an user to the
|
||||
* /etc/passwd database.
|
||||
*/
|
||||
void cleanup_report_add_user_passwd (void *user_name)
|
||||
{
|
||||
const char *name = (const char *)user_name;
|
||||
|
||||
SYSLOG ((LOG_ERR, "failed to add user %s to %s", name, pw_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_USER, Prog,
|
||||
"adding user to /etc/passwd",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup_report_add_user_shadow - Report failure to add an user to
|
||||
* /etc/shadow
|
||||
*
|
||||
* It should be registered when it is decided to add an user to the
|
||||
* /etc/shadow database.
|
||||
*/
|
||||
void cleanup_report_add_user_shadow (void *user_name)
|
||||
{
|
||||
const char *name = (const char *)user_name;
|
||||
|
||||
SYSLOG ((LOG_ERR, "failed to add user %s to %s", name, spw_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_ADD_USER, Prog,
|
||||
"adding user to /etc/shadow",
|
||||
name, AUDIT_NO_ID,
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup_unlock_passwd - Unlock the /etc/passwd database
|
||||
*
|
||||
* It should be registered after the passwd database is successfully locked.
|
||||
*/
|
||||
void cleanup_unlock_passwd (unused void *arg)
|
||||
{
|
||||
if (pw_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, pw_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger_message ("unlocking passwd file",
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup_unlock_shadow - Unlock the /etc/shadow database
|
||||
*
|
||||
* It should be registered after the shadow database is successfully locked.
|
||||
*/
|
||||
void cleanup_unlock_shadow (unused void *arg)
|
||||
{
|
||||
if (spw_unlock () == 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: failed to unlock %s\n"),
|
||||
Prog, spw_dbname ());
|
||||
SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger_message ("unlocking shadow file",
|
||||
SHADOW_AUDIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,14 +40,14 @@
|
||||
#ident "$Id$"
|
||||
|
||||
/* local function prototypes */
|
||||
static int is_listed (const char *cfgin, const char *tty, int def);
|
||||
static bool is_listed (const char *cfgin, const char *tty, bool def);
|
||||
|
||||
/*
|
||||
* This is now rather generic function which decides if "tty" is listed
|
||||
* under "cfgin" in config (directly or indirectly). Fallback to default if
|
||||
* something is bad.
|
||||
*/
|
||||
static int is_listed (const char *cfgin, const char *tty, int def)
|
||||
static bool is_listed (const char *cfgin, const char *tty, bool def)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[200], *cons, *s;
|
||||
@@ -57,8 +57,10 @@ static int is_listed (const char *cfgin, const char *tty, int def)
|
||||
* fallback to default.
|
||||
*/
|
||||
|
||||
if ((cons = getdef_str (cfgin)) == NULL)
|
||||
cons = getdef_str (cfgin);
|
||||
if (NULL == cons) {
|
||||
return def;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this isn't a filename, then it is a ":" delimited list of
|
||||
@@ -66,14 +68,15 @@ static int is_listed (const char *cfgin, const char *tty, int def)
|
||||
*/
|
||||
|
||||
if (*cons != '/') {
|
||||
cons = strcpy (buf, cons);
|
||||
while ((s = strtok (cons, ":")) != NULL) {
|
||||
if (strcmp (s, tty) == 0)
|
||||
return 1;
|
||||
strcpy (buf, cons);
|
||||
while ((s = strtok (buf, ":")) != NULL) {
|
||||
if (strcmp (s, tty) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cons = NULL;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -81,18 +84,20 @@ static int is_listed (const char *cfgin, const char *tty, int def)
|
||||
* console - otherwise root will never be allowed to login.
|
||||
*/
|
||||
|
||||
if ((fp = fopen (cons, "r")) == NULL)
|
||||
fp = fopen (cons, "r");
|
||||
if (NULL == fp) {
|
||||
return def;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if this tty is listed in the console file.
|
||||
*/
|
||||
|
||||
while (fgets (buf, sizeof (buf), fp) != NULL) {
|
||||
while (fgets (buf, (int) sizeof (buf), fp) != NULL) {
|
||||
buf[strlen (buf) - 1] = '\0';
|
||||
if (strcmp (buf, tty) == 0) {
|
||||
(void) fclose (fp);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +106,7 @@ static int is_listed (const char *cfgin, const char *tty, int def)
|
||||
*/
|
||||
|
||||
(void) fclose (fp);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -114,7 +119,12 @@ static int is_listed (const char *cfgin, const char *tty, int def)
|
||||
* that would allow an unauthorized root login.
|
||||
*/
|
||||
|
||||
int console (const char *tty)
|
||||
bool console (const char *tty)
|
||||
{
|
||||
return is_listed ("CONSOLE", tty, 1);
|
||||
if (strncmp (tty, "/dev/", 5) == 0) {
|
||||
tty += 5;
|
||||
}
|
||||
|
||||
return is_listed ("CONSOLE", tty, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
@@ -43,37 +44,37 @@
|
||||
#include "defines.h"
|
||||
#ifdef WITH_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
static int selinux_enabled = -1;
|
||||
#endif
|
||||
static const char *src_orig;
|
||||
static const char *dst_orig;
|
||||
static /*@null@*/const char *src_orig;
|
||||
static /*@null@*/const char *dst_orig;
|
||||
|
||||
struct link_name {
|
||||
dev_t ln_dev;
|
||||
ino_t ln_ino;
|
||||
int ln_count;
|
||||
nlink_t ln_count;
|
||||
char *ln_name;
|
||||
struct link_name *ln_next;
|
||||
/*@dependent@*/struct link_name *ln_next;
|
||||
};
|
||||
static struct link_name *links;
|
||||
static /*@exposed@*/struct link_name *links;
|
||||
|
||||
static int copy_entry (const char *src, const char *dst,
|
||||
long int uid, long int gid);
|
||||
static int copy_dir (const char *src, const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid);
|
||||
#ifdef S_IFLNK
|
||||
static char *readlink_malloc (const char *filename);
|
||||
static int copy_symlink (const char *src, const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid);
|
||||
#endif
|
||||
static int copy_hardlink (const char *src, const char *dst,
|
||||
struct link_name *lp);
|
||||
static int copy_special (const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid);
|
||||
static int copy_file (const char *src, const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
@@ -84,14 +85,21 @@ static int copy_file (const char *src, const char *dst,
|
||||
* selinux_file_context () should be called before any creation of file,
|
||||
* symlink, directory, ...
|
||||
*
|
||||
* Callers may have to Reset SELinux to create files with default
|
||||
* contexts:
|
||||
* setfscreatecon (NULL);
|
||||
*/
|
||||
static int selinux_file_context (const char *dst_name)
|
||||
int selinux_file_context (const char *dst_name)
|
||||
{
|
||||
static bool selinux_checked = false;
|
||||
static bool selinux_enabled;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
if (selinux_enabled < 0) {
|
||||
if (!selinux_checked) {
|
||||
selinux_enabled = is_selinux_enabled () > 0;
|
||||
selinux_checked = true;
|
||||
}
|
||||
|
||||
if (selinux_enabled) {
|
||||
/* Get the default security context for this file */
|
||||
if (matchpathcon (dst_name, 0, &scontext) < 0) {
|
||||
@@ -114,7 +122,7 @@ static int selinux_file_context (const char *dst_name)
|
||||
/*
|
||||
* remove_link - delete a link from the linked list
|
||||
*/
|
||||
static void remove_link (struct link_name *ln)
|
||||
static void remove_link (/*@only@*/struct link_name *ln)
|
||||
{
|
||||
struct link_name *lp;
|
||||
|
||||
@@ -131,6 +139,8 @@ static void remove_link (struct link_name *ln)
|
||||
}
|
||||
|
||||
if (NULL == lp) {
|
||||
free (ln->ln_name);
|
||||
free (ln);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -143,15 +153,19 @@ static void remove_link (struct link_name *ln)
|
||||
* check_link - see if a file is really a link
|
||||
*/
|
||||
|
||||
static struct link_name *check_link (const char *name, const struct stat *sb)
|
||||
static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, const struct stat *sb)
|
||||
{
|
||||
struct link_name *lp;
|
||||
int src_len;
|
||||
int dst_len;
|
||||
int name_len;
|
||||
int len;
|
||||
size_t src_len;
|
||||
size_t dst_len;
|
||||
size_t name_len;
|
||||
size_t len;
|
||||
|
||||
for (lp = links; lp; lp = lp->ln_next) {
|
||||
/* copy_tree () must be the entry point */
|
||||
assert (NULL != src_orig);
|
||||
assert (NULL != dst_orig);
|
||||
|
||||
for (lp = links; NULL != lp; lp = lp->ln_next) {
|
||||
if ((lp->ln_dev == sb->st_dev) && (lp->ln_ino == sb->st_ino)) {
|
||||
return lp;
|
||||
}
|
||||
@@ -169,7 +183,7 @@ static struct link_name *check_link (const char *name, const struct stat *sb)
|
||||
lp->ln_ino = sb->st_ino;
|
||||
lp->ln_count = sb->st_nlink;
|
||||
len = name_len - src_len + dst_len + 1;
|
||||
lp->ln_name = xmalloc (len);
|
||||
lp->ln_name = (char *) xmalloc (len);
|
||||
snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
|
||||
lp->ln_next = links;
|
||||
links = lp;
|
||||
@@ -186,10 +200,8 @@ static struct link_name *check_link (const char *name, const struct stat *sb)
|
||||
int copy_tree (const char *src_root, const char *dst_root,
|
||||
long int uid, long int gid)
|
||||
{
|
||||
char src_name[1024];
|
||||
char dst_name[1024];
|
||||
int err = 0;
|
||||
int set_orig = 0;
|
||||
bool set_orig = false;
|
||||
struct DIRECT *ent;
|
||||
DIR *dir;
|
||||
|
||||
@@ -216,10 +228,10 @@ int copy_tree (const char *src_root, const char *dst_root,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (src_orig == 0) {
|
||||
if (src_orig == NULL) {
|
||||
src_orig = src_root;
|
||||
dst_orig = dst_root;
|
||||
set_orig++;
|
||||
set_orig = true;
|
||||
}
|
||||
while ((0 == err) && (ent = readdir (dir)) != NULL) {
|
||||
/*
|
||||
@@ -227,35 +239,54 @@ int copy_tree (const char *src_root, const char *dst_root,
|
||||
*/
|
||||
if ((strcmp (ent->d_name, ".") != 0) &&
|
||||
(strcmp (ent->d_name, "..") != 0)) {
|
||||
/*
|
||||
* Make sure the resulting source and destination
|
||||
* filenames will fit in their buffers.
|
||||
*/
|
||||
if ( (strlen (src_root) + strlen (ent->d_name) + 2 >
|
||||
sizeof src_name)
|
||||
|| (strlen (dst_root) + strlen (ent->d_name) + 2 >
|
||||
sizeof dst_name)) {
|
||||
char *src_name;
|
||||
char *dst_name;
|
||||
size_t src_len = strlen (ent->d_name) + 2;
|
||||
size_t dst_len = strlen (ent->d_name) + 2;
|
||||
src_len += strlen (src_root);
|
||||
dst_len += strlen (dst_root);
|
||||
|
||||
src_name = (char *) malloc (src_len);
|
||||
dst_name = (char *) malloc (dst_len);
|
||||
|
||||
if ((NULL == src_name) || (NULL == dst_name)) {
|
||||
err = -1;
|
||||
} else {
|
||||
/*
|
||||
* Build the filename for both the source and
|
||||
* the destination files.
|
||||
*/
|
||||
snprintf (src_name, sizeof src_name, "%s/%s",
|
||||
snprintf (src_name, src_len, "%s/%s",
|
||||
src_root, ent->d_name);
|
||||
snprintf (dst_name, sizeof dst_name, "%s/%s",
|
||||
snprintf (dst_name, dst_len, "%s/%s",
|
||||
dst_root, ent->d_name);
|
||||
|
||||
err = copy_entry (src_name, dst_name, uid, gid);
|
||||
}
|
||||
if (NULL != src_name) {
|
||||
free (src_name);
|
||||
}
|
||||
if (NULL != dst_name) {
|
||||
free (dst_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
(void) closedir (dir);
|
||||
|
||||
if (set_orig) {
|
||||
src_orig = 0;
|
||||
dst_orig = 0;
|
||||
src_orig = NULL;
|
||||
dst_orig = NULL;
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
/* Reset SELinux to create files with default contexts */
|
||||
setfscreatecon (NULL);
|
||||
#endif
|
||||
|
||||
/* FIXME: with the call to remove_link, we could also check that
|
||||
* no links remain in links.
|
||||
* assert (NULL == links); */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -285,16 +316,28 @@ static int copy_entry (const char *src, const char *dst,
|
||||
if (LSTAT (src, &sb) == -1) {
|
||||
/* If we cannot stat the file, do not care. */
|
||||
} else {
|
||||
#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIM
|
||||
mt[0].tv_sec = sb.st_atim.tv_sec;
|
||||
mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
||||
#else
|
||||
mt[0].tv_sec = sb.st_atime;
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
|
||||
mt[0].tv_usec = sb.st_atimensec / 1000;
|
||||
#else
|
||||
mt[0].tv_usec = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
||||
mt[1].tv_sec = sb.st_mtim.tv_sec;
|
||||
mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
|
||||
#else
|
||||
mt[0].tv_sec = sb.st_atime;
|
||||
mt[0].tv_usec = sb.st_atimensec / 1000;
|
||||
mt[1].tv_sec = sb.st_mtime;
|
||||
#ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
mt[1].tv_usec = sb.st_mtimensec / 1000;
|
||||
#else
|
||||
mt[1].tv_usec = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (S_ISDIR (sb.st_mode)) {
|
||||
@@ -353,7 +396,7 @@ static int copy_entry (const char *src, const char *dst,
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_dir (const char *src, const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
@@ -380,6 +423,41 @@ static int copy_dir (const char *src, const char *dst,
|
||||
}
|
||||
|
||||
#ifdef S_IFLNK
|
||||
/*
|
||||
* readlink_malloc - wrapper for readlink
|
||||
*
|
||||
* return NULL on error.
|
||||
* The return string shall be freed by the caller.
|
||||
*/
|
||||
static char *readlink_malloc (const char *filename)
|
||||
{
|
||||
size_t size = 1024;
|
||||
|
||||
while (1) {
|
||||
ssize_t nchars;
|
||||
char *buffer = (char *) malloc (size);
|
||||
if (NULL == buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nchars = readlink (filename, buffer, size);
|
||||
|
||||
if (nchars < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (size_t) nchars < size) { /* The buffer was large enough */
|
||||
/* readlink does not nul-terminate */
|
||||
buffer[nchars] = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Try again with a bigger buffer */
|
||||
free (buffer);
|
||||
size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_symlink - copy a symlink
|
||||
*
|
||||
@@ -391,13 +469,14 @@ static int copy_dir (const char *src, const char *dst,
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_symlink (const char *src, const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid)
|
||||
{
|
||||
char oldlink[1024];
|
||||
char dummy[1024];
|
||||
int len;
|
||||
int err = 0;
|
||||
char *oldlink;
|
||||
|
||||
/* copy_tree () must be the entry point */
|
||||
assert (NULL != src_orig);
|
||||
assert (NULL != dst_orig);
|
||||
|
||||
/*
|
||||
* Get the name of the file which the link points
|
||||
@@ -407,17 +486,26 @@ static int copy_symlink (const char *src, const char *dst,
|
||||
* destination directory name.
|
||||
*/
|
||||
|
||||
len = readlink (src, oldlink, sizeof (oldlink) - 1);
|
||||
if (len < 0) {
|
||||
oldlink = readlink_malloc (src);
|
||||
if (NULL == oldlink) {
|
||||
return -1;
|
||||
}
|
||||
oldlink[len] = '\0'; /* readlink() does not NUL-terminate */
|
||||
|
||||
/* If src was a link to an entry of the src_orig directory itself,
|
||||
* create a link to the corresponding entry in the dst_orig
|
||||
* directory.
|
||||
* FIXME: This may change a relative link to an absolute link
|
||||
*/
|
||||
if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
|
||||
snprintf (dummy, sizeof dummy, "%s%s",
|
||||
size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
|
||||
char *dummy = (char *) malloc (len);
|
||||
snprintf (dummy, len, "%s%s",
|
||||
dst_orig,
|
||||
oldlink + strlen (src_orig));
|
||||
strcpy (oldlink, dummy);
|
||||
free (oldlink);
|
||||
oldlink = dummy;
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
selinux_file_context (dst);
|
||||
#endif
|
||||
@@ -425,17 +513,21 @@ static int copy_symlink (const char *src, const char *dst,
|
||||
|| (lchown (dst,
|
||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
|
||||
free (oldlink);
|
||||
return -1;
|
||||
}
|
||||
free (oldlink);
|
||||
|
||||
#ifdef HAVE_LUTIMES
|
||||
/* 2007-10-18: We don't care about
|
||||
* exit status of lutimes because
|
||||
* it returns ENOSYS on many system
|
||||
* - not implemented
|
||||
*/
|
||||
lutimes (dst, mt);
|
||||
#endif
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -454,10 +546,13 @@ static int copy_hardlink (const char *src, const char *dst,
|
||||
if (link (lp->ln_name, dst) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: why is it unlinked? This is a copy, not a move */
|
||||
if (unlink (src) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: idem, although it may never be used again */
|
||||
/* If the file could be unlinked, decrement the links counter,
|
||||
* and delete the file if it was the last reference */
|
||||
lp->ln_count--;
|
||||
@@ -479,7 +574,7 @@ static int copy_hardlink (const char *src, const char *dst,
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_special (const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
@@ -511,14 +606,14 @@ static int copy_special (const char *dst,
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_file (const char *src, const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[2],
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
int ifd;
|
||||
int ofd;
|
||||
char buf[1024];
|
||||
int cnt;
|
||||
ssize_t cnt;
|
||||
|
||||
ifd = open (src, O_RDONLY);
|
||||
if (ifd < 0) {
|
||||
@@ -527,32 +622,40 @@ static int copy_file (const char *src, const char *dst,
|
||||
#ifdef WITH_SELINUX
|
||||
selinux_file_context (dst);
|
||||
#endif
|
||||
ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, 0);
|
||||
ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
|
||||
if ( (ofd < 0)
|
||||
|| (chown (dst,
|
||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
||||
|| (chmod (dst, statp->st_mode & 07777) != 0)) {
|
||||
|| (fchown (ofd,
|
||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
||||
|| (fchmod (ofd, statp->st_mode & 07777) != 0)) {
|
||||
(void) close (ifd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
|
||||
if (write (ofd, buf, cnt) != cnt) {
|
||||
if (write (ofd, buf, (size_t)cnt) != cnt) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
(void) close (ifd);
|
||||
|
||||
#ifdef HAVE_FUTIMES
|
||||
if (futimes (ofd, mt) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (close (ofd) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef HAVE_FUTIMES
|
||||
if (utimes(dst, mt) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -566,20 +669,12 @@ static int copy_file (const char *src, const char *dst,
|
||||
|
||||
int remove_tree (const char *root)
|
||||
{
|
||||
char new_name[1024];
|
||||
char *new_name = NULL;
|
||||
int err = 0;
|
||||
struct DIRECT *ent;
|
||||
struct stat sb;
|
||||
DIR *dir;
|
||||
|
||||
/*
|
||||
* Make certain the directory exists.
|
||||
*/
|
||||
|
||||
if (access (root, F_OK) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the source directory and read each entry. Every file
|
||||
* entry in the directory is copied with the UID and GID set
|
||||
@@ -593,6 +688,7 @@ int remove_tree (const char *root)
|
||||
}
|
||||
|
||||
while ((ent = readdir (dir))) {
|
||||
size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
|
||||
|
||||
/*
|
||||
* Skip the "." and ".." entries
|
||||
@@ -607,12 +703,15 @@ int remove_tree (const char *root)
|
||||
* Make the filename for the current entry.
|
||||
*/
|
||||
|
||||
if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
|
||||
if (NULL != new_name) {
|
||||
free (new_name);
|
||||
}
|
||||
new_name = (char *) malloc (new_len);
|
||||
if (NULL == new_name) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
snprintf (new_name, sizeof new_name, "%s/%s", root,
|
||||
ent->d_name);
|
||||
snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
|
||||
if (LSTAT (new_name, &sb) == -1) {
|
||||
continue;
|
||||
}
|
||||
@@ -635,6 +734,9 @@ int remove_tree (const char *root)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NULL != new_name) {
|
||||
free (new_name);
|
||||
}
|
||||
(void) closedir (dir);
|
||||
|
||||
if (0 == err) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1992, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -46,7 +47,7 @@
|
||||
*/
|
||||
#define NEWENVP_STEP 16
|
||||
size_t newenvc = 0;
|
||||
char **newenvp = NULL;
|
||||
/*@null@*/char **newenvp = NULL;
|
||||
extern char **environ;
|
||||
|
||||
static const char *forbid[] = {
|
||||
@@ -85,15 +86,18 @@ void initenv (void)
|
||||
}
|
||||
|
||||
|
||||
void addenv (const char *string, const char *value)
|
||||
void addenv (const char *string, /*@null@*/const char *value)
|
||||
{
|
||||
char *cp, *newstring;
|
||||
size_t i;
|
||||
size_t n;
|
||||
|
||||
if (value) {
|
||||
newstring = xmalloc (strlen (string) + strlen (value) + 2);
|
||||
sprintf (newstring, "%s=%s", string, value);
|
||||
if (NULL != value) {
|
||||
size_t len = strlen (string) + strlen (value) + 2;
|
||||
int wlen;
|
||||
newstring = xmalloc (len);
|
||||
wlen = snprintf (newstring, len, "%s=%s", string, value);
|
||||
assert (wlen == (int) len -1);
|
||||
} else {
|
||||
newstring = xstrdup (string);
|
||||
}
|
||||
@@ -104,7 +108,7 @@ void addenv (const char *string, const char *value)
|
||||
*/
|
||||
|
||||
cp = strchr (newstring, '=');
|
||||
if (!cp) {
|
||||
if (NULL == cp) {
|
||||
free (newstring);
|
||||
return;
|
||||
}
|
||||
@@ -112,9 +116,10 @@ void addenv (const char *string, const char *value)
|
||||
n = (size_t) (cp - newstring);
|
||||
|
||||
for (i = 0; i < newenvc; i++) {
|
||||
if (strncmp (newstring, newenvp[i], n) == 0 &&
|
||||
(newenvp[i][n] == '=' || newenvp[i][n] == '\0'))
|
||||
if ( (strncmp (newstring, newenvp[i], n) == 0)
|
||||
&& (('=' == newenvp[i][n]) || ('\0' == newenvp[i][n]))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < newenvc) {
|
||||
@@ -151,12 +156,14 @@ void addenv (const char *string, const char *value)
|
||||
* environ so that it doesn't point to some
|
||||
* free memory area (realloc() could move it).
|
||||
*/
|
||||
if (environ == newenvp)
|
||||
if (environ == newenvp) {
|
||||
environ = __newenvp;
|
||||
}
|
||||
newenvp = __newenvp;
|
||||
} else {
|
||||
fputs (_("Environment overflow\n"), stderr);
|
||||
free (newenvp[--newenvc]);
|
||||
(void) fputs (_("Environment overflow\n"), stderr);
|
||||
newenvc--;
|
||||
free (newenvp[newenvc]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,21 +185,28 @@ void set_env (int argc, char *const *argv)
|
||||
char *cp;
|
||||
|
||||
for (; argc > 0; argc--, argv++) {
|
||||
if (strlen (*argv) >= sizeof variable)
|
||||
if (strlen (*argv) >= sizeof variable) {
|
||||
continue; /* ignore long entries */
|
||||
}
|
||||
|
||||
if (!(cp = strchr (*argv, '='))) {
|
||||
snprintf (variable, sizeof variable, "L%d", noname++);
|
||||
cp = strchr (*argv, '=');
|
||||
if (NULL == cp) {
|
||||
int wlen;
|
||||
wlen = snprintf (variable, sizeof variable, "L%d", noname);
|
||||
assert (wlen < (int) sizeof(variable));
|
||||
noname++;
|
||||
addenv (variable, *argv);
|
||||
} else {
|
||||
const char **p;
|
||||
|
||||
for (p = forbid; *p; p++)
|
||||
if (strncmp (*argv, *p, strlen (*p)) == 0)
|
||||
for (p = forbid; NULL != *p; p++) {
|
||||
if (strncmp (*argv, *p, strlen (*p)) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p) {
|
||||
strncpy (variable, *argv, cp - *argv);
|
||||
if (NULL != *p) {
|
||||
strncpy (variable, *argv, (size_t)(cp - *argv));
|
||||
variable[cp - *argv] = '\0';
|
||||
printf (_("You may not change $%s\n"),
|
||||
variable);
|
||||
@@ -220,27 +234,32 @@ void sanitize_env (void)
|
||||
char **cur;
|
||||
char **move;
|
||||
|
||||
for (cur = envp; *cur; cur++) {
|
||||
for (bad = forbid; *bad; bad++) {
|
||||
for (cur = envp; NULL != *cur; cur++) {
|
||||
for (bad = forbid; NULL != *bad; bad++) {
|
||||
if (strncmp (*cur, *bad, strlen (*bad)) == 0) {
|
||||
for (move = cur; *move; move++)
|
||||
for (move = cur; NULL != *move; move++) {
|
||||
*move = *(move + 1);
|
||||
}
|
||||
cur--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (cur = envp; *cur; cur++) {
|
||||
for (bad = noslash; *bad; bad++) {
|
||||
if (strncmp (*cur, *bad, strlen (*bad)) != 0)
|
||||
for (cur = envp; NULL != *cur; cur++) {
|
||||
for (bad = noslash; NULL != *bad; bad++) {
|
||||
if (strncmp (*cur, *bad, strlen (*bad)) != 0) {
|
||||
continue;
|
||||
if (!strchr (*cur, '/'))
|
||||
}
|
||||
if (strchr (*cur, '/') != NULL) {
|
||||
continue; /* OK */
|
||||
for (move = cur; *move; move++)
|
||||
}
|
||||
for (move = cur; NULL != *move; move++) {
|
||||
*move = *(move + 1);
|
||||
}
|
||||
cur--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2002 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,6 +36,7 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "defines.h"
|
||||
#include "faillog.h"
|
||||
#include "getdef.h"
|
||||
@@ -49,13 +51,23 @@
|
||||
void failure (uid_t uid, const char *tty, struct faillog *fl)
|
||||
{
|
||||
int fd;
|
||||
off_t offset_uid = (off_t) (sizeof *fl) * uid;
|
||||
|
||||
/*
|
||||
* Don't do anything if failure logging isn't set up.
|
||||
*/
|
||||
|
||||
if ((fd = open (FAILLOG_FILE, O_RDWR)) < 0)
|
||||
if (access (FAILLOG_FILE, F_OK) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open (FAILLOG_FILE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't write faillog entry for UID %lu in %s.",
|
||||
(unsigned long) uid, FAILLOG_FILE));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The file is indexed by UID value meaning that shared UID's
|
||||
@@ -63,9 +75,17 @@ void failure (uid_t uid, const char *tty, struct faillog *fl)
|
||||
* share just about everything else ...
|
||||
*/
|
||||
|
||||
lseek (fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
|
||||
if (read (fd, (char *) fl, sizeof *fl) != sizeof *fl)
|
||||
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|
||||
|| (read (fd, (char *) fl, sizeof *fl) != (ssize_t) sizeof *fl)) {
|
||||
/* This is not necessarily a failure. The file is
|
||||
* initially zero length.
|
||||
*
|
||||
* If lseek() or read() failed for any other reason, this
|
||||
* might reset the counter. But the new failure will be
|
||||
* logged.
|
||||
*/
|
||||
memzero (fl, sizeof *fl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the record. We increment the failure count to log the
|
||||
@@ -74,11 +94,12 @@ void failure (uid_t uid, const char *tty, struct faillog *fl)
|
||||
* updated as well.
|
||||
*/
|
||||
|
||||
if (fl->fail_cnt + 1 > 0)
|
||||
if (fl->fail_cnt + 1 > 0) {
|
||||
fl->fail_cnt++;
|
||||
}
|
||||
|
||||
strncpy (fl->fail_line, tty, sizeof fl->fail_line);
|
||||
time (&fl->fail_time);
|
||||
(void) time (&fl->fail_time);
|
||||
|
||||
/*
|
||||
* Seek back to the correct position in the file and write the
|
||||
@@ -87,26 +108,34 @@ void failure (uid_t uid, const char *tty, struct faillog *fl)
|
||||
* seem that great.
|
||||
*/
|
||||
|
||||
lseek (fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
|
||||
write (fd, (char *) fl, sizeof *fl);
|
||||
close (fd);
|
||||
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|
||||
|| (write (fd, (char *) fl, sizeof *fl) != (ssize_t) sizeof *fl)
|
||||
|| (close (fd) != 0)) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't write faillog entry for UID %lu in %s.",
|
||||
(unsigned long) uid, FAILLOG_FILE));
|
||||
(void) close (fd);
|
||||
}
|
||||
}
|
||||
|
||||
static int too_many_failures (const struct faillog *fl)
|
||||
static bool too_many_failures (const struct faillog *fl)
|
||||
{
|
||||
time_t now;
|
||||
|
||||
if (fl->fail_max == 0 || fl->fail_cnt < fl->fail_max)
|
||||
return 0;
|
||||
if ((0 == fl->fail_max) || (fl->fail_cnt < fl->fail_max)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fl->fail_locktime == 0)
|
||||
return 1; /* locked until reset manually */
|
||||
if (0 == fl->fail_locktime) {
|
||||
return true; /* locked until reset manually */
|
||||
}
|
||||
|
||||
time (&now);
|
||||
if (fl->fail_time + fl->fail_locktime < now)
|
||||
return 0; /* enough time since last failure */
|
||||
(void) time (&now);
|
||||
if ((fl->fail_time + fl->fail_locktime) < now) {
|
||||
return false; /* enough time since last failure */
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -114,21 +143,35 @@ static int too_many_failures (const struct faillog *fl)
|
||||
*
|
||||
* failcheck() is called AFTER the password has been validated. If the
|
||||
* account has been "attacked" with too many login failures, failcheck()
|
||||
* returns FALSE to indicate that the login should be denied even though
|
||||
* returns 0 to indicate that the login should be denied even though
|
||||
* the password is valid.
|
||||
*
|
||||
* failed indicates if the login failed AFTER the password has been
|
||||
* validated.
|
||||
*/
|
||||
|
||||
int failcheck (uid_t uid, struct faillog *fl, int failed)
|
||||
int failcheck (uid_t uid, struct faillog *fl, bool failed)
|
||||
{
|
||||
int fd;
|
||||
struct faillog fail;
|
||||
off_t offset_uid = (off_t) (sizeof *fl) * uid;
|
||||
|
||||
/*
|
||||
* Suppress the check if the log file isn't there.
|
||||
*/
|
||||
|
||||
if ((fd = open (FAILLOG_FILE, O_RDWR)) < 0)
|
||||
if (access (FAILLOG_FILE, F_OK) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd = open (FAILLOG_FILE, failed?O_RDONLY:O_RDWR);
|
||||
if (fd < 0) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't open the faillog file (%s) to check UID %lu. "
|
||||
"User access authorized.",
|
||||
FAILLOG_FILE, (unsigned long) uid));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the record from the file and determine if the user has
|
||||
@@ -142,14 +185,14 @@ int failcheck (uid_t uid, struct faillog *fl, int failed)
|
||||
* no need to reset the count.
|
||||
*/
|
||||
|
||||
lseek (fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
|
||||
if (read (fd, (char *) fl, sizeof *fl) != sizeof *fl) {
|
||||
close (fd);
|
||||
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|
||||
|| (read (fd, (char *) fl, sizeof *fl) != (ssize_t) sizeof *fl)) {
|
||||
(void) close (fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (too_many_failures (fl)) {
|
||||
close (fd);
|
||||
(void) close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -164,10 +207,18 @@ int failcheck (uid_t uid, struct faillog *fl, int failed)
|
||||
fail = *fl;
|
||||
fail.fail_cnt = 0;
|
||||
|
||||
lseek (fd, (off_t) sizeof fail * uid, SEEK_SET);
|
||||
write (fd, (char *) &fail, sizeof fail);
|
||||
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|
||||
|| (write (fd, (const void *) &fail, sizeof fail) != (ssize_t) sizeof fail)
|
||||
|| (close (fd) != 0)) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't reset faillog entry for UID %lu in %s.",
|
||||
(unsigned long) uid, FAILLOG_FILE));
|
||||
(void) close (fd);
|
||||
}
|
||||
} else {
|
||||
(void) close (fd);
|
||||
}
|
||||
close (fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -190,17 +241,18 @@ void failprint (const struct faillog *fail)
|
||||
#endif
|
||||
time_t NOW;
|
||||
|
||||
if (fail->fail_cnt == 0)
|
||||
if (0 == fail->fail_cnt) {
|
||||
return;
|
||||
}
|
||||
|
||||
tp = localtime (&(fail->fail_time));
|
||||
time (&NOW);
|
||||
(void) time (&NOW);
|
||||
|
||||
#if HAVE_STRFTIME
|
||||
/*
|
||||
* Print all information we have.
|
||||
*/
|
||||
strftime (lasttimeb, sizeof lasttimeb, "%c", tp);
|
||||
(void) strftime (lasttimeb, sizeof lasttimeb, "%c", tp);
|
||||
#else
|
||||
|
||||
/*
|
||||
@@ -210,35 +262,38 @@ void failprint (const struct faillog *fail)
|
||||
lasttime = asctime (tp);
|
||||
lasttime[24] = '\0';
|
||||
|
||||
if (NOW - fail->fail_time < YEAR)
|
||||
if ((NOW - fail->fail_time) < YEAR) {
|
||||
lasttime[19] = '\0';
|
||||
if (NOW - fail->fail_time < DAY)
|
||||
}
|
||||
if ((NOW - fail->fail_time) < DAY) {
|
||||
lasttime = lasttime + 11;
|
||||
}
|
||||
|
||||
if (*lasttime == ' ')
|
||||
if (' ' == *lasttime) {
|
||||
lasttime++;
|
||||
}
|
||||
#endif
|
||||
printf (ngettext ("%d failure since last login.\n"
|
||||
"Last was %s on %s.\n",
|
||||
"%d failures since last login.\n"
|
||||
"Last was %s on %s.\n",
|
||||
fail->fail_cnt),
|
||||
fail->fail_cnt, lasttime, fail->fail_line);
|
||||
(void) printf (ngettext ("%d failure since last login.\n"
|
||||
"Last was %s on %s.\n",
|
||||
"%d failures since last login.\n"
|
||||
"Last was %s on %s.\n",
|
||||
(unsigned long) fail->fail_cnt),
|
||||
fail->fail_cnt, lasttime, fail->fail_line);
|
||||
}
|
||||
|
||||
/*
|
||||
* failtmp - update the cummulative failure log
|
||||
* failtmp - update the cumulative failure log
|
||||
*
|
||||
* failtmp updates the (struct utmp) formatted failure log which
|
||||
* maintains a record of all login failures.
|
||||
*/
|
||||
|
||||
void failtmp (
|
||||
#ifdef HAVE_UTMPX_H
|
||||
void failtmp (const char *username,
|
||||
#ifdef USE_UTMPX
|
||||
const struct utmpx *failent
|
||||
#else
|
||||
#else /* !USE_UTMPX */
|
||||
const struct utmp *failent
|
||||
#endif
|
||||
#endif /* !USE_UTMPX */
|
||||
)
|
||||
{
|
||||
char *ftmp;
|
||||
@@ -249,21 +304,38 @@ void failtmp (
|
||||
* in login.defs, don't do this.
|
||||
*/
|
||||
|
||||
if (!(ftmp = getdef_str ("FTMP_FILE")))
|
||||
ftmp = getdef_str ("FTMP_FILE");
|
||||
if (NULL == ftmp) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the file for append. It must already exist for this
|
||||
* feature to be used.
|
||||
*/
|
||||
|
||||
if ((fd = open (ftmp, O_WRONLY | O_APPEND)) == -1)
|
||||
if (access (ftmp, F_OK) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open (ftmp, O_WRONLY | O_APPEND);
|
||||
if (-1 == fd) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't append failure of user %s to %s.",
|
||||
username, ftmp));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output the new failure record and close the log file.
|
||||
* Append the new failure record and close the log file.
|
||||
*/
|
||||
|
||||
write (fd, (const char *) failent, sizeof *failent);
|
||||
close (fd);
|
||||
if ( (write (fd, (const void *) failent, sizeof *failent) != (ssize_t) sizeof *failent)
|
||||
|| (close (fd) != 0)) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't append failure of user %s to %s.",
|
||||
username, ftmp));
|
||||
(void) close (fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1997 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,11 +36,11 @@
|
||||
|
||||
#include "defines.h"
|
||||
#include "faillog.h"
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#ifdef USE_UTMPX
|
||||
#include <utmpx.h>
|
||||
#else
|
||||
#else /* !USE_UTMPX */
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
#endif /* !USE_UTMPX */
|
||||
|
||||
/*
|
||||
* failure - make failure entry
|
||||
@@ -57,7 +58,7 @@ extern void failure (uid_t, const char *, struct faillog *);
|
||||
* returns FALSE to indicate that the login should be denied even though
|
||||
* the password is valid.
|
||||
*/
|
||||
extern int failcheck (uid_t, struct faillog *, int);
|
||||
extern int failcheck (uid_t uid, struct faillog *fl, bool failed);
|
||||
|
||||
/*
|
||||
* failprint - print line of failure information
|
||||
@@ -73,11 +74,11 @@ extern void failprint (const struct faillog *);
|
||||
* failtmp updates the (struct utmp) formatted failure log which
|
||||
* maintains a record of all login failures.
|
||||
*/
|
||||
#ifdef HAVE_UTMPX_H
|
||||
extern void failtmp (const struct utmpx *);
|
||||
#else
|
||||
extern void failtmp (const struct utmp *);
|
||||
#endif
|
||||
#ifdef USE_UTMPX
|
||||
extern void failtmp (const char *username, const struct utmpx *);
|
||||
#else /* !USE_UTMPX */
|
||||
extern void failtmp (const char *username, const struct utmp *);
|
||||
#endif /* !USE_UTMPX */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
184
libmisc/find_new_gid.c
Normal file
184
libmisc/find_new_gid.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 2008 - 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "groupio.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* find_new_gid - Find a new unused GID.
|
||||
*
|
||||
* If successful, find_new_gid provides an unused group ID in the
|
||||
* [GID_MIN:GID_MAX] range.
|
||||
* This ID should be higher than all the used GID, but if not possible,
|
||||
* the lowest unused ID in the range will be returned.
|
||||
*
|
||||
* Return 0 on success, -1 if no unused GIDs are available.
|
||||
*/
|
||||
int find_new_gid (bool sys_group,
|
||||
gid_t *gid,
|
||||
/*@null@*/gid_t const *preferred_gid)
|
||||
{
|
||||
const struct group *grp;
|
||||
gid_t gid_min, gid_max, group_id, id;
|
||||
bool *used_gids;
|
||||
|
||||
assert (gid != NULL);
|
||||
|
||||
if (!sys_group) {
|
||||
gid_min = (gid_t) getdef_ulong ("GID_MIN", 1000UL);
|
||||
gid_max = (gid_t) getdef_ulong ("GID_MAX", 60000UL);
|
||||
} else {
|
||||
gid_min = (gid_t) getdef_ulong ("SYS_GID_MIN", 101UL);
|
||||
gid_max = (gid_t) getdef_ulong ("GID_MIN", 1000UL) - 1;
|
||||
gid_max = (gid_t) getdef_ulong ("SYS_GID_MAX", (unsigned long) gid_max);
|
||||
}
|
||||
used_gids = alloca (sizeof (bool) * (gid_max +1));
|
||||
memset (used_gids, false, sizeof (bool) * (gid_max + 1));
|
||||
|
||||
if ( (NULL != preferred_gid)
|
||||
&& (*preferred_gid >= gid_min)
|
||||
&& (*preferred_gid <= gid_max)
|
||||
/* Check if the user exists according to NSS */
|
||||
&& (getgrgid (*preferred_gid) == NULL)
|
||||
/* Check also the local database in case of uncommitted
|
||||
* changes */
|
||||
&& (gr_locate_gid (*preferred_gid) == NULL)) {
|
||||
*gid = *preferred_gid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search the entire group file,
|
||||
* looking for the largest unused value.
|
||||
*
|
||||
* We check the list of groups according to NSS (setgrent/getgrent),
|
||||
* but we also check the local database (gr_rewind/gr_next) in case
|
||||
* some groups were created but the changes were not committed yet.
|
||||
*/
|
||||
if (sys_group) {
|
||||
/* setgrent / getgrent / endgrent can be very slow with
|
||||
* LDAP configurations (and many accounts).
|
||||
* Since there is a limited amount of IDs to be tested
|
||||
* for system accounts, we just check the existence
|
||||
* of IDs with getgrgid.
|
||||
*/
|
||||
group_id = gid_max;
|
||||
for (id = gid_max; id >= gid_min; id--) {
|
||||
if (getgrgid (id) != NULL) {
|
||||
group_id = id - 1;
|
||||
used_gids[id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
gr_rewind ();
|
||||
while ((grp = gr_next ()) != NULL) {
|
||||
if ((grp->gr_gid <= group_id) && (grp->gr_gid >= gid_min)) {
|
||||
group_id = grp->gr_gid - 1;
|
||||
}
|
||||
/* create index of used GIDs */
|
||||
if (grp->gr_gid <= gid_max) {
|
||||
used_gids[grp->gr_gid] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
group_id = gid_min;
|
||||
setgrent ();
|
||||
while ((grp = getgrent ()) != NULL) {
|
||||
if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) {
|
||||
group_id = grp->gr_gid + 1;
|
||||
}
|
||||
/* create index of used GIDs */
|
||||
if (grp->gr_gid <= gid_max) {
|
||||
used_gids[grp->gr_gid] = true;
|
||||
}
|
||||
}
|
||||
endgrent ();
|
||||
|
||||
gr_rewind ();
|
||||
while ((grp = gr_next ()) != NULL) {
|
||||
if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) {
|
||||
group_id = grp->gr_gid + 1;
|
||||
}
|
||||
/* create index of used GIDs */
|
||||
if (grp->gr_gid <= gid_max) {
|
||||
used_gids[grp->gr_gid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If a group with GID equal to GID_MAX exists, the above algorithm
|
||||
* will give us GID_MAX+1 even if not unique. Search for the first
|
||||
* free GID starting with GID_MIN.
|
||||
*/
|
||||
if (sys_group) {
|
||||
if (group_id == gid_min - 1) {
|
||||
for (group_id = gid_max; group_id >= gid_min; group_id--) {
|
||||
if (false == used_gids[group_id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( group_id < gid_min ) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique system GID (no more available GIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN,
|
||||
"no more available GID on the system"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (group_id == gid_max + 1) {
|
||||
for (group_id = gid_min; group_id < gid_max; group_id++) {
|
||||
if (false == used_gids[group_id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group_id == gid_max) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique GID (no more available GIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available GID on the system"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*gid = group_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "pwio.h"
|
||||
#include "groupio.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* find_new_uid - Find a new unused UID.
|
||||
*
|
||||
* If successful, find_new_uid provides an unused user ID in the
|
||||
* [UID_MIN:UID_MAX] range.
|
||||
* This ID should be higher than all the used UID, but if not possible,
|
||||
* the lowest unused ID in the range will be returned.
|
||||
*
|
||||
* Return 0 on success, -1 if no unused UIDs are available.
|
||||
*/
|
||||
int find_new_uid (int sys_user, uid_t *uid, uid_t const *preferred_uid)
|
||||
{
|
||||
const struct passwd *pwd;
|
||||
uid_t uid_min, uid_max, user_id;
|
||||
|
||||
assert (uid != NULL);
|
||||
|
||||
if (sys_user == 0) {
|
||||
uid_min = getdef_unum ("UID_MIN", 1000);
|
||||
uid_max = getdef_unum ("UID_MAX", 60000);
|
||||
} else {
|
||||
uid_min = getdef_unum ("SYS_UID_MIN", 1);
|
||||
uid_max = getdef_unum ("UID_MIN", 1000) - 1;
|
||||
uid_max = getdef_unum ("SYS_UID_MAX", uid_max);
|
||||
}
|
||||
|
||||
if ( (NULL != preferred_uid)
|
||||
&& (*preferred_uid >= uid_min)
|
||||
&& (*preferred_uid <= uid_max)
|
||||
/* Check if the user exists according to NSS */
|
||||
&& (getpwuid (*preferred_uid) == NULL)
|
||||
/* Check also the local database in case of uncommitted
|
||||
* changes */
|
||||
&& (pw_locate_uid (*preferred_uid) == NULL)) {
|
||||
*uid = *preferred_uid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
user_id = uid_min;
|
||||
|
||||
/*
|
||||
* Search the entire password file,
|
||||
* looking for the largest unused value.
|
||||
*
|
||||
* We check the list of users according to NSS (setpwent/getpwent),
|
||||
* but we also check the local database (pw_rewind/pw_next) in case
|
||||
* some users were created but the changes were not committed yet.
|
||||
*/
|
||||
setpwent ();
|
||||
pw_rewind ();
|
||||
while ( ((pwd = getpwent ()) != NULL)
|
||||
|| ((pwd = pw_next ()) != NULL)) {
|
||||
if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) {
|
||||
user_id = pwd->pw_uid + 1;
|
||||
}
|
||||
}
|
||||
endpwent ();
|
||||
|
||||
/*
|
||||
* If a user with UID equal to UID_MAX exists, the above algorithm
|
||||
* will give us UID_MAX+1 even if not unique. Search for the first
|
||||
* free UID starting with UID_MIN (it's O(n*n) but can be avoided
|
||||
* by not having users with UID equal to UID_MAX). --marekm
|
||||
*/
|
||||
if (user_id == uid_max + 1) {
|
||||
for (user_id = uid_min; user_id < uid_max; user_id++) {
|
||||
/* local, no need for xgetpwuid */
|
||||
if ( (getpwuid (user_id) == NULL)
|
||||
&& (pw_locate_uid (user_id) == NULL)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (user_id == uid_max) {
|
||||
fputs (_("Can't get unique UID (no more available UIDs)\n"), stderr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*uid = user_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* find_new_gid - Find a new unused GID.
|
||||
*
|
||||
* If successful, find_new_gid provides an unused group ID in the
|
||||
* [GID_MIN:GID_MAX] range.
|
||||
* This ID should be higher than all the used GID, but if not possible,
|
||||
* the lowest unused ID in the range will be returned.
|
||||
*
|
||||
* Return 0 on success, -1 if no unused GIDs are available.
|
||||
*/
|
||||
int find_new_gid (int sys_group, gid_t *gid, gid_t const *preferred_gid)
|
||||
{
|
||||
const struct group *grp;
|
||||
gid_t gid_min, gid_max, group_id;
|
||||
|
||||
assert (gid != NULL);
|
||||
|
||||
if (sys_group == 0) {
|
||||
gid_min = getdef_unum ("GID_MIN", 1000);
|
||||
gid_max = getdef_unum ("GID_MAX", 60000);
|
||||
} else {
|
||||
gid_min = getdef_unum ("SYS_GID_MIN", 1);
|
||||
gid_max = getdef_unum ("GID_MIN", 1000) - 1;
|
||||
gid_max = getdef_unum ("SYS_GID_MAX", gid_max);
|
||||
}
|
||||
|
||||
if ( (NULL != preferred_gid)
|
||||
&& (*preferred_gid >= gid_min)
|
||||
&& (*preferred_gid <= gid_max)
|
||||
/* Check if the user exists according to NSS */
|
||||
&& (getgrgid (*preferred_gid) == NULL)
|
||||
/* Check also the local database in case of uncommitted
|
||||
* changes */
|
||||
&& (gr_locate_gid (*preferred_gid) == NULL)) {
|
||||
*gid = *preferred_gid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
group_id = gid_min;
|
||||
|
||||
/*
|
||||
* Search the entire group file,
|
||||
* looking for the largest unused value.
|
||||
*
|
||||
* We check the list of users according to NSS (setpwent/getpwent),
|
||||
* but we also check the local database (pw_rewind/pw_next) in case
|
||||
* some groups were created but the changes were not committed yet.
|
||||
*/
|
||||
setgrent ();
|
||||
gr_rewind ();
|
||||
while ( ((grp = getgrent ()) != NULL)
|
||||
|| ((grp = gr_next ()) != NULL)) {
|
||||
if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) {
|
||||
group_id = grp->gr_gid + 1;
|
||||
}
|
||||
}
|
||||
endgrent ();
|
||||
|
||||
/*
|
||||
* If a group with GID equal to GID_MAX exists, the above algorithm
|
||||
* will give us GID_MAX+1 even if not unique. Search for the first
|
||||
* free GID starting with GID_MIN (it's O(n*n) but can be avoided
|
||||
* by not having users with GID equal to GID_MAX). --marekm
|
||||
*/
|
||||
if (group_id == gid_max + 1) {
|
||||
for (group_id = gid_min; group_id < gid_max; group_id++) {
|
||||
/* local, no need for xgetgrgid */
|
||||
if ( (getgrgid (group_id) == NULL)
|
||||
&& (gr_locate_gid (group_id) == NULL)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group_id == gid_max) {
|
||||
fputs (_("Can't get unique GID (no more available GIDs)\n"), stderr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*gid = group_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
184
libmisc/find_new_uid.c
Normal file
184
libmisc/find_new_uid.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 2008 - 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "pwio.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* find_new_uid - Find a new unused UID.
|
||||
*
|
||||
* If successful, find_new_uid provides an unused user ID in the
|
||||
* [UID_MIN:UID_MAX] range.
|
||||
* This ID should be higher than all the used UID, but if not possible,
|
||||
* the lowest unused ID in the range will be returned.
|
||||
*
|
||||
* Return 0 on success, -1 if no unused UIDs are available.
|
||||
*/
|
||||
int find_new_uid (bool sys_user,
|
||||
uid_t *uid,
|
||||
/*@null@*/uid_t const *preferred_uid)
|
||||
{
|
||||
const struct passwd *pwd;
|
||||
uid_t uid_min, uid_max, user_id, id;
|
||||
bool *used_uids;
|
||||
|
||||
assert (uid != NULL);
|
||||
|
||||
if (!sys_user) {
|
||||
uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL);
|
||||
uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL);
|
||||
} else {
|
||||
uid_min = (uid_t) getdef_ulong ("SYS_UID_MIN", 101UL);
|
||||
uid_max = (uid_t) getdef_ulong ("UID_MIN", 1000UL) - 1;
|
||||
uid_max = (uid_t) getdef_ulong ("SYS_UID_MAX", (unsigned long) uid_max);
|
||||
}
|
||||
used_uids = alloca (sizeof (bool) * (uid_max +1));
|
||||
memset (used_uids, false, sizeof (bool) * (uid_max + 1));
|
||||
|
||||
if ( (NULL != preferred_uid)
|
||||
&& (*preferred_uid >= uid_min)
|
||||
&& (*preferred_uid <= uid_max)
|
||||
/* Check if the user exists according to NSS */
|
||||
&& (getpwuid (*preferred_uid) == NULL)
|
||||
/* Check also the local database in case of uncommitted
|
||||
* changes */
|
||||
&& (pw_locate_uid (*preferred_uid) == NULL)) {
|
||||
*uid = *preferred_uid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search the entire password file,
|
||||
* looking for the largest unused value.
|
||||
*
|
||||
* We check the list of users according to NSS (setpwent/getpwent),
|
||||
* but we also check the local database (pw_rewind/pw_next) in case
|
||||
* some users were created but the changes were not committed yet.
|
||||
*/
|
||||
if (sys_user) {
|
||||
/* setpwent / getpwent / endpwent can be very slow with
|
||||
* LDAP configurations (and many accounts).
|
||||
* Since there is a limited amount of IDs to be tested
|
||||
* for system accounts, we just check the existence
|
||||
* of IDs with getpwuid.
|
||||
*/
|
||||
user_id = uid_max;
|
||||
for (id = uid_max; id >= uid_min; id--) {
|
||||
if (getpwuid (id) != NULL) {
|
||||
user_id = id - 1;
|
||||
used_uids[id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
pw_rewind ();
|
||||
while ((pwd = pw_next ()) != NULL) {
|
||||
if ((pwd->pw_uid <= user_id) && (pwd->pw_uid >= uid_min)) {
|
||||
user_id = pwd->pw_uid - 1;
|
||||
}
|
||||
/* create index of used UIDs */
|
||||
if (pwd->pw_uid <= uid_max) {
|
||||
used_uids[pwd->pw_uid] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user_id = uid_min;
|
||||
setpwent ();
|
||||
while ((pwd = getpwent ()) != NULL) {
|
||||
if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) {
|
||||
user_id = pwd->pw_uid + 1;
|
||||
}
|
||||
/* create index of used UIDs */
|
||||
if (pwd->pw_uid <= uid_max) {
|
||||
used_uids[pwd->pw_uid] = true;
|
||||
}
|
||||
}
|
||||
endpwent ();
|
||||
|
||||
pw_rewind ();
|
||||
while ((pwd = pw_next ()) != NULL) {
|
||||
if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) {
|
||||
user_id = pwd->pw_uid + 1;
|
||||
}
|
||||
/* create index of used UIDs */
|
||||
if (pwd->pw_uid <= uid_max) {
|
||||
used_uids[pwd->pw_uid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If a user with UID equal to UID_MAX exists, the above algorithm
|
||||
* will give us UID_MAX+1 even if not unique. Search for the first
|
||||
* free UID starting with UID_MIN.
|
||||
*/
|
||||
if (sys_user) {
|
||||
if (user_id == uid_min - 1) {
|
||||
for (user_id = uid_max; user_id >= uid_min; user_id--) {
|
||||
if (false == used_uids[user_id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (user_id < uid_min ) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique system UID (no more available UIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN,
|
||||
"no more available UID on the system"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (user_id == uid_max + 1) {
|
||||
for (user_id = uid_min; user_id < uid_max; user_id++) {
|
||||
if (false == used_uids[user_id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (user_id == uid_max) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique UID (no more available UIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available UID on the system"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*uid = user_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ relunit : tUNUMBER tYEAR_UNIT {
|
||||
|
||||
number : tUNUMBER
|
||||
{
|
||||
if (yyHaveTime && yyHaveDate && !yyHaveRel)
|
||||
if ((yyHaveTime != 0) && (yyHaveDate != 0) && (yyHaveRel == 0))
|
||||
yyYear = $1;
|
||||
else
|
||||
{
|
||||
@@ -647,10 +647,10 @@ static int LookupWord (char *buff)
|
||||
register char *q;
|
||||
register const TABLE *tp;
|
||||
int i;
|
||||
int abbrev;
|
||||
bool abbrev;
|
||||
|
||||
/* Make it lowercase. */
|
||||
for (p = buff; *p; p++)
|
||||
for (p = buff; '\0' != *p; p++)
|
||||
if (ISUPPER (*p))
|
||||
*p = tolower (*p);
|
||||
|
||||
@@ -667,14 +667,14 @@ static int LookupWord (char *buff)
|
||||
|
||||
/* See if we have an abbreviation for a month. */
|
||||
if (strlen (buff) == 3)
|
||||
abbrev = 1;
|
||||
abbrev = true;
|
||||
else if (strlen (buff) == 4 && buff[3] == '.')
|
||||
{
|
||||
abbrev = 1;
|
||||
abbrev = true;
|
||||
buff[3] = '\0';
|
||||
}
|
||||
else
|
||||
abbrev = 0;
|
||||
abbrev = false;
|
||||
|
||||
for (tp = MonthDayTable; tp->name; tp++)
|
||||
{
|
||||
@@ -743,14 +743,14 @@ static int LookupWord (char *buff)
|
||||
}
|
||||
|
||||
/* Drop out any periods and try the timezone table again. */
|
||||
for (i = 0, p = q = buff; *q; q++)
|
||||
for (i = 0, p = q = buff; '\0' != *q; q++)
|
||||
if (*q != '.')
|
||||
*p++ = *q;
|
||||
else
|
||||
i++;
|
||||
*p = '\0';
|
||||
if (i)
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (0 != i)
|
||||
for (tp = TimezoneTable; NULL != tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
@@ -790,7 +790,7 @@ yylex (void)
|
||||
yyInput--;
|
||||
if (sign < 0)
|
||||
yylval.Number = -yylval.Number;
|
||||
return sign ? tSNUMBER : tUNUMBER;
|
||||
return (0 != sign) ? tSNUMBER : tUNUMBER;
|
||||
}
|
||||
if (ISALPHA (c))
|
||||
{
|
||||
@@ -874,7 +874,8 @@ time_t get_date (const char *p, const time_t *now)
|
||||
tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
|
||||
tm.tm_mon = yyMonth - 1 + yyRelMonth;
|
||||
tm.tm_mday = yyDay + yyRelDay;
|
||||
if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
|
||||
if ((yyHaveTime != 0) ||
|
||||
( (yyHaveRel != 0) && (yyHaveDate == 0) && (yyHaveDay == 0) ))
|
||||
{
|
||||
tm.tm_hour = ToHour (yyHour, yyMeridian);
|
||||
if (tm.tm_hour < 0)
|
||||
|
||||
66
libmisc/getgr_nam_gid.c
Normal file
66
libmisc/getgr_nam_gid.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
/*
|
||||
* getgr_nam_gid - Return a pointer to the group specified by a string.
|
||||
* The string may be a valid GID or a valid groupname.
|
||||
* If the group does not exist on the system, NULL is returned.
|
||||
*/
|
||||
extern /*@null@*/struct group *getgr_nam_gid (const char *grname)
|
||||
{
|
||||
long long int gid;
|
||||
char *endptr;
|
||||
|
||||
if (NULL == grname) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
gid = strtoll (grname, &endptr, 10);
|
||||
if ( ('\0' != *grname)
|
||||
&& ('\0' == *endptr)
|
||||
&& (ERANGE != errno)
|
||||
&& (/*@+longintegral@*/gid == (gid_t)gid)/*@=longintegral@*/) {
|
||||
return xgetgrgid ((gid_t) gid);
|
||||
}
|
||||
return xgetgrnam (grname);
|
||||
}
|
||||
|
||||
124
libmisc/getrange.c
Normal file
124
libmisc/getrange.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id: $"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
/*
|
||||
* Parse a range and indicate if the range is valid.
|
||||
* Valid ranges are in the form:
|
||||
* <long> -> min=max=long has_min has_max
|
||||
* -<long> -> max=long !has_min has_max
|
||||
* <long>- -> min=long has_min !has_max
|
||||
* <long1>-<long2> -> min=long1 max=long2 has_min has_max
|
||||
*
|
||||
* If the range is valid, getrange returns 1.
|
||||
* If the range is not valid, getrange returns 0.
|
||||
*/
|
||||
int getrange (char *range,
|
||||
unsigned long *min, bool *has_min,
|
||||
unsigned long *max, bool *has_max)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long n;
|
||||
|
||||
if (NULL == range) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ('-' == range[0]) {
|
||||
if (!isdigit(range[1])) {
|
||||
/* invalid */
|
||||
return 0;
|
||||
}
|
||||
errno = 0;
|
||||
n = strtoul (&range[1], &endptr, 10);
|
||||
if (('\0' != *endptr) || (ERANGE == errno)) {
|
||||
/* invalid */
|
||||
return 0;
|
||||
}
|
||||
/* -<long> */
|
||||
*has_min = false;
|
||||
*has_max = true;
|
||||
*max = n;
|
||||
} else {
|
||||
errno = 0;
|
||||
n = strtoul (range, &endptr, 10);
|
||||
if (ERANGE == errno) {
|
||||
/* invalid */
|
||||
return 0;
|
||||
}
|
||||
switch (*endptr) {
|
||||
case '\0':
|
||||
/* <long> */
|
||||
*has_min = true;
|
||||
*has_max = true;
|
||||
*min = n;
|
||||
*max = n;
|
||||
break;
|
||||
case '-':
|
||||
endptr++;
|
||||
if ('\0' == *endptr) {
|
||||
/* <long>- */
|
||||
*has_min = true;
|
||||
*has_max = false;
|
||||
*min = n;
|
||||
} else if (!isdigit (*endptr)) {
|
||||
/* invalid */
|
||||
return 0;
|
||||
} else {
|
||||
*has_min = true;
|
||||
*min = n;
|
||||
errno = 0;
|
||||
n = strtoul (endptr, &endptr, 10);
|
||||
if ( ('\0' != *endptr)
|
||||
|| (ERANGE == errno)) {
|
||||
/* invalid */
|
||||
return 0;
|
||||
}
|
||||
/* <long>-<long> */
|
||||
*has_max = true;
|
||||
*max = n;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Copyright (c) 1991 - 1993, Chip Rosenthal
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -36,21 +37,22 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#include "getdef.h"
|
||||
#include <pwd.h>
|
||||
/*
|
||||
* hushed - determine if a user receives login messages
|
||||
*
|
||||
* Look in the hushed-logins file (or user's home directory) to see
|
||||
* if the user is to receive the login-time messages.
|
||||
*/
|
||||
int hushed (const struct passwd *pw)
|
||||
bool hushed (const char *username)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char *hushfile;
|
||||
char buf[BUFSIZ];
|
||||
int found;
|
||||
bool found;
|
||||
FILE *fp;
|
||||
|
||||
/*
|
||||
@@ -58,8 +60,15 @@ int hushed (const struct passwd *pw)
|
||||
* defined, default to a noisy login.
|
||||
*/
|
||||
|
||||
if ((hushfile = getdef_str ("HUSHLOGIN_FILE")) == NULL)
|
||||
return 0;
|
||||
hushfile = getdef_str ("HUSHLOGIN_FILE");
|
||||
if (NULL == hushfile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pw = getpwnam (username);
|
||||
if (NULL == pw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not a fully rooted path then see if the
|
||||
@@ -73,17 +82,19 @@ int hushed (const struct passwd *pw)
|
||||
|
||||
/*
|
||||
* If this is a fully rooted path then go through the file
|
||||
* and see if this user is in there.
|
||||
* and see if this user, or its shell is in there.
|
||||
*/
|
||||
|
||||
if ((fp = fopen (hushfile, "r")) == NULL)
|
||||
return 0;
|
||||
|
||||
for (found = 0; !found && fgets (buf, sizeof buf, fp);) {
|
||||
fp = fopen (hushfile, "r");
|
||||
if (NULL == fp) {
|
||||
return false;
|
||||
}
|
||||
for (found = false; !found && (fgets (buf, (int) sizeof buf, fp) == buf);) {
|
||||
buf[strlen (buf) - 1] = '\0';
|
||||
found = !strcmp (buf,
|
||||
buf[0] == '/' ? pw->pw_shell : pw->pw_name);
|
||||
found = (strcmp (buf, pw->pw_shell) == 0) ||
|
||||
(strcmp (buf, pw->pw_name) == 0);
|
||||
}
|
||||
(void) fclose (fp);
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1997, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -50,15 +51,23 @@
|
||||
*
|
||||
* isexpired calculates the expiration date based on the
|
||||
* password expiration criteria.
|
||||
*
|
||||
* Return value:
|
||||
* 0: The password is still valid
|
||||
* 1: The password has expired, it must be changed
|
||||
* 2: The password has expired since a long time and the account is
|
||||
* now disabled. (password cannot be changed)
|
||||
* 3: The account has expired
|
||||
*/
|
||||
/*ARGSUSED*/ int isexpired (const struct passwd *pw, const struct spwd *sp)
|
||||
int isexpired (const struct passwd *pw, /*@null@*/const struct spwd *sp)
|
||||
{
|
||||
long now;
|
||||
|
||||
now = time ((time_t *) 0) / SCALE;
|
||||
now = (long) time ((time_t *) 0) / SCALE;
|
||||
|
||||
if (!sp)
|
||||
sp = pwd_to_spwd (pw);
|
||||
if (NULL == sp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quick and easy - there is an expired account field
|
||||
@@ -66,8 +75,9 @@
|
||||
* one first since it is worse.
|
||||
*/
|
||||
|
||||
if (sp->sp_expire > 0 && now >= sp->sp_expire)
|
||||
if ((sp->sp_expire > 0) && (now >= sp->sp_expire)) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Last changed date 1970-01-01 (not very likely) means that
|
||||
@@ -77,12 +87,17 @@
|
||||
* if /etc/shadow doesn't exist, getspnam() still succeeds and
|
||||
* returns sp_lstchg==0 (must change password) instead of -1!
|
||||
*/
|
||||
if (sp->sp_lstchg == 0 && !strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING))
|
||||
if ( (0 == sp->sp_lstchg)
|
||||
&& (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sp->sp_lstchg > 0 && sp->sp_max >= 0 && sp->sp_inact >= 0 &&
|
||||
now >= sp->sp_lstchg + sp->sp_max + sp->sp_inact)
|
||||
if ( (sp->sp_lstchg > 0)
|
||||
&& (sp->sp_max >= 0)
|
||||
&& (sp->sp_inact >= 0)
|
||||
&& (now >= (sp->sp_lstchg + sp->sp_max + sp->sp_inact))) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The last and max fields must be present for an account
|
||||
@@ -90,9 +105,11 @@
|
||||
* is considered to be infinite.
|
||||
*/
|
||||
|
||||
if (sp->sp_lstchg == -1 ||
|
||||
sp->sp_max == -1 || sp->sp_max >= (10000L * DAY / SCALE))
|
||||
if ( (-1 == sp->sp_lstchg)
|
||||
|| (-1 == sp->sp_max)
|
||||
|| (sp->sp_max >= (10000L * DAY / SCALE))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate today's day and the day on which the password
|
||||
@@ -100,7 +117,9 @@
|
||||
* the password has expired.
|
||||
*/
|
||||
|
||||
if (now >= sp->sp_lstchg + sp->sp_max)
|
||||
if (now >= (sp->sp_lstchg + sp->sp_max)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
171
libmisc/limits.c
171
libmisc/limits.c
@@ -65,49 +65,53 @@
|
||||
* multiplier - value*multiplier is the actual limit
|
||||
*/
|
||||
static int
|
||||
setrlimit_value (unsigned int rlimit, const char *value,
|
||||
setrlimit_value (unsigned int resource, const char *value,
|
||||
unsigned int multiplier)
|
||||
{
|
||||
struct rlimit rlim;
|
||||
long limit;
|
||||
char **endptr = (char **) &value;
|
||||
const char *value_orig = value;
|
||||
|
||||
limit = strtol (value, endptr, 10);
|
||||
if (limit == 0 && value_orig == *endptr) /* no chars read */
|
||||
if (getlong (value, &limit) == 0) {
|
||||
return 0;
|
||||
}
|
||||
limit *= multiplier;
|
||||
rlim.rlim_cur = limit;
|
||||
rlim.rlim_max = limit;
|
||||
if (setrlimit (rlimit, &rlim))
|
||||
if (limit != (rlim_t) limit) {
|
||||
return 0;
|
||||
}
|
||||
rlim.rlim_cur = (rlim_t) limit;
|
||||
rlim.rlim_max = (rlim_t) limit;
|
||||
if (setrlimit (resource, &rlim) != 0) {
|
||||
return LOGIN_ERROR_RLIMIT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_prio (const char *value)
|
||||
{
|
||||
int prio;
|
||||
char **endptr = (char **) &value;
|
||||
long prio;
|
||||
|
||||
prio = strtol (value, endptr, 10);
|
||||
if ((prio == 0) && (value == *endptr))
|
||||
if ( (getlong (value, &prio) == 0)
|
||||
|| (prio != (int) prio)) {
|
||||
return 0;
|
||||
if (setpriority (PRIO_PROCESS, 0, prio))
|
||||
}
|
||||
if (setpriority (PRIO_PROCESS, 0, (int) prio) != 0) {
|
||||
return LOGIN_ERROR_RLIMIT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_umask (const char *value)
|
||||
{
|
||||
mode_t mask;
|
||||
char **endptr = (char **) &value;
|
||||
unsigned long int mask;
|
||||
|
||||
mask = strtol (value, endptr, 8) & 0777;
|
||||
if ((mask == 0) && (value == *endptr))
|
||||
if ( (getulong (value, &mask) == 0)
|
||||
|| (mask != (mode_t) mask)) {
|
||||
return 0;
|
||||
umask (mask);
|
||||
}
|
||||
|
||||
(void) umask ((mode_t) mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -115,46 +119,49 @@ static int set_umask (const char *value)
|
||||
/* Counts the number of user logins and check against the limit */
|
||||
static int check_logins (const char *name, const char *maxlogins)
|
||||
{
|
||||
#if HAVE_UTMPX_H
|
||||
#ifdef USE_UTMPX
|
||||
struct utmpx *ut;
|
||||
#else
|
||||
#else /* !USE_UTMPX */
|
||||
struct utmp *ut;
|
||||
#endif
|
||||
unsigned int limit, count;
|
||||
char **endptr = (char **) &maxlogins;
|
||||
const char *ml_orig = maxlogins;
|
||||
#endif /* !USE_UTMPX */
|
||||
unsigned long limit, count;
|
||||
|
||||
limit = strtol (maxlogins, endptr, 10);
|
||||
if (limit == 0 && ml_orig == *endptr) /* no chars read */
|
||||
if (getulong (maxlogins, &limit) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (limit == 0) { /* maximum 0 logins ? */
|
||||
if (0 == limit) { /* maximum 0 logins ? */
|
||||
SYSLOG ((LOG_WARN, "No logins allowed for `%s'\n", name));
|
||||
return LOGIN_ERROR_LOGIN;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
#if HAVE_UTMPX_H
|
||||
#ifdef USE_UTMPX
|
||||
setutxent ();
|
||||
while ((ut = getutxent ())) {
|
||||
#else
|
||||
#else /* !USE_UTMPX */
|
||||
setutent ();
|
||||
while ((ut = getutent ())) {
|
||||
#endif
|
||||
if (ut->ut_type != USER_PROCESS)
|
||||
#endif /* !USE_UTMPX */
|
||||
if (USER_PROCESS != ut->ut_type) {
|
||||
continue;
|
||||
if (ut->ut_user[0] == '\0')
|
||||
}
|
||||
if ('\0' == ut->ut_user[0]) {
|
||||
continue;
|
||||
if (strncmp (name, ut->ut_user, sizeof (ut->ut_user)) != 0)
|
||||
}
|
||||
if (strncmp (name, ut->ut_user, sizeof (ut->ut_user)) != 0) {
|
||||
continue;
|
||||
if (++count > limit)
|
||||
}
|
||||
count++;
|
||||
if (count > limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if HAVE_UTMPX_H
|
||||
#ifdef USE_UTMPX
|
||||
endutxent ();
|
||||
#else
|
||||
#else /* !USE_UTMPX */
|
||||
endutent ();
|
||||
#endif
|
||||
#endif /* !USE_UTMPX */
|
||||
/*
|
||||
* This is called after setutmp(), so the number of logins counted
|
||||
* includes the user who is currently trying to log in.
|
||||
@@ -203,10 +210,11 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
{
|
||||
const char *pp;
|
||||
int retval = 0;
|
||||
bool reported = false;
|
||||
|
||||
pp = buf;
|
||||
|
||||
while (*pp != '\0')
|
||||
while ('\0' != *pp) {
|
||||
switch (*pp++) {
|
||||
#ifdef RLIMIT_AS
|
||||
case 'a':
|
||||
@@ -298,14 +306,24 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
/* LIMIT the number of concurent logins */
|
||||
/* LIMIT the number of concurrent logins */
|
||||
retval |= check_logins (name, pp);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
retval |= set_prio (pp);
|
||||
break;
|
||||
default:
|
||||
/* Only report invalid strings once */
|
||||
if (!reported) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Invalid limit string: '%s'",
|
||||
pp-1));
|
||||
reported = true;
|
||||
retval |= LOGIN_ERROR_RLIMIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -336,8 +354,9 @@ static int setup_user_limits (const char *uname)
|
||||
* - username must start on first column
|
||||
* A better (smarter) checking should be done --cristiang */
|
||||
while (fgets (buf, 1024, fil) != NULL) {
|
||||
if (buf[0] == '#' || buf[0] == '\n')
|
||||
if (('#' == buf[0]) || ('\n' == buf[0])) {
|
||||
continue;
|
||||
}
|
||||
memzero (tempbuf, sizeof (tempbuf));
|
||||
/* a valid line should have a username, then spaces,
|
||||
* then limits
|
||||
@@ -357,11 +376,12 @@ static int setup_user_limits (const char *uname)
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose (fil);
|
||||
(void) fclose (fil);
|
||||
if (limits[0] == '\0') {
|
||||
/* no user specific limits */
|
||||
if (deflimits[0] == '\0') /* no default limits */
|
||||
if (deflimits[0] == '\0') { /* no default limits */
|
||||
return 0;
|
||||
}
|
||||
strcpy (limits, deflimits); /* use the default limits */
|
||||
}
|
||||
return do_user_limits (limits, uname);
|
||||
@@ -372,19 +392,21 @@ static int setup_user_limits (const char *uname)
|
||||
static void setup_usergroups (const struct passwd *info)
|
||||
{
|
||||
const struct group *grp;
|
||||
mode_t oldmask;
|
||||
mode_t tmpmask;
|
||||
|
||||
/*
|
||||
* if not root, and UID == GID, and username is the same as primary
|
||||
* group name, set umask group bits to be the same as owner bits
|
||||
* (examples: 022 -> 002, 077 -> 007).
|
||||
*/
|
||||
if (info->pw_uid != 0 && info->pw_uid == info->pw_gid) {
|
||||
if ((0 != info->pw_uid) && (info->pw_uid == info->pw_gid)) {
|
||||
/* local, no need for xgetgrgid */
|
||||
grp = getgrgid (info->pw_gid);
|
||||
if (grp && (strcmp (info->pw_name, grp->gr_name) == 0)) {
|
||||
oldmask = umask (0777);
|
||||
umask ((oldmask & ~070) | ((oldmask >> 3) & 070));
|
||||
if ( (NULL != grp)
|
||||
&& (strcmp (info->pw_name, grp->gr_name) == 0)) {
|
||||
tmpmask = umask (0777);
|
||||
tmpmask = (tmpmask & ~070) | ((tmpmask >> 3) & 070);
|
||||
(void) umask (tmpmask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,11 +418,10 @@ static void setup_usergroups (const struct passwd *info)
|
||||
void setup_limits (const struct passwd *info)
|
||||
{
|
||||
char *cp;
|
||||
int i;
|
||||
long l;
|
||||
|
||||
if (getdef_bool ("USERGROUPS_ENAB"))
|
||||
if (getdef_bool ("USERGROUPS_ENAB")) {
|
||||
setup_usergroups (info);
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the GECOS field contains values for NICE, UMASK or ULIMIT.
|
||||
@@ -410,33 +431,59 @@ void setup_limits (const struct passwd *info)
|
||||
|
||||
if (getdef_bool ("QUOTAS_ENAB")) {
|
||||
#ifdef LIMITS
|
||||
if (info->pw_uid != 0)
|
||||
if (info->pw_uid != 0) {
|
||||
if (setup_user_limits (info->pw_name) &
|
||||
LOGIN_ERROR_LOGIN) {
|
||||
fputs (_("Too many logins.\n"), stderr);
|
||||
sleep (2);
|
||||
exit (1);
|
||||
(void) fputs (_("Too many logins.\n"), stderr);
|
||||
(void) sleep (2); /* XXX: Should be FAIL_DELAY */
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (cp = info->pw_gecos; cp != NULL; cp = strchr (cp, ',')) {
|
||||
if (*cp == ',')
|
||||
if (',' == *cp) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (strncmp (cp, "pri=", 4) == 0) {
|
||||
i = atoi (cp + 4);
|
||||
if (i >= -20 && i <= 20)
|
||||
(void) nice (i);
|
||||
long int inc;
|
||||
if ( (getlong (cp + 4, &inc) == 1)
|
||||
&& (inc >= -20) && (inc <= 20)) {
|
||||
errno = 0;
|
||||
if ( (nice ((int) inc) != -1)
|
||||
|| (0 != errno)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed to parse or failed to nice() */
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't set the nice value for user %s",
|
||||
info->pw_name));
|
||||
|
||||
continue;
|
||||
}
|
||||
if (strncmp (cp, "ulimit=", 7) == 0) {
|
||||
l = strtol (cp + 7, (char **) 0, 10);
|
||||
set_filesize_limit (l);
|
||||
long int blocks;
|
||||
if ( (getlong (cp + 7, &blocks) == 0)
|
||||
|| (blocks != (int) blocks)
|
||||
|| (set_filesize_limit ((int) blocks) != 0)) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't set the ulimit for user %s",
|
||||
info->pw_name));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strncmp (cp, "umask=", 6) == 0) {
|
||||
i = strtol (cp + 6, (char **) 0, 8) & 0777;
|
||||
(void) umask (i);
|
||||
unsigned long int mask;
|
||||
if ( (getulong (cp + 6, &mask) == 0)
|
||||
|| (mask != (mode_t) mask)) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't set umask value for user %s",
|
||||
info->pw_name));
|
||||
} else {
|
||||
(void) umask ((mode_t) mask);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -29,13 +29,11 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Removed duplicated code from gpmain.c, useradd.c, userdel.c and
|
||||
usermod.c. --marekm */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <assert.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
/*
|
||||
@@ -45,11 +43,14 @@
|
||||
* name, and if not present it is added to a freshly allocated
|
||||
* list of users.
|
||||
*/
|
||||
char **add_list (char **list, const char *member)
|
||||
/*@only@*/ /*@out@*/char **add_list (/*@returned@*/ /*@only@*/char **list, const char *member)
|
||||
{
|
||||
int i;
|
||||
char **tmp;
|
||||
|
||||
assert (NULL != member);
|
||||
assert (NULL != list);
|
||||
|
||||
/*
|
||||
* Scan the list for the new name. Return the original list
|
||||
* pointer if it is present.
|
||||
@@ -92,11 +93,14 @@ char **add_list (char **list, const char *member)
|
||||
* list of users.
|
||||
*/
|
||||
|
||||
char **del_list (char **list, const char *member)
|
||||
/*@only@*/ /*@out@*/char **del_list (/*@returned@*/ /*@only@*/char **list, const char *member)
|
||||
{
|
||||
int i, j;
|
||||
char **tmp;
|
||||
|
||||
assert (NULL != member);
|
||||
assert (NULL != list);
|
||||
|
||||
/*
|
||||
* Scan the list for the old name. Return the original list
|
||||
* pointer if it is not present.
|
||||
@@ -137,17 +141,19 @@ char **del_list (char **list, const char *member)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
char **dup_list (char *const *list)
|
||||
/*@only@*/ /*@out@*/char **dup_list (char *const *list)
|
||||
{
|
||||
int i;
|
||||
char **tmp;
|
||||
|
||||
for (i = 0; list[i]; i++);
|
||||
assert (NULL != list);
|
||||
|
||||
for (i = 0; NULL != list[i]; i++);
|
||||
|
||||
tmp = (char **) xmalloc ((i + 1) * sizeof (char *));
|
||||
|
||||
i = 0;
|
||||
while (*list) {
|
||||
while (NULL != *list) {
|
||||
tmp[i] = xstrdup (*list);
|
||||
i++;
|
||||
list++;
|
||||
@@ -157,27 +163,34 @@ char **dup_list (char *const *list)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int is_on_list (char *const *list, const char *member)
|
||||
bool is_on_list (char *const *list, const char *member)
|
||||
{
|
||||
while (*list) {
|
||||
assert (NULL != member);
|
||||
assert (NULL != list);
|
||||
|
||||
while (NULL != *list) {
|
||||
if (strcmp (*list, member) == 0) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* comma_to_list - convert comma-separated list to (char *) array
|
||||
*/
|
||||
|
||||
char **comma_to_list (const char *comma)
|
||||
/*@only@*/char **comma_to_list (const char *comma)
|
||||
{
|
||||
char *members;
|
||||
char **array;
|
||||
int i;
|
||||
char *cp, *cp2;
|
||||
const char *cp;
|
||||
char *cp2;
|
||||
|
||||
assert (NULL != comma);
|
||||
|
||||
/*
|
||||
* Make a copy since we are going to be modifying the list
|
||||
|
||||
@@ -49,9 +49,11 @@
|
||||
* UID is extracted from the global (struct passwd) entry and the
|
||||
* TTY information is gotten from the (struct utmp).
|
||||
*/
|
||||
void
|
||||
dolastlog (struct lastlog *ll, const struct passwd *pw, const char *line,
|
||||
const char *host)
|
||||
void dolastlog (
|
||||
struct lastlog *ll,
|
||||
const struct passwd *pw,
|
||||
/*@unique@*/const char *line,
|
||||
/*@unique@*/const char *host)
|
||||
{
|
||||
int fd;
|
||||
off_t offset;
|
||||
@@ -62,18 +64,23 @@ dolastlog (struct lastlog *ll, const struct passwd *pw, const char *line,
|
||||
* If the file does not exist, don't create it.
|
||||
*/
|
||||
|
||||
if ((fd = open (LASTLOG_FILE, O_RDWR)) == -1)
|
||||
fd = open (LASTLOG_FILE, O_RDWR);
|
||||
if (-1 == fd) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The file is indexed by UID number. Seek to the record
|
||||
* for this UID. Negative UID's will create problems, but ...
|
||||
*/
|
||||
|
||||
offset = (unsigned long) pw->pw_uid * sizeof newlog;
|
||||
offset = (off_t) pw->pw_uid * sizeof newlog;
|
||||
|
||||
if (lseek (fd, offset, SEEK_SET) != offset) {
|
||||
close (fd);
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't read last lastlog entry for UID %lu in %s. Entry not updated.",
|
||||
(unsigned long) pw->pw_uid, LASTLOG_FILE));
|
||||
(void) close (fd);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,19 +90,27 @@ dolastlog (struct lastlog *ll, const struct passwd *pw, const char *line,
|
||||
* the way we read the old one in.
|
||||
*/
|
||||
|
||||
if (read (fd, (char *) &newlog, sizeof newlog) != sizeof newlog)
|
||||
if (read (fd, (void *) &newlog, sizeof newlog) != (ssize_t) sizeof newlog) {
|
||||
memzero (&newlog, sizeof newlog);
|
||||
if (ll)
|
||||
}
|
||||
if (NULL != ll) {
|
||||
*ll = newlog;
|
||||
}
|
||||
|
||||
ll_time = newlog.ll_time;
|
||||
time (&ll_time);
|
||||
(void) time (&ll_time);
|
||||
newlog.ll_time = ll_time;
|
||||
strncpy (newlog.ll_line, line, sizeof newlog.ll_line);
|
||||
#if HAVE_LL_HOST
|
||||
strncpy (newlog.ll_host, host, sizeof newlog.ll_host);
|
||||
#endif
|
||||
if (lseek (fd, offset, SEEK_SET) == offset)
|
||||
write (fd, (char *) &newlog, sizeof newlog);
|
||||
close (fd);
|
||||
if ( (lseek (fd, offset, SEEK_SET) != offset)
|
||||
|| (write (fd, (const void *) &newlog, sizeof newlog) != (ssize_t) sizeof newlog)
|
||||
|| (close (fd) != 0)) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Can't write lastlog entry for UID %lu in %s.",
|
||||
(unsigned long) pw->pw_uid, LASTLOG_FILE));
|
||||
(void) close (fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1993, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
@@ -43,7 +44,7 @@
|
||||
|
||||
static void login_exit (unused int sig)
|
||||
{
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -86,17 +87,21 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
* be displayed and display it before the prompt.
|
||||
*/
|
||||
|
||||
if (prompt) {
|
||||
if (NULL != prompt) {
|
||||
cp = getdef_str ("ISSUE_FILE");
|
||||
if (cp && (fp = fopen (cp, "r"))) {
|
||||
while ((i = getc (fp)) != EOF)
|
||||
putc (i, stdout);
|
||||
if (NULL != cp) {
|
||||
fp = fopen (cp, "r");
|
||||
if (NULL != fp) {
|
||||
while ((i = getc (fp)) != EOF) {
|
||||
(void) putc (i, stdout);
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
(void) fclose (fp);
|
||||
}
|
||||
}
|
||||
gethostname (buf, sizeof buf);
|
||||
printf (prompt, buf);
|
||||
fflush (stdout);
|
||||
(void) fflush (stdout);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -105,12 +110,14 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
*/
|
||||
|
||||
memzero (buf, sizeof buf);
|
||||
if (fgets (buf, sizeof buf, stdin) != buf)
|
||||
exit (1);
|
||||
if (fgets (buf, (int) sizeof buf, stdin) != buf) {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
cp = strchr (buf, '\n');
|
||||
if (!cp)
|
||||
exit (1);
|
||||
if (NULL == cp) {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
*cp = '\0'; /* remove \n [ must be there ] */
|
||||
|
||||
/*
|
||||
@@ -122,11 +129,13 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
for (i = 0; i < namesize - 1 && isgraph (*cp); name[i++] = *cp++);
|
||||
while (isgraph (*cp))
|
||||
while (isgraph (*cp)) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (*cp)
|
||||
if ('\0' != *cp) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
name[i] = '\0';
|
||||
|
||||
@@ -136,19 +145,23 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
* to do this, and I just take the easy way out.
|
||||
*/
|
||||
|
||||
if (*cp != '\0') { /* process new variables */
|
||||
if ('\0' != *cp) { /* process new variables */
|
||||
char *nvar;
|
||||
int count = 1;
|
||||
|
||||
for (envc = 0; envc < MAX_ENV; envc++) {
|
||||
nvar = strtok (envc ? (char *) 0 : cp, " \t,");
|
||||
if (!nvar)
|
||||
nvar = strtok ((0 != envc) ? (char *) 0 : cp, " \t,");
|
||||
if (NULL == nvar) {
|
||||
break;
|
||||
if (strchr (nvar, '=')) {
|
||||
}
|
||||
if (strchr (nvar, '=') != NULL) {
|
||||
envp[envc] = nvar;
|
||||
} else {
|
||||
envp[envc] = xmalloc (strlen (nvar) + 32);
|
||||
sprintf (envp[envc], "L%d=%s", count++, nvar);
|
||||
size_t len = strlen (nvar) + 32;
|
||||
int wlen;
|
||||
envp[envc] = xmalloc (len);
|
||||
wlen = snprintf (envp[envc], len, "L%d=%s", count++, nvar);
|
||||
assert (wlen == (int) len -1);
|
||||
}
|
||||
}
|
||||
set_env (envc, envp);
|
||||
@@ -158,8 +171,9 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
* Set the SIGQUIT handler back to its original value
|
||||
*/
|
||||
|
||||
signal (SIGQUIT, sigquit);
|
||||
(void) signal (SIGQUIT, sigquit);
|
||||
#ifdef SIGTSTP
|
||||
signal (SIGTSTP, sigtstp);
|
||||
(void) signal (SIGTSTP, sigtstp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1991, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,6 +33,7 @@
|
||||
#include <config.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -46,34 +48,45 @@ void mailcheck (void)
|
||||
struct stat statbuf;
|
||||
char *mailbox;
|
||||
|
||||
if (!getdef_bool ("MAIL_CHECK_ENAB"))
|
||||
if (!getdef_bool ("MAIL_CHECK_ENAB")) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check incoming mail in Maildir format - J.
|
||||
*/
|
||||
if ((mailbox = getenv ("MAILDIR"))) {
|
||||
mailbox = getenv ("MAILDIR");
|
||||
if (NULL != mailbox) {
|
||||
char *newmail;
|
||||
size_t len = strlen (mailbox) + 5;
|
||||
int wlen;
|
||||
|
||||
newmail = xmalloc (len);
|
||||
wlen = snprintf (newmail, len, "%s/new", mailbox);
|
||||
assert (wlen == (int) len - 1);
|
||||
|
||||
newmail = xmalloc (strlen (mailbox) + 5);
|
||||
sprintf (newmail, "%s/new", mailbox);
|
||||
if (stat (newmail, &statbuf) != -1 && statbuf.st_size != 0) {
|
||||
if (statbuf.st_mtime > statbuf.st_atime) {
|
||||
free (newmail);
|
||||
puts (_("You have new mail."));
|
||||
(void) puts (_("You have new mail."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
free (newmail);
|
||||
}
|
||||
|
||||
if (!(mailbox = getenv ("MAIL")))
|
||||
mailbox = getenv ("MAIL");
|
||||
if (NULL == mailbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0)
|
||||
puts (_("No mail."));
|
||||
else if (statbuf.st_atime > statbuf.st_mtime)
|
||||
puts (_("You have mail."));
|
||||
else
|
||||
puts (_("You have new mail."));
|
||||
if ( (stat (mailbox, &statbuf) == -1)
|
||||
|| (statbuf.st_size == 0)) {
|
||||
(void) puts (_("No mail."));
|
||||
} else if (statbuf.st_atime > statbuf.st_mtime) {
|
||||
(void) puts (_("You have mail."));
|
||||
} else {
|
||||
(void) puts (_("You have new mail."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 1996 - 1997, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
#include "prototypes.h"
|
||||
struct passwd *get_my_pwent (void)
|
||||
/*@null@*/ /*@only@*/struct passwd *get_my_pwent (void)
|
||||
{
|
||||
struct passwd *pw;
|
||||
const char *cp = getlogin ();
|
||||
@@ -57,8 +57,12 @@ struct passwd *get_my_pwent (void)
|
||||
* XXX - when running from su, will return the current user (not
|
||||
* the original user, like getlogin() does). Does this matter?
|
||||
*/
|
||||
if (cp && *cp && (pw = xgetpwnam (cp)) && pw->pw_uid == ruid)
|
||||
return pw;
|
||||
if ((NULL != cp) && ('\0' != *cp)) {
|
||||
pw = xgetpwnam (cp);
|
||||
if ((NULL != pw) && (pw->pw_uid == ruid)) {
|
||||
return pw;
|
||||
}
|
||||
}
|
||||
|
||||
return xgetpwuid (ruid);
|
||||
}
|
||||
|
||||
@@ -50,24 +50,26 @@
|
||||
/*
|
||||
* can't be a palindrome - like `R A D A R' or `M A D A M'
|
||||
*/
|
||||
static int palindrome (unused const char *old, const char *new)
|
||||
static bool palindrome (unused const char *old, const char *new)
|
||||
{
|
||||
int i, j;
|
||||
size_t i, j;
|
||||
|
||||
i = strlen (new);
|
||||
|
||||
for (j = 0; j < i; j++)
|
||||
if (new[i - j - 1] != new[j])
|
||||
return 0;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (new[i - j - 1] != new[j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* more than half of the characters are different ones.
|
||||
*/
|
||||
|
||||
static int similar (const char *old, const char *new)
|
||||
static bool similar (const char *old, const char *new)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
@@ -77,17 +79,21 @@ static int similar (const char *old, const char *new)
|
||||
* the new password is long enough. Please feel free to suggest
|
||||
* something better... --marekm
|
||||
*/
|
||||
if (strlen (new) >= 8)
|
||||
return 0;
|
||||
if (strlen (new) >= 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = j = 0; new[i] && old[i]; i++)
|
||||
if (strchr (new, old[i]))
|
||||
for (i = j = 0; ('\0' != new[i]) && ('\0' != old[i]); i++) {
|
||||
if (strchr (new, old[i]) != NULL) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= j * 2)
|
||||
return 0;
|
||||
if (i >= j * 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -96,22 +102,23 @@ static int similar (const char *old, const char *new)
|
||||
|
||||
static int simple (unused const char *old, const char *new)
|
||||
{
|
||||
int digits = 0;
|
||||
int uppers = 0;
|
||||
int lowers = 0;
|
||||
int others = 0;
|
||||
bool digits = false;
|
||||
bool uppers = false;
|
||||
bool lowers = false;
|
||||
bool others = false;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
for (i = 0; new[i]; i++) {
|
||||
if (isdigit (new[i]))
|
||||
digits++;
|
||||
else if (isupper (new[i]))
|
||||
uppers++;
|
||||
else if (islower (new[i]))
|
||||
lowers++;
|
||||
else
|
||||
others++;
|
||||
for (i = 0; '\0' != new[i]; i++) {
|
||||
if (isdigit (new[i])) {
|
||||
digits = true;
|
||||
} else if (isupper (new[i])) {
|
||||
uppers = true;
|
||||
} else if (islower (new[i])) {
|
||||
lowers = true;
|
||||
} else {
|
||||
others = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,27 +127,33 @@ static int simple (unused const char *old, const char *new)
|
||||
*/
|
||||
|
||||
size = 9;
|
||||
if (digits)
|
||||
if (digits) {
|
||||
size--;
|
||||
if (uppers)
|
||||
}
|
||||
if (uppers) {
|
||||
size--;
|
||||
if (lowers)
|
||||
}
|
||||
if (lowers) {
|
||||
size--;
|
||||
if (others)
|
||||
}
|
||||
if (others) {
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size <= i)
|
||||
return 0;
|
||||
if (size <= i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *str_lower (char *string)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
for (cp = string; *cp; cp++)
|
||||
for (cp = string; '\0' != *cp; cp++) {
|
||||
*cp = tolower (*cp);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
@@ -160,8 +173,9 @@ static const char *password_check (const char *old, const char *new,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (strcmp (new, old) == 0)
|
||||
if (strcmp (new, old) == 0) {
|
||||
return _("no change");
|
||||
}
|
||||
|
||||
newmono = str_lower (xstrdup (new));
|
||||
oldmono = str_lower (xstrdup (old));
|
||||
@@ -169,33 +183,32 @@ static const char *password_check (const char *old, const char *new,
|
||||
strcpy (wrapped, oldmono);
|
||||
strcat (wrapped, oldmono);
|
||||
|
||||
if (palindrome (oldmono, newmono))
|
||||
if (palindrome (oldmono, newmono)) {
|
||||
msg = _("a palindrome");
|
||||
|
||||
if (!msg && strcmp (oldmono, newmono) == 0)
|
||||
} else if (strcmp (oldmono, newmono) == 0) {
|
||||
msg = _("case changes only");
|
||||
|
||||
if (!msg && similar (oldmono, newmono))
|
||||
} else if (similar (oldmono, newmono)) {
|
||||
msg = _("too similar");
|
||||
|
||||
if (!msg && simple (old, new))
|
||||
} else if (simple (old, new)) {
|
||||
msg = _("too simple");
|
||||
|
||||
if (!msg && strstr (wrapped, newmono))
|
||||
} else if (strstr (wrapped, newmono) != NULL) {
|
||||
msg = _("rotated");
|
||||
|
||||
} else {
|
||||
#ifdef HAVE_LIBCRACK
|
||||
/*
|
||||
* Invoke Alec Muffett's cracklib routines.
|
||||
*/
|
||||
/*
|
||||
* Invoke Alec Muffett's cracklib routines.
|
||||
*/
|
||||
|
||||
if (!msg && (dictpath = getdef_str ("CRACKLIB_DICTPATH")))
|
||||
dictpath = getdef_str ("CRACKLIB_DICTPATH");
|
||||
if (NULL != dictpath) {
|
||||
#ifdef HAVE_LIBCRACK_PW
|
||||
msg = FascistCheckPw (new, dictpath, pwdp);
|
||||
msg = FascistCheckPw (new, dictpath, pwdp);
|
||||
#else
|
||||
msg = FascistCheck (new, dictpath);
|
||||
msg = FascistCheck (new, dictpath);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
strzero (newmono);
|
||||
strzero (oldmono);
|
||||
strzero (wrapped);
|
||||
@@ -206,11 +219,11 @@ static const char *password_check (const char *old, const char *new,
|
||||
return msg;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static const char *obscure_msg (const char *old, const char *new,
|
||||
/*ARGSUSED*/
|
||||
static const char *obscure_msg (const char *old, const char *new,
|
||||
const struct passwd *pwdp)
|
||||
{
|
||||
int maxlen, oldlen, newlen;
|
||||
size_t maxlen, oldlen, newlen;
|
||||
char *new1, *old1;
|
||||
const char *msg;
|
||||
char *result;
|
||||
@@ -218,50 +231,60 @@ static const char *password_check (const char *old, const char *new,
|
||||
oldlen = strlen (old);
|
||||
newlen = strlen (new);
|
||||
|
||||
if (newlen < getdef_num ("PASS_MIN_LEN", 0))
|
||||
if (newlen < (size_t) getdef_num ("PASS_MIN_LEN", 0)) {
|
||||
return _("too short");
|
||||
}
|
||||
|
||||
/*
|
||||
* Remaining checks are optional.
|
||||
*/
|
||||
if (!getdef_bool ("OBSCURE_CHECKS_ENAB"))
|
||||
if (!getdef_bool ("OBSCURE_CHECKS_ENAB")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msg = password_check (old, new, pwdp);
|
||||
if (msg)
|
||||
if (NULL != msg) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if ((result = getdef_str ("ENCRYPT_METHOD")) == NULL) {
|
||||
result = getdef_str ("ENCRYPT_METHOD");
|
||||
if (NULL == result) {
|
||||
/* The traditional crypt() truncates passwords to 8 chars. It is
|
||||
possible to circumvent the above checks by choosing an easy
|
||||
8-char password and adding some random characters to it...
|
||||
Example: "password$%^&*123". So check it again, this time
|
||||
truncated to the maximum length. Idea from npasswd. --marekm */
|
||||
|
||||
if (getdef_bool ("MD5_CRYPT_ENAB"))
|
||||
if (getdef_bool ("MD5_CRYPT_ENAB")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( !strcmp (result, "MD5")
|
||||
if ( (strcmp (result, "MD5") == 0)
|
||||
#ifdef USE_SHA_CRYPT
|
||||
|| !strcmp (result, "SHA256")
|
||||
|| !strcmp (result, "SHA512")
|
||||
|| (strcmp (result, "SHA256") == 0)
|
||||
|| (strcmp (result, "SHA512") == 0)
|
||||
#endif
|
||||
)
|
||||
) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
maxlen = getdef_num ("PASS_MAX_LEN", 8);
|
||||
if (oldlen <= maxlen && newlen <= maxlen)
|
||||
maxlen = (size_t) getdef_num ("PASS_MAX_LEN", 8);
|
||||
if ( (oldlen <= maxlen)
|
||||
&& (newlen <= maxlen)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new1 = xstrdup (new);
|
||||
old1 = xstrdup (old);
|
||||
if (newlen > maxlen)
|
||||
if (newlen > maxlen) {
|
||||
new1[maxlen] = '\0';
|
||||
if (oldlen > maxlen)
|
||||
}
|
||||
if (oldlen > maxlen) {
|
||||
old1[maxlen] = '\0';
|
||||
}
|
||||
|
||||
msg = password_check (old1, new1, pwdp);
|
||||
|
||||
@@ -285,7 +308,7 @@ int obscure (const char *old, const char *new, const struct passwd *pwdp)
|
||||
{
|
||||
const char *msg = obscure_msg (old, new, pwdp);
|
||||
|
||||
if (msg) {
|
||||
if (NULL != msg) {
|
||||
printf (_("Bad password: %s. "), msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,10 +37,7 @@
|
||||
|
||||
|
||||
/*
|
||||
* Change the user's password using PAM. Requires libpam and libpam_misc
|
||||
* (for misc_conv). Note: libpam_misc is probably Linux-PAM specific,
|
||||
* so you may have to port it if you want to use this code on non-Linux
|
||||
* systems with PAM (such as Solaris 2.6). --marekm
|
||||
* Change the user's password using PAM.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -50,7 +47,7 @@
|
||||
#include "pam_defs.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
void do_pam_passwd (const char *user, int silent, int change_expired)
|
||||
void do_pam_passwd (const char *user, bool silent, bool change_expired)
|
||||
{
|
||||
pam_handle_t *pamh = NULL;
|
||||
int flags = 0, ret;
|
||||
@@ -76,7 +73,7 @@ void do_pam_passwd (const char *user, int silent, int change_expired)
|
||||
}
|
||||
|
||||
fputs (_("passwd: password updated successfully\n"), stderr);
|
||||
pam_end (pamh, PAM_SUCCESS);
|
||||
(void) pam_end (pamh, PAM_SUCCESS);
|
||||
}
|
||||
#else /* !USE_PAM */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
|
||||
167
libmisc/pam_pass_non_interractive.c
Normal file
167
libmisc/pam_pass_non_interractive.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id:$"
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
/*@null@*/ /*@only@*/static char *non_interactive_password = NULL;
|
||||
static int ni_conv (int num_msg,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
unused void *appdata_ptr);
|
||||
static struct pam_conv non_interactive_pam_conv = {
|
||||
ni_conv,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int ni_conv (int num_msg,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
unused void *appdata_ptr)
|
||||
{
|
||||
struct pam_response *responses;
|
||||
int count;
|
||||
|
||||
assert (NULL != non_interactive_password);
|
||||
|
||||
if (num_msg <= 0) {
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
responses = (struct pam_response *) calloc ((size_t) num_msg,
|
||||
sizeof (*responses));
|
||||
if (NULL == responses) {
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
for (count=0; count < num_msg; count++) {
|
||||
responses[count].resp_retcode = 0;
|
||||
|
||||
switch (msg[count]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
fprintf (stderr,
|
||||
_("%s: PAM modules requesting echoing are not supported.\n"),
|
||||
Prog);
|
||||
goto failed_conversation;
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
responses[count].resp = strdup (non_interactive_password);
|
||||
if (NULL == responses[count].resp) {
|
||||
goto failed_conversation;
|
||||
}
|
||||
break;
|
||||
case PAM_ERROR_MSG:
|
||||
if ( (NULL == msg[count]->msg)
|
||||
|| (fprintf (stderr, "%s\n", msg[count]->msg) <0)) {
|
||||
goto failed_conversation;
|
||||
}
|
||||
responses[count].resp = NULL;
|
||||
break;
|
||||
case PAM_TEXT_INFO:
|
||||
if ( (NULL == msg[count]->msg)
|
||||
|| (fprintf (stdout, "%s\n", msg[count]->msg) <0)) {
|
||||
goto failed_conversation;
|
||||
}
|
||||
responses[count].resp = NULL;
|
||||
break;
|
||||
default:
|
||||
(void) fprintf (stderr,
|
||||
_("%s: conversation type %d not supported.\n"),
|
||||
Prog, msg[count]->msg_style);
|
||||
goto failed_conversation;
|
||||
}
|
||||
}
|
||||
|
||||
*resp = responses;
|
||||
|
||||
return PAM_SUCCESS;
|
||||
|
||||
failed_conversation:
|
||||
for (count=0; count < num_msg; count++) {
|
||||
if (NULL != responses[count].resp) {
|
||||
memset (responses[count].resp, 0,
|
||||
strlen (responses[count].resp));
|
||||
free (responses[count].resp);
|
||||
responses[count].resp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free (responses);
|
||||
*resp = NULL;
|
||||
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Change non interactively the user's password using PAM.
|
||||
*
|
||||
* Return 0 on success, 1 on failure.
|
||||
*/
|
||||
int do_pam_passwd_non_interractive (const char *pam_service,
|
||||
const char *username,
|
||||
const char* password)
|
||||
{
|
||||
pam_handle_t *pamh = NULL;
|
||||
int ret;
|
||||
|
||||
ret = pam_start (pam_service, username, &non_interactive_pam_conv, &pamh);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
fprintf (stderr,
|
||||
_("%s: (user %s) pam_start failure %d\n"),
|
||||
Prog, username, ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
non_interactive_password = password;
|
||||
ret = pam_chauthtok (pamh, 0);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
fprintf (stderr,
|
||||
_("%s: (user %s) pam_chauthtok() failed, error:\n"
|
||||
"%s\n"),
|
||||
Prog, username, pam_strerror (pamh, ret));
|
||||
}
|
||||
|
||||
(void) pam_end (pamh, PAM_SUCCESS);
|
||||
|
||||
return ((PAM_SUCCESS == ret) ? 0 : 1);
|
||||
}
|
||||
#else /* !USE_PAM */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !USE_PAM */
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1997, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,6 +34,8 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#ifndef USE_PAM
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
@@ -64,7 +66,12 @@ struct spwd *pwd_to_spwd (const struct passwd *pw)
|
||||
*/
|
||||
sp.sp_min = 0;
|
||||
sp.sp_max = (10000L * DAY) / SCALE;
|
||||
sp.sp_lstchg = time ((time_t *) 0) / SCALE;
|
||||
sp.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
|
||||
if (0 == sp.sp_lstchg) {
|
||||
/* Better disable aging than requiring a password
|
||||
* change */
|
||||
sp.sp_lstchg = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -74,7 +81,11 @@ struct spwd *pwd_to_spwd (const struct passwd *pw)
|
||||
sp.sp_warn = -1;
|
||||
sp.sp_expire = -1;
|
||||
sp.sp_inact = -1;
|
||||
sp.sp_flag = -1;
|
||||
sp.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||
|
||||
return &sp;
|
||||
}
|
||||
#else /* USE_PAM */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "defines.h"
|
||||
#include "pwauth.h"
|
||||
|
||||
void passwd_check (const char *user, const char *passwd, const char *progname)
|
||||
void passwd_check (const char *user, const char *passwd, unused const char *progname)
|
||||
{
|
||||
struct spwd *sp;
|
||||
|
||||
@@ -50,9 +50,9 @@ void passwd_check (const char *user, const char *passwd, const char *progname)
|
||||
}
|
||||
if (pw_auth (passwd, user, PW_LOGIN, (char *) 0) != 0) {
|
||||
SYSLOG ((LOG_WARN, "incorrect password for `%s'", user));
|
||||
sleep (1);
|
||||
(void) sleep (1);
|
||||
fprintf (stderr, _("Incorrect password for %s.\n"), user);
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#else /* USE_PAM */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -110,26 +110,30 @@ static struct {
|
||||
-1, -1}
|
||||
};
|
||||
|
||||
static void get_remote_string (char *buf, int size)
|
||||
static void get_remote_string (char *buf, size_t size)
|
||||
{
|
||||
for (;;) {
|
||||
if (read (0, buf, 1) != 1)
|
||||
exit (1);
|
||||
if (*buf == '\0')
|
||||
if (read (0, buf, 1) != 1) {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if ('\0' == *buf) {
|
||||
return;
|
||||
if (--size > 0)
|
||||
}
|
||||
--size;
|
||||
if (size > 0) {
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/}
|
||||
|
||||
int
|
||||
do_rlogin (const char *remote_host, char *name, int namelen, char *term,
|
||||
int termlen)
|
||||
do_rlogin (const char *remote_host, char *name, size_t namelen, char *term,
|
||||
size_t termlen)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
char remote_name[32];
|
||||
char *cp;
|
||||
int remote_speed = 9600;
|
||||
unsigned long remote_speed = 9600;
|
||||
int speed_name = B9600;
|
||||
int i;
|
||||
TERMIO termio;
|
||||
@@ -138,17 +142,23 @@ do_rlogin (const char *remote_host, char *name, int namelen, char *term,
|
||||
get_remote_string (name, namelen);
|
||||
get_remote_string (term, termlen);
|
||||
|
||||
if ((cp = strchr (term, '/'))) {
|
||||
*cp++ = '\0';
|
||||
cp = strchr (term, '/');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
|
||||
if (!(remote_speed = atoi (cp)))
|
||||
if (getulong (cp, &remote_speed) == 0) {
|
||||
remote_speed = 9600;
|
||||
}
|
||||
}
|
||||
for (i = 0; speed_table[i].spd_baud != remote_speed &&
|
||||
speed_table[i].spd_name != -1; i++);
|
||||
for (i = 0;
|
||||
( (speed_table[i].spd_baud != remote_speed)
|
||||
&& (speed_table[i].spd_name != -1));
|
||||
i++);
|
||||
|
||||
if (speed_table[i].spd_name != -1)
|
||||
if (-1 != speed_table[i].spd_name) {
|
||||
speed_name = speed_table[i].spd_name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the terminal in cooked mode with echo turned on.
|
||||
@@ -165,8 +175,10 @@ do_rlogin (const char *remote_host, char *name, int namelen, char *term,
|
||||
#endif
|
||||
STTY (0, &termio);
|
||||
|
||||
if (!(pwd = getpwnam (name))) /* local, no need for xgetpwnam */
|
||||
pwd = getpwnam (name); /* local, no need for xgetpwnam */
|
||||
if (NULL == pwd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ruserok() returns 0 for success on modern systems, and 1 on
|
||||
|
||||
@@ -20,18 +20,15 @@
|
||||
#include "getdef.h"
|
||||
|
||||
/* local function prototypes */
|
||||
#ifndef HAVE_L64A
|
||||
char *l64a(long value);
|
||||
#endif /* !HAVE_L64A */
|
||||
static void seedRNG (void);
|
||||
static char *gensalt (unsigned int salt_size);
|
||||
static /*@observer@*/const char *gensalt (size_t salt_size);
|
||||
#ifdef USE_SHA_CRYPT
|
||||
static unsigned int SHA_salt_size (void);
|
||||
static const char *SHA_salt_rounds (int *prefered_rounds);
|
||||
static size_t SHA_salt_size (void);
|
||||
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds);
|
||||
#endif /* USE_SHA_CRYPT */
|
||||
|
||||
#ifndef HAVE_L64A
|
||||
static char *l64a(long value)
|
||||
static /*@observer@*/char *l64a(long value)
|
||||
{
|
||||
static char buf[8];
|
||||
char *s = buf;
|
||||
@@ -46,14 +43,15 @@ static char *l64a(long value)
|
||||
for (i = 0; value != 0 && i < 6; i++) {
|
||||
digit = value & 0x3f;
|
||||
|
||||
if (digit < 2)
|
||||
if (digit < 2) {
|
||||
*s = digit + '.';
|
||||
else if (digit < 12)
|
||||
} else if (digit < 12) {
|
||||
*s = digit + '0' - 2;
|
||||
else if (digit < 38)
|
||||
} else if (digit < 38) {
|
||||
*s = digit + 'A' - 12;
|
||||
else
|
||||
} else {
|
||||
*s = digit + 'a' - 38;
|
||||
}
|
||||
|
||||
value >>= 6;
|
||||
s++;
|
||||
@@ -71,8 +69,8 @@ static void seedRNG (void)
|
||||
static int seeded = 0;
|
||||
|
||||
if (0 == seeded) {
|
||||
gettimeofday(&tv, NULL);
|
||||
srandom (tv.tv_sec + tv.tv_usec);
|
||||
(void) gettimeofday (&tv, NULL);
|
||||
srandom (tv.tv_sec ^ tv.tv_usec ^ getpid ());
|
||||
seeded = 1;
|
||||
}
|
||||
}
|
||||
@@ -88,18 +86,14 @@ static void seedRNG (void)
|
||||
* The size of the salt string is between 8 and 16 bytes for the SHA crypt
|
||||
* methods.
|
||||
*/
|
||||
static unsigned int SHA_salt_size (void)
|
||||
static size_t SHA_salt_size (void)
|
||||
{
|
||||
double rand_size;
|
||||
seedRNG ();
|
||||
rand_size = (double) 9.0 * random () / RAND_MAX;
|
||||
return 8 + rand_size;
|
||||
return (size_t) (8 + rand_size);
|
||||
}
|
||||
|
||||
/* ! Arguments evaluated twice ! */
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
/* Default number of rounds if not explicitly specified. */
|
||||
#define ROUNDS_DEFAULT 5000
|
||||
/* Minimum number of rounds. */
|
||||
@@ -110,7 +104,7 @@ static unsigned int SHA_salt_size (void)
|
||||
/*
|
||||
* Return a salt prefix specifying the rounds number for the SHA crypt methods.
|
||||
*/
|
||||
static const char *SHA_salt_rounds (int *prefered_rounds)
|
||||
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds)
|
||||
{
|
||||
static char rounds_prefix[18];
|
||||
long rounds;
|
||||
@@ -120,41 +114,49 @@ static const char *SHA_salt_rounds (int *prefered_rounds)
|
||||
long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
|
||||
double rand_rounds;
|
||||
|
||||
if (-1 == min_rounds && -1 == max_rounds)
|
||||
if ((-1 == min_rounds) && (-1 == max_rounds)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (-1 == min_rounds)
|
||||
if (-1 == min_rounds) {
|
||||
min_rounds = max_rounds;
|
||||
}
|
||||
|
||||
if (-1 == max_rounds)
|
||||
if (-1 == max_rounds) {
|
||||
max_rounds = min_rounds;
|
||||
}
|
||||
|
||||
if (min_rounds > max_rounds)
|
||||
if (min_rounds > max_rounds) {
|
||||
max_rounds = min_rounds;
|
||||
}
|
||||
|
||||
seedRNG ();
|
||||
rand_rounds = (double) (max_rounds-min_rounds+1.0) * random ();
|
||||
rand_rounds /= RAND_MAX;
|
||||
rounds = min_rounds + rand_rounds;
|
||||
} else if (0 == *prefered_rounds)
|
||||
} else if (0 == *prefered_rounds) {
|
||||
return "";
|
||||
else
|
||||
} else {
|
||||
rounds = *prefered_rounds;
|
||||
}
|
||||
|
||||
/* Sanity checks. The libc should also check this, but this
|
||||
* protects against a rounds_prefix overflow. */
|
||||
if (rounds < ROUNDS_MIN)
|
||||
if (rounds < ROUNDS_MIN) {
|
||||
rounds = ROUNDS_MIN;
|
||||
}
|
||||
|
||||
if (rounds > ROUNDS_MAX)
|
||||
if (rounds > ROUNDS_MAX) {
|
||||
rounds = ROUNDS_MAX;
|
||||
}
|
||||
|
||||
snprintf (rounds_prefix, 18, "rounds=%ld$", rounds);
|
||||
|
||||
/* Sanity checks. That should not be necessary. */
|
||||
rounds_prefix[17] = '\0';
|
||||
if ('$' != rounds_prefix[16])
|
||||
if ('$' != rounds_prefix[16]) {
|
||||
rounds_prefix[17] = '$';
|
||||
}
|
||||
|
||||
return rounds_prefix;
|
||||
}
|
||||
@@ -166,7 +168,7 @@ static const char *SHA_salt_rounds (int *prefered_rounds)
|
||||
#define MAX_SALT_SIZE 16
|
||||
#define MIN_SALT_SIZE 8
|
||||
|
||||
static char *gensalt (unsigned int salt_size)
|
||||
static /*@observer@*/const char *gensalt (size_t salt_size)
|
||||
{
|
||||
static char salt[32];
|
||||
|
||||
@@ -179,6 +181,7 @@ static char *gensalt (unsigned int salt_size)
|
||||
do {
|
||||
strcat (salt, l64a (random()));
|
||||
} while (strlen (salt) < salt_size);
|
||||
|
||||
salt[salt_size] = '\0';
|
||||
|
||||
return salt;
|
||||
@@ -199,7 +202,7 @@ static char *gensalt (unsigned int salt_size)
|
||||
* * For the SHA256 and SHA512 method, this specifies the number of rounds
|
||||
* (if not NULL).
|
||||
*/
|
||||
char *crypt_make_salt (const char *meth, void *arg)
|
||||
/*@observer@*/const char *crypt_make_salt (/*@null@*/const char *meth, /*@null@*/void *arg)
|
||||
{
|
||||
/* Max result size for the SHA methods:
|
||||
* +3 $5$
|
||||
@@ -216,8 +219,10 @@ char *crypt_make_salt (const char *meth, void *arg)
|
||||
if (NULL != meth)
|
||||
method = meth;
|
||||
else {
|
||||
if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL)
|
||||
method = getdef_bool ("MD5_CRYPT_ENAB") ? "MD5" : "DES";
|
||||
method = getdef_str ("ENCRYPT_METHOD");
|
||||
if (NULL == method) {
|
||||
method = getdef_bool ("MD5_CRYPT_ENAB") ? "MD5" : "DES";
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == strcmp (method, "MD5")) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -39,14 +40,21 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* setup_uid_gid() split in two functions for PAM support -
|
||||
* pam_setcred() needs to be called after initgroups(), but
|
||||
* before setuid().
|
||||
* setup_groups - set the group credentials
|
||||
* set the group ID to the value from the password file entry
|
||||
* set the supplementary group IDs
|
||||
*
|
||||
* In case of PAM enabled configurations, this shall be called before
|
||||
* pam_setcred.
|
||||
*
|
||||
* Returns 0 on success, or -1 on failure.
|
||||
*/
|
||||
int setup_groups (const struct passwd *info)
|
||||
{
|
||||
@@ -55,9 +63,10 @@ int setup_groups (const struct passwd *info)
|
||||
* file.
|
||||
*/
|
||||
if (setgid (info->pw_gid) == -1) {
|
||||
int err = errno;
|
||||
perror ("setgid");
|
||||
SYSLOG ((LOG_ERR, "bad group ID `%d' for user `%s': %m\n",
|
||||
info->pw_gid, info->pw_name));
|
||||
SYSLOG ((LOG_ERR, "bad group ID `%d' for user `%s': %s\n",
|
||||
info->pw_gid, info->pw_name, strerror (err)));
|
||||
closelog ();
|
||||
return -1;
|
||||
}
|
||||
@@ -67,9 +76,10 @@ int setup_groups (const struct passwd *info)
|
||||
* the group set from the /etc/group file.
|
||||
*/
|
||||
if (initgroups (info->pw_name, info->pw_gid) == -1) {
|
||||
int err = errno;
|
||||
perror ("initgroups");
|
||||
SYSLOG ((LOG_ERR, "initgroups failed for user `%s': %m\n",
|
||||
info->pw_name));
|
||||
SYSLOG ((LOG_ERR, "initgroups failed for user `%s': %s\n",
|
||||
info->pw_name, strerror (err)));
|
||||
closelog ();
|
||||
return -1;
|
||||
}
|
||||
@@ -77,15 +87,21 @@ int setup_groups (const struct passwd *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* change_uid - Set the real UID
|
||||
*
|
||||
* Returns 0 on success, or -1 on failure.
|
||||
*/
|
||||
int change_uid (const struct passwd *info)
|
||||
{
|
||||
/*
|
||||
* Set the real UID to the UID value in the password file.
|
||||
*/
|
||||
if (setuid (info->pw_uid)) {
|
||||
if (setuid (info->pw_uid) != 0) {
|
||||
int err = errno;
|
||||
perror ("setuid");
|
||||
SYSLOG ((LOG_ERR, "bad user ID `%d' for user `%s': %m\n",
|
||||
(int) info->pw_uid, info->pw_name));
|
||||
SYSLOG ((LOG_ERR, "bad user ID `%d' for user `%s': %s\n",
|
||||
(int) info->pw_uid, info->pw_name, strerror (err)));
|
||||
closelog ();
|
||||
return -1;
|
||||
}
|
||||
@@ -103,22 +119,30 @@ int change_uid (const struct passwd *info)
|
||||
* Returns 0 on success, or -1 on failure.
|
||||
*/
|
||||
|
||||
int setup_uid_gid (const struct passwd *info, int is_console)
|
||||
#if defined (HAVE_INITGROUPS) && ! (defined USE_PAM)
|
||||
int setup_uid_gid (const struct passwd *info, bool is_console)
|
||||
#else
|
||||
int setup_uid_gid (const struct passwd *info)
|
||||
#endif
|
||||
{
|
||||
if (setup_groups (info) < 0)
|
||||
if (setup_groups (info) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_INITGROUPS
|
||||
#if defined (HAVE_INITGROUPS) && ! defined (USE_PAM)
|
||||
if (is_console) {
|
||||
char *cp = getdef_str ("CONSOLE_GROUPS");
|
||||
|
||||
if (cp && add_groups (cp))
|
||||
if ((NULL != cp) && (add_groups (cp) != 0)) {
|
||||
perror ("Warning: add_groups");
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_INITGROUPS */
|
||||
#endif /* HAVE_INITGROUPS && !USE_PAM*/
|
||||
|
||||
if (change_uid (info) < 0)
|
||||
if (change_uid (info) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
@@ -52,9 +53,13 @@ static void
|
||||
addenv_path (const char *varname, const char *dirname, const char *filename)
|
||||
{
|
||||
char *buf;
|
||||
size_t len = strlen (dirname) + strlen (filename) + 2;
|
||||
int wlen;
|
||||
|
||||
buf = xmalloc (len);
|
||||
wlen = snprintf (buf, len, "%s/%s", dirname, filename);
|
||||
assert (wlen == (int) len - 1);
|
||||
|
||||
buf = xmalloc (strlen (dirname) + strlen (filename) + 2);
|
||||
sprintf (buf, "%s/%s", dirname, filename);
|
||||
addenv (varname, buf);
|
||||
free (buf);
|
||||
}
|
||||
@@ -66,31 +71,38 @@ static void read_env_file (const char *filename)
|
||||
char *cp, *name, *val;
|
||||
|
||||
fp = fopen (filename, "r");
|
||||
if (!fp)
|
||||
if (NULL == fp) {
|
||||
return;
|
||||
}
|
||||
while (fgets (buf, sizeof buf, fp) == buf) {
|
||||
cp = strrchr (buf, '\n');
|
||||
if (!cp)
|
||||
if (NULL == cp) {
|
||||
break;
|
||||
}
|
||||
*cp = '\0';
|
||||
|
||||
cp = buf;
|
||||
/* ignore whitespace and comments */
|
||||
while (*cp && isspace (*cp))
|
||||
while (('\0' != *cp) && isspace (*cp)) {
|
||||
cp++;
|
||||
if (*cp == '\0' || *cp == '#')
|
||||
}
|
||||
if (('\0' == *cp) || ('#' == *cp)) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* ignore lines which don't follow the name=value format
|
||||
* (for example, the "export NAME" shell commands)
|
||||
*/
|
||||
name = cp;
|
||||
while (*cp && !isspace (*cp) && *cp != '=')
|
||||
while (('\0' != *cp) && !isspace (*cp) && ('=' != *cp)) {
|
||||
cp++;
|
||||
if (*cp != '=')
|
||||
}
|
||||
if ('=' != *cp) {
|
||||
continue;
|
||||
}
|
||||
/* NUL-terminate the name */
|
||||
*cp++ = '\0';
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
val = cp;
|
||||
#if 0 /* XXX untested, and needs rewrite with fewer goto's :-) */
|
||||
/*
|
||||
@@ -174,7 +186,7 @@ static void read_env_file (const char *filename)
|
||||
*/
|
||||
addenv (name, val);
|
||||
}
|
||||
fclose (fp);
|
||||
(void) fclose (fp);
|
||||
}
|
||||
#endif /* USE_PAM */
|
||||
|
||||
@@ -213,9 +225,9 @@ void setup_env (struct passwd *info)
|
||||
"unable to cd to `%s' for user `%s'\n",
|
||||
info->pw_dir, info->pw_name));
|
||||
closelog ();
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
puts (_("No directory, logging in with HOME=/"));
|
||||
(void) puts (_("No directory, logging in with HOME=/"));
|
||||
info->pw_dir = temp_pw_dir;
|
||||
}
|
||||
|
||||
@@ -229,8 +241,8 @@ void setup_env (struct passwd *info)
|
||||
* Create the SHELL environmental variable and export it.
|
||||
*/
|
||||
|
||||
if (info->pw_shell == (char *) 0 || !*info->pw_shell) {
|
||||
static char temp_pw_shell[] = "/bin/sh";
|
||||
if ((NULL == info->pw_shell) || ('\0' == *info->pw_shell)) {
|
||||
static char temp_pw_shell[] = SHELL;
|
||||
|
||||
info->pw_shell = temp_pw_shell;
|
||||
}
|
||||
@@ -251,7 +263,7 @@ void setup_env (struct passwd *info)
|
||||
|
||||
cp = getdef_str ((info->pw_uid == 0) ? "ENV_SUPATH" : "ENV_PATH");
|
||||
|
||||
if (!cp) {
|
||||
if (NULL == cp) {
|
||||
/* not specified, use a minimal default */
|
||||
addenv ("PATH=/bin:/usr/bin", NULL);
|
||||
} else if (strchr (cp, '=')) {
|
||||
@@ -269,23 +281,30 @@ void setup_env (struct passwd *info)
|
||||
*/
|
||||
|
||||
if (getdef_bool ("MAIL_CHECK_ENAB")) {
|
||||
if ((cp = getdef_str ("MAIL_DIR")))
|
||||
cp = getdef_str ("MAIL_DIR");
|
||||
if (NULL != cp) {
|
||||
addenv_path ("MAIL", cp, info->pw_name);
|
||||
else if ((cp = getdef_str ("MAIL_FILE")))
|
||||
addenv_path ("MAIL", info->pw_dir, cp);
|
||||
else {
|
||||
} else {
|
||||
cp = getdef_str ("MAIL_FILE");
|
||||
if (NULL != cp) {
|
||||
addenv_path ("MAIL", info->pw_dir, cp);
|
||||
} else {
|
||||
#if defined(MAIL_SPOOL_FILE)
|
||||
addenv_path ("MAIL", info->pw_dir, MAIL_SPOOL_FILE);
|
||||
addenv_path ("MAIL", info->pw_dir, MAIL_SPOOL_FILE);
|
||||
#elif defined(MAIL_SPOOL_DIR)
|
||||
addenv_path ("MAIL", MAIL_SPOOL_DIR, info->pw_name);
|
||||
addenv_path ("MAIL", MAIL_SPOOL_DIR, info->pw_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read environment from optional config file. --marekm
|
||||
*/
|
||||
if ((envf = getdef_str ("ENVIRON_FILE")))
|
||||
envf = getdef_str ("ENVIRON_FILE");
|
||||
if (NULL != envf) {
|
||||
read_env_file (envf);
|
||||
}
|
||||
#endif /* !USE_PAM */
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1991, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2009 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -46,14 +47,11 @@ extern size_t newenvc;
|
||||
* shell begins by trying to figure out what argv[0] is going to
|
||||
* be for the named process. The user may pass in that argument,
|
||||
* or it will be the last pathname component of the file with a
|
||||
* '-' prepended. The first attempt is to just execute the named
|
||||
* file. If the errno comes back "ENOEXEC", the file is assumed
|
||||
* at first glance to be a shell script. The first two characters
|
||||
* must be "#!", in which case "/bin/sh" is executed to process
|
||||
* the file. If all that fails, give up in disgust ...
|
||||
* '-' prepended.
|
||||
* Then, it executes the named file.
|
||||
*/
|
||||
|
||||
int shell (const char *file, const char *arg, char *const envp[])
|
||||
int shell (const char *file, /*@null@*/const char *arg, char *const envp[])
|
||||
{
|
||||
char arg0[1024];
|
||||
int err;
|
||||
@@ -82,30 +80,14 @@ int shell (const char *file, const char *arg, char *const envp[])
|
||||
execle (file, arg, (char *) 0, envp);
|
||||
err = errno;
|
||||
|
||||
/* Linux handles #! in the kernel, and bash doesn't make
|
||||
sense of "#!" so it wouldn't work anyway... --marekm */
|
||||
#ifndef __linux__
|
||||
/*
|
||||
* It is perfectly OK to have a shell script for a login
|
||||
* shell, and this code attempts to support that. It
|
||||
* relies on the standard shell being able to make sense
|
||||
* of the "#!" magic number.
|
||||
*/
|
||||
if (err == ENOEXEC) {
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen (file, "r"))) {
|
||||
if (getc (fp) == '#' && getc (fp) == '!') {
|
||||
fclose (fp);
|
||||
execle ("/bin/sh", "sh",
|
||||
file, (char *) 0, envp);
|
||||
err = errno;
|
||||
} else {
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
if (access (file, R_OK|X_OK) == 0) {
|
||||
/*
|
||||
* Assume this is a shell script (with no shebang).
|
||||
* Interpret it with /bin/sh
|
||||
*/
|
||||
execle (SHELL, "sh", "-", file, (char *)0, envp);
|
||||
err = errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Obviously something is really wrong - I can't figure out
|
||||
@@ -117,3 +99,4 @@ int shell (const char *file, const char *arg, char *const envp[])
|
||||
perror (arg0);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,14 +69,16 @@ long strtoday (const char *str)
|
||||
* which is not what we expect, unless you're a BOFH :-).
|
||||
* (useradd sets sp_expire = current date for new lusers)
|
||||
*/
|
||||
if (!str || *str == '\0')
|
||||
if ((NULL == str) || ('\0' == *str)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
t = get_date (str, (time_t *) 0);
|
||||
if (t == (time_t) - 1)
|
||||
if ((time_t) - 1 == t) {
|
||||
return -1;
|
||||
}
|
||||
/* convert seconds to days since 1970-01-01 */
|
||||
return (t + DAY / 2) / DAY;
|
||||
return (long) (t + DAY / 2) / DAY;
|
||||
}
|
||||
|
||||
#else /* !USE_GETDATE */
|
||||
@@ -129,14 +131,16 @@ long strtoday (const char *str)
|
||||
memzero (&tp, sizeof tp);
|
||||
for (fmt = date_formats; *fmt; fmt++) {
|
||||
cp = strptime ((char *) str, *fmt, &tp);
|
||||
if (!cp || *cp != '\0')
|
||||
if ((NULL == cp) || ('\0' != *cp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = mktime (&tp);
|
||||
if (result == (time_t) - 1)
|
||||
if ((time_t) - 1 == result) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return result / DAY; /* success */
|
||||
return (long) (result / DAY); /* success */
|
||||
}
|
||||
return -1;
|
||||
#else
|
||||
@@ -151,8 +155,9 @@ long strtoday (const char *str)
|
||||
* is compiled in ...
|
||||
*/
|
||||
|
||||
if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3)
|
||||
if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* the month, day of the month, and year are checked for
|
||||
@@ -160,23 +165,28 @@ long strtoday (const char *str)
|
||||
* 1970 and 2069.
|
||||
*/
|
||||
|
||||
if (month < 1 || month > 12)
|
||||
if ((month < 1) || (month > 12)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (day < 1)
|
||||
if (day < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((month != 2 || (year % 4) != 0) && day > days[month])
|
||||
if ( ((2 != month) || ((year % 4) != 0))
|
||||
&& (day > days[month])) {
|
||||
return -1;
|
||||
else if ((month == 2 && (year % 4) == 0) && day > 29)
|
||||
} else if ((month == 2) && ((year % 4) == 0) && (day > 29)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (year < 0)
|
||||
if (year < 0) {
|
||||
return -1;
|
||||
else if (year <= 69)
|
||||
} else if (year <= 69) {
|
||||
year += 2000;
|
||||
else if (year <= 99)
|
||||
} else if (year <= 99) {
|
||||
year += 1900;
|
||||
}
|
||||
|
||||
/*
|
||||
* On systems with 32-bit signed time_t, time wraps around in 2038
|
||||
@@ -184,8 +194,9 @@ long strtoday (const char *str)
|
||||
* This limit can be removed once no one is using 32-bit systems
|
||||
* anymore :-). --marekm
|
||||
*/
|
||||
if (year < 1970 || year > 2037)
|
||||
if ((year < 1970) || (year > 2037)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* the total number of days is the total number of days in all
|
||||
|
||||
@@ -58,7 +58,7 @@ void subsystem (const struct passwd *pw)
|
||||
printf (_("Invalid root directory '%s'\n"), pw->pw_dir);
|
||||
SYSLOG ((LOG_WARN, BAD_SUBROOT2, pw->pw_dir, pw->pw_name));
|
||||
closelog ();
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -71,6 +71,6 @@ void subsystem (const struct passwd *pw)
|
||||
pw->pw_dir);
|
||||
SYSLOG ((LOG_WARN, NO_SUBROOT2, pw->pw_dir, pw->pw_name));
|
||||
closelog ();
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1992, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -40,10 +41,11 @@
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* sulog - log a SU command execution result
|
||||
*/
|
||||
void sulog (const char *tty, int success, const char *oldname, const char *name)
|
||||
void sulog (const char *tty, bool success, const char *oldname, const char *name)
|
||||
{
|
||||
char *sulog_file;
|
||||
time_t now;
|
||||
@@ -74,25 +76,29 @@ void sulog (const char *tty, int success, const char *oldname, const char *name)
|
||||
oldgid = 0;
|
||||
}
|
||||
fp = fopen (sulog_file, "a+");
|
||||
umask (oldmask);
|
||||
(void) umask (oldmask);
|
||||
if ((oldgid != 0) && (setgid (oldgid) != 0)) {
|
||||
perror ("setgid");
|
||||
SYSLOG ((LOG_ERR,
|
||||
"can't switch back to group `%d' in sulog",
|
||||
oldgid));
|
||||
/* Do not return if the group permission were raised. */
|
||||
exit (1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (fp == (FILE *) 0)
|
||||
if (fp == (FILE *) 0) {
|
||||
return; /* can't open or create logfile */
|
||||
}
|
||||
|
||||
time (&now);
|
||||
(void) time (&now);
|
||||
tm = localtime (&now);
|
||||
|
||||
fprintf (fp, "SU %.02d/%.02d %.02d:%.02d %c %s %s-%s\n",
|
||||
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
|
||||
success ? '+' : '-', tty, oldname, name);
|
||||
|
||||
fflush (fp);
|
||||
(void) fflush (fp);
|
||||
fsync (fileno (fp));
|
||||
fclose (fp);
|
||||
/* TODO: log if failure */
|
||||
}
|
||||
|
||||
|
||||
72
libmisc/system.c
Normal file
72
libmisc/system.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2009 , Dan Walsh <dwalsh@redhat.com>
|
||||
* 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>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
int safe_system (const char *command,
|
||||
const char *argv[],
|
||||
const char *env[],
|
||||
int ignore_stderr)
|
||||
{
|
||||
int status = -1;
|
||||
int fd;
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid) { /* Parent */
|
||||
if (waitpid (pid, &status, 0) > 0) {
|
||||
return status;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open ("/dev/null", O_RDWR);
|
||||
/* Child */
|
||||
dup2 (fd, 0); // Close Stdin
|
||||
if (ignore_stderr) {
|
||||
dup2 (fd, 2); // Close Stderr
|
||||
}
|
||||
|
||||
execve (command, (char *const *) argv, (char *const *) env);
|
||||
fprintf (stderr, _("Failed to exec '%s'\n"), argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1997, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -49,30 +50,41 @@ void ttytype (const char *line)
|
||||
char type[BUFSIZ];
|
||||
char port[BUFSIZ];
|
||||
|
||||
if (getenv ("TERM"))
|
||||
if (getenv ("TERM") != NULL) {
|
||||
return;
|
||||
if ((typefile = getdef_str ("TTYTYPE_FILE")) == NULL)
|
||||
}
|
||||
typefile = getdef_str ("TTYTYPE_FILE");
|
||||
if (NULL == typefile) {
|
||||
return;
|
||||
if (access (typefile, F_OK))
|
||||
}
|
||||
if (access (typefile, F_OK) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(fp = fopen (typefile, "r"))) {
|
||||
fp = fopen (typefile, "r");
|
||||
if (NULL == fp) {
|
||||
perror (typefile);
|
||||
return;
|
||||
}
|
||||
while (fgets (buf, sizeof buf, fp)) {
|
||||
if (buf[0] == '#')
|
||||
while (fgets (buf, (int) sizeof buf, fp) == buf) {
|
||||
if (buf[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((cp = strchr (buf, '\n')))
|
||||
cp = strchr (buf, '\n');
|
||||
if (NULL != cp) {
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
if (sscanf (buf, "%s %s", type, port) == 2 &&
|
||||
strcmp (line, port) == 0)
|
||||
if ((sscanf (buf, "%s %s", type, port) == 2) &&
|
||||
(strcmp (line, port) == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!feof (fp) && !ferror (fp))
|
||||
if ((feof (fp) == 0) && (ferror (fp) == 0)) {
|
||||
addenv ("TERM", type);
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
(void) fclose (fp);
|
||||
}
|
||||
|
||||
|
||||
11
libmisc/tz.c
11
libmisc/tz.c
@@ -33,6 +33,8 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifndef USE_PAM
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -40,6 +42,7 @@
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* tz - return local timezone name
|
||||
*
|
||||
@@ -53,11 +56,9 @@ char *tz (const char *fname)
|
||||
const char *def_tz = "TZ=CST6CDT";
|
||||
|
||||
if ((fp = fopen (fname, "r")) == NULL ||
|
||||
fgets (tzbuf, sizeof (tzbuf), fp) == NULL) {
|
||||
#ifndef USE_PAM
|
||||
fgets (tzbuf, (int) sizeof (tzbuf), fp) == NULL) {
|
||||
if (!(def_tz = getdef_str ("ENV_TZ")) || def_tz[0] == '/')
|
||||
def_tz = "TZ=CST6CDT";
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
strcpy (tzbuf, def_tz);
|
||||
} else
|
||||
@@ -68,3 +69,7 @@ char *tz (const char *fname)
|
||||
|
||||
return tzbuf;
|
||||
}
|
||||
#else /* !USE_PAM */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
|
||||
@@ -50,14 +50,21 @@
|
||||
#endif
|
||||
#include "prototypes.h"
|
||||
|
||||
void set_filesize_limit (int blocks)
|
||||
int set_filesize_limit (int blocks)
|
||||
{
|
||||
int ret = -1;
|
||||
#if HAVE_ULIMIT_H
|
||||
ulimit (UL_SETFSIZE, blocks);
|
||||
if (ulimit (UL_SETFSIZE, blocks) != -1) {
|
||||
ret = 0;
|
||||
}
|
||||
#elif defined(RLIMIT_FSIZE)
|
||||
struct rlimit rlimit_fsize;
|
||||
|
||||
rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
|
||||
setrlimit (RLIMIT_FSIZE, &rlimit_fsize);
|
||||
rlimit_fsize.rlim_cur = 512L * blocks;
|
||||
rlimit_fsize.rlim_max = rlimit_fsize.rlim_cur;
|
||||
ret = setrlimit (RLIMIT_FSIZE, &rlimit_fsize);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
228
libmisc/user_busy.c
Normal file
228
libmisc/user_busy.c
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id: $"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
#ifdef __linux__
|
||||
static int check_status (const char *sname, uid_t uid);
|
||||
static int user_busy_processes (uid_t uid);
|
||||
#else /* !__linux__ */
|
||||
static int user_busy_utmp (const char *name);
|
||||
#endif /* !__linux__ */
|
||||
|
||||
/*
|
||||
* user_busy - check if an user if currently running processes
|
||||
*/
|
||||
int user_busy (const char *name, uid_t uid)
|
||||
{
|
||||
/* There are no standard ways to get the list of processes.
|
||||
* An option could be to run an external tool (ps).
|
||||
*/
|
||||
#ifdef __linux__
|
||||
/* On Linux, directly parse /proc */
|
||||
return user_busy_processes (uid);
|
||||
#else /* !__linux__ */
|
||||
/* If we cannot rely on /proc, check is there is a record in utmp
|
||||
* indicating that the user is still logged in */
|
||||
return user_busy_utmp (name);
|
||||
#endif /* !__linux__ */
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
static int user_busy_utmp (const char *name)
|
||||
{
|
||||
#ifdef USE_UTMPX
|
||||
struct utmpx *utent;
|
||||
|
||||
setutxent ();
|
||||
while ((utent = getutxent ()) != NULL)
|
||||
#else /* !USE_UTMPX */
|
||||
struct utmp *utent;
|
||||
|
||||
setutent ();
|
||||
while ((utent = getutent ()) != NULL)
|
||||
#endif /* !USE_UTMPX */
|
||||
{
|
||||
if (utent->ut_type != USER_PROCESS) {
|
||||
continue;
|
||||
}
|
||||
if (strncmp (utent->ut_user, name, sizeof utent->ut_user) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (kill (utent->ut_pid, 0) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !__linux__ */
|
||||
|
||||
#ifdef __linux__
|
||||
static int check_status (const char *sname, uid_t uid)
|
||||
{
|
||||
/* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */
|
||||
char status[40];
|
||||
char line[1024];
|
||||
FILE *sfile;
|
||||
|
||||
snprintf (status, 40, "/proc/%s/status", sname);
|
||||
status[39] = '\0';
|
||||
|
||||
sfile = fopen (status, "r");
|
||||
if (NULL == sfile) {
|
||||
return 0;
|
||||
}
|
||||
while (fgets (line, sizeof (line), sfile) == line) {
|
||||
if (strncmp (line, "Uid:\t", 5) == 0) {
|
||||
unsigned long ruid, euid, suid;
|
||||
assert (uid == (unsigned long) uid);
|
||||
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)) {
|
||||
(void) fclose (sfile);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* Ignore errors. This is just a best effort. */
|
||||
}
|
||||
(void) fclose (sfile);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
(void) fclose (sfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int user_busy_processes (uid_t uid)
|
||||
{
|
||||
DIR *proc;
|
||||
struct dirent *ent;
|
||||
char *tmp_d_name;
|
||||
pid_t pid;
|
||||
DIR *task_dir;
|
||||
/* 22: /proc/xxxxxxxxxx/task + \0 */
|
||||
char task_path[22];
|
||||
char root_path[22];
|
||||
struct stat sbroot;
|
||||
struct stat sbroot_process;
|
||||
|
||||
proc = opendir ("/proc");
|
||||
if (proc == NULL) {
|
||||
perror ("opendir /proc");
|
||||
return 0;
|
||||
}
|
||||
if (stat ("/", &sbroot) != 0) {
|
||||
perror ("stat (\"/\")");
|
||||
(void) closedir (proc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((ent = readdir (proc)) != NULL) {
|
||||
tmp_d_name = ent->d_name;
|
||||
/*
|
||||
* Ingo Molnar's patch introducing NPTL for 2.4 hides
|
||||
* threads in the /proc directory by prepending a period.
|
||||
* This patch is applied by default in some RedHat
|
||||
* kernels.
|
||||
*/
|
||||
if ( (strcmp (tmp_d_name, ".") == 0)
|
||||
|| (strcmp (tmp_d_name, "..") == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (*tmp_d_name == '.') {
|
||||
tmp_d_name++;
|
||||
}
|
||||
|
||||
/* Check if this is a valid PID */
|
||||
if (get_pid (tmp_d_name, &pid) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if the process is in our chroot */
|
||||
snprintf (root_path, 22, "/proc/%lu/root", (unsigned long) pid);
|
||||
root_path[21] = '\0';
|
||||
if (stat (root_path, &sbroot_process) != 0) {
|
||||
continue;
|
||||
}
|
||||
if ( (sbroot.st_dev != sbroot_process.st_dev)
|
||||
|| (sbroot.st_ino != sbroot_process.st_ino)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (check_status (tmp_d_name, uid) != 0) {
|
||||
(void) closedir (proc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf (task_path, 22, "/proc/%lu/task", (unsigned long) pid);
|
||||
task_path[21] = '\0';
|
||||
task_dir = opendir (task_path);
|
||||
if (task_dir != NULL) {
|
||||
while ((ent = readdir (task_dir)) != NULL) {
|
||||
pid_t tid;
|
||||
if (get_pid (ent->d_name, &tid) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (tid == pid) {
|
||||
continue;
|
||||
}
|
||||
if (check_status (task_path+6, uid) != 0) {
|
||||
(void) closedir (proc);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
(void) closedir (task_dir);
|
||||
} else {
|
||||
/* Ignore errors. This is just a best effort */
|
||||
}
|
||||
}
|
||||
|
||||
(void) closedir (proc);
|
||||
return 0;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
617
libmisc/utmp.c
617
libmisc/utmp.c
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -37,193 +37,102 @@
|
||||
|
||||
#include <utmp.h>
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
#ifdef USE_UTMPX
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
struct utmpx utxent;
|
||||
#endif
|
||||
struct utmp utent;
|
||||
|
||||
#define NO_UTENT \
|
||||
_("No utmp entry. You must exec \"login\" from the lowest level \"sh\"")
|
||||
#define NO_TTY \
|
||||
_("Unable to determine your tty name.")
|
||||
|
||||
/*
|
||||
* checkutmp - see if utmp file is correct for this process
|
||||
*
|
||||
* System V is very picky about the contents of the utmp file
|
||||
* and requires that a slot for the current process exist.
|
||||
* The utmp file is scanned for an entry with the same process
|
||||
* ID. If no entry exists the process exits with a message.
|
||||
*
|
||||
* The "picky" flag is for network and other logins that may
|
||||
* use special flags. It allows the pid checks to be overridden.
|
||||
* This means that getty should never invoke login with any
|
||||
* command line flags.
|
||||
* is_my_tty -- determine if "tty" is the same TTY stdin is using
|
||||
*/
|
||||
|
||||
#if defined(__linux__) /* XXX */
|
||||
|
||||
void checkutmp (int picky)
|
||||
static bool is_my_tty (const char *tty)
|
||||
{
|
||||
/* full_tty shall be at least sizeof utmp.ut_line + 5 */
|
||||
char full_tty[200];
|
||||
/* tmptty shall be bigger than full_tty */
|
||||
static char tmptty[sizeof (full_tty)+1];
|
||||
|
||||
if ('/' != *tty) {
|
||||
(void) snprintf (full_tty, sizeof full_tty, "/dev/%s", tty);
|
||||
tty = &full_tty[0];
|
||||
}
|
||||
|
||||
if ('\0' == tmptty[0]) {
|
||||
const char *tname = ttyname (STDIN_FILENO);
|
||||
if (NULL != tname) {
|
||||
(void) strncpy (tmptty, tname, sizeof tmptty);
|
||||
tmptty[sizeof (tmptty) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == tmptty) {
|
||||
(void) puts (_("Unable to determine your tty name."));
|
||||
exit (EXIT_FAILURE);
|
||||
} else if (strncmp (tty, tmptty, sizeof (tmptty)) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get_current_utmp - return the most probable utmp entry for the current
|
||||
* session
|
||||
*
|
||||
* The utmp file is scanned for an entry with the same process ID.
|
||||
* The line enterred by the *getty / telnetd, etc. should also match
|
||||
* the current terminal.
|
||||
*
|
||||
* When an entry is returned by get_current_utmp, and if the utmp
|
||||
* structure has a ut_id field, this field should be used to update
|
||||
* the entry information.
|
||||
*
|
||||
* Return NULL if no entries exist in utmp for the current process.
|
||||
*/
|
||||
/*@null@*/ /*@only@*/struct utmp *get_current_utmp (void)
|
||||
{
|
||||
char *line;
|
||||
struct utmp *ut;
|
||||
pid_t pid = getpid ();
|
||||
struct utmp *ret = NULL;
|
||||
|
||||
setutent ();
|
||||
|
||||
/* First, try to find a valid utmp entry for this process. */
|
||||
while ((ut = getutent ()))
|
||||
if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
|
||||
(ut->ut_type == LOGIN_PROCESS
|
||||
|| ut->ut_type == USER_PROCESS))
|
||||
while ((ut = getutent ()) != NULL) {
|
||||
if ( (ut->ut_pid == getpid ())
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_ID
|
||||
&& ('\0' != ut->ut_id[0])
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
|
||||
&& ( (LOGIN_PROCESS == ut->ut_type)
|
||||
|| (USER_PROCESS == ut->ut_type))
|
||||
#endif
|
||||
/* A process may have failed to close an entry
|
||||
* Check if this entry refers to the current tty */
|
||||
&& is_my_tty (ut->ut_line)) {
|
||||
break;
|
||||
|
||||
/* If there is one, just use it, otherwise create a new one. */
|
||||
if (ut) {
|
||||
utent = *ut;
|
||||
} else {
|
||||
if (picky) {
|
||||
puts (NO_UTENT);
|
||||
exit (1);
|
||||
}
|
||||
line = ttyname (0);
|
||||
if (!line) {
|
||||
puts (NO_TTY);
|
||||
exit (1);
|
||||
}
|
||||
if (strncmp (line, "/dev/", 5) == 0)
|
||||
line += 5;
|
||||
memset ((void *) &utent, 0, sizeof utent);
|
||||
utent.ut_type = LOGIN_PROCESS;
|
||||
utent.ut_pid = pid;
|
||||
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
||||
/* XXX - assumes /dev/tty?? */
|
||||
strncpy (utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
|
||||
strcpy (utent.ut_user, "LOGIN");
|
||||
utent.ut_time = time (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(LOGIN_PROCESS)
|
||||
|
||||
void checkutmp (int picky)
|
||||
{
|
||||
char *line;
|
||||
struct utmp *ut;
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
struct utmpx *utx;
|
||||
#endif
|
||||
pid_t pid = getpid ();
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
setutxent ();
|
||||
#endif
|
||||
setutent ();
|
||||
|
||||
if (picky) {
|
||||
#if HAVE_UTMPX_H
|
||||
while ((utx = getutxent ()))
|
||||
if (utx->ut_pid == pid)
|
||||
break;
|
||||
|
||||
if (utx)
|
||||
utxent = *utx;
|
||||
#endif
|
||||
while ((ut = getutent ()))
|
||||
if (ut->ut_pid == pid)
|
||||
break;
|
||||
|
||||
if (ut)
|
||||
utent = *ut;
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
endutxent ();
|
||||
#endif
|
||||
endutent ();
|
||||
|
||||
if (!ut) {
|
||||
puts (NO_UTENT);
|
||||
exit (1);
|
||||
}
|
||||
#ifndef UNIXPC
|
||||
|
||||
/*
|
||||
* If there is no ut_line value in this record, fill
|
||||
* it in by getting the TTY name and stuffing it in
|
||||
* the structure. The UNIX/PC is broken in this regard
|
||||
* and needs help ...
|
||||
*/
|
||||
|
||||
if (utent.ut_line[0] == '\0')
|
||||
#endif /* !UNIXPC */
|
||||
{
|
||||
if (!(line = ttyname (0))) {
|
||||
puts (NO_TTY);
|
||||
exit (1);
|
||||
}
|
||||
if (strncmp (line, "/dev/", 5) == 0)
|
||||
line += 5;
|
||||
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
||||
#if HAVE_UTMPX_H
|
||||
strncpy (utxent.ut_line, line, sizeof utxent.ut_line);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (!(line = ttyname (0))) {
|
||||
puts (NO_TTY);
|
||||
exit (1);
|
||||
}
|
||||
if (strncmp (line, "/dev/", 5) == 0)
|
||||
line += 5;
|
||||
|
||||
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
||||
if ((ut = getutline (&utent)))
|
||||
strncpy (utent.ut_id, ut->ut_id, sizeof ut->ut_id);
|
||||
|
||||
strcpy (utent.ut_user, "LOGIN");
|
||||
utent.ut_pid = getpid ();
|
||||
utent.ut_type = LOGIN_PROCESS;
|
||||
utent.ut_time = time (NULL);
|
||||
#if HAVE_UTMPX_H
|
||||
strncpy (utxent.ut_line, line, sizeof utxent.ut_line);
|
||||
if ((utx = getutxline (&utxent)))
|
||||
strncpy (utxent.ut_id, utx->ut_id, sizeof utxent.ut_id);
|
||||
|
||||
strcpy (utxent.ut_user, "LOGIN");
|
||||
utxent.ut_pid = utent.ut_pid;
|
||||
utxent.ut_type = utent.ut_type;
|
||||
if (sizeof (utxent.ut_tv) == sizeof (struct timeval))
|
||||
gettimeofday ((struct timeval *) &utxent.ut_tv, NULL);
|
||||
else {
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday (&tv, NULL);
|
||||
utxent.ut_tv.tv_sec = tv.tv_sec;
|
||||
utxent.ut_tv.tv_usec = tv.tv_usec;
|
||||
}
|
||||
utent.ut_time = utxent.ut_tv.tv_sec;
|
||||
#endif
|
||||
if (NULL != ut) {
|
||||
ret = (struct utmp *) xmalloc (sizeof (*ret));
|
||||
memcpy (ret, ut, sizeof (*ret));
|
||||
}
|
||||
|
||||
endutent ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Some systems already have updwtmp() and possibly updwtmpx(). Others
|
||||
* don't, so we re-implement these functions if necessary. --marekm
|
||||
* don't, so we re-implement these functions if necessary.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UPDWTMP
|
||||
static void updwtmp (const char *filename, const struct utmp *ut)
|
||||
{
|
||||
@@ -237,7 +146,7 @@ static void updwtmp (const char *filename, const struct utmp *ut)
|
||||
}
|
||||
#endif /* ! HAVE_UPDWTMP */
|
||||
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#ifdef USE_UTMPX
|
||||
#ifndef HAVE_UPDWTMPX
|
||||
static void updwtmpx (const char *filename, const struct utmpx *utx)
|
||||
{
|
||||
@@ -250,131 +159,297 @@ static void updwtmpx (const char *filename, const struct utmpx *utx)
|
||||
}
|
||||
}
|
||||
#endif /* ! HAVE_UPDWTMPX */
|
||||
#endif /* ! HAVE_UTMPX_H */
|
||||
#endif /* ! USE_UTMPX */
|
||||
|
||||
|
||||
/*
|
||||
* setutmp - put a USER_PROCESS entry in the utmp file
|
||||
* prepare_utmp - prepare an utmp entry so that it can be logged in a
|
||||
* utmp/wtmp file.
|
||||
*
|
||||
* setutmp changes the type of the current utmp entry to
|
||||
* USER_PROCESS. the wtmp file will be updated as well.
|
||||
* It accepts an utmp entry in input (ut) to return an entry with
|
||||
* the right ut_id. This is typically an entry returned by
|
||||
* get_current_utmp
|
||||
* If ut is NULL, ut_id will be forged based on the line argument.
|
||||
*
|
||||
* The ut_host field of the input structure may also be kept, and is
|
||||
* used to define the ut_addr/ut_addr_v6 fields. (if these fields
|
||||
* exist)
|
||||
*
|
||||
* Other fields are discarded and filed with new values (if they
|
||||
* exist).
|
||||
*
|
||||
* The returned structure shall be freed by the caller.
|
||||
*/
|
||||
|
||||
#if defined(__linux__) /* XXX */
|
||||
|
||||
void setutmp (const char *name, const char *line, const char *host)
|
||||
/*@only@*/struct utmp *prepare_utmp (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
/*@null@*/const struct utmp *ut)
|
||||
{
|
||||
utent.ut_type = USER_PROCESS;
|
||||
strncpy (utent.ut_user, name, sizeof utent.ut_user);
|
||||
utent.ut_time = time (NULL);
|
||||
/* other fields already filled in by checkutmp above */
|
||||
setutent ();
|
||||
pututline (&utent);
|
||||
endutent ();
|
||||
updwtmp (_WTMP_FILE, &utent);
|
||||
struct timeval tv;
|
||||
char *hostname = NULL;
|
||||
struct utmp *utent;
|
||||
|
||||
assert (NULL != name);
|
||||
assert (NULL != line);
|
||||
|
||||
|
||||
|
||||
if ( (NULL != host)
|
||||
&& ('\0' != host[0])) {
|
||||
hostname = (char *) xmalloc (strlen (host) + 1);
|
||||
strcpy (hostname, host);
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
} else if ( (NULL != ut)
|
||||
&& (NULL != ut->ut_host)
|
||||
&& ('\0' != ut->ut_host[0])) {
|
||||
hostname = (char *) xmalloc (sizeof (ut->ut_host) + 1);
|
||||
strncpy (hostname, ut->ut_host, sizeof (ut->ut_host));
|
||||
hostname[sizeof (ut->ut_host)] = '\0';
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_HOST */
|
||||
}
|
||||
|
||||
if (strncmp(line, "/dev/", 5) == 0) {
|
||||
line += 5;
|
||||
}
|
||||
|
||||
|
||||
utent = (struct utmp *) xmalloc (sizeof (*utent));
|
||||
memzero (utent, sizeof (*utent));
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
|
||||
utent->ut_type = USER_PROCESS;
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_TYPE */
|
||||
utent->ut_pid = getpid ();
|
||||
strncpy (utent->ut_line, line, sizeof (utent->ut_line));
|
||||
#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));
|
||||
}
|
||||
#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));
|
||||
#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));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_HOST */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
|
||||
utent->ut_syslen = MIN (strlen (hostname),
|
||||
sizeof (utent->ut_host));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_SYSLEN */
|
||||
#if defined(HAVE_STRUCT_UTMP_UT_ADDR) || defined(HAVE_STRUCT_UTMP_UT_ADDR_V6)
|
||||
if (getaddrinfo (hostname, NULL, NULL, &info) == 0) {
|
||||
/* getaddrinfo might not be reliable.
|
||||
* Just try to log what may be useful.
|
||||
*/
|
||||
if (info->ai_family == AF_INET) {
|
||||
struct sockaddr_in *sa =
|
||||
(struct sockaddr_in *) info->ai_addr;
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_ADDR
|
||||
memcpy (&(utent->ut_addr),
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utent->ut_addr),
|
||||
sizeof (sa->sin_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ADDR */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_ADDR_V6
|
||||
memcpy (utent->ut_addr_v6,
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utent->ut_addr_v6),
|
||||
sizeof (sa->sin_addr)));
|
||||
} else if (info->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa =
|
||||
(struct sockaddr_in6 *) info->ai_addr;
|
||||
memcpy (utent->ut_addr_v6,
|
||||
&(sa->sin6_addr),
|
||||
MIN (sizeof (utent->ut_addr_v6),
|
||||
sizeof (sa->sin6_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ADDR_V6 */
|
||||
}
|
||||
freeaddrinfo (info);
|
||||
}
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_ADDR || HAVE_STRUCT_UTMP_UT_ADDR_V6 */
|
||||
free (hostname);
|
||||
}
|
||||
/* ut_exit is only for DEAD_PROCESS */
|
||||
utent->ut_session = getsid (0);
|
||||
if (gettimeofday (&tv, NULL) == 0) {
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_TIME
|
||||
utent->ut_time = tv.tv_sec;
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_TIME */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_XTIME
|
||||
utent->ut_xtime = tv.tv_usec;
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_XTIME */
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_TV
|
||||
utent->ut_tv.tv_sec = tv.tv_sec;
|
||||
utent->ut_tv.tv_usec = tv.tv_usec;
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_TV */
|
||||
}
|
||||
|
||||
return utent;
|
||||
}
|
||||
|
||||
#elif HAVE_UTMPX_H
|
||||
|
||||
void setutmp (const char *name, const char *line, const char *host)
|
||||
/*
|
||||
* setutmp - Update an entry in utmp and log an entry in wtmp
|
||||
*
|
||||
* Return 1 on failure and 0 on success.
|
||||
*/
|
||||
int setutmp (struct utmp *ut)
|
||||
{
|
||||
struct utmp *utmp, utline;
|
||||
struct utmpx *utmpx, utxline;
|
||||
pid_t pid = getpid ();
|
||||
int found_utmpx = 0, found_utmp = 0;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* The canonical device name doesn't include "/dev/"; skip it
|
||||
* if it is already there.
|
||||
*/
|
||||
assert (NULL != ut);
|
||||
|
||||
if (strncmp (line, "/dev/", 5) == 0)
|
||||
setutent ();
|
||||
if (pututline (ut) == NULL) {
|
||||
err = 1;
|
||||
}
|
||||
endutent ();
|
||||
|
||||
updwtmp (_WTMP_FILE, ut);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef USE_UTMPX
|
||||
/*
|
||||
* prepare_utmpx - the UTMPX version for prepare_utmp
|
||||
*/
|
||||
/*@only@*/struct utmpx *prepare_utmpx (const char *name,
|
||||
const char *line,
|
||||
const char *host,
|
||||
/*@null@*/const struct utmp *ut)
|
||||
{
|
||||
struct timeval tv;
|
||||
char *hostname = NULL;
|
||||
struct utmpx *utxent;
|
||||
|
||||
assert (NULL != name);
|
||||
assert (NULL != line);
|
||||
|
||||
|
||||
|
||||
if ( (NULL != host)
|
||||
&& ('\0' != host[0])) {
|
||||
hostname = (char *) xmalloc (strlen (host) + 1);
|
||||
strcpy (hostname, host);
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
} else if ( (NULL != ut)
|
||||
&& (NULL != ut->ut_host)
|
||||
&& ('\0' != ut->ut_host[0])) {
|
||||
hostname = (char *) xmalloc (sizeof (ut->ut_host) + 1);
|
||||
strncpy (hostname, ut->ut_host, sizeof (ut->ut_host));
|
||||
hostname[sizeof (ut->ut_host)] = '\0';
|
||||
#endif /* HAVE_STRUCT_UTMP_UT_TYPE */
|
||||
}
|
||||
|
||||
if (strncmp(line, "/dev/", 5) == 0) {
|
||||
line += 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update utmpx. We create an empty entry in case there is
|
||||
* no matching entry in the utmpx file.
|
||||
*/
|
||||
utxent = (struct utmpx *) xmalloc (sizeof (*utxent));
|
||||
memzero (utxent, sizeof (*utxent));
|
||||
|
||||
|
||||
|
||||
utxent->ut_type = USER_PROCESS;
|
||||
utxent->ut_pid = getpid ();
|
||||
strncpy (utxent->ut_line, line, sizeof (utxent->ut_line));
|
||||
/* existence of ut->ut_id is enforced by configure */
|
||||
if (NULL != ut) {
|
||||
strncpy (utxent->ut_id, ut->ut_id, sizeof (utxent->ut_id));
|
||||
} else {
|
||||
/* XXX - assumes /dev/tty?? */
|
||||
strncpy (utxent->ut_id, line + 3, sizeof (utxent->ut_id));
|
||||
}
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_NAME
|
||||
strncpy (utxent->ut_name, name, sizeof (utxent->ut_name));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_NAME */
|
||||
strncpy (utxent->ut_user, name, sizeof (utxent->ut_user));
|
||||
if (NULL != hostname) {
|
||||
struct addrinfo *info = NULL;
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_HOST
|
||||
strncpy (utxent->ut_host, hostname, sizeof (utxent->ut_host));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_HOST */
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
|
||||
utxent->ut_syslen = MIN (strlen (hostname),
|
||||
sizeof (utxent->ut_host));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_SYSLEN */
|
||||
#if defined(HAVE_STRUCT_UTMPX_UT_ADDR) || defined(HAVE_STRUCT_UTMPX_UT_ADDR_V6)
|
||||
if (getaddrinfo (hostname, NULL, NULL, &info) == 0) {
|
||||
/* getaddrinfo might not be reliable.
|
||||
* Just try to log what may be useful.
|
||||
*/
|
||||
if (info->ai_family == AF_INET) {
|
||||
struct sockaddr_in *sa =
|
||||
(struct sockaddr_in *) info->ai_addr;
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_ADDR
|
||||
memcpy (utxent->ut_addr,
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utxent->ut_addr),
|
||||
sizeof (sa->sin_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_ADDR */
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_ADDR_V6
|
||||
memcpy (utxent->ut_addr_v6,
|
||||
&(sa->sin_addr),
|
||||
MIN (sizeof (utxent->ut_addr_v6),
|
||||
sizeof (sa->sin_addr)));
|
||||
} else if (info->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa =
|
||||
(struct sockaddr_in6 *) info->ai_addr;
|
||||
memcpy (utxent->ut_addr_v6,
|
||||
&(sa->sin6_addr),
|
||||
MIN (sizeof (utxent->ut_addr_v6),
|
||||
sizeof (sa->sin6_addr)));
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
|
||||
}
|
||||
freeaddrinfo (info);
|
||||
}
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_ADDR || HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
|
||||
free (hostname);
|
||||
}
|
||||
/* ut_exit is only for DEAD_PROCESS */
|
||||
utxent->ut_session = getsid (0);
|
||||
if (gettimeofday (&tv, NULL) == 0) {
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_TIME
|
||||
utxent->ut_time = tv.tv_sec;
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_TIME */
|
||||
#ifdef HAVE_STRUCT_UTMPX_UT_XTIME
|
||||
utxent->ut_xtime = tv.tv_usec;
|
||||
#endif /* HAVE_STRUCT_UTMPX_UT_XTIME */
|
||||
utxent->ut_tv.tv_sec = tv.tv_sec;
|
||||
utxent->ut_tv.tv_usec = tv.tv_usec;
|
||||
}
|
||||
|
||||
return utxent;
|
||||
}
|
||||
|
||||
/*
|
||||
* setutmpx - the UTMPX version for setutmp
|
||||
*/
|
||||
int setutmpx (struct utmpx *utx)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
assert (NULL != utx);
|
||||
|
||||
setutxent ();
|
||||
setutent ();
|
||||
|
||||
while (utmpx = getutxent ()) {
|
||||
if (utmpx->ut_pid == pid) {
|
||||
found_utmpx = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (utmp = getutent ()) {
|
||||
if (utmp->ut_pid == pid) {
|
||||
found_utmp = 1;
|
||||
break;
|
||||
}
|
||||
if (pututxline (utx) == NULL) {
|
||||
err = 1;
|
||||
}
|
||||
endutxent ();
|
||||
|
||||
/*
|
||||
* If the entry matching `pid' cannot be found, create a new
|
||||
* entry with the device name in it.
|
||||
*/
|
||||
updwtmpx (_WTMP_FILE "x", utx);
|
||||
|
||||
if (!found_utmpx) {
|
||||
memset ((void *) &utxline, 0, sizeof utxline);
|
||||
strncpy (utxline.ut_line, line, sizeof utxline.ut_line);
|
||||
utxline.ut_pid = getpid ();
|
||||
} else {
|
||||
utxline = *utmpx;
|
||||
if (strncmp (utxline.ut_line, "/dev/", 5) == 0) {
|
||||
memmove (utxline.ut_line, utxline.ut_line + 5,
|
||||
sizeof utxline.ut_line - 5);
|
||||
utxline.ut_line[sizeof utxline.ut_line - 5] = '\0';
|
||||
}
|
||||
}
|
||||
if (!found_utmp) {
|
||||
memset ((void *) &utline, 0, sizeof utline);
|
||||
strncpy (utline.ut_line, utxline.ut_line,
|
||||
sizeof utline.ut_line);
|
||||
utline.ut_pid = utxline.ut_pid;
|
||||
} else {
|
||||
utline = *utmp;
|
||||
if (strncmp (utline.ut_line, "/dev/", 5) == 0) {
|
||||
memmove (utline.ut_line, utline.ut_line + 5,
|
||||
sizeof utline.ut_line - 5);
|
||||
utline.ut_line[sizeof utline.ut_line - 5] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the fields in the utmpx entry and write it out. Do
|
||||
* the utmp entry at the same time to make sure things don't
|
||||
* get messed up.
|
||||
*/
|
||||
|
||||
strncpy (utxline.ut_user, name, sizeof utxline.ut_user);
|
||||
strncpy (utline.ut_user, name, sizeof utline.ut_user);
|
||||
|
||||
utline.ut_type = utxline.ut_type = USER_PROCESS;
|
||||
|
||||
if (sizeof (utxline.ut_tv) == sizeof (struct timeval))
|
||||
gettimeofday ((struct timeval *) &utxline.ut_tv, NULL);
|
||||
else {
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday (&tv, NULL);
|
||||
utxline.ut_tv.tv_sec = tv.tv_sec;
|
||||
utxline.ut_tv.tv_usec = tv.tv_usec;
|
||||
}
|
||||
utline.ut_time = utxline.ut_tv.tv_sec;
|
||||
|
||||
strncpy (utxline.ut_host, host ? host : "", sizeof utxline.ut_host);
|
||||
|
||||
pututxline (&utxline);
|
||||
pututline (&utline);
|
||||
|
||||
updwtmpx (_WTMP_FILE "x", &utxline);
|
||||
updwtmp (_WTMP_FILE, &utline);
|
||||
|
||||
utxent = utxline;
|
||||
utent = utline;
|
||||
return err;
|
||||
}
|
||||
#endif /* USE_UTMPX */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1993, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 , Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -49,7 +49,7 @@
|
||||
* is used to indicate that a dummy salt must be used to encrypt the
|
||||
* password anyway.
|
||||
*/
|
||||
int valid (const char *password, const struct passwd *ent)
|
||||
bool valid (const char *password, const struct passwd *ent)
|
||||
{
|
||||
const char *encrypted;
|
||||
const char *salt;
|
||||
@@ -61,18 +61,19 @@ int valid (const char *password, const struct passwd *ent)
|
||||
* routine is meant to waste CPU time.
|
||||
*/
|
||||
|
||||
if (ent->pw_name && !ent->pw_passwd[0]) {
|
||||
if (!password[0])
|
||||
return (1); /* user entered nothing */
|
||||
else
|
||||
return (0); /* user entered something! */
|
||||
if ((NULL != ent->pw_name) && ('\0' == ent->pw_passwd[0])) {
|
||||
if ('\0' == password[0]) {
|
||||
return true; /* user entered nothing */
|
||||
} else {
|
||||
return false; /* user entered something! */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no entry then we need a salt to use.
|
||||
*/
|
||||
|
||||
if (ent->pw_name == (char *) 0 || ent->pw_passwd[0] == '\0') {
|
||||
if ((NULL == ent->pw_name) || ('\0' == ent->pw_passwd[0])) {
|
||||
salt = "xx";
|
||||
} else {
|
||||
salt = ent->pw_passwd;
|
||||
@@ -93,9 +94,11 @@ int valid (const char *password, const struct passwd *ent)
|
||||
* cause non-existent users to not be validated.
|
||||
*/
|
||||
|
||||
if (ent->pw_name && strcmp (encrypted, ent->pw_passwd) == 0)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
if ( (NULL != ent->pw_name)
|
||||
&& (strcmp (encrypted, ent->pw_passwd) == 0)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -52,7 +52,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
#define XFUNCTION_NAME XPREFIX (FUNCTION_NAME)
|
||||
@@ -64,7 +64,7 @@
|
||||
#define STRINGIZE(name) STRINGIZE1 (name)
|
||||
#define STRINGIZE1(name) #name
|
||||
|
||||
LOOKUP_TYPE *XFUNCTION_NAME (ARG_TYPE ARG_NAME)
|
||||
/*@null@*/ /*@only@*/LOOKUP_TYPE *XFUNCTION_NAME (ARG_TYPE ARG_NAME)
|
||||
{
|
||||
#if HAVE_FUNCTION_R
|
||||
LOOKUP_TYPE *result=NULL;
|
||||
@@ -79,7 +79,7 @@ LOOKUP_TYPE *XFUNCTION_NAME (ARG_TYPE ARG_NAME)
|
||||
exit (13);
|
||||
}
|
||||
|
||||
do {
|
||||
while (true) {
|
||||
int status;
|
||||
LOOKUP_TYPE *resbuf = NULL;
|
||||
buffer = (char *)realloc (buffer, length);
|
||||
@@ -91,7 +91,7 @@ LOOKUP_TYPE *XFUNCTION_NAME (ARG_TYPE ARG_NAME)
|
||||
errno = 0;
|
||||
status = REENTRANT_NAME(ARG_NAME, result, buffer,
|
||||
length, &resbuf);
|
||||
if (!status && (resbuf == result)) {
|
||||
if ((0 ==status) && (resbuf == result)) {
|
||||
/* Build a result structure that can be freed by
|
||||
* the shadow *_free functions. */
|
||||
LOOKUP_TYPE *ret_result = DUP_FUNCTION(result);
|
||||
@@ -106,8 +106,14 @@ LOOKUP_TYPE *XFUNCTION_NAME (ARG_TYPE ARG_NAME)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length *= 4;
|
||||
} while (length < MAX_LENGTH);
|
||||
if (length <= ((size_t)-1 / 4)) {
|
||||
length *= 4;
|
||||
} else if (length == (size_t) -1) {
|
||||
break;
|
||||
} else {
|
||||
length = (size_t) -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
free(result);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user