Compare commits
1294 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 868d7b34ea | |||
| 30e62bc3bd | |||
| a630fba34b | |||
| 92cb9d7785 | |||
| 0f31dc5c2c | |||
| 2a6164cc4a | |||
| 53763ae6ee | |||
| a850520981 | |||
| c0e4ccd032 | |||
| f2e8294bdb | |||
| e2f1fcca0e | |||
| aaaaf21b6f | |||
| 9a9c9231db | |||
| 292f59f43d | |||
| 585b6f00f5 | |||
| abb879fd4f | |||
| f7c2a54212 | |||
| c628caf174 | |||
| 6938bab429 | |||
| 0c9f641408 | |||
| 19f08785f0 | |||
| 535f54076c | |||
| 445e97ba7c | |||
| d12d300c98 | |||
| 32f641b207 | |||
| 9724147344 | |||
| dce030ffb8 | |||
| 1654f42194 | |||
| 3ff3cd9c78 | |||
| 3a0160beb0 | |||
| d594243fbb | |||
| 02916e9cb2 | |||
| 1fdaf69376 | |||
| 2fa4234fc7 | |||
| 3b6ccf642c | |||
| 126fbe57bc | |||
| 6c3d4ebf6e | |||
| eb366c255c | |||
| 6c4545544f | |||
| d8e54618fe | |||
| adf7378d73 | |||
| 624d57c08c | |||
| 06eb4e4d76 | |||
| 497e90751b | |||
| a757b458ff | |||
| 387da46d73 | |||
| b17a17c93d | |||
| 1ff0b37134 | |||
| 63a96706b1 | |||
| a97399dd0a | |||
| f2476d3ce8 | |||
| fc832e4648 | |||
| 7d02af944f | |||
| 82b5983301 | |||
| 234af5cf67 | |||
| 09c752f00f | |||
| 5b4082d007 | |||
| cdc8c1e25b | |||
| 4bec156db1 | |||
| 33f85e93a1 | |||
| 6be18d45e1 | |||
| 7e2b522a15 | |||
| d7e2bd6fe1 | |||
| 4ad2697cc4 | |||
| 5bb28a0a7f | |||
| 4b85dc66d4 | |||
| 049f9a7f6b | |||
| 117bc66c6f | |||
| 26bbee8c86 | |||
| ab9fad7943 | |||
| 7903557988 | |||
| 0e0101043b | |||
| fb582ce72f | |||
| 679a29da7e | |||
| d7c9550b7f | |||
| e385338ee8 | |||
| 2b6312b337 | |||
| ecfcaed0b5 | |||
| f20c688a18 | |||
| 7687ae4dbd | |||
| 4624e9fca1 | |||
| 009e09fd58 | |||
| a5bf83d2e7 | |||
| 4bcbe13689 | |||
| 049b08481a | |||
| 02b200c9aa | |||
| 234e8fa7b1 | |||
| c4539fc4f9 | |||
| 9dd720a285 | |||
| 1c1e0b0c68 | |||
| adb83f7796 | |||
| 28a02dc83e | |||
| e318bb9b06 | |||
| 05388f748d | |||
| e481437ab9 | |||
| 6becc82e26 | |||
| c6847011e8 | |||
| 065aae682c | |||
| 33c33a32a2 | |||
| cd551ef728 | |||
| fa986b1d73 | |||
| 4616fe71e7 | |||
| 537b8cd90b | |||
| d4b6d1549b | |||
| f4a84efb46 | |||
| 6f9124b7f7 | |||
| 496fc2919d | |||
| 905eb76cec | |||
| 0c821fcf0c | |||
| 93086e9aa7 | |||
| c3cf23b00c | |||
| ffd35d8902 | |||
| c7b4f317f9 | |||
| 9b58a623f4 | |||
| 1a20189b83 | |||
| bd102eaa35 | |||
| ea04eb301d | |||
| c93897a8d7 | |||
| c82ed0c15e | |||
| 9eb191edc4 | |||
| e65cc6aebc | |||
| b3b1f5d4a4 | |||
| bc8257cf73 | |||
| dbf230e4cf | |||
| 2f0d14eb21 | |||
| d4535015a0 | |||
| 14b108728a | |||
| dbfad7d1c9 | |||
| 738d92a4bd | |||
| 7a3bb4d0ea | |||
| a026ea6bbf | |||
| 5939e066db | |||
| af9984bff1 | |||
| 0faec51bf0 | |||
| 5d0d784197 | |||
| 1aed7ae945 | |||
| 68ebbf9360 | |||
| 83db204477 | |||
| 456bdb78f8 | |||
| 8281c82e32 | |||
| a6154b8572 | |||
| 9d37173b24 | |||
| bd920ab36a | |||
| 1d767fb779 | |||
| 8eb6f8ace4 | |||
| 0871122443 | |||
| d5b15f8633 | |||
| ec1951c181 | |||
| 9d169ffc41 | |||
| 0fe42f571c | |||
| b0e86b959f | |||
| ea7af4e154 | |||
| 3d670ba7ed | |||
| 2f1f45d64f | |||
| 663824ef4c | |||
| c6cab4a7ba | |||
| e34f49c196 | |||
| 322db32971 | |||
| f9831a4a1a | |||
| 2b22a6909d | |||
| ca1d912e6b | |||
| 3ac8d97825 | |||
| e9e8e3270f | |||
| 91d4ab622b | |||
| b8cbc2c113 | |||
| dfe95bd08b | |||
| eb1d2de0e9 | |||
| 5f7649fb37 | |||
| e367d111e5 | |||
| 95fd179683 | |||
| c0aa8a876e | |||
| 6e4b2fe25d | |||
| e6416fd81b | |||
| 186b1b7ac1 | |||
| 38c079366d | |||
| 77e39de1e6 | |||
| 2c542f6c65 | |||
| b30e9614c3 | |||
| cc7ea6e8e5 | |||
| fa90ac11c8 | |||
| 716f3f99ce | |||
| 0f4347d148 | |||
| 8492dee663 | |||
| 514c1328b6 | |||
| 7cfe134090 | |||
| df6ec1d169 | |||
| b865e14f25 | |||
| 697901a328 | |||
| 9f1a43996c | |||
| 7273c25cc2 | |||
| c0818ab01d | |||
| f4cbf38ad7 | |||
| 0409c91a7f | |||
| 4faf42b31b | |||
| 786e44f6dd | |||
| bc22009031 | |||
| 4ea269d23e | |||
| f28660f5dd | |||
| 246d5c1c25 | |||
| c464ec5570 | |||
| b628850a09 | |||
| fe159b7668 | |||
| 325bf584ce | |||
| 5cd04d03f9 | |||
| ae169c4046 | |||
| 0dffc7c612 | |||
| 5d53e0bf07 | |||
| b5fb1b38ee | |||
| c917ed7b76 | |||
| 08f5577018 | |||
| 1021195bfe | |||
| a8361e7410 | |||
| 7384865775 | |||
| fd9d79a1a3 | |||
| c44b71cec2 | |||
| bbf4b79bc4 | |||
| abb5c99114 | |||
| 88128000c9 | |||
| 599cc003da | |||
| e7938d5a30 | |||
| bd32c1c8fc | |||
| fb0f702cbf | |||
| a04287cf24 | |||
| 569bd1d54f | |||
| 2df8c0728d | |||
| bd4dc81a82 | |||
| f8642a1986 | |||
| e24700fd5d | |||
| 18c5c6139d | |||
| af0f55a625 | |||
| 3f09f7b6fb | |||
| dfd19fc35b | |||
| 0407fa8813 | |||
| e84df9e163 | |||
| 46ad1856ac | |||
| 87257a49a1 | |||
| 9d3546c695 | |||
| 287a9041a1 | |||
| 22bfaf9e26 | |||
| 2748b4230a | |||
| 6bd08f7d18 | |||
| 00f01dd416 | |||
| 01a8df79b3 | |||
| 9a10373ddb | |||
| b065fa4741 | |||
| 3f35983656 | |||
| c32743808d | |||
| ec98f190c1 | |||
| cf8101aaae | |||
| 4047d1fe8e | |||
| 6f38f43fdd | |||
| dc732e7734 | |||
| 291c6fcc87 | |||
| 94d40b4521 | |||
| 3c9836a298 | |||
| a271076041 | |||
| e8c44a4c12 | |||
| d041eec354 | |||
| b215e9d02c | |||
| 994a3b463c | |||
| 508b968cb1 | |||
| 6afa2aaf9d | |||
| 342c934a35 | |||
| 49930bd3a6 | |||
| 7ea342579e | |||
| 875d2d49c1 | |||
| 83aa88466d | |||
| 607f1dd549 | |||
| 6baeb25038 | |||
| 32cfa176f2 | |||
| b01bd3b139 | |||
| 0a7888b1fa | |||
| 43a917cce5 | |||
| 089cf55e2c | |||
| 316a153abb | |||
| 6e6494680d | |||
| 6155e91f4e | |||
| 967bfb0376 | |||
| 9cb21c2bdf | |||
| 5cb839d977 | |||
| b128222477 | |||
| fc95155aa4 | |||
| 320707fcb0 | |||
| 4086aed1ed | |||
| 096dad6305 | |||
| 4772689d27 | |||
| 1566921dd8 | |||
| 04062cda11 | |||
| c040058fe3 | |||
| c56fe7117b | |||
| e2f74c347b | |||
| f929bfd90b | |||
| c889ebc2c9 | |||
| a3a1cf6536 | |||
| 7e0e931519 | |||
| 97a76bd9e6 | |||
| 69332884b1 | |||
| 992c1723af | |||
| 8eee5d03fd | |||
| 77be9c35c7 | |||
| f7ae4d48f4 | |||
| 1d8487d851 | |||
| 52aba825af | |||
| 25b1a8d591 | |||
| 5de28353d4 | |||
| 7b36b160f7 | |||
| 00e629c0ba | |||
| 942f1945bb | |||
| 69301dfa24 | |||
| 8762f465d4 | |||
| 140510de9d | |||
| 125a5dc309 | |||
| e78be3df43 | |||
| d60b59b156 | |||
| 6543c600d8 | |||
| 5070132ee6 | |||
| 143b97193d | |||
| 2a991a3ce9 | |||
| 3f2bbcfa91 | |||
| 8a2e3d500c | |||
| c48011d19c | |||
| ebe6def4b7 | |||
| a8533719ed | |||
| c667083c81 | |||
| e5bb71b2fd | |||
| b2753b146a | |||
| 724442c3af | |||
| b6aaaba35e | |||
| fa6c58a773 | |||
| 8a1e92aff1 | |||
| 12ce42be44 | |||
| 915cc6bb9c | |||
| 2cc7da6058 | |||
| 142d788c81 | |||
| 33c6a170a5 | |||
| fd4405b763 | |||
| dfceca8427 | |||
| 54c1660969 | |||
| eebcacfae8 | |||
| 4ed08824e5 | |||
| 3e942adb21 | |||
| 085d04c3dd | |||
| ed4a0157c4 | |||
| 93f1f35123 | |||
| 9f7f3b013e | |||
| 5a6ddf3b57 | |||
| 0512c187c8 | |||
| f32d4a359b | |||
| 401d0743af | |||
| a847899b52 | |||
| 88c1a6d98d | |||
| ef095ceef1 | |||
| 4c9ec2f5a4 | |||
| d7add53f06 | |||
| 2aa7427e2b | |||
| 1ec36eabb2 | |||
| bd3c39f1c8 | |||
| 258944e331 | |||
| 51d65f37e5 | |||
| 0f332f48bc | |||
| a73d4aee75 | |||
| 7f53048875 | |||
| b1a5cda91e | |||
| 66b7bc0dcf | |||
| eaaac67d4f | |||
| 3cc3948d71 | |||
| 08096ed24a | |||
| 92a678c250 | |||
| 81de782d1e | |||
| d83eccdded | |||
| 681b66b13c | |||
| 2958bd050b | |||
| 38f493aff2 | |||
| 19bac44dde | |||
| b49712ed32 | |||
| cdbe1310cc | |||
| b462f5335f | |||
| 115a4e89e2 | |||
| 9d935d9be1 | |||
| 7eca1112fb | |||
| fe2a266c50 | |||
| e97df9b1ec | |||
| d048459d36 | |||
| 88fa0651bf | |||
| 4e038f3ae7 | |||
| 6c6c8d3a33 | |||
| a8a921184f | |||
| cbd2472b7c | |||
| a0efca4581 | |||
| 4e1da34601 | |||
| b03df41906 | |||
| 8ca6eea938 | |||
| 1c2ad5e6b9 | |||
| 991fee82df | |||
| b52ce71c27 | |||
| e78d22469f | |||
| c4e8b411d4 | |||
| 3a51b90145 | |||
| a2cd3e9ef0 | |||
| 1cbb562c23 | |||
| 558977bb2b | |||
| 332709da65 | |||
| a74587a4ea | |||
| 1e13749483 | |||
| 1a1b8fcc36 | |||
| 23262b249c | |||
| 5687be5f31 | |||
| e293aa9cfc | |||
| edf7547ad5 | |||
| 2cac079ef4 | |||
| 5afc1c5b5f | |||
| 3025fefc41 | |||
| 00a5cff244 | |||
| fc0ed79e5d | |||
| 13c618465d | |||
| 3c52a84ff8 | |||
| 2bb99b8fe6 | |||
| d2808b1b51 | |||
| b679cdbd3e | |||
| a5f034f272 | |||
| 82fa6eccf9 | |||
| 8d39357c84 | |||
| aff40d8515 | |||
| 51cfc1f89a | |||
| 816220f90c | |||
| 50b23584d7 | |||
| c1d36a8acb | |||
| caefe9e8de | |||
| 64d7688acb | |||
| 408b8a5482 | |||
| ce2941ca0d | |||
| 47797ca665 | |||
| 1697c192ac | |||
| 5837240451 | |||
| 2c8171f8c8 | |||
| fbb59823c5 | |||
| fe87a1ad96 | |||
| 38e3e35c72 | |||
| a8f7132113 | |||
| 3d921155e0 | |||
| fe34a2a0e4 | |||
| e24deea4c9 | |||
| d6276066dd | |||
| d2e1e9ce85 | |||
| e61db2c618 | |||
| c40c49536e | |||
| dd2033c40c | |||
| d66a1fe069 | |||
| beb75c6fd6 | |||
| c0c2b99164 | |||
| ebad423023 | |||
| c5898d9f02 | |||
| ee87cda65d | |||
| 5b41b7d1b1 | |||
| 4633164857 | |||
| 59c2dabb26 | |||
| 42324e5017 | |||
| 52c081b02c | |||
| bb3f810611 | |||
| d5255da20b | |||
| 70971457b7 | |||
| ff8b1ebafa | |||
| 83f1380600 | |||
| 1ecca8439d | |||
| 58ee899dce | |||
| 10e388efc2 | |||
| fb97da1ce1 | |||
| 4aaf05d72e | |||
| 6bf2d74dfc | |||
| 4be18d3299 | |||
| 0d725c1e60 | |||
| 3c69af9ed3 | |||
| 89b96cb85c | |||
| 99dbd4b9ee | |||
| 67ec1a5266 | |||
| 2fd5815546 | |||
| cba31b52b3 | |||
| eadcb472e1 | |||
| b3b6d9d77c | |||
| 48dcf7852e | |||
| 73a876a056 | |||
| f50603a5fc | |||
| 164dcfe65b | |||
| fb356b1344 | |||
| a3d91ae318 | |||
| 65b4f58703 | |||
| 54551c7d6e | |||
| d877e3fcac | |||
| dbfe7dd42e | |||
| 45b4187596 | |||
| 44c63795a7 | |||
| 36244ac1ff | |||
| d3790feac0 | |||
| b63aca9a2c | |||
| 8f2f2a0d9d | |||
| 5d57ca10d9 | |||
| a5913d98e1 | |||
| 5f3e3c2c62 | |||
| c53e4c1d77 | |||
| 6d8be68071 | |||
| fb28c99b8a | |||
| acaed3deab | |||
| bb47fdf25e | |||
| 97bb5b2b6d | |||
| c0f0c67864 | |||
| e91b0f0517 | |||
| 3f1f999e2d | |||
| c63bc6bfaa | |||
| a54907dce3 | |||
| 2c57c399bf | |||
| a063580dbb | |||
| a2c6e429b3 | |||
| f3e07f105e | |||
| f21700d876 | |||
| 34669aa651 | |||
| 08248f0859 | |||
| 722be83a14 | |||
| ea1a6e814b | |||
| 2c930b19ba | |||
| 75e8eaad78 | |||
| b74d6cfb98 | |||
| a95d4ac1b5 | |||
| b9c9d411ff | |||
| 05cc753275 | |||
| af4a1c4e6b | |||
| ef39098a1b | |||
| 6671b44434 | |||
| b2dbde4b8c | |||
| 57cb36333b | |||
| bfacc99ac3 | |||
| e2192e119d | |||
| 4e0ac33eae | |||
| 8078e5bd54 | |||
| 146a0da7b3 | |||
| ad7b83fc86 | |||
| c668c49a15 | |||
| 3574346318 | |||
| 008be2848e | |||
| 63261593c8 | |||
| 18b14eb4a8 | |||
| 4724e503b0 | |||
| 2c4d93c7cf | |||
| 148c1c0984 | |||
| 6bc784b95a | |||
| d275cce099 | |||
| 5136659a59 | |||
| 414816064f | |||
| dcf96e43fa | |||
| ea7d7bb644 | |||
| 60891cd197 | |||
| 0556fea593 | |||
| 74fcf6f28d | |||
| 70eb03ec29 | |||
| 856d26cb4b | |||
| 1adf386345 | |||
| 02137de419 | |||
| 73516df908 | |||
| 3025b9ebac | |||
| e235f372ce | |||
| 62ace035c6 | |||
| 07a169d964 | |||
| 8e2b91c8cc | |||
| 831ff281d0 | |||
| 29ad485d17 | |||
| 51f740e23e | |||
| c751f4a6ec | |||
| 742868dc2d | |||
| 9b8bddd179 | |||
| 1987203745 | |||
| f7abcfb39a | |||
| 016bc8b813 | |||
| 66b1a59efe | |||
| bd4750126b | |||
| 0fba6bd347 | |||
| eb9db854d7 | |||
| 7d68d59cc2 | |||
| f9311ba61d | |||
| 60d2888605 | |||
| c2ada4c306 | |||
| 310ef194a1 | |||
| daf30eff79 | |||
| a90585f1d6 | |||
| 4be6d423e4 | |||
| 2db724bc50 | |||
| 452b9c26e4 | |||
| d0c05b0143 | |||
| 36aeb4e9ee | |||
| f8d4b66edd | |||
| 483de7d614 | |||
| a95ed40bf0 | |||
| 686efcfcb1 | |||
| bd6f2760a3 | |||
| 15631009b4 | |||
| 8eb822ebf3 | |||
| aa95b1b763 | |||
| 92e3a5e386 | |||
| 4c22dcfbfd | |||
| 4f459198db | |||
| 056f7352ef | |||
| 0c2939b331 | |||
| 68e3d685fd | |||
| 0209d3f185 | |||
| ef6890c31d | |||
| 1e98b3b559 | |||
| 223238d265 | |||
| 33f1f69e9c | |||
| fb04f2723a | |||
| 78d4265f65 | |||
| c2aed5345e | |||
| 2392894eb0 | |||
| 59fa2c0763 | |||
| 7081b2df85 | |||
| 1f34221552 | |||
| c43681a068 | |||
| 992fab50ee | |||
| 15be89f89d | |||
| d2902c8d3b | |||
| 8e51ec9ee4 | |||
| 7d82f203ee | |||
| c07711de1d | |||
| cb610d54b4 | |||
| 2f36da5201 | |||
| 954e3d2e71 | |||
| 830ae266c4 | |||
| 6eae751e70 | |||
| f0e0c35f2b | |||
| dc8253450d | |||
| 8d28d8cca0 | |||
| 274afc2c61 | |||
| 5717fe9ca8 | |||
| b6b2c756c9 | |||
| db57db52cf | |||
| 08fd4b69e8 | |||
| 24130c882d | |||
| 759f94e17a | |||
| 90c0525c7e | |||
| 5ac4918bdd | |||
| 3f9af9deb9 | |||
| c6b0664f52 | |||
| e36c0a418a | |||
| efc8c61f75 | |||
| 44c690cd9a | |||
| f84a88a824 | |||
| c33ceddc26 | |||
| 6a750c7a50 | |||
| f288c4fcef | |||
| ee9e506af2 | |||
| 8a122a90fa | |||
| 45f141ce69 | |||
| a9824dc6a3 | |||
| 84228eaeda | |||
| c739407f92 | |||
| 578d495f91 | |||
| bdd68116b7 | |||
| c8508fabd0 | |||
| 36bc770ed4 | |||
| 5701e147ef | |||
| 5fc99f02cf | |||
| 411f540590 | |||
| b2bd56a012 | |||
| a3bf32fe87 | |||
| 9e93c984f7 | |||
| d7ce9430ca | |||
| 0fb53623a5 | |||
| 9ad34243aa | |||
| 06f719e501 | |||
| f439149cb3 | |||
| 32c0b283ef | |||
| 6e91297fa2 | |||
| 752ca15da4 | |||
| e33cb8ae12 | |||
| 10bd7bab14 | |||
| 84f0ae00d2 | |||
| e3f213305b | |||
| d886cf40ef | |||
| d572e3b1f9 | |||
| 816bd48c83 | |||
| 05563a7832 | |||
| 93e3044c6d | |||
| 6825e6c90a | |||
| 6401c5b4ee | |||
| 4471e5419d | |||
| 2b820c534d | |||
| 765993846d | |||
| d9073bb033 | |||
| efbff6a3d9 | |||
| 61abb4645c | |||
| 11d1b661db | |||
| b95b766bc0 | |||
| 4094dc0c96 | |||
| b7fffe8f7e | |||
| a87e2bcdf1 | |||
| 6564241674 | |||
| dc5b2a2ec0 | |||
| 924cc34647 | |||
| 68061f2059 | |||
| 67d2bb6e0a | |||
| 99b5feadd9 | |||
| 507f96cdeb | |||
| 6fbc11ce21 | |||
| ff2baed5db | |||
| 94da3dc5c8 | |||
| 9df58a7545 | |||
| 5b017af90d | |||
| a7a7a1fdea | |||
| ca0ccaba27 | |||
| 8f1836bad9 | |||
| 61fc90b268 | |||
| 1d5a926cc2 | |||
| 7f5a14817d | |||
| 9bf01bf010 | |||
| 358bd9b359 | |||
| dd50014055 | |||
| a84b0cafdd | |||
| a4dee3d1ad | |||
| 340729bbe8 | |||
| 4518826376 | |||
| c07397695a | |||
| aa38e0da9a | |||
| ef45bb2496 | |||
| edec2d057d | |||
| 66897b6f6d | |||
| af064545bf | |||
| 9ab9e6f331 | |||
| 65c2617140 | |||
| 24468e4525 | |||
| df11d701e1 | |||
| d2fa8c5d4b | |||
| e01bad7d3c | |||
| 4c4896f0d5 | |||
| 5fadb341c3 | |||
| 29ee91ae7d | |||
| 5533eb40d1 | |||
| 533d2bab3d | |||
| f68f813073 | |||
| 7edb32e75f | |||
| acf11efe54 | |||
| a887847ca2 | |||
| c17f5ec460 | |||
| df5dafe049 | |||
| 3c32fd4a29 | |||
| ecb6f0c3e3 | |||
| 169e14c7ac | |||
| 316fa38dbc | |||
| 884895ae25 | |||
| 464456fa31 | |||
| bab349b46e | |||
| 46a72bc342 | |||
| ee43f47f45 | |||
| 71c6165dcd | |||
| 51c1fc93e3 | |||
| 17887b216d | |||
| 01eab0c3b9 | |||
| 6b65c6aeae | |||
| 3fb292f3c7 | |||
| a8bf8af5aa | |||
| d8c8e8b4b6 | |||
| 930e76ad0d | |||
| 83b5a746d9 | |||
| a7f8176be6 | |||
| 1b4db814ea | |||
| 9ae9ca833a | |||
| 66f87b8caf | |||
| bba85fcae3 | |||
| a0104a9ed8 | |||
| 112e015f05 | |||
| e6246599eb | |||
| 1d049b6aed | |||
| 37e2a687e3 | |||
| a113b87c45 | |||
| b999d48941 | |||
| 2cb54158b8 | |||
| 420943657c | |||
| 4911773b77 | |||
| 980c804153 | |||
| 578947e661 | |||
| 5e87ff0615 | |||
| d409947e9a | |||
| ba527c728e | |||
| 50bb452dd1 | |||
| 90ac3a3207 | |||
| 684de2abff | |||
| 44faa3b796 | |||
| 138682fd30 | |||
| 373dd2dc3d | |||
| 3ea09ae998 | |||
| 115aeef1c4 | |||
| 2883ff6ad5 | |||
| c3b6417226 | |||
| eceedf43cf | |||
| 6f8dd000f6 | |||
| 2e46882a9b | |||
| 5917347c6f | |||
| 7d5732cb49 | |||
| 1a8d386288 | |||
| 0f26591422 | |||
| cd1bd8bf4c | |||
| b84b918464 | |||
| 00f573fce2 | |||
| 9951b1f569 | |||
| 0094abea6e | |||
| 8781aff637 | |||
| a5e3dbb0e3 | |||
| 29bd7e1929 | |||
| e1a4b6e57b | |||
| 5884ba907c | |||
| 64fe2f7db6 | |||
| 3bdf723bab | |||
| 9126425a21 | |||
| bfbd83239e | |||
| d9d1bb4acb | |||
| 5d3a785c55 | |||
| eeab0bebfa | |||
| d611d54ed4 | |||
| 1fb1486c8a | |||
| d83866d006 | |||
| 14ebc92d8c | |||
| 45986f8dc8 | |||
| 561ba96ec7 | |||
| cfad7327a5 | |||
| 316bc6b3f4 | |||
| ac53650da5 | |||
| 94c52130be | |||
| ee2b88b7b1 | |||
| 1955170a14 | |||
| 9fdd176e45 | |||
| bae65562ef | |||
| 95d1e146b2 | |||
| fcb7222b1a | |||
| 5d491ef9da | |||
| c0ce911b5e | |||
| 673c2a6f9a | |||
| 2cffa14105 | |||
| c485cfabd8 | |||
| 3b3c8001fe | |||
| 5f2e4b18f8 | |||
| 2cc8c2c0dc | |||
| d5b3092331 | |||
| 89f7b0868c | |||
| 87253ca906 | |||
| 7296cbdbfe | |||
| a8f26262cf | |||
| f28ad4b251 | |||
| 5620c5ab5d | |||
| 23fd6cb1da | |||
| a881a2c8d4 | |||
| 60fc4bbf57 | |||
| 7903a1b767 | |||
| 4dbca60435 | |||
| a168d046f3 | |||
| 08489a4e22 | |||
| 0d66002c95 | |||
| e8ab31d009 | |||
| ee1952424d | |||
| b6c1a8579e | |||
| 64ddc26bbf | |||
| 4e65be1211 | |||
| 9be164101d | |||
| 48b2c4bff4 | |||
| 7a16f4582d | |||
| b10cba0e0a | |||
| d3b95d1d26 | |||
| 04b950b824 | |||
| 4145b98314 | |||
| 52a38d5509 | |||
| a6769c050b | |||
| d172cccd07 | |||
| 945eb8f50b | |||
| c11132a3a1 | |||
| 32726af23a | |||
| 1c78e3f3b8 | |||
| 9151e673e4 | |||
| 042d6c48b3 | |||
| cdd3ebfcf1 | |||
| faaa8daffb | |||
| e108f473ec | |||
| f100b5ea7e | |||
| 8690c74d6a | |||
| 788374bd8c | |||
| d755279fad | |||
| fb7906760e | |||
| 1a7960421e | |||
| 56845ad1c1 | |||
| 1e0450dfb1 | |||
| 46f6d77c55 | |||
| 17deaa39f5 | |||
| f243d4077d | |||
| f741583f1a | |||
| 1586a91909 | |||
| de8a22a2f4 | |||
| 19d5ec6921 | |||
| 9f34a68dba | |||
| 0c1cbaede8 | |||
| e363962dd2 | |||
| 659684836d | |||
| 19699033bf | |||
| 011c5155fa | |||
| c18ec76e85 | |||
| b261fbd7bb | |||
| c0a22d7b56 | |||
| 4f275ec75b | |||
| 1528ae16a0 | |||
| d069726634 | |||
| 2aa73f7823 | |||
| c71d787454 | |||
| c1eecc94ec | |||
| 917e9af67b | |||
| 6e6ef6fd57 | |||
| 6e26b9a42c | |||
| 85c27fd775 | |||
| 4efcee14e4 | |||
| e4a5d4de87 | |||
| 4502d89d87 | |||
| b2b259a985 | |||
| 1640d73997 | |||
| 1b4d4b6708 | |||
| 22591a77b2 | |||
| 1161388b2b | |||
| 4fb8cf2f6b | |||
| db0d48471e | |||
| b949241d12 | |||
| 4dfd1519ac | |||
| 59e64f8b82 | |||
| 7ac5cc7dd0 | |||
| 2c24c012bd | |||
| cc8be680ca | |||
| 3084e71acb | |||
| a92f55b609 | |||
| daa8d1141e | |||
| 360f12cd44 | |||
| e570b8ded4 | |||
| bd4a6c9966 | |||
| 4049c0e69e | |||
| 05823ad867 | |||
| 82d767d121 | |||
| 6e2c6ffdf7 | |||
| 5762d08f4f | |||
| 61bb0aa943 | |||
| 2f1e13ff7a | |||
| 653d22c3e9 | |||
| 8f008f8319 | |||
| e538a4e2a3 | |||
| 29050eadb5 | |||
| f3ef11056f | |||
| ae0229549d | |||
| 2e1652fdec | |||
| 72ba5c4de7 | |||
| d2a516a75d | |||
| 725e83ac21 | |||
| 3f84cb3699 | |||
| d65129f3c8 | |||
| 57f9d5ae9c | |||
| 2ecea675ee | |||
| f64c88d629 | |||
| 3c608e56f6 | |||
| f54a68ac76 | |||
| 3bb7c43694 | |||
| 61ba4bf46e | |||
| 184f9d40e6 | |||
| f3afeb9c04 | |||
| 2a2c8190ec | |||
| 45154f1d68 | |||
| 7861eaa5ec | |||
| f0a63185c9 | |||
| 7d8ca29bea | |||
| e4fbf98b18 | |||
| f4d95eecc0 | |||
| 900943192f | |||
| b9163f6348 | |||
| 0530588266 | |||
| b26f73f427 | |||
| e2068416c9 | |||
| a2d23700e4 | |||
| 0857837e64 | |||
| d15f2c6214 | |||
| 6eb0500d3d | |||
| 7b8c4952a8 | |||
| 4beca611fb | |||
| 1aa30ba551 | |||
| fc5cd8840e | |||
| ec2b9f59f7 | |||
| 799f30b08d | |||
| bf90350fe7 | |||
| c017dd73aa | |||
| 9195f6085d | |||
| 057cbaa4ae | |||
| aa2957e62a | |||
| 50eafd769b | |||
| cecae46ccf | |||
| 0b5574c28a | |||
| c237be820b | |||
| eee4152981 | |||
| 2afa955401 | |||
| 704f28df98 | |||
| edbdb4bf03 | |||
| d3195c6b5f | |||
| 8fcb361fb8 | |||
| f870cc7eab | |||
| 03e5751102 | |||
| 05b55446da | |||
| f1db2383fc | |||
| cd10be6c91 | |||
| 2b5ba27ff8 | |||
| fa96d1bb78 | |||
| 23afb3fd07 | |||
| 6f05b866bc | |||
| 603d949ed5 | |||
| 4ce849a5ed | |||
| 7b0116c5b4 | |||
| a52a8d8a5d | |||
| 75936bf9f7 | |||
| 0d00d3eecf | |||
| 93ee4927bc | |||
| 5570ec21b4 | |||
| 5530a47d76 | |||
| fc0057ff35 | |||
| ec309dcac8 | |||
| ee0e0f9943 | |||
| 7f842bdf4f | |||
| 7c96d6cbcc | |||
| 5eb9ed0aaf | |||
| 94c1763f71 | |||
| 1304a3106b | |||
| a9c38f4902 | |||
| e2bdb4ff83 | |||
| 41accaf963 | |||
| 5f37d13405 | |||
| 745bcb5406 | |||
| 1f4f00acad | |||
| 905e14ee83 | |||
| f8d47df43b | |||
| 934bfa5969 | |||
| 00d1ab6454 | |||
| 019048c555 | |||
| 6223c40c2d | |||
| e7c09ab3df | |||
| 75fa697526 | |||
| 771a3624f5 | |||
| 7fed07f1e9 | |||
| 7180f03376 | |||
| 2aefca0f2e | |||
| 7e8aa5429a | |||
| 2be8650d2c | |||
| 495125415b | |||
| 1def4ef49d | |||
| bb67476209 | |||
| e8373305b4 | |||
| 275ffe2e01 | |||
| a210d898b6 | |||
| 8bce7fc016 | |||
| 39cecdab06 | |||
| a7fee9db00 | |||
| d4e630b8cc | |||
| 82b92af086 | |||
| c23e851074 | |||
| c2333946c0 | |||
| 2c6782b501 | |||
| c2f5088067 | |||
| 8195a2b5d8 | |||
| 2798e35d86 | |||
| d1753cc25d | |||
| a5ded26850 | |||
| d51420bb01 | |||
| aec025dbf6 | |||
| 95257d63a1 | |||
| 9cfc91a935 | |||
| 13873a8799 | |||
| cc6eaf9584 | |||
| 1a164919f1 | |||
| 3bdad35e9f | |||
| 275ac4c5e0 | |||
| 504a89d25b | |||
| 42666a6b03 | |||
| c786f4887f | |||
| 75f4b049a6 | |||
| 907025eb40 | |||
| 66d71aafb7 | |||
| 317939e821 | |||
| 1340beed16 | |||
| e9045e9f55 | |||
| 69371ba2c2 | |||
| dbe0b96404 | |||
| 43e65fdd46 | |||
| 5d6f4f8ea4 | |||
| b63c830547 | |||
| 927c2f06a3 | |||
| 40a16a1b04 | |||
| 6be3ac560b | |||
| b661b913b5 | |||
| b273c4d19f | |||
| 7ebfb5c90f | |||
| 3abd71c526 | |||
| dc90c77285 | |||
| 2f71935616 | |||
| 941e94f1d2 | |||
| 4be8077a56 | |||
| aef33a89c2 | |||
| 1ddde00b1d | |||
| f66bd259cf | |||
| ea34d36d62 | |||
| b5403415f7 | |||
| a8ca723277 | |||
| 14f44bd9c9 | |||
| c9281b5bb9 | |||
| ce737cf543 | |||
| e8723c375f | |||
| 6b14946d81 | |||
| 597bb764f1 | |||
| f406d16b7b | |||
| 58baa7aa61 | |||
| f140c3a0e5 | |||
| 99d0164837 | |||
| 143f479869 | |||
| 7864e1edf5 | |||
| ed6107c8c5 | |||
| d4d8ab87ac | |||
| af89454645 | |||
| e10346124f | |||
| 0d3d7722c1 | |||
| 72ba55b056 | |||
| 82cfc819a8 | |||
| 699edaab3b | |||
| a342b207b2 | |||
| ee163bed33 | |||
| f4b544786c | |||
| d7fa77f03b | |||
| a9b8e7aaa3 | |||
| 0419fc4f5f | |||
| 7de49dec7b | |||
| 0398323a60 | |||
| 8b4f07692e | |||
| dffc624b37 | |||
| d1bad25f40 | |||
| 229f243ca0 | |||
| 91f972bb59 | |||
| 493009ac91 | |||
| 0355e4e930 | |||
| 8184041c7e | |||
| 1d336d3a1e | |||
| 991ce97170 | |||
| bf480028f5 | |||
| ab9427420e | |||
| 07e462f01f | |||
| 7eb6a4b3a4 | |||
| 471a2df3a6 | |||
| 7e398a169b | |||
| 7bb81f6c3e | |||
| c56d59c90b | |||
| 791ebc58dd | |||
| 3f63005e91 | |||
| f7a00a2334 | |||
| 6a2f349ec5 | |||
| 4f667bb442 | |||
| 22294bfac8 | |||
| 07e67e1350 | |||
| 660ed49daf | |||
| fad23b25a1 | |||
| 6b74294844 | |||
| 11a564b6bd | |||
| 939386aabb | |||
| 01ed010aed | |||
| 52ec0ba938 | |||
| 4f8310dfde | |||
| 263f37a69b | |||
| 56483122b6 | |||
| 16362e289b | |||
| 586a8f9e9e | |||
| a9249dbb0a | |||
| 47733f1a0f | |||
| bb02ec3261 | |||
| c3689fa60b | |||
| dc0947da78 | |||
| 427b60f288 | |||
| 902aad57af | |||
| 6afd7859f8 | |||
| cfce9890fb | |||
| 4b98379ce1 | |||
| ee3d411024 | |||
| 40d1598165 | |||
| 97961b8bee | |||
| fcd5b38caf | |||
| 052e9105f7 | |||
| 4375be4642 | |||
| 5ebb35654b | |||
| a83124dade | |||
| f729486b33 | |||
| d1eae4c7e3 | |||
| 9b6beb496a | |||
| 6e0fa02fd0 | |||
| f19f67c39c | |||
| 823735750a | |||
| 68b6e6d2be | |||
| e19c7200eb | |||
| be3a05eab2 | |||
| 5e38d92a95 | |||
| 5204a15f95 | |||
| 680a4985ea | |||
| dfce564026 | |||
| 52c2bb51fb | |||
| 6b14a0d08c | |||
| 395914c162 | |||
| 8e2010a26c | |||
| 86498400da | |||
| abffa73776 | |||
| 0cbbdb32c4 | |||
| 79fa4f3343 | |||
| ab50cd2bd8 | |||
| 27f67dcad0 | |||
| 6a1dea6602 | |||
| 657271eb04 | |||
| 2db82460b1 | |||
| 07c6e99725 | |||
| f77e9d0d80 | |||
| a996fac57b | |||
| 8228f99c36 | |||
| 41b5cc2d20 | |||
| d1f5c949a9 | |||
| 29025e40f4 | |||
| 1d6673a166 | |||
| fba0a83c03 | |||
| 7195eb991d | |||
| 9f4653b0df | |||
| 99fbf50fa2 | |||
| ee15c8717f | |||
| 37b4c8737f | |||
| 1d969818fd | |||
| 4ca259adaa | |||
| 11e132c8eb | |||
| 8402479e16 | |||
| aa35a8e46e | |||
| 51d181ca58 | |||
| 1bc0a303dc | |||
| 43211abb65 | |||
| 8acf9cd11d | |||
| fe71812b1d | |||
| a013f8519b | |||
| c0e7dcd2fd | |||
| 5d6c314304 | |||
| c5fc8dd75d | |||
| ad694905be | |||
| 6c4e2931ef | |||
| fd39a24b34 | |||
| ccc65bfde7 | |||
| f13f60504a | |||
| 33d3e28a7f | |||
| 69798dde65 | |||
| ad6730687f | |||
| e7d57e1a77 | |||
| f9b8a95b92 | |||
| 5cd1d6e287 | |||
| 59910c45d5 | |||
| a8b11f5c18 | |||
| d562701538 | |||
| 9866af3777 | |||
| 391a384715 | |||
| 5ba95d4c53 | |||
| 291b28ac52 | |||
| 0fce70b091 | |||
| c5c94a1d2c | |||
| 289913e5ff | |||
| e770e87035 | |||
| 248d5fd870 | |||
| 7fa666b909 | |||
| 27db71370a | |||
| a632c4047e | |||
| cc873b51c3 | |||
| 5c46f26505 | |||
| b70e0a466f | |||
| d7ac25f813 | |||
| 1af98ea784 | |||
| 2be243c143 | |||
| 1e51ab0b23 | |||
| a845c67c60 | |||
| 756700ddf3 | |||
| da18e77e9a | |||
| 38e7ec3316 | |||
| ee792a8fa1 | |||
| 1f8e2dcda2 | |||
| f103e6263d | |||
| 031279dfb2 | |||
| 2a58111fc1 | |||
| d346c7c6a7 | |||
| 1a86dc913f | |||
| 1e6b107d99 | |||
| 8806b07bd2 | |||
| ff60398b1c | |||
| 32e2ef34a3 | |||
| 91b60a955c | |||
| 3d10e75117 | |||
| 915e78ee2d | |||
| 9031103c24 | |||
| 3db03960be | |||
| afa1c65d32 | |||
| 41aa36a0a3 |
@@ -0,0 +1,43 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: debug
|
||||||
|
run: |
|
||||||
|
id
|
||||||
|
which bash
|
||||||
|
whoami
|
||||||
|
env
|
||||||
|
ps -ef
|
||||||
|
pwd
|
||||||
|
cat /proc/self/uid_map
|
||||||
|
cat /proc/self/status
|
||||||
|
systemd-detect-virt
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install automake autopoint xsltproc gettext expect byacc libtool
|
||||||
|
- name: configure
|
||||||
|
run: |
|
||||||
|
./autogen.sh --without-selinux --disable-man
|
||||||
|
grep ENABLE_ config.status
|
||||||
|
- run: make
|
||||||
|
- run: make install DESTDIR=${HOME}/rootfs
|
||||||
|
- run: sudo make install
|
||||||
|
- run: |
|
||||||
|
cd tests
|
||||||
|
sudo ./run_some
|
||||||
|
cat testsuite.log
|
||||||
@@ -17,6 +17,8 @@ Makefile.in
|
|||||||
/ABOUT-NLS
|
/ABOUT-NLS
|
||||||
/aclocal.m4
|
/aclocal.m4
|
||||||
/autom4te.cache
|
/autom4te.cache
|
||||||
|
/compile
|
||||||
|
/config.cache
|
||||||
/config.guess
|
/config.guess
|
||||||
/config.h
|
/config.h
|
||||||
/config.h.in
|
/config.h.in
|
||||||
@@ -44,4 +46,6 @@ Makefile.in
|
|||||||
/po/stamp-po
|
/po/stamp-po
|
||||||
|
|
||||||
/shadow.spec
|
/shadow.spec
|
||||||
|
/shadow-*.tar.*
|
||||||
/libmisc/getdate.c
|
/libmisc/getdate.c
|
||||||
|
/libsubid/subid.h
|
||||||
|
|||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
dist: bionic
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: c
|
||||||
|
|
||||||
|
compiler:
|
||||||
|
- gcc
|
||||||
|
- clang
|
||||||
|
|
||||||
|
arch:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
- ppc64le
|
||||||
|
- s390x
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get -y install -qq automake autopoint xsltproc libselinux1-dev gettext expect
|
||||||
|
- sudo apt-get -y install -qq byacc libtool
|
||||||
|
script:
|
||||||
|
- ./autogen.sh --without-selinux --disable-man
|
||||||
|
- grep ENABLE_ config.status
|
||||||
|
- make
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- secure: "G47VYFrtzqalrVjixTqBG9Qsa8EZRcaqsh1k6fq5JgEyHmMQActpvTUDs9FXf1MEqiY5XX3VDVfBsZgKPHgmHsMzD1bX11xpnpGByB8g7gr8I3u2ZkCREqgi77a5l3LeBh+seWiambe/DYOgvPCNa6pCynLgR9advqtgKhpCruU="
|
||||||
|
|
||||||
|
addons:
|
||||||
|
coverity_scan:
|
||||||
|
|
||||||
|
project:
|
||||||
|
name: "shadow-maint/shadow"
|
||||||
|
description: "Upstream shadow utils tree"
|
||||||
|
|
||||||
|
notification_email: christian.brauner@ubuntu.com,serge@hallyn.com
|
||||||
|
|
||||||
|
build_command_prepend: "./autogen.sh --without-selinux --disable-man"
|
||||||
|
build_command: "make -j4"
|
||||||
|
branch_pattern: master
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cat /proc/self/uid_map
|
||||||
|
- cat /proc/self/status
|
||||||
|
- systemd-detect-virt
|
||||||
|
- ./autogen.sh --without-selinux --disable-man
|
||||||
|
- grep ENABLE_ config.status
|
||||||
|
- make
|
||||||
|
- sudo make install
|
||||||
|
- (cd tests; sudo ./run_some; cat testsuite.log)
|
||||||
|
|
||||||
|
# vim:et:ts=2:sw=2
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
Thanks to at least the following people for sending patches, bug
|
||||||
|
reports and various comments. This list may be incomplete, I received
|
||||||
|
a lot of mail...
|
||||||
|
|
||||||
|
# Maintainers
|
||||||
|
Tomasz Kłoczko <kloczek@pld.org.pl> (2000-2007)
|
||||||
|
Nicolas François <nicolas.francois@centraliens.net> (2007-2014)
|
||||||
|
Serge E. Hallyn <serge@hallyn.com> (2014-now)
|
||||||
|
Christian Brauner <christian@brauner.io> (2019-now)
|
||||||
|
|
||||||
|
# Authors and contributors
|
||||||
|
Adam Rudnicki <adam@v-lo.krakow.pl>
|
||||||
|
Alan Curry <pacman@tardis.mars.net>
|
||||||
|
Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
Alexander O. Yuriev <alex@bach.cis.temple.edu>
|
||||||
|
Algis Rudys <arudys@rice.edu>
|
||||||
|
Andreas Jaeger <aj@arthur.rhein-neckar.de>
|
||||||
|
Andy Zaugg <andy.zaugg@gmail.com>
|
||||||
|
Aniello Del Sorbo <anidel@edu-gw.dia.unisa.it>
|
||||||
|
Anton Gluck <gluc@midway.uchicago.edu>
|
||||||
|
Arkadiusz Miskiewicz <misiek@pld.org.pl>
|
||||||
|
Ben Collins <bcollins@debian.org>
|
||||||
|
Brian R. Gaeke <brg@dgate.org>
|
||||||
|
Calle Karlsson <ckn@kash.se>
|
||||||
|
Chip Rosenthal <chip@unicom.com>
|
||||||
|
Chris Evans <lady0110@sable.ox.ac.uk>
|
||||||
|
Chris Lamb <chris@chris-lamb.co.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>
|
||||||
|
David Frey <David.Frey@lugs.ch>
|
||||||
|
Ed Carp <ecarp@netcom.com>
|
||||||
|
Ed Neville <ed@s5h.net>
|
||||||
|
Eric W. Biederman" <ebiederm@xmission.com>
|
||||||
|
Floody <flood@evcom.net>
|
||||||
|
Frank Denis <j@4u.net>
|
||||||
|
George Kraft IV <gk4@us.ibm.com>
|
||||||
|
Greg Mortensen <loki@world.std.com>
|
||||||
|
Guido van Rooij
|
||||||
|
Guy Maor <maor@debian.org>
|
||||||
|
Hrvoje Dogan <hdogan@bjesomar.srce.hr>
|
||||||
|
Iker Pedrosa <ipedrosa@redhat.com>
|
||||||
|
Jakub Hrozek <jhrozek@redhat.com>
|
||||||
|
Janos Farkas <chexum@bankinf.banki.hu>
|
||||||
|
Jason Franklin <jason.franklin@quoininc.com>
|
||||||
|
Jay Soffian <jay@lw.net>
|
||||||
|
Jesse Thilo <Jesse.Thilo@pobox.com>
|
||||||
|
Joey Hess <joey@kite.ml.org>
|
||||||
|
John Adelsberger <jja@umr.edu>
|
||||||
|
Jonathan Hankins <jhankins@mailserv.homewood.k12.al.us>
|
||||||
|
Jon Lewis <jlewis@lewis.org>
|
||||||
|
Joshua Cowan <jcowan@hermit.reslife.okstate.edu>
|
||||||
|
Judd Bourgeois <shagboy@bluesky.net>
|
||||||
|
Juergen Heinzl <unicorn@noris.net>
|
||||||
|
Juha Virtanen <jiivee@iki.fi>
|
||||||
|
Julian Pidancet <julian.pidancet@gmail.com>
|
||||||
|
Julianne Frances Haugh <julie78787@gmail.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>
|
||||||
|
Michael Vetter <jubalh@iodoru.org>
|
||||||
|
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>
|
||||||
|
Pavel Machek <pavel@bug.ucw.cz>
|
||||||
|
Peter Vrabec <pvrabec@redhat.com>
|
||||||
|
Phillip Street
|
||||||
|
Rafał Maszkowski <rzm@icm.edu.pl>
|
||||||
|
Rani Chouha <ranibey@smartec.com>
|
||||||
|
Sami Kerola <kerolasa@rocketmail.com>
|
||||||
|
Scott Garman <scott.a.garman@intel.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>
|
||||||
|
Tim Hockin <thockin@eagle.ais.net>
|
||||||
|
Timo Karjalainen <timok@iki.fi>
|
||||||
|
Ulisses Alonso Camaro <ulisses@pusa.eleinf.uv.es>
|
||||||
|
Werner Fink <werner@suse.de>
|
||||||
+10
-3
@@ -2,7 +2,14 @@
|
|||||||
|
|
||||||
EXTRA_DIST = NEWS README TODO shadow.spec.in
|
EXTRA_DIST = NEWS README TODO shadow.spec.in
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = 1.5 dist-bzip2 foreign
|
SUBDIRS = libmisc lib
|
||||||
|
|
||||||
SUBDIRS = po man libmisc lib src \
|
if ENABLE_SUBIDS
|
||||||
contrib doc etc
|
SUBDIRS += libsubid
|
||||||
|
endif
|
||||||
|
|
||||||
|
SUBDIRS += src po contrib doc etc
|
||||||
|
|
||||||
|
if ENABLE_REGENERATE_MAN
|
||||||
|
SUBDIRS += man
|
||||||
|
endif
|
||||||
|
|||||||
@@ -1,6 +1,207 @@
|
|||||||
$Id$
|
$Id$
|
||||||
|
|
||||||
shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24
|
shadow-4.1.5.1 -> shadow-4.2 UNRELEASED
|
||||||
|
|
||||||
|
*** general
|
||||||
|
* Handle libc whose crypt() returns NULL when passed a salt that
|
||||||
|
violates specs or system requirements (e.g. FIPS140). This is needed
|
||||||
|
with glibc/eglibc 2.17 for tools checking passwords (passwd (non PAM
|
||||||
|
enabled) or newgrp), and for tools generating encrypted passwords
|
||||||
|
(chgpasswd, chpasswd, or gpasswd when non PAM enabled or when a fixed
|
||||||
|
crypt method is requested on the command line, and newusers, or passwd
|
||||||
|
in their non PAM enabled versions)
|
||||||
|
* Fix segfault when reading groups split on multiple lines. This impacts
|
||||||
|
most user/group management tools when MAX_MEMBERS_PER_GROUP is set.
|
||||||
|
|
||||||
|
- su
|
||||||
|
* When su receives a signal (SIGTERM, or SIGINT/SIGQUIT in non
|
||||||
|
interactive mode), kill the child process group, rather than just the
|
||||||
|
immediate child.
|
||||||
|
* Fix segmentation faults for users without a proper home or shell in
|
||||||
|
their passwd entries.
|
||||||
|
|
||||||
|
- login
|
||||||
|
* Fix segmentation faults for users without a proper home or shell in
|
||||||
|
their passwd entries.
|
||||||
|
|
||||||
|
*** documentation
|
||||||
|
* Fixed useradd man page (--home-dir option, instead of --home).
|
||||||
|
|
||||||
|
*** translation
|
||||||
|
* Updated Russian translation.
|
||||||
|
* Updated German man pages translation.
|
||||||
|
* Fixed gshadow Japanese man page translation.
|
||||||
|
|
||||||
|
shadow-4.1.5 -> shadow-4.1.5.1 2012-05-25
|
||||||
|
|
||||||
|
- login
|
||||||
|
* Log into utmp(x) when PAM is enabled, but do not log into wtmp.
|
||||||
|
This complete pam_lastlog which logs into wtmp and in into utmp(x).
|
||||||
|
- su
|
||||||
|
* non PAM enabled versions: do not fail if su is called without a
|
||||||
|
controlling terminal.
|
||||||
|
- userdel
|
||||||
|
* Fix segfault when userdel removes the user's group.
|
||||||
|
|
||||||
|
*** documentation
|
||||||
|
* .so links now point to paths relative to the top-level manual hierarchy
|
||||||
|
|
||||||
|
*** translation
|
||||||
|
* Updated French man pages translation.
|
||||||
|
* Updated German man pages translation.
|
||||||
|
* Updated Polish man pages translation. (logoutd.8)
|
||||||
|
|
||||||
|
shadow-4.1.4.3 -> shadow-4.1.5 2012-02-12
|
||||||
|
|
||||||
|
*** security
|
||||||
|
* su -c could be abused by the executed command to invoke commands with
|
||||||
|
the caller privileges. See below. (CVE-2005-4890)
|
||||||
|
|
||||||
|
*** general
|
||||||
|
* report usage error to stderr, but report usage help to stdout (and return
|
||||||
|
zero) when explicitly requested (e.g. with --help).
|
||||||
|
* initial support for tcb (http://openwall.com/tcb/) for useradd,
|
||||||
|
userdel, usermod, chage, pwck, vipw.
|
||||||
|
* Added support for ACLs and Extended Attributes in useradd and usermod.
|
||||||
|
Support shall be enabled with the new --with-acl or --with-attr
|
||||||
|
configure options.
|
||||||
|
* Added diagnosis for lock failures.
|
||||||
|
* use libsemanage instead of the semanage tool.
|
||||||
|
|
||||||
|
- chage
|
||||||
|
* Add --root option.
|
||||||
|
- chfn
|
||||||
|
* Add --root option.
|
||||||
|
- chgpasswd
|
||||||
|
* When the gshadow file exists but there are no gshadow entries, an entry
|
||||||
|
is created if the password is changed and group requires a
|
||||||
|
shadow entry.
|
||||||
|
* Add --root option.
|
||||||
|
- chpasswd
|
||||||
|
* PAM enabled versions: restore the -e option to allow restoring
|
||||||
|
passwords without knowing those passwords. Restore together the -m
|
||||||
|
and -c options. (These options were removed in shadow-4.1.4 on PAM
|
||||||
|
enabled versions)
|
||||||
|
* When the shadow file exists but there are no shadow entries, an entry
|
||||||
|
is created if the password is changed and passwd requires a
|
||||||
|
shadow entry.
|
||||||
|
* Add --root option.
|
||||||
|
- chsh
|
||||||
|
* Add --root option.
|
||||||
|
- faillog
|
||||||
|
* The -l, -m, -r, -t options only act on the existing users, unless -a is
|
||||||
|
specified.
|
||||||
|
* Add --root option.
|
||||||
|
- gpasswd
|
||||||
|
* Add --root option.
|
||||||
|
- groupadd
|
||||||
|
* Add --root option.
|
||||||
|
- groupdel
|
||||||
|
* Add --root option.
|
||||||
|
- groupmems
|
||||||
|
* Fix parsing of gshadow entries.
|
||||||
|
* Add --root option.
|
||||||
|
- groupmod
|
||||||
|
* Fixed groupmod when configured with --enable-account-tools-setuid.
|
||||||
|
* When the gshadow file exists but there are no gshadow entries, an entry
|
||||||
|
is created if the password is changed and group requires a
|
||||||
|
shadow entry.
|
||||||
|
* Add --root option.
|
||||||
|
- grpck
|
||||||
|
* Add --root option.
|
||||||
|
* NIS entries were dropped by -s (sort).
|
||||||
|
- grpconv
|
||||||
|
* Add --root option.
|
||||||
|
- grpunconv
|
||||||
|
* Add --root option.
|
||||||
|
- lastlog
|
||||||
|
* Add --root option.
|
||||||
|
- login
|
||||||
|
* Fixed limits support (non PAM enabled versions only)
|
||||||
|
* Added support for infinite limits and group based limits (non PAM
|
||||||
|
enabled versions only)
|
||||||
|
* Fixed infinite loop when CONSOLE is configured with a colon-separated
|
||||||
|
list of TTYs.
|
||||||
|
* Fixed warning and support for CONSOLE_GROUPS for users member of more
|
||||||
|
than 16 groups.
|
||||||
|
* Do not log into utmp(x) or wtmp when PAM is enabled. This is done by
|
||||||
|
pam_lastlog.
|
||||||
|
- newgrp, sg
|
||||||
|
* Fix parsing of gshadow entries.
|
||||||
|
- newusers
|
||||||
|
* Add --root option.
|
||||||
|
- passwd
|
||||||
|
* Add --root option.
|
||||||
|
- pwpck
|
||||||
|
* NIS entries were dropped by -s (sort).
|
||||||
|
* Add --root option.
|
||||||
|
- pwconv
|
||||||
|
* Add --root option.
|
||||||
|
- pwunconv
|
||||||
|
* Add --root option.
|
||||||
|
- useradd
|
||||||
|
* If the skeleton directory contained hardlinked files, copies of the
|
||||||
|
hardlink were removed from the skeleton directory.
|
||||||
|
* Add --root option.
|
||||||
|
- userdel
|
||||||
|
* Check the existence of the user's mail spool before trying to remove
|
||||||
|
it. If it does not exist, a warning is issued, but no failure.
|
||||||
|
* Do not remove a group with the same name as the user (usergroup) if
|
||||||
|
this group isn't the user's primary group.
|
||||||
|
* Add --root option.
|
||||||
|
* Add --selinux-user option.
|
||||||
|
- usermod
|
||||||
|
* Accept options in any order (username not necessarily at the end)
|
||||||
|
* When the shadow file exists but there are no shadow entries, an entry
|
||||||
|
is created if the password is changed and passwd requires a
|
||||||
|
shadow entry, or if aging features are used (-e or -f).
|
||||||
|
* Add --root option.
|
||||||
|
- su
|
||||||
|
* Document the su exit values.
|
||||||
|
* When su receives a signal, wait for the child to terminate (after
|
||||||
|
sending a SIGTERM), and kill it only if it did not terminate by itself.
|
||||||
|
No delay will be enforced if the child cooperates.
|
||||||
|
* Default ENV_SUPATH is /sbin:/bin:/usr/sbin:/usr/bin
|
||||||
|
* Fixed infinite loop when CONSOLE is configured with a colon-separated
|
||||||
|
list of TTYs.
|
||||||
|
* Fixed warning and support for CONSOLE_GROUPS for users member of more
|
||||||
|
than 16 groups.
|
||||||
|
* Do not forward the controlling terminal to commands executed with -c.
|
||||||
|
This prevents tty hijacking which could lead to execution with the
|
||||||
|
caller's privileges.
|
||||||
|
* Close PAM sessions as root. This will be more friendly to PAM modules
|
||||||
|
like pam_mount or pam_systemd.
|
||||||
|
* Added support for PAM modules which change PAM_USER.
|
||||||
|
|
||||||
|
*** translation
|
||||||
|
* Updated Brazilian Portuguese translation.
|
||||||
|
* Updated Catalan translation.
|
||||||
|
* Updated Czech translation.
|
||||||
|
* Updated Danish translation.
|
||||||
|
* New Danish man pages translation.
|
||||||
|
* Updated French translation.
|
||||||
|
* Updated French man pages translation.
|
||||||
|
* Updated German translation.
|
||||||
|
* Updated German man pages translation.
|
||||||
|
* Updated Greek translation.
|
||||||
|
* Updated Italian man pages translation.
|
||||||
|
* Updated Japanese translation.
|
||||||
|
* Updated Kazakh translation.
|
||||||
|
* Updated Norwegian Bokmål translation.
|
||||||
|
* Updated Portuguese translation.
|
||||||
|
* Updated Russian translation.
|
||||||
|
* Updated Simplified Chinese translation.
|
||||||
|
* Updated Simplified Chinese man pages translation.
|
||||||
|
* Updated Swedish translation.
|
||||||
|
* Updated Vietnamese translation.
|
||||||
|
|
||||||
|
shadow-4.1.4.2 -> shadow-4.1.4.3 2011-02-15
|
||||||
|
|
||||||
|
*** security
|
||||||
|
- CVE-2011-0721: An insufficient input sanitation in chfn can be exploited
|
||||||
|
to create users or groups in a NIS environment.
|
||||||
|
|
||||||
|
shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24
|
||||||
|
|
||||||
- general
|
- general
|
||||||
* Improved support for large groups (impacts most user/group management
|
* Improved support for large groups (impacts most user/group management
|
||||||
@@ -310,7 +511,7 @@ shadow-4.1.0 -> shadow-4.1.1 02-04-2008
|
|||||||
faillog faster.
|
faillog faster.
|
||||||
- gpasswd
|
- gpasswd
|
||||||
* Fix failures when the gshadow file is not present.
|
* Fix failures when the gshadow file is not present.
|
||||||
* When a password is moved to the gshadow file, use "x" instead of "x"
|
* When a password is moved to the gshadow file, use "x" instead of "!"
|
||||||
to indicate that the password is shadowed (consistency with grpconv).
|
to indicate that the password is shadowed (consistency with grpconv).
|
||||||
* Make sure the group and gshadow files are unlocked on exit.
|
* Make sure the group and gshadow files are unlocked on exit.
|
||||||
- groupadd
|
- groupadd
|
||||||
@@ -453,9 +654,9 @@ shadow-4.0.18.2 -> shadow-4.1.0 09-12-2007
|
|||||||
- Use MD5_CRYPT_ENAB, ENCRYPT_METHOD, SHA_CRYPT_MIN_ROUNDS, and
|
- Use MD5_CRYPT_ENAB, ENCRYPT_METHOD, SHA_CRYPT_MIN_ROUNDS, and
|
||||||
SHA_CRYPT_MAX_ROUNDS to define the default encryption algorithm for the
|
SHA_CRYPT_MAX_ROUNDS to define the default encryption algorithm for the
|
||||||
passwords.
|
passwords.
|
||||||
- chpaswd, chgpasswd, newusers: New options -c/--crypt-method and
|
- chpasswd, chgpasswd, newusers: New options -c/--crypt-method and
|
||||||
-s/--sha-rounds to supersede the system default encryption algorithm.
|
-s/--sha-rounds to supersede the system default encryption algorithm.
|
||||||
- chpaswd, chgpasswd, newusers: DES is no more the default algorithm. They
|
- chpasswd, chgpasswd, newusers: DES is no more the default algorithm. They
|
||||||
will respect the system default configured in /etc/login.defs
|
will respect the system default configured in /etc/login.defs
|
||||||
|
|
||||||
*** documentation:
|
*** documentation:
|
||||||
@@ -500,14 +701,14 @@ shadow-4.0.17 -> shadow-4.0.18 01-08-2006
|
|||||||
- groupadd, groupmod, useradd, usermod: fixed UID/GID overflow (fixed
|
- groupadd, groupmod, useradd, usermod: fixed UID/GID overflow (fixed
|
||||||
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=198920)
|
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=198920)
|
||||||
- passwd, useradd, usermod: fixed inactive/mindays/warndays/maxdays overflow
|
- passwd, useradd, usermod: fixed inactive/mindays/warndays/maxdays overflow
|
||||||
(simillar to RH#198920),
|
(similar to RH#198920),
|
||||||
- groupmems: rewrited for use PAM and getopt_long() and now it is enabled
|
- groupmems: rewritten for use PAM and getopt_long() and now it is enabled
|
||||||
for build and install (patch by George Kraft <gk4@swbell.net>),
|
for build and install (patch by George Kraft <gk4@swbell.net>),
|
||||||
- S/Key: removed assign getpass() to libshadow_getpass() on autoconf level
|
- S/Key: removed assign getpass() to libshadow_getpass() on autoconf level
|
||||||
(patch by Ulrich Mueller <ulm@kph.uni-mainz.de>; http://bugs.gentoo.org/139966),
|
(patch by Ulrich Mueller <ulm@kph.uni-mainz.de>; http://bugs.gentoo.org/139966),
|
||||||
- usermod: back to previous -a option semantics and clarify -a behavior
|
- usermod: back to previous -a option semantics and clarify -a behavior
|
||||||
on documentation level (by Greg Schafer <gschafer@zip.com.au>),
|
on documentation level (by Greg Schafer <gschafer@zip.com.au>),
|
||||||
- chsh, groupmod: rewrited for use getopt_long().
|
- chsh, groupmod: rewritten for use getopt_long().
|
||||||
- updated translations: ca, cs, da, eu, fr, gl, hu, ko, pl, pt, ru, sv, tr, uk, vi.
|
- updated translations: ca, cs, da, eu, fr, gl, hu, ko, pl, pt, ru, sv, tr, uk, vi.
|
||||||
*** documentation:
|
*** documentation:
|
||||||
- fr and ru man pages are up to date,
|
- fr and ru man pages are up to date,
|
||||||
@@ -542,7 +743,7 @@ shadow-4.0.15 -> shadow-4.0.16 05-06-2006
|
|||||||
|
|
||||||
*** general:
|
*** general:
|
||||||
- userdel: better fix for old CERT VU#312962 (which was fixed in shadow 4.0.8):
|
- userdel: better fix for old CERT VU#312962 (which was fixed in shadow 4.0.8):
|
||||||
fixed forgoten checking of the return value from fchown() before
|
fixed forgotten checking of the return value from fchown() before
|
||||||
proceeding with the fchmod() (based on Owl patch prepared by
|
proceeding with the fchmod() (based on Owl patch prepared by
|
||||||
Rafal Wojtczuk <nergal@owl.openwall.com>),
|
Rafal Wojtczuk <nergal@owl.openwall.com>),
|
||||||
- userdel: use login.defs::MAIL_DIR instead hardcoded /var/mail in created
|
- userdel: use login.defs::MAIL_DIR instead hardcoded /var/mail in created
|
||||||
@@ -554,7 +755,7 @@ shadow-4.0.15 -> shadow-4.0.16 05-06-2006
|
|||||||
passwords and libshadow_getpass() is used only because libc getpass()
|
passwords and libshadow_getpass() is used only because libc getpass()
|
||||||
do not handles password prompting with echo enabled,
|
do not handles password prompting with echo enabled,
|
||||||
- move login.defs::MD5_CRYPT_ENAB to non-PAM part,
|
- move login.defs::MD5_CRYPT_ENAB to non-PAM part,
|
||||||
- userdel: rewrited for use getopt_log(),
|
- userdel: rewritten for use getopt_log(),
|
||||||
- install default/template configuration files:
|
- install default/template configuration files:
|
||||||
-- if shadow is configured with use PAM install /etc/pam.d/* files,
|
-- if shadow is configured with use PAM install /etc/pam.d/* files,
|
||||||
-- if shadow do not uses PAM install /etc/{limits,login.acces} files,
|
-- if shadow do not uses PAM install /etc/{limits,login.acces} files,
|
||||||
@@ -592,7 +793,7 @@ shadow-4.0.15 -> shadow-4.0.16 05-06-2006
|
|||||||
- updated ru login.defs(5), passwd(1), userdel(8), usermod(8) man pages,
|
- updated ru login.defs(5), passwd(1), userdel(8), usermod(8) man pages,
|
||||||
- pw_auth(3) man page removed (outdated),
|
- pw_auth(3) man page removed (outdated),
|
||||||
- install limits(5), login.access(5) and porttime(5) man pages only when
|
- install limits(5), login.access(5) and porttime(5) man pages only when
|
||||||
shadow is builded with PAM support disabled,
|
shadow is built with PAM support disabled,
|
||||||
- passwd(1): better document how password strength is checked
|
- passwd(1): better document how password strength is checked
|
||||||
(fixed http://bugs.debian.org/115380),
|
(fixed http://bugs.debian.org/115380),
|
||||||
- usermod(8): added missing -a option description
|
- usermod(8): added missing -a option description
|
||||||
@@ -615,7 +816,7 @@ shadow-4.0.14 -> shadow-4.0.15 13-03-2006
|
|||||||
- login: default UMASK if not specified in login.defs is 022 (pointed by
|
- login: default UMASK if not specified in login.defs is 022 (pointed by
|
||||||
Peter Vrabec <pvrabec@redhat.com>),
|
Peter Vrabec <pvrabec@redhat.com>),
|
||||||
- chgpasswd: new tool (by Jonas Meurer <mejo@debian.org>),
|
- chgpasswd: new tool (by Jonas Meurer <mejo@debian.org>),
|
||||||
- lastlog: print the usage and exit if an additional argument is profided to
|
- lastlog: print the usage and exit if an additional argument is provided to
|
||||||
lastlog (merge 488_laslog_verify_arguments Debian patch),
|
lastlog (merge 488_laslog_verify_arguments Debian patch),
|
||||||
- login, newgrp, nologin, su: do not link with libselinux (merge
|
- login, newgrp, nologin, su: do not link with libselinux (merge
|
||||||
490_link_selinux_only_when_needed Debian patch),
|
490_link_selinux_only_when_needed Debian patch),
|
||||||
@@ -629,9 +830,9 @@ shadow-4.0.14 -> shadow-4.0.15 13-03-2006
|
|||||||
tries exceeded,
|
tries exceeded,
|
||||||
- always prints the number of tries in the syslog entry.
|
- always prints the number of tries in the syslog entry.
|
||||||
- add special handling for PAM_ABORT
|
- add special handling for PAM_ABORT
|
||||||
- add an entry to failog, as when USE_PAM is not defined. (#53164)
|
- add an entry to faillog, as when USE_PAM is not defined. (#53164)
|
||||||
- changed pam_end to PAM_END. This is certainly was a mistake. PAM_END is
|
- changed pam_end to PAM_END. This is certainly was a mistake. PAM_END is
|
||||||
pam_close_seesion + pam_end. Here, the session is still not open, we
|
pam_close_session + pam_end. Here, the session is still not open, we
|
||||||
don't have to close it.
|
don't have to close it.
|
||||||
- a HAVE_PAM_FAIL_DELAY is missing,
|
- a HAVE_PAM_FAIL_DELAY is missing,
|
||||||
- su: fixed pam session support (patch from Topi Miettinen; fixed #57526,
|
- su: fixed pam session support (patch from Topi Miettinen; fixed #57526,
|
||||||
@@ -639,7 +840,7 @@ shadow-4.0.14 -> shadow-4.0.15 13-03-2006
|
|||||||
- userdel: user's group is already removed by update_groups().
|
- userdel: user's group is already removed by update_groups().
|
||||||
remove_group() is not needed (bug introduced in 4.0.14 on merge FC fixes).
|
remove_group() is not needed (bug introduced in 4.0.14 on merge FC fixes).
|
||||||
Fixed by Nicolas François <nicolas.francois@centraliens.net>,
|
Fixed by Nicolas François <nicolas.francois@centraliens.net>,
|
||||||
- useradd: allways remove group and gshadow databases lock, Fixed by Nicolas
|
- useradd: always remove group and gshadow databases lock, Fixed by Nicolas
|
||||||
François <nicolas.francois@centraliens.net>
|
François <nicolas.francois@centraliens.net>
|
||||||
(http://bugs.debian.org/348250)
|
(http://bugs.debian.org/348250)
|
||||||
- auditing fixes:
|
- auditing fixes:
|
||||||
@@ -647,14 +848,14 @@ shadow-4.0.14 -> shadow-4.0.15 13-03-2006
|
|||||||
added audit_logger() prototype),
|
added audit_logger() prototype),
|
||||||
- useradd: fixed excess audit_logger() argument,
|
- useradd: fixed excess audit_logger() argument,
|
||||||
- chage: added missing \n on display password status if password must be
|
- chage: added missing \n on display password status if password must be
|
||||||
chaged,
|
changed,
|
||||||
- useradd: fixed allow non-unique UID (http://bugs.debian.org/351281),
|
- useradd: fixed allow non-unique UID (http://bugs.debian.org/351281),
|
||||||
- variouse code cleanups for make possible compilation of shadow with -Wall
|
- various code cleanups for make possible compilation of shadow with -Wall
|
||||||
-Werror (by Alexander Gattin <xrgtn@yandex.ru>),
|
-Werror (by Alexander Gattin <xrgtn@yandex.ru>),
|
||||||
- su: move exit() outside libmisc/shell.c::shell() for handle shell() errors
|
- su: move exit() outside libmisc/shell.c::shell() for handle shell() errors
|
||||||
on higher level (now is better visable where some programs exit with 126
|
on higher level (now is better visable where some programs exit with 126
|
||||||
and 127 exit codes); added new shell() parameter (char *const envp[])
|
and 127 exit codes); added new shell() parameter (char *const envp[])
|
||||||
which allow fix preserving enviloment in su on using -p, (patch by
|
which allow fix preserving enviroment in su on using -p, (patch by
|
||||||
Alexander Gattin <xrgtn@yandex.ru>),
|
Alexander Gattin <xrgtn@yandex.ru>),
|
||||||
- su: added handle -c,--command option for GNU su compliance (merge
|
- su: added handle -c,--command option for GNU su compliance (merge
|
||||||
437_su_-c_option Debian patch),
|
437_su_-c_option Debian patch),
|
||||||
@@ -702,7 +903,7 @@ shadow-4.0.13 -> shadow-4.0.14 03-01-2006
|
|||||||
- userdel: make the -f option force the removal of the user's group (even if it
|
- userdel: make the -f option force the removal of the user's group (even if it
|
||||||
is the primary group of another user)
|
is the primary group of another user)
|
||||||
(merge 453_userdel_-f_removes_group Debian patch),
|
(merge 453_userdel_-f_removes_group Debian patch),
|
||||||
- usermod: rewrited for use getopt_long() (Christian Perrier <bubulle@kheops.frmug.org>),
|
- usermod: rewritten for use getopt_long() (Christian Perrier <bubulle@kheops.frmug.org>),
|
||||||
- grpck: fixed segmentation fault on using -s when /etc/gshadow is empty (fix by
|
- grpck: fixed segmentation fault on using -s when /etc/gshadow is empty (fix by
|
||||||
Tomasz Lemiech <szpajder@staszic.waw.pl>),
|
Tomasz Lemiech <szpajder@staszic.waw.pl>),
|
||||||
- passwd: remove handle -f, -g and -s options.
|
- passwd: remove handle -f, -g and -s options.
|
||||||
@@ -711,7 +912,7 @@ shadow-4.0.13 -> shadow-4.0.14 03-01-2006
|
|||||||
Nicolas François <nicolas.francois@centraliens.net>)
|
Nicolas François <nicolas.francois@centraliens.net>)
|
||||||
- su: export $USER and $SHELL as well as $HOME (http://bugs.debian.org/11003 and
|
- su: export $USER and $SHELL as well as $HOME (http://bugs.debian.org/11003 and
|
||||||
http://bugs.debian.org/11189),
|
http://bugs.debian.org/11189),
|
||||||
- su, vipw: rewrited for use getopt_long(),
|
- su, vipw: rewritten for use getopt_long(),
|
||||||
- su: log successful/failed through syslog (http://bugs.debian.org/190215),
|
- su: log successful/failed through syslog (http://bugs.debian.org/190215),
|
||||||
- updated translations: ca, cs, da, eu, fi, fr, it, pl, pt, ru, sv, tl, vi,
|
- updated translations: ca, cs, da, eu, fi, fr, it, pl, pt, ru, sv, tl, vi,
|
||||||
- new translations: gl.
|
- new translations: gl.
|
||||||
@@ -745,7 +946,7 @@ shadow-4.0.12 -> shadow-4.0.13 10-10-2005
|
|||||||
|
|
||||||
*** general:
|
*** general:
|
||||||
- chage: removed duplicated pam_start(),
|
- chage: removed duplicated pam_start(),
|
||||||
- chfn, chsh: finished PAM support usin pam_start() and co.,
|
- chfn, chsh: finished PAM support using pam_start() and co.,
|
||||||
- userdel: userdel should not remove the group which is primary for someone else
|
- userdel: userdel should not remove the group which is primary for someone else
|
||||||
(fix by Nicolas François <nicolas.francois@centraliens.net>
|
(fix by Nicolas François <nicolas.francois@centraliens.net>
|
||||||
http://bugs.debian.org/295416),
|
http://bugs.debian.org/295416),
|
||||||
@@ -754,7 +955,7 @@ shadow-4.0.12 -> shadow-4.0.13 10-10-2005
|
|||||||
- fixedlib/commonio.c: don't assume selinux is enabled if is_selinux_enabled()
|
- fixedlib/commonio.c: don't assume selinux is enabled if is_selinux_enabled()
|
||||||
returns -1 (merge isSelinuxEnabled FC patch by Jeremy Katz <katzj@redhat.com>),
|
returns -1 (merge isSelinuxEnabled FC patch by Jeremy Katz <katzj@redhat.com>),
|
||||||
- login, su (non-PAM case): fixed setup max address space limits (added missing break
|
- login, su (non-PAM case): fixed setup max address space limits (added missing break
|
||||||
statement in case) spoted by Lasse Collin <lasse.collin@tukaani.org>,
|
statement in case) spotted by Lasse Collin <lasse.collin@tukaani.org>,
|
||||||
- auditing support added. Patch prepared by Peter Vrabec <pvrabec@redhat.com> basing
|
- auditing support added. Patch prepared by Peter Vrabec <pvrabec@redhat.com> basing
|
||||||
on work by Steve Grubb from http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=159215
|
on work by Steve Grubb from http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=159215
|
||||||
Now auditing support have commands: chage, gpasswd, groupadd, groupdel, groupmod,
|
Now auditing support have commands: chage, gpasswd, groupadd, groupdel, groupmod,
|
||||||
@@ -771,12 +972,12 @@ shadow-4.0.12 -> shadow-4.0.13 10-10-2005
|
|||||||
This will permit to adduser Debian script to detect if chage failed because the
|
This will permit to adduser Debian script to detect if chage failed because the
|
||||||
system doesn't have shadowed passwords (fix for http://bugs.debian.org/317012),
|
system doesn't have shadowed passwords (fix for http://bugs.debian.org/317012),
|
||||||
- merge 010_more-i18ned-messages Debian patch which adds i18n support for few
|
- merge 010_more-i18ned-messages Debian patch which adds i18n support for few
|
||||||
more messages (orginaly patch was prepared by Guillem Jover <guillem@debian.org>),
|
more messages (originally patch was prepared by Guillem Jover <guillem@debian.org>),
|
||||||
- lastlog: added handle -b option which allow print only lastlog records older than
|
- lastlog: added handle -b option which allow print only lastlog records older than
|
||||||
specified DAYS (fix by <miles@lubin.us>),
|
specified DAYS (fix by <miles@lubin.us>),
|
||||||
- chpasswd, gpasswd, newusers: fixed libmisc/salt.c for use login.defs::MD5_CRYPT_ENAB
|
- chpasswd, gpasswd, newusers: fixed libmisc/salt.c for use login.defs::MD5_CRYPT_ENAB
|
||||||
only if PAM support is disabled (fix by John Gatewood Ham <zappaman@buraphalinux.org>),
|
only if PAM support is disabled (fix by John Gatewood Ham <zappaman@buraphalinux.org>),
|
||||||
- passwd: rewrited for use getopt_long(),
|
- passwd: rewritten for use getopt_long(),
|
||||||
- newgrp: when newgrp process sits between parent and child shells, it should
|
- newgrp: when newgrp process sits between parent and child shells, it should
|
||||||
propagate STOPs from child to parent and CONTs from parent to child,
|
propagate STOPs from child to parent and CONTs from parent to child,
|
||||||
otherwise e.g. bash's "suspend" command won't work
|
otherwise e.g. bash's "suspend" command won't work
|
||||||
@@ -786,11 +987,11 @@ shadow-4.0.12 -> shadow-4.0.13 10-10-2005
|
|||||||
- chsh(1), groupadd(8), newusers(8), pwconv(8), useradd(8), userdel(8), usermod(8):
|
- chsh(1), groupadd(8), newusers(8), pwconv(8), useradd(8), userdel(8), usermod(8):
|
||||||
added missing references to /etc/login.defs and login.defs(5)
|
added missing references to /etc/login.defs and login.defs(5)
|
||||||
(Christian Perrier <bubulle@kheops.frmug.org>),
|
(Christian Perrier <bubulle@kheops.frmug.org>),
|
||||||
- passwd(5): rewrited based on work by Greg Wooledge <greg@wooledge.org>
|
- passwd(5): rewritten based on work by Greg Wooledge <greg@wooledge.org>
|
||||||
http://bugs.debian.org/328113
|
http://bugs.debian.org/328113
|
||||||
- login(1): added securetty(5) to SEE ALSO section
|
- login(1): added securetty(5) to SEE ALSO section
|
||||||
(fixed Debian bug http://bugs.debian.org/325773),
|
(fixed Debian bug http://bugs.debian.org/325773),
|
||||||
- groupadd(8), useradd(8): fix regular expression describing alloved login/group
|
- groupadd(8), useradd(8): fix regular expression describing allowed login/group
|
||||||
names (pointed by Nicolas François <nicolas.francois@centraliens.net>)
|
names (pointed by Nicolas François <nicolas.francois@centraliens.net>)
|
||||||
(correct is [a-z_][a-z0-9_-]*[$]),
|
(correct is [a-z_][a-z0-9_-]*[$]),
|
||||||
- groupadd(8), useradd(8): documents in CAVEATS section the limitations shadow
|
- groupadd(8), useradd(8): documents in CAVEATS section the limitations shadow
|
||||||
@@ -800,9 +1001,9 @@ shadow-4.0.12 -> shadow-4.0.13 10-10-2005
|
|||||||
shadow-4.0.11.1 -> shadow-4.0.12 22-08-2005
|
shadow-4.0.11.1 -> shadow-4.0.12 22-08-2005
|
||||||
|
|
||||||
*** general:
|
*** general:
|
||||||
- newgrp, login: remove using login.defs::CLOSE_SESSIONS variable and allways
|
- newgrp, login: remove using login.defs::CLOSE_SESSIONS variable and always
|
||||||
close PAM session,
|
close PAM session,
|
||||||
- fixed configure.in: realy enable shadow group support by default (pointed by
|
- fixed configure.in: really enable shadow group support by default (pointed by
|
||||||
Greg Schafer <gschafer@zip.com.au> and Peter Vrabec <pvrabec@redhat.com>),
|
Greg Schafer <gschafer@zip.com.au> and Peter Vrabec <pvrabec@redhat.com>),
|
||||||
- login.defs: removed handle QMAIL_DIR variable,
|
- login.defs: removed handle QMAIL_DIR variable,
|
||||||
- login: allow regular user to login on read-only root file system (not only for root)
|
- login: allow regular user to login on read-only root file system (not only for root)
|
||||||
@@ -827,9 +1028,9 @@ shadow-4.0.11.1 -> shadow-4.0.12 22-08-2005
|
|||||||
period and permit brute-force attacks (fixed http://bugs.debian.org/288827),
|
period and permit brute-force attacks (fixed http://bugs.debian.org/288827),
|
||||||
- uClibc fixes (by Martin Schlemmer <azarah@nosferatu.za.org>):
|
- uClibc fixes (by Martin Schlemmer <azarah@nosferatu.za.org>):
|
||||||
added require ngettext (added [need-ngettext] to AM_GNU_GETTEXT() parameters)
|
added require ngettext (added [need-ngettext] to AM_GNU_GETTEXT() parameters)
|
||||||
and stub prototype for ngettext() in lib/prototypes.h (neccessary if shadow
|
and stub prototype for ngettext() in lib/prototypes.h (necessary if shadow
|
||||||
compiled with disabled NLS support)
|
compiled with disabled NLS support)
|
||||||
- groupadd: rewrited for use getopt_long(),
|
- groupadd: rewritten for use getopt_long(),
|
||||||
- groupadd, groupdel, groupmod, userdel: do OPENLOG() before pam_start(),
|
- groupadd, groupdel, groupmod, userdel: do OPENLOG() before pam_start(),
|
||||||
- groupadd: fixed double OPENLOG(),
|
- groupadd: fixed double OPENLOG(),
|
||||||
- removed lib/{grpack,gspack,pwpack,sppack}.c and prototypes from lib/prototypes.h
|
- removed lib/{grpack,gspack,pwpack,sppack}.c and prototypes from lib/prototypes.h
|
||||||
@@ -865,7 +1066,7 @@ shadow-4.0.10 -> shadow-4.0.11 18-07-2005
|
|||||||
- su: ignore SIGINT while authenticating. A ^C could defeat the waiting period and
|
- su: ignore SIGINT while authenticating. A ^C could defeat the waiting period and
|
||||||
permit brute-force attacks. Also ignore SIGQUIT.
|
permit brute-force attacks. Also ignore SIGQUIT.
|
||||||
Fixed: http://bugs.debian.org/52372 and http://bugs.debian.org/288827
|
Fixed: http://bugs.debian.org/52372 and http://bugs.debian.org/288827
|
||||||
- useradd: rewrited for use getopt_long(),
|
- useradd: rewritten for use getopt_long(),
|
||||||
- newgrp: add fix for handle splitted NIS groups: extends the functionality that,
|
- newgrp: add fix for handle splitted NIS groups: extends the functionality that,
|
||||||
if the requested group is given, all groups of the same GID are tested for
|
if the requested group is given, all groups of the same GID are tested for
|
||||||
membership of the requesting user.
|
membership of the requesting user.
|
||||||
@@ -896,7 +1097,7 @@ shadow-4.0.10 -> shadow-4.0.11 18-07-2005
|
|||||||
- updated translations: cs, da, de, es, fi, pl, pt, ro, ru, sk.
|
- updated translations: cs, da, de, es, fi, pl, pt, ro, ru, sk.
|
||||||
*** documentation:
|
*** documentation:
|
||||||
- pwck(8): document -q option (based on Debian patch for fix http://bugs.debian.org/309408)
|
- pwck(8): document -q option (based on Debian patch for fix http://bugs.debian.org/309408)
|
||||||
- pwck(8): rewrited OPTIONS section and better SYNOPSIS,
|
- pwck(8): rewritten OPTIONS section and better SYNOPSIS,
|
||||||
- lastlog(8): document that lastlog is a sparse file, and don't need to be rotated
|
- lastlog(8): document that lastlog is a sparse file, and don't need to be rotated
|
||||||
http://bugs.debian.org/219321
|
http://bugs.debian.org/219321
|
||||||
- login(8): better explain the respective roles of login, init and getty with regards
|
- login(8): better explain the respective roles of login, init and getty with regards
|
||||||
@@ -910,12 +1111,12 @@ shadow-4.0.9 -> shadow-4.0.10 28-06-2005
|
|||||||
|
|
||||||
*** general:
|
*** general:
|
||||||
- mkpasswd: removed,
|
- mkpasswd: removed,
|
||||||
- userdel: now deletes user groups from /etc/gshdow as well as /etc/group.
|
- userdel: now deletes user groups from /etc/gshadow as well as /etc/group.
|
||||||
Fix by Nicolas François <nicolas.francois@centraliens.net>.
|
Fix by Nicolas François <nicolas.francois@centraliens.net>.
|
||||||
http://bugs.debian.org/99442
|
http://bugs.debian.org/99442
|
||||||
- usermod: when relocating a user's home directory, don't fail and remove the new
|
- usermod: when relocating a user's home directory, don't fail and remove the new
|
||||||
home directory if we can't remove the old home directory for some
|
home directory if we can't remove the old home directory for some
|
||||||
reason; the results can be spectularly poort if, for instance, only
|
reason; the results can be spectacularly poor if, for instance, only
|
||||||
the rmdir() fails. Patch prepared by Timo Lindfors <lindi-spamtrap@newmail.com>.
|
the rmdir() fails. Patch prepared by Timo Lindfors <lindi-spamtrap@newmail.com>.
|
||||||
http://bugs.debian.org/166369
|
http://bugs.debian.org/166369
|
||||||
- su: fix syslogs to be less ambiguous. Use old:new format instead of old-new
|
- su: fix syslogs to be less ambiguous. Use old:new format instead of old-new
|
||||||
@@ -923,7 +1124,7 @@ shadow-4.0.9 -> shadow-4.0.10 28-06-2005
|
|||||||
http://bugs.debian.org/213592
|
http://bugs.debian.org/213592
|
||||||
- removed not used now libmisc/setup.c,
|
- removed not used now libmisc/setup.c,
|
||||||
- login: use also UTMPX API instead UTMP on failure (login was affected for this
|
- login: use also UTMPX API instead UTMP on failure (login was affected for this
|
||||||
when shadow was builded without PAM support)
|
when shadow was built without PAM support)
|
||||||
patch by Nicolas François <nicolas.francois@centraliens.net>
|
patch by Nicolas François <nicolas.francois@centraliens.net>
|
||||||
- login: the PAM session needs to be closed as root, thus before change_uid()
|
- login: the PAM session needs to be closed as root, thus before change_uid()
|
||||||
http://bugs.debian.org/53570 http://bugs.debian.org/195048 http://bugs.debian.org/211884
|
http://bugs.debian.org/53570 http://bugs.debian.org/195048 http://bugs.debian.org/211884
|
||||||
@@ -934,12 +1135,12 @@ shadow-4.0.9 -> shadow-4.0.10 28-06-2005
|
|||||||
http://bugs.debian.org/48002
|
http://bugs.debian.org/48002
|
||||||
- login: fixed username on succesful login (was using the normal username,
|
- login: fixed username on succesful login (was using the normal username,
|
||||||
when it should have used pam_user) http://bugs.debian.org/47819
|
when it should have used pam_user) http://bugs.debian.org/47819
|
||||||
- remove using SHADOWPWD #define so now shadow is allways builded with shadow
|
- remove using SHADOWPWD #define so now shadow is always built with shadow
|
||||||
passwowd support,
|
password support,
|
||||||
- chage: rewrited for use getopt_long(),
|
- chage: rewritten for use getopt_long(),
|
||||||
- updated translations: ca, cs, da, fi, pl, ru, zh_TW.
|
- updated translations: ca, cs, da, fi, pl, ru, zh_TW.
|
||||||
*** documentation:
|
*** documentation:
|
||||||
- most of the man pages now are generated from XML files so in case submiting any
|
- most of the man pages now are generated from XML files so in case submitting any
|
||||||
chages to this resources please make diff to XML files,
|
chages to this resources please make diff to XML files,
|
||||||
- chfn: give more details about the influence of login.defs on what's allowed to
|
- chfn: give more details about the influence of login.defs on what's allowed to
|
||||||
users.
|
users.
|
||||||
@@ -947,7 +1148,7 @@ shadow-4.0.9 -> shadow-4.0.10 28-06-2005
|
|||||||
shadow-4.0.8 -> shadow-4.0.9 23-05-2005
|
shadow-4.0.8 -> shadow-4.0.9 23-05-2005
|
||||||
|
|
||||||
*** general:
|
*** general:
|
||||||
- passwd: fixed segfault in non-PAM connfiguration
|
- passwd: fixed segfault in non-PAM configuration
|
||||||
(submited by Greg Schafer <gschafer@zip.com.au>),
|
(submited by Greg Schafer <gschafer@zip.com.au>),
|
||||||
- newgrp: fixed NULL pointer dereference - getlogin() and ttyname() can
|
- newgrp: fixed NULL pointer dereference - getlogin() and ttyname() can
|
||||||
return NULL which is not checked (http://bugs.debian.org/162303),
|
return NULL which is not checked (http://bugs.debian.org/162303),
|
||||||
@@ -969,15 +1170,15 @@ shadow-4.0.7 -> shadow-4.0.8 26-04-2005
|
|||||||
- configure.in: add using AC_GNU_SOURCE macro for kill compilation warnings about
|
- configure.in: add using AC_GNU_SOURCE macro for kill compilation warnings about
|
||||||
implicit declaration of function `fseeko',
|
implicit declaration of function `fseeko',
|
||||||
- faillog: changed faillog record display format for allow fit in 80 columns all
|
- faillog: changed faillog record display format for allow fit in 80 columns all
|
||||||
faillog atributies,
|
faillog attributes,
|
||||||
- removed NDBM code (unused),
|
- removed NDBM code (unused),
|
||||||
- fixed use of SU_WHEEL_ONLY in su. Now su realy is avalaible for wheel group
|
- fixed use of SU_WHEEL_ONLY in su. Now su really is available for wheel group
|
||||||
members. Thanks to Mike Frysinger <vapier@gentoo.org> for report:
|
members. Thanks to Mike Frysinger <vapier@gentoo.org> for report:
|
||||||
http://bugs.gentoo.org/show_bug.cgi?id=80345
|
http://bugs.gentoo.org/show_bug.cgi?id=80345
|
||||||
- drop never finished kerberos and des_rpc support (for kerberos support back firs
|
- drop never finished kerberos and des_rpc support (for kerberos support back firs
|
||||||
must be prepared modularization),
|
must be prepared modularization),
|
||||||
- fixed UTMP path detection (by Kelledin <kelledin@users.sf.net>),
|
- fixed UTMP path detection (by Kelledin <kelledin@users.sf.net>),
|
||||||
- useradd: rewrited group count to dynamic (by John Newbigin
|
- useradd: rewritten group count to dynamic (by John Newbigin
|
||||||
<jnewbigin@ict.swin.edu.au>),
|
<jnewbigin@ict.swin.edu.au>),
|
||||||
- login: fixed create lastlog entry fo users never loged in on non-PAM
|
- login: fixed create lastlog entry fo users never loged in on non-PAM
|
||||||
variant of login (fix by <oracular@ziplip.com>),
|
variant of login (fix by <oracular@ziplip.com>),
|
||||||
@@ -992,7 +1193,7 @@ shadow-4.0.7 -> shadow-4.0.8 26-04-2005
|
|||||||
fchmod() is executed. (Actually, we could also pass the final "mode" to
|
fchmod() is executed. (Actually, we could also pass the final "mode" to
|
||||||
the open() call and then save the consequent fchmod().)
|
the open() call and then save the consequent fchmod().)
|
||||||
- SELinux changes: added changes in chage, chfn, chsh, passwd for allow
|
- SELinux changes: added changes in chage, chfn, chsh, passwd for allow
|
||||||
construct more grained user password/accuunt properties on SELinux
|
construct more grained user password/account properties on SELinux
|
||||||
policies level. Patch originally based on RH changes (submited by Chris
|
policies level. Patch originally based on RH changes (submited by Chris
|
||||||
PeBenito <pebenito@gentoo.org>),
|
PeBenito <pebenito@gentoo.org>),
|
||||||
- added SELinux changes: in libmisc/copydir.c (based on Fedora patch),
|
- added SELinux changes: in libmisc/copydir.c (based on Fedora patch),
|
||||||
@@ -1010,7 +1211,7 @@ shadow-4.0.7 -> shadow-4.0.8 26-04-2005
|
|||||||
- newgrp(1): fix #251926, #166173, #113191 Debian bugs: explain why editing /etc/group
|
- newgrp(1): fix #251926, #166173, #113191 Debian bugs: explain why editing /etc/group
|
||||||
(without gshadow) doesn't permit to use newgrp,
|
(without gshadow) doesn't permit to use newgrp,
|
||||||
- newgrp(1): newgrp uses /bin/sh (not bash),
|
- newgrp(1): newgrp uses /bin/sh (not bash),
|
||||||
- faillog(8): updated after rewrited faillog command for use getopt_long(),
|
- faillog(8): updated after rewritten faillog command for use getopt_long(),
|
||||||
- login(1): removed fragment about abilities pass enviroment variables in login prompt,
|
- login(1): removed fragment about abilities pass enviroment variables in login prompt,
|
||||||
- gshadow(5): new file (by Nicolas Nicolas François <nicolas.francois@centraliens.net>),
|
- gshadow(5): new file (by Nicolas Nicolas François <nicolas.francois@centraliens.net>),
|
||||||
- usermod(8): fixed #302388 Debian bug: added separated -o option description,
|
- usermod(8): fixed #302388 Debian bug: added separated -o option description,
|
||||||
@@ -1028,24 +1229,24 @@ shadow-4.0.6 -> shadow-4.0.7 26-01-2005
|
|||||||
-- use fseeko() instead fseek() and remove casting file offsets to unsigned
|
-- use fseeko() instead fseek() and remove casting file offsets to unsigned
|
||||||
long.
|
long.
|
||||||
- lastlog:
|
- lastlog:
|
||||||
-- rewrited source code using the same style as in chpasswd.c,
|
-- rewritten source code using the same style as in chpasswd.c,
|
||||||
-- open lastlog file after finish parse comman line optiomns
|
-- open lastlog file after finish parse commandline options
|
||||||
(now --help otput can be displayd for users without lastlog
|
(now --help output can be displayed for users without lastlog
|
||||||
file read permission),
|
file read permission),
|
||||||
-- cleanups in lastlog(8) man page using the same style as in
|
-- cleanups in lastlog(8) man page using the same style as in
|
||||||
chpasswd(8).
|
chpasswd(8).
|
||||||
- chpasswd:
|
- chpasswd:
|
||||||
-- switch chpasswd to use getopt_long() and adds a --md5 option
|
-- switch chpasswd to use getopt_long() and adds a --md5 option
|
||||||
(by Ian Gulliver <ian@penguinhosting.net>),
|
(by Ian Gulliver <ian@penguinhosting.net>),
|
||||||
-- rewrited chpasswd(8) man page.
|
-- rewritten chpasswd(8) man page.
|
||||||
|
|
||||||
shadow-4.0.5 -> shadow-4.0.6 08-11-2004
|
shadow-4.0.5 -> shadow-4.0.6 08-11-2004
|
||||||
|
|
||||||
- su: fixed adding of pam_env env variables to enviroment
|
- su: fixed adding of pam_env env variables to enviroment
|
||||||
(Martin Schlemmer <azarah@nosferatu.za.org>),
|
(Martin Schlemmer <azarah@nosferatu.za.org>),
|
||||||
- autoconf: fixed filling MAIL_SPOOL_DIR and MAIL_SPOOL_FILE variables
|
- autoconf: fixed filling MAIL_SPOOL_DIR and MAIL_SPOOL_FILE variables
|
||||||
which was allways empty (Gregorio Guidi <g.guidi@sns.it>),
|
which was always empty (Gregorio Guidi <g.guidi@sns.it>),
|
||||||
- realuy closse security bug in libmisc/pwdcheck.c,
|
- really close security bug in libmisc/pwdcheck.c,
|
||||||
- added missing template/example PAM service config files for chfn, chsh and
|
- added missing template/example PAM service config files for chfn, chsh and
|
||||||
userdel,
|
userdel,
|
||||||
- do not translate variable names from /etc/default/useradd during
|
- do not translate variable names from /etc/default/useradd during
|
||||||
@@ -1056,10 +1257,10 @@ shadow-4.0.4.1 -> shadow-4.0.5 27-10-2004
|
|||||||
- change libmisc to private static library,
|
- change libmisc to private static library,
|
||||||
- added SELinux support (basing on patch from Gentoo),
|
- added SELinux support (basing on patch from Gentoo),
|
||||||
- chage: more verbose/human readable -l output. This output is much more
|
- chage: more verbose/human readable -l output. This output is much more
|
||||||
beter for send directly via email for each users as message with account
|
better for send directly via email for each users as message with account
|
||||||
status (for example as message with warning about account/password expiration),
|
status (for example as message with warning about account/password expiration),
|
||||||
- login: fixed handle -f option: now it works correctly without specify "-h
|
- login: fixed handle -f option: now it works correctly without specify "-h
|
||||||
<host>" if open login session localy is required (thanks for help
|
<host>" if open login session locally is required (thanks for help
|
||||||
investigate bug for Krzysztof Kotlenga),
|
investigate bug for Krzysztof Kotlenga),
|
||||||
- userdel: when removing a user with userdel, userdel was always exits with 1 (fixed).
|
- userdel: when removing a user with userdel, userdel was always exits with 1 (fixed).
|
||||||
Based on http://bugs.gentoo.org/show_bug.cgi?id=66687,
|
Based on http://bugs.gentoo.org/show_bug.cgi?id=66687,
|
||||||
@@ -1073,7 +1274,7 @@ shadow-4.0.4.1 -> shadow-4.0.5 27-10-2004
|
|||||||
makes httpd Option SymlinkIfOwnerMatch break for default weg pages
|
makes httpd Option SymlinkIfOwnerMatch break for default weg pages
|
||||||
including symlinks placed into /etc/skel/public_html for example.
|
including symlinks placed into /etc/skel/public_html for example.
|
||||||
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=66819
|
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=66819
|
||||||
- su: add pam_open_session() support. If builded without PAM support
|
- su: add pam_open_session() support. If built without PAM support
|
||||||
propagate $DISPLAY and $XAUTHORITY enviroment variables.
|
propagate $DISPLAY and $XAUTHORITY enviroment variables.
|
||||||
Based on http://www.gentoo.org/cgi-bin/viewcvs.cgi/sys-apps/shadow/files/shadow-4.0.4.1-su-pam_open_session.patch?rev=1.1
|
Based on http://www.gentoo.org/cgi-bin/viewcvs.cgi/sys-apps/shadow/files/shadow-4.0.4.1-su-pam_open_session.patch?rev=1.1
|
||||||
- applied 036_pam_access_with_preauth.patch Debian patch submited by Bjorn
|
- applied 036_pam_access_with_preauth.patch Debian patch submited by Bjorn
|
||||||
@@ -1086,11 +1287,11 @@ shadow-4.0.4.1 -> shadow-4.0.5 27-10-2004
|
|||||||
Use constant strings rather than argv[0] for syslog ident in the user
|
Use constant strings rather than argv[0] for syslog ident in the user
|
||||||
management commands,
|
management commands,
|
||||||
shadow-4.0.4.1-owl-tmp.diff:
|
shadow-4.0.4.1-owl-tmp.diff:
|
||||||
Remove using mktemp() if mkstemp() prototype not found (use allways mkstemp()),
|
Remove using mktemp() if mkstemp() prototype not found (use always mkstemp()),
|
||||||
shadow-4.0.4.1-owl-check-reads.diff:
|
shadow-4.0.4.1-owl-check-reads.diff:
|
||||||
Add checking for read errors in commonio and vipw/vigr (not doing so could
|
Add checking for read errors in commonio and vipw/vigr (not doing so could
|
||||||
result in data loss when the records are written back),
|
result in data loss when the records are written back),
|
||||||
- fixed securirty bug in libmisc/pwdcheck.c which allow unauthorized
|
- fixed security bug in libmisc/pwdcheck.c which allow unauthorized
|
||||||
account properties modification.
|
account properties modification.
|
||||||
Affected tools: chfn and chsh.
|
Affected tools: chfn and chsh.
|
||||||
Bug was discovered by Martin Schulze <joey@infodrom.org>.
|
Bug was discovered by Martin Schulze <joey@infodrom.org>.
|
||||||
@@ -1106,12 +1307,12 @@ shadow-4.0.4.1 -> shadow-4.0.5 27-10-2004
|
|||||||
|
|
||||||
shadow-4.0.4 => shadow-4.0.4.1 14-01-2004
|
shadow-4.0.4 => shadow-4.0.4.1 14-01-2004
|
||||||
- bug fixes in automake files for generate correct tar ball on "make dist":
|
- bug fixes in automake files for generate correct tar ball on "make dist":
|
||||||
added mising "EXTRA_DIST = $(man_MANS)" in man/*/Makefile.am.
|
added missing "EXTRA_DIST = $(man_MANS)" in man/*/Makefile.am.
|
||||||
|
|
||||||
shadow-4.0.3 => shadow-4.0.4 14-01-2004
|
shadow-4.0.3 => shadow-4.0.4 14-01-2004
|
||||||
|
|
||||||
*** general:
|
*** general:
|
||||||
- added missing information about -f options in groupadd usage mesage
|
- added missing information about -f options in groupadd usage message
|
||||||
(document this also in man page),
|
(document this also in man page),
|
||||||
- removed TCFS support (tcfs is dead),
|
- removed TCFS support (tcfs is dead),
|
||||||
- convert all po/*.po files to utf-8,
|
- convert all po/*.po files to utf-8,
|
||||||
@@ -1119,7 +1320,7 @@ shadow-4.0.3 => shadow-4.0.4 14-01-2004
|
|||||||
per service flushing method instead HUPing nscd process),
|
per service flushing method instead HUPing nscd process),
|
||||||
- removed old AUTH_METHODS dependent code,
|
- removed old AUTH_METHODS dependent code,
|
||||||
- chage: now all code depend on SHADOWPWD. If shadow will not be configured
|
- chage: now all code depend on SHADOWPWD. If shadow will not be configured
|
||||||
on autoconf level for using shadow possword chage is olny stub which
|
on autoconf level for using shadow password chage is olny stub which
|
||||||
informs "chage not configured for shadow password support."
|
informs "chage not configured for shadow password support."
|
||||||
- dpasswd: removed,
|
- dpasswd: removed,
|
||||||
- login: remove handle login.defs::DIALUPS_CHECK_ENAB code,
|
- login: remove handle login.defs::DIALUPS_CHECK_ENAB code,
|
||||||
@@ -1127,7 +1328,7 @@ shadow-4.0.3 => shadow-4.0.4 14-01-2004
|
|||||||
- ALL tools, libraries: remove old SVR4, SVR4_SI86_EUA BSD_QUOTA and ATT_AGE
|
- ALL tools, libraries: remove old SVR4, SVR4_SI86_EUA BSD_QUOTA and ATT_AGE
|
||||||
dependent code,
|
dependent code,
|
||||||
- ALL: ready for gettext 0.11.5, automake 1.7.4, autoconf 2.57,
|
- ALL: ready for gettext 0.11.5, automake 1.7.4, autoconf 2.57,
|
||||||
- logoutd, userd: handle also utmpx if avalaile,
|
- logoutd, userd: handle also utmpx if available,
|
||||||
- newgrp: fix for non-PAM version
|
- newgrp: fix for non-PAM version
|
||||||
Use CLOSE_SESSIONS depending code only when USE_PAM.
|
Use CLOSE_SESSIONS depending code only when USE_PAM.
|
||||||
The problem was reported by Mattias Webjorn Eriksson using Slackware
|
The problem was reported by Mattias Webjorn Eriksson using Slackware
|
||||||
@@ -1155,7 +1356,7 @@ shadow-4.0.3 => shadow-4.0.4 14-01-2004
|
|||||||
|
|
||||||
shadow-4.0.2 => shadow-4.0.3 13-03-2002
|
shadow-4.0.2 => shadow-4.0.3 13-03-2002
|
||||||
|
|
||||||
- added variouse cs, de, fr, id, it, ko man pages found mainly in national
|
- added various cs, de, fr, id, it, ko man pages found mainly in national
|
||||||
man pages translations projects (this documents are not synced with
|
man pages translations projects (this documents are not synced with
|
||||||
current en version but you know .. "Documentations is lik sex. When it is
|
current en version but you know .. "Documentations is lik sex. When it is
|
||||||
good it very very good. Whet it is bad it is better than nothing."). Any
|
good it very very good. Whet it is bad it is better than nothing."). Any
|
||||||
@@ -1171,9 +1372,9 @@ shadow-4.0.2 => shadow-4.0.3 13-03-2002
|
|||||||
shadow-4.0.1 => shadow-4.0.2 17-02-2002
|
shadow-4.0.1 => shadow-4.0.2 17-02-2002
|
||||||
|
|
||||||
- resolve many fuzzy translations also all this which may cause problems on
|
- resolve many fuzzy translations also all this which may cause problems on
|
||||||
displaing long uid/gid,
|
displaying long uid/gid,
|
||||||
- allow use "$" on ending in cereated by useradd usermname accounts for allow
|
- allow use "$" on ending in created by useradd username accounts for allow
|
||||||
create machine acounts for samba (thanks to Jerome Borsboom
|
create machine accounts for samba (thanks to Jerome Borsboom
|
||||||
<borsboom@tch.fgg.eur.nl> for point this problem in 4.0.1),
|
<borsboom@tch.fgg.eur.nl> for point this problem in 4.0.1),
|
||||||
- fix small but ugly bug in configure.in in libpam_mics library detection.
|
- fix small but ugly bug in configure.in in libpam_mics library detection.
|
||||||
|
|
||||||
@@ -1193,7 +1394,7 @@ shadow-4.0.0 => shadow-4.0.1
|
|||||||
as root. If root does read-only, there's no lock needed. Added missing
|
as root. If root does read-only, there's no lock needed. Added missing
|
||||||
"#include <errno.h>" for above (me).
|
"#include <errno.h>" for above (me).
|
||||||
shadow-4.0.0-owl-warnings.diff
|
shadow-4.0.0-owl-warnings.diff
|
||||||
Olny one fix from this patch was aplayd because other was fixed few days
|
Olny one fix from this patch was applied because other was fixed few days
|
||||||
before :)
|
before :)
|
||||||
shadow-4.0.0-owl-check_names.diff
|
shadow-4.0.0-owl-check_names.diff
|
||||||
Merge only prat this patch with checking login name matching; checking
|
Merge only prat this patch with checking login name matching; checking
|
||||||
@@ -1201,7 +1402,7 @@ shadow-4.0.0 => shadow-4.0.1
|
|||||||
probably _POSIX_LOGIN_NAME_MAX from <bits/posix1_lim.h>,
|
probably _POSIX_LOGIN_NAME_MAX from <bits/posix1_lim.h>,
|
||||||
shadow-4.0.0-owl-chage-drop-priv.diff
|
shadow-4.0.0-owl-chage-drop-priv.diff
|
||||||
shadow-4.0.0-owl-pam-auth.diff
|
shadow-4.0.0-owl-pam-auth.diff
|
||||||
Merge part with reorder initialize PAM and checkin is chage is runed by
|
Merge part with reorder initialize PAM and checking if chage is runed by
|
||||||
root or not - now chage can be runed from non-root account for checking
|
root or not - now chage can be runed from non-root account for checking
|
||||||
by user own account information (if PAM enabled).
|
by user own account information (if PAM enabled).
|
||||||
- fixes for handle/print correctly 32bit uid/gid (Thorsten Kukuk <kukuk@suse.de>),
|
- fixes for handle/print correctly 32bit uid/gid (Thorsten Kukuk <kukuk@suse.de>),
|
||||||
@@ -1245,30 +1446,30 @@ shadow-20001016 => shadow-4.0.0 06-01-2002
|
|||||||
- much better automake support,
|
- much better automake support,
|
||||||
- added pt_BR man pages for gpasswd(1), groupadd(8), groupdel(8),
|
- added pt_BR man pages for gpasswd(1), groupadd(8), groupdel(8),
|
||||||
groupmod(8), shadow(5) (man pages for other nations also are welcome),
|
groupmod(8), shadow(5) (man pages for other nations also are welcome),
|
||||||
- mamny small fixes and updates nad improvements in man pages,
|
- many small fixes and updates nad improvements in man pages,
|
||||||
- aplayed Debian patch to man pages for shadowconfig,
|
- applied Debian patch to man pages for shadowconfig,
|
||||||
- remove limit to 6 chars logged tty name (012_libmisc_sulog.c.diff Debian
|
- remove limit to 6 chars logged tty name (012_libmisc_sulog.c.diff Debian
|
||||||
patch).
|
patch).
|
||||||
|
|
||||||
shadow-20001012 -> shadow-20001016:
|
shadow-20001012 -> shadow-20001016:
|
||||||
- conditionaly disabled body reload_nscd() because not every
|
- conditionally disabled body reload_nscd() because not every
|
||||||
version of nscd can handle it (this can be enabled by define
|
version of nscd can handle it (this can be enabled by define
|
||||||
ENABLE_NSCD_SIGHUP) (Marek Michałkiewicz <marekm@linux.org.pl>)
|
ENABLE_NSCD_SIGHUP) (Marek Michałkiewicz <marekm@linux.org.pl>)
|
||||||
- fixes on autoconf/automake level for dist target,
|
- fixes on autoconf/automake level for dist target,
|
||||||
- Julianne F. Haugh new contact adress.
|
- Julianne F. Haugh new contact address.
|
||||||
|
|
||||||
shadow-20000902 => shadow-20001012
|
shadow-20000902 => shadow-20001012
|
||||||
|
|
||||||
- removed /redhat directory with obsoleted files (partialy rewrited spec
|
- removed /redhat directory with obsoleted files (partially rewritten spec
|
||||||
file is now in root directory),
|
file is now in root directory),
|
||||||
- aplayed shadow-19990827-group.patch patch from RH wich prevents adduser
|
- applied shadow-19990827-group.patch patch from RH wich prevents adduser
|
||||||
overwrite previously existing groups in adduser,
|
overwrite previously existing groups in adduser,
|
||||||
- added PAM support for chage (bind to "chage" PAM config file) also
|
- added PAM support for chage (bind to "chage" PAM config file) also
|
||||||
added PAM support for all other small tools like chpasswd, groupadd,
|
added PAM support for all other small tools like chpasswd, groupadd,
|
||||||
groupdel, groupmod, newusers, useradd, userdel, usermod (bind to common
|
groupdel, groupmod, newusers, useradd, userdel, usermod (bind to common
|
||||||
"shadow" PAM config file) - this modificaytions mainly based on
|
"shadow" PAM config file) - this modifications mainly based on
|
||||||
modifications prepared by Janek Rękojarski <baggins@pld.org.pl>,
|
modifications prepared by Janek Rękojarski <baggins@pld.org.pl>,
|
||||||
- many small fixes and improvments in automake (mow "make dist"
|
- many small fixes and improvements in automake (mow "make dist"
|
||||||
works correctly),
|
works correctly),
|
||||||
- added cs translation (Jiri Pavlovsky <Jiri.Pavlovsky@ff.cuni.cz>).
|
- added cs translation (Jiri Pavlovsky <Jiri.Pavlovsky@ff.cuni.cz>).
|
||||||
|
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
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/upstream
|
|
||||||
|
|
||||||
SVN web interface
|
|
||||||
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
|
|
||||||
commit list: pkg-shadow-commits@lists.alioth.debian.org
|
|
||||||
|
|
||||||
Mailing lists subscription
|
|
||||||
http://lists.alioth.debian.org/mailman/listinfo/pkg-shadow-devel
|
|
||||||
http://lists.alioth.debian.org/mailman/listinfo/pkg-shadow-commits
|
|
||||||
|
|
||||||
Mailing lists archives:
|
|
||||||
http://lists.alioth.debian.org/pipermail/pkg-shadow-devel/
|
|
||||||
http://lists.alioth.debian.org/pipermail/pkg-shadow-commits/
|
|
||||||
|
|
||||||
S/Key support:
|
|
||||||
Shadow can be built with S/Key support using the S/Key package from:
|
|
||||||
|
|
||||||
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libskey/
|
|
||||||
or
|
|
||||||
http://gentoo.osuosl.org/distfiles/skey-1.1.5.tar.bz2
|
|
||||||
|
|
||||||
Authors and contributors
|
|
||||||
========================
|
|
||||||
|
|
||||||
Thanks to at least the following people for sending me patches, bug
|
|
||||||
reports and various comments. This list may be incomplete, I received
|
|
||||||
a lot of mail...
|
|
||||||
|
|
||||||
|
|
||||||
Adam Rudnicki <adam@v-lo.krakow.pl>
|
|
||||||
Alan Curry <pacman@tardis.mars.net>
|
|
||||||
Alexander O. Yuriev <alex@bach.cis.temple.edu>
|
|
||||||
Algis Rudys <arudys@rice.edu>
|
|
||||||
Andreas Jaeger <aj@arthur.rhein-neckar.de>
|
|
||||||
Aniello Del Sorbo <anidel@edu-gw.dia.unisa.it>
|
|
||||||
Anton Gluck <gluc@midway.uchicago.edu>
|
|
||||||
Arkadiusz Miskiewicz <misiek@pld.org.pl>
|
|
||||||
Ben Collins <bcollins@debian.org>
|
|
||||||
Brian R. Gaeke <brg@dgate.org>
|
|
||||||
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>
|
|
||||||
David Frey <David.Frey@lugs.ch>
|
|
||||||
Ed Carp <ecarp@netcom.com>
|
|
||||||
Floody <flood@evcom.net>
|
|
||||||
Frank Denis <j@4u.net>
|
|
||||||
George Kraft IV <gk4@us.ibm.com>
|
|
||||||
Greg Mortensen <loki@world.std.com>
|
|
||||||
Guido van Rooij
|
|
||||||
Guy Maor <maor@debian.org>
|
|
||||||
Hrvoje Dogan <hdogan@bjesomar.srce.hr>
|
|
||||||
Janos Farkas <chexum@bankinf.banki.hu>
|
|
||||||
Jay Soffian <jay@lw.net>
|
|
||||||
Jesse Thilo <Jesse.Thilo@pobox.com>
|
|
||||||
Joey Hess <joey@kite.ml.org>
|
|
||||||
John Adelsberger <jja@umr.edu>
|
|
||||||
Jonathan Hankins <jhankins@mailserv.homewood.k12.al.us>
|
|
||||||
Jon Lewis <jlewis@lewis.org>
|
|
||||||
Joshua Cowan <jcowan@hermit.reslife.okstate.edu>
|
|
||||||
Judd Bourgeois <shagboy@bluesky.net>
|
|
||||||
Juergen Heinzl <unicorn@noris.net>
|
|
||||||
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>
|
|
||||||
Pavel Machek <pavel@bug.ucw.cz>
|
|
||||||
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>
|
|
||||||
Tim Hockin <thockin@eagle.ais.net>
|
|
||||||
Timo Karjalainen <timok@iki.fi>
|
|
||||||
Ulisses Alonso Camaro <ulisses@pusa.eleinf.uv.es>
|
|
||||||
Werner Fink <werner@suse.de>
|
|
||||||
|
|
||||||
Maintainers
|
|
||||||
===========
|
|
||||||
|
|
||||||
Tomasz Kłoczko <kloczek@pld.org.pl> (2000-2007)
|
|
||||||
Nicolas François <nicolas.francois@centraliens.net> (2007-now)
|
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# shadow-utils
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The shadow-utils package includes the necessary programs for
|
||||||
|
converting UNIX password files to the shadow password format, plus
|
||||||
|
programs for managing user and group accounts. The pwconv command
|
||||||
|
converts passwords to the shadow password format. The pwunconv command
|
||||||
|
unconverts shadow passwords and generates a passwd file (a standard
|
||||||
|
UNIX password file). The pwck command checks the integrity of password
|
||||||
|
and shadow files. The lastlog command prints out the last login times
|
||||||
|
for all users. The useradd, userdel, and usermod commands are used for
|
||||||
|
managing user accounts. The groupadd, groupdel, and groupmod commands
|
||||||
|
are used for managing group accounts.
|
||||||
|
|
||||||
|
## Sites
|
||||||
|
* [Homepage](https://github.com/shadow-maint/shadow)
|
||||||
|
* [Issue tracker](https://github.com/shadow-maint/shadow/issues)
|
||||||
|
* [Releases](https://github.com/shadow-maint/shadow/releases)
|
||||||
|
|
||||||
|
## Contacts
|
||||||
|
There are several ways to contact us:
|
||||||
|
* [the general discussion mailing list](
|
||||||
|
https://alioth-lists.debian.net/mailman/listinfo/pkg-shadow-devel)
|
||||||
|
* the #shadow IRC channel on libera.chat:
|
||||||
|
* irc://irc.libera.chat/shadow
|
||||||
|
|
||||||
|
### Mailing archives
|
||||||
|
* [the general discussion mailing list archive](
|
||||||
|
https://alioth-lists.debian.net/pipermail/pkg-shadow-devel/)
|
||||||
|
* [the commit mailing list archive](
|
||||||
|
https://alioth-lists-archive.debian.net/pipermail/pkg-shadow-commits/),
|
||||||
|
only used for historical purposes
|
||||||
|
|
||||||
|
## Authors and maintainers
|
||||||
|
Authors and maintainers are listed in [AUTHORS.md](
|
||||||
|
https://github.com/shadow-maint/shadow/blob/master/AUTHORS.md).
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
At the moment only the latest release is supported.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Security vulnerabilities may be reported to
|
||||||
|
* Serge Hallyn <serge@hallyn.com> (B175CFA98F192AF2)
|
||||||
|
* Christian Brauner <christian@brauner.io> (4880B8C9BD0E5106FC070F4F7B3C391EFEA93624)
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
* Create a common usage function that'd take the array of
|
||||||
|
long options and an array of descriptions and output that so things would
|
||||||
|
be standardized across the utils.
|
||||||
|
Usage strings should be normalized and split first.
|
||||||
|
Investigate optparse.
|
||||||
|
|
||||||
|
|
||||||
/etc/default/useradd
|
/etc/default/useradd
|
||||||
* GROUP=1000 should accept a group name.
|
* GROUP=1000 should accept a group name.
|
||||||
|
|
||||||
@@ -108,7 +115,13 @@ ALL:
|
|||||||
entry (with a password).
|
entry (with a password).
|
||||||
- Add check to move passwd passwords to shadow if there is a shadow
|
- Add check to move passwd passwords to shadow if there is a shadow
|
||||||
file.
|
file.
|
||||||
|
- Support an alternative /etc/tcb directory as second parameter.
|
||||||
|
- add options -g / -G to specify alternative group / gshadow files
|
||||||
|
|
||||||
- su
|
- su
|
||||||
- add a login.defs configuration parameter to add variables to keep in
|
- add a login.defs configuration parameter to add variables to keep in
|
||||||
the environment with "su -l" (TERM/TERMCOLOR/...
|
the environment with "su -l" (TERM/TERMCOLOR/...)
|
||||||
|
|
||||||
|
- vipw
|
||||||
|
- set ACLs and XATTRs on the temporary file (and backups?)
|
||||||
|
- vipw + selinux -> use lib/selinux.c
|
||||||
|
|||||||
+3
-1
@@ -1,10 +1,12 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
|
||||||
autoreconf -v -f --install || exit 1
|
autoreconf -v -f --install || exit 1
|
||||||
|
|
||||||
./configure \
|
./configure \
|
||||||
CFLAGS="-O2 -Wall" \
|
CFLAGS="-O2 -Wall" \
|
||||||
--enable-man \
|
--enable-man \
|
||||||
--enable-maintainer-mode \
|
--enable-maintainer-mode \
|
||||||
--disable-shared \
|
--enable-shared \
|
||||||
--without-libpam \
|
--without-libpam \
|
||||||
--with-selinux \
|
--with-selinux \
|
||||||
"$@"
|
"$@"
|
||||||
|
|||||||
+261
-32
@@ -1,16 +1,29 @@
|
|||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
AC_INIT
|
AC_PREREQ([2.69])
|
||||||
AM_INIT_AUTOMAKE(shadow, 4.1.4.2)
|
m4_define([libsubid_abi_major], 4)
|
||||||
|
m4_define([libsubid_abi_minor], 0)
|
||||||
|
m4_define([libsubid_abi_micro], 0)
|
||||||
|
m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro])
|
||||||
|
AC_INIT([shadow], [4.10], [pkg-shadow-devel@lists.alioth.debian.org], [],
|
||||||
|
[https://github.com/shadow-maint/shadow])
|
||||||
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz])
|
||||||
|
AC_CONFIG_MACRO_DIRS([m4])
|
||||||
|
AM_SILENT_RULES([yes])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
|
||||||
|
AC_SUBST([LIBSUBID_ABI_MAJOR], [libsubid_abi_major])
|
||||||
|
AC_SUBST([LIBSUBID_ABI_MINOR], [libsubid_abi_minor])
|
||||||
|
AC_SUBST([LIBSUBID_ABI_MICRO], [libsubid_abi_micro])
|
||||||
|
AC_SUBST([LIBSUBID_ABI], [libsubid_abi])
|
||||||
|
|
||||||
dnl Some hacks...
|
dnl Some hacks...
|
||||||
test "$prefix" = "NONE" && prefix="/usr"
|
test "$prefix" = "NONE" && prefix="/usr"
|
||||||
test "$prefix" = "/usr" && exec_prefix=""
|
test "$prefix" = "/usr" && exec_prefix=""
|
||||||
|
|
||||||
AC_GNU_SOURCE
|
AC_GNU_SOURCE
|
||||||
|
|
||||||
AM_DISABLE_SHARED
|
|
||||||
AM_ENABLE_STATIC
|
AM_ENABLE_STATIC
|
||||||
|
AM_ENABLE_SHARED
|
||||||
|
|
||||||
AM_MAINTAINER_MODE
|
AM_MAINTAINER_MODE
|
||||||
|
|
||||||
@@ -19,7 +32,6 @@ AC_PROG_CC
|
|||||||
AC_ISC_POSIX
|
AC_ISC_POSIX
|
||||||
AC_PROG_LN_S
|
AC_PROG_LN_S
|
||||||
AC_PROG_YACC
|
AC_PROG_YACC
|
||||||
AM_C_PROTOTYPES
|
|
||||||
AM_PROG_LIBTOOL
|
AM_PROG_LIBTOOL
|
||||||
|
|
||||||
dnl Checks for libraries.
|
dnl Checks for libraries.
|
||||||
@@ -30,18 +42,21 @@ AC_HEADER_STDC
|
|||||||
AC_HEADER_SYS_WAIT
|
AC_HEADER_SYS_WAIT
|
||||||
AC_HEADER_STDBOOL
|
AC_HEADER_STDBOOL
|
||||||
|
|
||||||
AC_CHECK_HEADERS(errno.h fcntl.h limits.h unistd.h sys/time.h utmp.h \
|
AC_CHECK_HEADERS(crypt.h errno.h fcntl.h limits.h unistd.h sys/time.h utmp.h \
|
||||||
utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h paths.h \
|
utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h paths.h \
|
||||||
utime.h ulimit.h sys/resource.h gshadow.h lastlog.h \
|
utime.h ulimit.h sys/capability.h sys/random.h sys/resource.h \
|
||||||
locale.h rpc/key_prot.h netdb.h)
|
gshadow.h lastlog.h locale.h rpc/key_prot.h netdb.h acl/libacl.h \
|
||||||
|
attr/libattr.h attr/error_context.h)
|
||||||
|
|
||||||
dnl shadow now uses the libc's shadow implementation
|
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_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
|
||||||
|
|
||||||
AC_CHECK_FUNCS(l64a fchmod fchown fsync futimes getgroups gethostname getspnam \
|
AC_CHECK_FUNCS(arc4random_buf l64a fchmod fchown fsync futimes getgroups \
|
||||||
gettimeofday getusershell getutent initgroups lchown lckpwdf lstat \
|
gethostname getentropy getrandom getspnam gettimeofday getusershell \
|
||||||
lutimes memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
|
getutent initgroups lchown lckpwdf lstat lutimes memcpy memset \
|
||||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo)
|
setgroups sigaction strchr updwtmp updwtmpx innetgr getpwnam_r \
|
||||||
|
getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo ruserok \
|
||||||
|
dlopen)
|
||||||
AC_SYS_LARGEFILE
|
AC_SYS_LARGEFILE
|
||||||
|
|
||||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
@@ -70,12 +85,6 @@ AC_CHECK_MEMBERS([struct utmp.ut_type,
|
|||||||
struct utmp.ut_time,
|
struct utmp.ut_time,
|
||||||
struct utmp.ut_xtime,
|
struct utmp.ut_xtime,
|
||||||
struct utmp.ut_tv],,,[[#include <utmp.h>]])
|
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,
|
AC_CHECK_MEMBERS([struct utmpx.ut_name,
|
||||||
struct utmpx.ut_host,
|
struct utmpx.ut_host,
|
||||||
@@ -112,7 +121,9 @@ AC_REPLACE_FUNCS(sgetgrent sgetpwent sgetspent)
|
|||||||
AC_REPLACE_FUNCS(snprintf strcasecmp strdup strerror strstr)
|
AC_REPLACE_FUNCS(snprintf strcasecmp strdup strerror strstr)
|
||||||
|
|
||||||
AC_CHECK_FUNC(setpgrp)
|
AC_CHECK_FUNC(setpgrp)
|
||||||
AC_FUNC_SETPGRP
|
AC_CHECK_FUNC(secure_getenv, [AC_DEFINE(HAS_SECURE_GETENV,
|
||||||
|
1,
|
||||||
|
[Defined to 1 if you have the declaration of 'secure_getenv'])])
|
||||||
|
|
||||||
if test "$ac_cv_header_shadow_h" = "yes"; then
|
if test "$ac_cv_header_shadow_h" = "yes"; then
|
||||||
AC_CACHE_CHECK(for working shadow group support,
|
AC_CACHE_CHECK(for working shadow group support,
|
||||||
@@ -195,8 +206,10 @@ AC_DEFINE_UNQUOTED(PASSWD_PROGRAM, "$shadow_cv_passwd_dir/passwd",
|
|||||||
|
|
||||||
dnl XXX - quick hack, should disappear before anyone notices :).
|
dnl XXX - quick hack, should disappear before anyone notices :).
|
||||||
AC_DEFINE(USE_SYSLOG, 1, [Define to use syslog().])
|
AC_DEFINE(USE_SYSLOG, 1, [Define to use syslog().])
|
||||||
AC_DEFINE(RLOGIN, 1, [Define if login should support the -r flag for rlogind.])
|
if test "$ac_cv_func_ruserok" = "yes"; then
|
||||||
AC_DEFINE(RUSEROK, 0, [Define to the ruserok() "success" return value (0 or 1).])
|
AC_DEFINE(RLOGIN, 1, [Define if login should support the -r flag for rlogind.])
|
||||||
|
AC_DEFINE(RUSEROK, 0, [Define to the ruserok() "success" return value (0 or 1).])
|
||||||
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE(shadowgrp,
|
AC_ARG_ENABLE(shadowgrp,
|
||||||
[AC_HELP_STRING([--enable-shadowgrp], [enable shadow group support @<:@default=yes@:>@])],
|
[AC_HELP_STRING([--enable-shadowgrp], [enable shadow group support @<:@default=yes@:>@])],
|
||||||
@@ -224,7 +237,7 @@ AC_ARG_ENABLE(account-tools-setuid,
|
|||||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-account-tools-setuid)
|
*) AC_MSG_ERROR(bad value ${enableval} for --enable-account-tools-setuid)
|
||||||
;;
|
;;
|
||||||
esac],
|
esac],
|
||||||
[enable_acct_tools_setuid="maybe"]
|
[enable_acct_tools_setuid="no"]
|
||||||
)
|
)
|
||||||
|
|
||||||
AC_ARG_ENABLE(utmpx,
|
AC_ARG_ENABLE(utmpx,
|
||||||
@@ -238,30 +251,61 @@ AC_ARG_ENABLE(utmpx,
|
|||||||
[enable_utmpx="no"]
|
[enable_utmpx="no"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(subordinate-ids,
|
||||||
|
[AC_HELP_STRING([--enable-subordinate-ids],
|
||||||
|
[support subordinate ids @<:@default=yes@:>@])],
|
||||||
|
[enable_subids="${enableval}"],
|
||||||
|
[enable_subids="maybe"]
|
||||||
|
)
|
||||||
|
|
||||||
AC_ARG_WITH(audit,
|
AC_ARG_WITH(audit,
|
||||||
[AC_HELP_STRING([--with-audit], [use auditing support @<:@default=yes if found@:>@])],
|
[AC_HELP_STRING([--with-audit], [use auditing support @<:@default=yes if found@:>@])],
|
||||||
[with_audit=$withval], [with_audit=maybe])
|
[with_audit=$withval], [with_audit=maybe])
|
||||||
AC_ARG_WITH(libpam,
|
AC_ARG_WITH(libpam,
|
||||||
[AC_HELP_STRING([--with-libpam], [use libpam for PAM support @<:@default=yes if found@:>@])],
|
[AC_HELP_STRING([--with-libpam], [use libpam for PAM support @<:@default=yes if found@:>@])],
|
||||||
[with_libpam=$withval], [with_libpam=maybe])
|
[with_libpam=$withval], [with_libpam=maybe])
|
||||||
|
AC_ARG_WITH(btrfs,
|
||||||
|
[AC_HELP_STRING([--with-btrfs], [add BtrFS support @<:@default=yes if found@:>@])],
|
||||||
|
[with_btrfs=$withval], [with_btrfs=maybe])
|
||||||
AC_ARG_WITH(selinux,
|
AC_ARG_WITH(selinux,
|
||||||
[AC_HELP_STRING([--with-selinux], [use SELinux support @<:@default=yes if found@:>@])],
|
[AC_HELP_STRING([--with-selinux], [use SELinux support @<:@default=yes if found@:>@])],
|
||||||
[with_selinux=$withval], [with_selinux=maybe])
|
[with_selinux=$withval], [with_selinux=maybe])
|
||||||
|
AC_ARG_WITH(acl,
|
||||||
|
[AC_HELP_STRING([--with-acl], [use ACL support @<:@default=yes if found@:>@])],
|
||||||
|
[with_acl=$withval], [with_acl=maybe])
|
||||||
|
AC_ARG_WITH(attr,
|
||||||
|
[AC_HELP_STRING([--with-attr], [use Extended Attribute support @<:@default=yes if found@:>@])],
|
||||||
|
[with_attr=$withval], [with_attr=maybe])
|
||||||
AC_ARG_WITH(skey,
|
AC_ARG_WITH(skey,
|
||||||
[AC_HELP_STRING([--with-skey], [use S/Key support @<:@default=no@:>@])],
|
[AC_HELP_STRING([--with-skey], [use S/Key support @<:@default=no@:>@])],
|
||||||
[with_skey=$withval], [with_skey=no])
|
[with_skey=$withval], [with_skey=no])
|
||||||
|
AC_ARG_WITH(tcb,
|
||||||
|
[AC_HELP_STRING([--with-tcb], [use tcb support (incomplete) @<:@default=yes if found@:>@])],
|
||||||
|
[with_tcb=$withval], [with_tcb=maybe])
|
||||||
AC_ARG_WITH(libcrack,
|
AC_ARG_WITH(libcrack,
|
||||||
[AC_HELP_STRING([--with-libcrack], [use libcrack @<:@default=yes if found and if PAM not enabled@:>@])],
|
[AC_HELP_STRING([--with-libcrack], [use libcrack @<:@default=no@:>@])],
|
||||||
[with_libcrack=$withval], [with_libcrack=no])
|
[with_libcrack=$withval], [with_libcrack=no])
|
||||||
AC_ARG_WITH(sha-crypt,
|
AC_ARG_WITH(sha-crypt,
|
||||||
[AC_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])],
|
[AC_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])],
|
||||||
[with_sha_crypt=$withval], [with_sha_crypt=yes])
|
[with_sha_crypt=$withval], [with_sha_crypt=yes])
|
||||||
|
AC_ARG_WITH(bcrypt,
|
||||||
|
[AC_HELP_STRING([--with-bcrypt], [allow the bcrypt password encryption algorithm @<:@default=no@:>@])],
|
||||||
|
[with_bcrypt=$withval], [with_bcrypt=no])
|
||||||
|
AC_ARG_WITH(yescrypt,
|
||||||
|
[AC_HELP_STRING([--with-yescrypt], [allow the yescrypt password encryption algorithm @<:@default=no@:>@])],
|
||||||
|
[with_yescrypt=$withval], [with_yescrypt=no])
|
||||||
AC_ARG_WITH(nscd,
|
AC_ARG_WITH(nscd,
|
||||||
[AC_HELP_STRING([--with-nscd], [enable support for nscd @<:@default=yes@:>@])],
|
[AC_HELP_STRING([--with-nscd], [enable support for nscd @<:@default=yes@:>@])],
|
||||||
[with_nscd=$withval], [with_nscd=yes])
|
[with_nscd=$withval], [with_nscd=yes])
|
||||||
|
AC_ARG_WITH(sssd,
|
||||||
|
[AC_HELP_STRING([--with-sssd], [enable support for flushing sssd caches @<:@default=yes@:>@])],
|
||||||
|
[with_sssd=$withval], [with_sssd=yes])
|
||||||
AC_ARG_WITH(group-name-max-length,
|
AC_ARG_WITH(group-name-max-length,
|
||||||
[AC_HELP_STRING([--with-group-name-max-length], [set max group name length @<:@default=16@:>@])],
|
[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])
|
[with_group_name_max_length=$withval], [with_group_name_max_length=yes])
|
||||||
|
AC_ARG_WITH(su,
|
||||||
|
[AC_HELP_STRING([--with-su], [build and install su program and man page @<:@default=yes@:>@])],
|
||||||
|
[with_su=$withval], [with_su=yes])
|
||||||
|
|
||||||
if test "$with_group_name_max_length" = "no" ; then
|
if test "$with_group_name_max_length" = "no" ; then
|
||||||
with_group_name_max_length=0
|
with_group_name_max_length=0
|
||||||
@@ -277,12 +321,33 @@ 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
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(ENABLE_SHARED, test "x$enable_shared" = "xyes")
|
||||||
|
|
||||||
|
AM_CONDITIONAL(USE_BCRYPT, test "x$with_bcrypt" = "xyes")
|
||||||
|
if test "$with_bcrypt" = "yes"; then
|
||||||
|
AC_DEFINE(USE_BCRYPT, 1, [Define to allow the bcrypt password encryption algorithm])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(USE_YESCRYPT, test "x$with_yescrypt" = "xyes")
|
||||||
|
if test "$with_yescrypt" = "yes"; then
|
||||||
|
AC_DEFINE(USE_YESCRYPT, 1, [Define to allow the yescrypt password encryption algorithm])
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$with_nscd" = "yes"; then
|
if test "$with_nscd" = "yes"; then
|
||||||
AC_CHECK_FUNC(posix_spawn,
|
AC_CHECK_FUNC(posix_spawn,
|
||||||
[AC_DEFINE(USE_NSCD, 1, [Define to support flushing of nscd caches])],
|
[AC_DEFINE(USE_NSCD, 1, [Define to support flushing of nscd caches])],
|
||||||
[AC_MSG_ERROR([posix_spawn is needed for nscd support])])
|
[AC_MSG_ERROR([posix_spawn is needed for nscd support])])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$with_sssd" = "yes"; then
|
||||||
|
AC_CHECK_FUNC(posix_spawn,
|
||||||
|
[AC_DEFINE(USE_SSSD, 1, [Define to support flushing of sssd caches])],
|
||||||
|
[AC_MSG_ERROR([posix_spawn is needed for sssd support])])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AS_IF([test "$with_su" != "no"], AC_DEFINE(WITH_SU, 1, [Build with su]))
|
||||||
|
AM_CONDITIONAL([WITH_SU], [test "x$with_su" != "xno"])
|
||||||
|
|
||||||
dnl Check for some functions in libc first, only if not found check for
|
dnl Check for some functions in libc first, only if not found check for
|
||||||
dnl other libraries. This should prevent linking libnsl if not really
|
dnl other libraries. This should prevent linking libnsl if not really
|
||||||
dnl needed (Linux glibc, Irix), but still link it if needed (Solaris).
|
dnl needed (Linux glibc, Irix), but still link it if needed (Solaris).
|
||||||
@@ -291,6 +356,17 @@ AC_SEARCH_LIBS(inet_ntoa, inet)
|
|||||||
AC_SEARCH_LIBS(socket, socket)
|
AC_SEARCH_LIBS(socket, socket)
|
||||||
AC_SEARCH_LIBS(gethostbyname, nsl)
|
AC_SEARCH_LIBS(gethostbyname, nsl)
|
||||||
|
|
||||||
|
AC_CHECK_LIB([econf],[econf_readDirs],[LIBECONF="-leconf"],[LIBECONF=""])
|
||||||
|
if test -n "$LIBECONF"; then
|
||||||
|
ECONF_CPPFLAGS="-DUSE_ECONF=1"
|
||||||
|
AC_ARG_ENABLE([vendordir],
|
||||||
|
AS_HELP_STRING([--enable-vendordir=DIR], [Directory for distribution provided configuration files]),,[])
|
||||||
|
fi
|
||||||
|
AC_SUBST(ECONF_CPPFLAGS)
|
||||||
|
AC_SUBST(LIBECONF)
|
||||||
|
AC_SUBST([VENDORDIR], [$enable_vendordir])
|
||||||
|
AM_CONDITIONAL([HAVE_VENDORDIR], [test "x$enable_vendordir" != x])
|
||||||
|
|
||||||
if test "$enable_shadowgrp" = "yes"; then
|
if test "$enable_shadowgrp" = "yes"; then
|
||||||
AC_DEFINE(SHADOWGRP, 1, [Define to support the shadow group file.])
|
AC_DEFINE(SHADOWGRP, 1, [Define to support the shadow group file.])
|
||||||
fi
|
fi
|
||||||
@@ -303,20 +379,96 @@ if test "$enable_man" = "yes"; then
|
|||||||
AC_PATH_PROG([XSLTPROC], [xsltproc])
|
AC_PATH_PROG([XSLTPROC], [xsltproc])
|
||||||
if test -z "$XSLTPROC"; then
|
if test -z "$XSLTPROC"; then
|
||||||
enable_man=no
|
enable_man=no
|
||||||
|
AC_MSG_ERROR([xsltproc is missing.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl check for DocBook DTD and stylesheets in the local catalog.
|
dnl check for DocBook DTD and stylesheets in the local catalog.
|
||||||
JH_CHECK_XML_CATALOG([-//OASIS//DTD DocBook XML V4.1.2//EN],
|
JH_CHECK_XML_CATALOG([-//OASIS//DTD DocBook XML V4.5//EN],
|
||||||
[DocBook XML DTD V4.1.2], [], enable_man=no)
|
[DocBook XML DTD V4.5], [], enable_man=no)
|
||||||
JH_CHECK_XML_CATALOG([http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl],
|
JH_CHECK_XML_CATALOG([http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl],
|
||||||
[DocBook XSL Stylesheets >= 1.70.1], [], enable_man=no)
|
[DocBook XSL Stylesheets >= 1.70.1], [], enable_man=no)
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(ENABLE_REGENERATE_MAN, test "x$enable_man" != "xno")
|
AM_CONDITIONAL(ENABLE_REGENERATE_MAN, test "x$enable_man" != "xno")
|
||||||
|
|
||||||
|
if test "$enable_subids" != "no"; then
|
||||||
|
dnl
|
||||||
|
dnl FIXME: check if 32 bit UIDs/GIDs are supported by libc
|
||||||
|
dnl
|
||||||
|
AC_CHECK_SIZEOF([uid_t],, [#include "sys/types.h"])
|
||||||
|
AC_CHECK_SIZEOF([gid_t],, [#include "sys/types.h"])
|
||||||
|
|
||||||
|
if test "$ac_cv_sizeof_uid_t" -ge 4 && test "$ac_cv_sizeof_gid_t" -ge 4; then
|
||||||
|
AC_DEFINE(ENABLE_SUBIDS, 1, [Define to support the subordinate IDs.])
|
||||||
|
enable_subids="yes"
|
||||||
|
else
|
||||||
|
if test "x$enable_subids" = "xyes"; then
|
||||||
|
AC_MSG_ERROR([Cannot enable support the subordinate IDs on systems where gid_t or uid_t has less than 32 bits])
|
||||||
|
fi
|
||||||
|
enable_subids="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(ENABLE_SUBIDS, test "x$enable_subids" != "xno")
|
||||||
|
|
||||||
AC_SUBST(LIBCRYPT)
|
AC_SUBST(LIBCRYPT)
|
||||||
AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
|
AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
|
||||||
[AC_MSG_ERROR([crypt() not found])])
|
[AC_MSG_ERROR([crypt() not found])])
|
||||||
|
|
||||||
|
AC_SUBST(LIYESCRYPT)
|
||||||
|
AC_CHECK_LIB(crypt, crypt, [LIYESCRYPT=-lcrypt],
|
||||||
|
[AC_MSG_ERROR([crypt() not found])])
|
||||||
|
|
||||||
|
AC_SUBST(LIBACL)
|
||||||
|
if test "$with_acl" != "no"; then
|
||||||
|
AC_CHECK_HEADERS(acl/libacl.h attr/error_context.h, [acl_header="yes"], [acl_header="no"])
|
||||||
|
if test "$acl_header$with_acl" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([acl/libacl.h or attr/error_context.h is missing])
|
||||||
|
elif test "$acl_header" = "yes" ; then
|
||||||
|
AC_CHECK_LIB(acl, perm_copy_file,
|
||||||
|
[AC_CHECK_LIB(acl, perm_copy_fd,
|
||||||
|
[acl_lib="yes"],
|
||||||
|
[acl_lib="no"])],
|
||||||
|
[acl_lib="no"])
|
||||||
|
if test "$acl_lib$with_acl" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([libacl not found])
|
||||||
|
elif test "$acl_lib" = "no" ; then
|
||||||
|
with_acl="no"
|
||||||
|
else
|
||||||
|
AC_DEFINE(WITH_ACL, 1,
|
||||||
|
[Build shadow with ACL support])
|
||||||
|
LIBACL="-lacl"
|
||||||
|
with_acl="yes"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
with_acl="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(LIBATTR)
|
||||||
|
if test "$with_attr" != "no"; then
|
||||||
|
AC_CHECK_HEADERS(attr/libattr.h attr/error_context.h, [attr_header="yes"], [attr_header="no"])
|
||||||
|
if test "$attr_header$with_attr" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([attr/libattr.h or attr/error_context.h is missing])
|
||||||
|
elif test "$attr_header" = "yes" ; then
|
||||||
|
AC_CHECK_LIB(attr, attr_copy_file,
|
||||||
|
[AC_CHECK_LIB(attr, attr_copy_fd,
|
||||||
|
[attr_lib="yes"],
|
||||||
|
[attr_lib="no"])],
|
||||||
|
[attr_lib="no"])
|
||||||
|
if test "$attr_lib$with_attr" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([libattr not found])
|
||||||
|
elif test "$attr_lib" = "no" ; then
|
||||||
|
with_attr="no"
|
||||||
|
else
|
||||||
|
AC_DEFINE(WITH_ATTR, 1,
|
||||||
|
[Build shadow with Extended Attributes support])
|
||||||
|
LIBATTR="-lattr"
|
||||||
|
with_attr="yes"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
with_attr="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
AC_SUBST(LIBAUDIT)
|
AC_SUBST(LIBAUDIT)
|
||||||
if test "$with_audit" != "no"; then
|
if test "$with_audit" != "no"; then
|
||||||
AC_CHECK_HEADER(libaudit.h, [audit_header="yes"], [audit_header="no"])
|
AC_CHECK_HEADER(libaudit.h, [audit_header="yes"], [audit_header="no"])
|
||||||
@@ -360,29 +512,80 @@ if test "$with_libcrack" = "yes"; then
|
|||||||
AC_DEFINE(HAVE_LIBCRACK_PW, 1, [Defined if it includes *Pw functions.]))
|
AC_DEFINE(HAVE_LIBCRACK_PW, 1, [Defined if it includes *Pw functions.]))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$with_btrfs" != "no"; then
|
||||||
|
AC_CHECK_HEADERS([sys/statfs.h linux/magic.h linux/btrfs_tree.h], \
|
||||||
|
[btrfs_headers="yes"], [btrfs_headers="no"])
|
||||||
|
if test "$btrfs_headers$with_btrfs" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([One of sys/statfs.h linux/magic.h linux/btrfs_tree.h is missing])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$btrfs_headers" = "yes" ; then
|
||||||
|
AC_DEFINE(WITH_BTRFS, 1, [Build shadow with BtrFS support])
|
||||||
|
with_btrfs="yes"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(WITH_BTRFS, test x$with_btrfs = xyes)
|
||||||
|
|
||||||
AC_SUBST(LIBSELINUX)
|
AC_SUBST(LIBSELINUX)
|
||||||
|
AC_SUBST(LIBSEMANAGE)
|
||||||
if test "$with_selinux" != "no"; then
|
if test "$with_selinux" != "no"; then
|
||||||
AC_CHECK_HEADERS(selinux/selinux.h, [selinux_header="yes"], [selinux_header="no"])
|
AC_CHECK_HEADERS(selinux/selinux.h, [selinux_header="yes"], [selinux_header="no"])
|
||||||
if test "$selinux_header$with_selinux" = "noyes" ; then
|
if test "$selinux_header$with_selinux" = "noyes" ; then
|
||||||
AC_MSG_ERROR([selinux/selinux.h is missing])
|
AC_MSG_ERROR([selinux/selinux.h is missing])
|
||||||
elif test "$selinux_header" = "yes" ; then
|
fi
|
||||||
AC_CHECK_LIB(selinux, is_selinux_enabled,
|
|
||||||
[selinux_lib="yes"], [selinux_lib="no"])
|
AC_CHECK_HEADERS(semanage/semanage.h, [semanage_header="yes"], [semanage_header="no"])
|
||||||
|
if test "$semanage_header$with_selinux" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([semanage/semanage.h is missing])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$selinux_header$semanage_header" = "yesyes" ; then
|
||||||
|
AC_CHECK_LIB(selinux, is_selinux_enabled, [selinux_lib="yes"], [selinux_lib="no"])
|
||||||
if test "$selinux_lib$with_selinux" = "noyes" ; then
|
if test "$selinux_lib$with_selinux" = "noyes" ; then
|
||||||
AC_MSG_ERROR([libselinux not found])
|
AC_MSG_ERROR([libselinux not found])
|
||||||
elif test "$selinux_lib" = "no" ; then
|
fi
|
||||||
with_selinux="no"
|
|
||||||
else
|
AC_CHECK_LIB(semanage, semanage_connect, [semanage_lib="yes"], [semanage_lib="no"])
|
||||||
|
if test "$semanage_lib$with_selinux" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([libsemanage not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$selinux_lib$semanage_lib" = "yesyes" ; then
|
||||||
AC_DEFINE(WITH_SELINUX, 1,
|
AC_DEFINE(WITH_SELINUX, 1,
|
||||||
[Build shadow with SELinux support])
|
[Build shadow with SELinux support])
|
||||||
LIBSELINUX="-lselinux"
|
LIBSELINUX="-lselinux"
|
||||||
|
LIBSEMANAGE="-lsemanage"
|
||||||
with_selinux="yes"
|
with_selinux="yes"
|
||||||
|
else
|
||||||
|
with_selinux="no"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
with_selinux="no"
|
with_selinux="no"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(LIBTCB)
|
||||||
|
if test "$with_tcb" != "no"; then
|
||||||
|
AC_CHECK_HEADERS(tcb.h, [tcb_header="yes"], [tcb_header="no"])
|
||||||
|
if test "$tcb_header$with_tcb" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([tcb.h is missing])
|
||||||
|
elif test "$tcb_header" = "yes" ; then
|
||||||
|
AC_CHECK_LIB(tcb, tcb_is_suspect, [tcb_lib="yes"], [tcb_lib="no"])
|
||||||
|
if test "$tcb_lib$with_tcb" = "noyes" ; then
|
||||||
|
AC_MSG_ERROR([libtcb not found])
|
||||||
|
elif test "$tcb_lib" = "no" ; then
|
||||||
|
with_tcb="no"
|
||||||
|
else
|
||||||
|
AC_DEFINE(WITH_TCB, 1, [Build shadow with tcb support (incomplete)])
|
||||||
|
LIBTCB="-ltcb"
|
||||||
|
with_tcb="yes"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
with_tcb="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(WITH_TCB, test x$with_tcb = xyes)
|
||||||
|
|
||||||
AC_SUBST(LIBPAM)
|
AC_SUBST(LIBPAM)
|
||||||
if test "$with_libpam" != "no"; then
|
if test "$with_libpam" != "no"; then
|
||||||
AC_CHECK_LIB(pam, pam_start,
|
AC_CHECK_LIB(pam, pam_start,
|
||||||
@@ -437,7 +640,7 @@ if test "$with_libpam" = "yes"; then
|
|||||||
LIBS=$save_libs
|
LIBS=$save_libs
|
||||||
|
|
||||||
AC_DEFINE(USE_PAM, 1, [Define to support Pluggable Authentication Modules])
|
AC_DEFINE(USE_PAM, 1, [Define to support Pluggable Authentication Modules])
|
||||||
AC_DEFINE_UNQUOTED(SHADOW_PAM_CONVERSATION, [$pam_conv_function],[PAM converstation to use])
|
AC_DEFINE_UNQUOTED(SHADOW_PAM_CONVERSATION, [$pam_conv_function],[PAM conversation to use])
|
||||||
AM_CONDITIONAL(USE_PAM, [true])
|
AM_CONDITIONAL(USE_PAM, [true])
|
||||||
|
|
||||||
AC_MSG_CHECKING(use login and su access checking if PAM not used)
|
AC_MSG_CHECKING(use login and su access checking if PAM not used)
|
||||||
@@ -467,6 +670,19 @@ if test "$enable_acct_tools_setuid" != "no"; then
|
|||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(ACCT_TOOLS_SETUID, test "x$enable_acct_tools_setuid" = "xyes")
|
AM_CONDITIONAL(ACCT_TOOLS_SETUID, test "x$enable_acct_tools_setuid" = "xyes")
|
||||||
|
|
||||||
|
|
||||||
|
AC_ARG_WITH(fcaps,
|
||||||
|
[AC_HELP_STRING([--with-fcaps], [use file capabilities instead of suid binaries for newuidmap/newgidmap @<:@default=no@:>@])],
|
||||||
|
[with_fcaps=$withval], [with_fcaps=no])
|
||||||
|
AM_CONDITIONAL(FCAPS, test "x$with_fcaps" = "xyes")
|
||||||
|
|
||||||
|
if test "x$with_fcaps" = "xyes"; then
|
||||||
|
AC_CHECK_PROGS(capcmd, "setcap")
|
||||||
|
if test "x$capcmd" = "x" ; then
|
||||||
|
AC_MSG_ERROR([setcap command not available])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
AC_SUBST(LIBSKEY)
|
AC_SUBST(LIBSKEY)
|
||||||
AC_SUBST(LIBMD)
|
AC_SUBST(LIBMD)
|
||||||
if test "$with_skey" = "yes"; then
|
if test "$with_skey" = "yes"; then
|
||||||
@@ -503,8 +719,9 @@ AC_CONFIG_FILES([
|
|||||||
doc/Makefile
|
doc/Makefile
|
||||||
man/Makefile
|
man/Makefile
|
||||||
man/config.xml
|
man/config.xml
|
||||||
man/po/Makefile.in
|
man/po/Makefile
|
||||||
man/cs/Makefile
|
man/cs/Makefile
|
||||||
|
man/da/Makefile
|
||||||
man/de/Makefile
|
man/de/Makefile
|
||||||
man/es/Makefile
|
man/es/Makefile
|
||||||
man/fi/Makefile
|
man/fi/Makefile
|
||||||
@@ -523,6 +740,8 @@ AC_CONFIG_FILES([
|
|||||||
man/zh_TW/Makefile
|
man/zh_TW/Makefile
|
||||||
libmisc/Makefile
|
libmisc/Makefile
|
||||||
lib/Makefile
|
lib/Makefile
|
||||||
|
libsubid/Makefile
|
||||||
|
libsubid/subid.h
|
||||||
src/Makefile
|
src/Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
etc/Makefile
|
etc/Makefile
|
||||||
@@ -541,8 +760,18 @@ if test "$with_libpam" = "yes"; then
|
|||||||
echo " suid account management tools: $enable_acct_tools_setuid"
|
echo " suid account management tools: $enable_acct_tools_setuid"
|
||||||
fi
|
fi
|
||||||
echo " SELinux support: $with_selinux"
|
echo " SELinux support: $with_selinux"
|
||||||
|
echo " BtrFS support: $with_btrfs"
|
||||||
|
echo " ACL support: $with_acl"
|
||||||
|
echo " Extended Attributes support: $with_attr"
|
||||||
|
echo " tcb support (incomplete): $with_tcb"
|
||||||
echo " shadow group support: $enable_shadowgrp"
|
echo " shadow group support: $enable_shadowgrp"
|
||||||
echo " S/Key support: $with_skey"
|
echo " S/Key support: $with_skey"
|
||||||
echo " SHA passwords encryption: $with_sha_crypt"
|
echo " SHA passwords encryption: $with_sha_crypt"
|
||||||
|
echo " bcrypt passwords encryption: $with_bcrypt"
|
||||||
|
echo " yescrypt passwords encryption: $with_yescrypt"
|
||||||
echo " nscd support: $with_nscd"
|
echo " nscd support: $with_nscd"
|
||||||
|
echo " sssd support: $with_sssd"
|
||||||
|
echo " subordinate IDs support: $enable_subids"
|
||||||
|
echo " use file caps: $with_fcaps"
|
||||||
|
echo " install su: $with_su"
|
||||||
echo
|
echo
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
** 1/28/95
|
** 1/28/95
|
||||||
** shadow-adduser 1.3:
|
** shadow-adduser 1.3:
|
||||||
**
|
**
|
||||||
** Basically a bug-fix on my additions in 1.2. Thanx to Terry Stewart
|
** Basically a bug-fix on my additions in 1.2. Thanks to Terry Stewart
|
||||||
** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced.
|
** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced.
|
||||||
** It was such a stupid bug that I would have never seen it myself.
|
** It was such a stupid bug that I would have never seen it myself.
|
||||||
**
|
**
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@
|
|||||||
** 1/28/95
|
** 1/28/95
|
||||||
** shadow-adduser 1.3:
|
** shadow-adduser 1.3:
|
||||||
**
|
**
|
||||||
** Basically a bug-fix on my additions in 1.2. Thanx to Terry Stewart
|
** Basically a bug-fix on my additions in 1.2. Thanks to Terry Stewart
|
||||||
** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced.
|
** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced.
|
||||||
** It was such a stupid bug that I would have never seen it myself.
|
** It was such a stupid bug that I would have never seen it myself.
|
||||||
**
|
**
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ def_home_dir=/home/users
|
|||||||
# default shell
|
# default shell
|
||||||
def_shell=/bin/tcsh
|
def_shell=/bin/tcsh
|
||||||
|
|
||||||
# Defaul expiration date (mm/dd/yy)
|
# Default expiration date (mm/dd/yy)
|
||||||
def_expire=""
|
def_expire=""
|
||||||
|
|
||||||
# default dates
|
# default dates
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ X.B groupmems
|
|||||||
\fB-D\fR |
|
\fB-D\fR |
|
||||||
[\fB-g\fI group_name \fR]
|
[\fB-g\fI group_name \fR]
|
||||||
X.SH DESCRIPTION
|
X.SH DESCRIPTION
|
||||||
The \fBgroupmems\fR utility allows a user to administer his/her own
|
The \fBgroupmems\fR utility allows a user to administer their own
|
||||||
group membership list without the requirement of superuser privileges.
|
group membership list without the requirement of superuser privileges.
|
||||||
The \fBgroupmems\fR utility is for systems that configure its users to
|
The \fBgroupmems\fR utility is for systems that configure its users to
|
||||||
be in their own name sake primary group (i.e., guest / guest).
|
be in their own name sake primary group (i.e., guest / guest).
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Hello Marek,
|
|||||||
|
|
||||||
I have created a diffile against the 980403 release that adds
|
I have created a diffile against the 980403 release that adds
|
||||||
functionality to newusers for automatic handling of users with only
|
functionality to newusers for automatic handling of users with only
|
||||||
anonomous ftp login (using the guestgroup feature in ftpaccess, which
|
anonymous ftp login (using the guestgroup feature in ftpaccess, which
|
||||||
means that the users home directory looks like '/home/user/./'). It also
|
means that the users home directory looks like '/home/user/./'). It also
|
||||||
adds a commandline argument to specify an initial directory structure
|
adds a commandline argument to specify an initial directory structure
|
||||||
for such users, with a tarball normally containing the bin,lib,etc
|
for such users, with a tarball normally containing the bin,lib,etc
|
||||||
|
|||||||
@@ -1311,7 +1311,7 @@
|
|||||||
|
|
||||||
This means that fred's password is valid, it was last changed on
|
This means that fred's password is valid, it was last changed on
|
||||||
03/04/96, it can be changed at any time, it expires after 60 days,
|
03/04/96, it can be changed at any time, it expires after 60 days,
|
||||||
fred will not be warned, and and the account won't be disabled when
|
fred will not be warned, and the account won't be disabled when
|
||||||
the password expires.
|
the password expires.
|
||||||
|
|
||||||
This simply means that if fred logs in after the password expires, he
|
This simply means that if fred logs in after the password expires, he
|
||||||
@@ -1487,7 +1487,7 @@
|
|||||||
|
|
||||||
If a user logs into a line that is listed in /etc/dialups, and his
|
If a user logs into a line that is listed in /etc/dialups, and his
|
||||||
shell is listed in the file /etc/d_passwd he will be allowed access
|
shell is listed in the file /etc/d_passwd he will be allowed access
|
||||||
only by suppling the correct password.
|
only by supplying the correct password.
|
||||||
|
|
||||||
Another useful purpose for using dial-up passwords might be to setup a
|
Another useful purpose for using dial-up passwords might be to setup a
|
||||||
line that only allows a certain type of connect (perhaps a PPP or UUCP
|
line that only allows a certain type of connect (perhaps a PPP or UUCP
|
||||||
|
|||||||
+1
-2
@@ -15,7 +15,7 @@ Changes:
|
|||||||
- code merged into lmain.c --cristiang
|
- code merged into lmain.c --cristiang
|
||||||
|
|
||||||
TODO: - support groups in the limits file
|
TODO: - support groups in the limits file
|
||||||
(only usernames are supported at this momment :-( )
|
(only usernames are supported at this moment :-( )
|
||||||
|
|
||||||
Setting user limits for shadow login program
|
Setting user limits for shadow login program
|
||||||
|
|
||||||
@@ -63,4 +63,3 @@ To completely disable limits for a user, a single dash (-) will do.
|
|||||||
Also, please note that all limit settings are set PER LOGIN. They are
|
Also, please note that all limit settings are set PER LOGIN. They are
|
||||||
not global, nor are they permanent. Perhaps global limits will come, but
|
not global, nor are they permanent. Perhaps global limits will come, but
|
||||||
for now this will have to do ;)
|
for now this will have to do ;)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# S/Key support
|
||||||
|
shadow-utils can be built with S/Key support using the S/Key package from:
|
||||||
|
* http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libskey/ or
|
||||||
|
* https://gentoo.osuosl.org/distfiles/skey-1.1.5.tar.bz2
|
||||||
@@ -37,4 +37,3 @@ New ideas to add to this list are welcome, too. --marekm
|
|||||||
per-user configuration, to be executed with run-parts. Some hooks should
|
per-user configuration, to be executed with run-parts. Some hooks should
|
||||||
be executed at package install time for existing users, likewise for
|
be executed at package install time for existing users, likewise for
|
||||||
package removal and possibly modification. (Debian Bug#36019)
|
package removal and possibly modification. (Debian Bug#36019)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<head>
|
||||||
|
<title>shadow - Welcome</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2> Welcome!</h2>
|
||||||
|
<p> This is the shadow tool suite home page. </p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can find releases <a href="https://github.com/shadow-maint/shadow/releases">here</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Raise issues, request features, and report bugs <a href="https://github.com/shadow-maint/shadow/issues">here</a>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
+1
-2
@@ -4,8 +4,7 @@
|
|||||||
sysconf_DATA = login.defs
|
sysconf_DATA = login.defs
|
||||||
|
|
||||||
defaultdir = $(sysconfdir)/default
|
defaultdir = $(sysconfdir)/default
|
||||||
default_DATA = \
|
default_DATA =
|
||||||
useradd
|
|
||||||
|
|
||||||
nonpam_files = \
|
nonpam_files = \
|
||||||
limits \
|
limits \
|
||||||
|
|||||||
+145
-53
@@ -6,18 +6,18 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# Delay in seconds before being allowed another attempt after a login failure
|
# 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.
|
# Note: When PAM is used, some modules may enforce a minimum delay (e.g.
|
||||||
# pam_unix enforces a 2s delay)
|
# pam_unix(8) enforces a 2s delay)
|
||||||
#
|
#
|
||||||
FAIL_DELAY 3
|
FAIL_DELAY 3
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable logging and display of /var/log/faillog login failure info.
|
# Enable logging and display of /var/log/faillog login(1) failure info.
|
||||||
#
|
#
|
||||||
FAILLOG_ENAB yes
|
FAILLOG_ENAB yes
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable display of unknown usernames when login failures are recorded.
|
# Enable display of unknown usernames when login(1) failures are recorded.
|
||||||
#
|
#
|
||||||
LOG_UNKFAIL_ENAB no
|
LOG_UNKFAIL_ENAB no
|
||||||
|
|
||||||
@@ -27,10 +27,19 @@ LOG_UNKFAIL_ENAB no
|
|||||||
LOG_OK_LOGINS no
|
LOG_OK_LOGINS no
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable logging and display of /var/log/lastlog login time info.
|
# Enable logging and display of /var/log/lastlog login(1) time info.
|
||||||
#
|
#
|
||||||
LASTLOG_ENAB yes
|
LASTLOG_ENAB yes
|
||||||
|
|
||||||
|
#
|
||||||
|
# Limit the highest user ID number for which the lastlog entries should
|
||||||
|
# be updated.
|
||||||
|
#
|
||||||
|
# No LASTLOG_UID_MAX means that there is no user ID limit for writing
|
||||||
|
# lastlog entries.
|
||||||
|
#
|
||||||
|
#LASTLOG_UID_MAX
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable checking and display of mailbox status upon login.
|
# Enable checking and display of mailbox status upon login.
|
||||||
#
|
#
|
||||||
@@ -50,13 +59,13 @@ OBSCURE_CHECKS_ENAB yes
|
|||||||
PORTTIME_CHECKS_ENAB yes
|
PORTTIME_CHECKS_ENAB yes
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable setting of ulimit, umask, and niceness from passwd gecos field.
|
# Enable setting of ulimit, umask, and niceness from passwd(5) gecos field.
|
||||||
#
|
#
|
||||||
QUOTAS_ENAB yes
|
QUOTAS_ENAB yes
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable "syslog" logging of su activity - in addition to sulog file logging.
|
# Enable "syslog" logging of su(1) activity - in addition to sulog file logging.
|
||||||
# SYSLOG_SG_ENAB does the same for newgrp and sg.
|
# SYSLOG_SG_ENAB does the same for newgrp(1) and sg(1).
|
||||||
#
|
#
|
||||||
SYSLOG_SU_ENAB yes
|
SYSLOG_SU_ENAB yes
|
||||||
SYSLOG_SG_ENAB yes
|
SYSLOG_SG_ENAB yes
|
||||||
@@ -64,13 +73,13 @@ SYSLOG_SG_ENAB yes
|
|||||||
#
|
#
|
||||||
# If defined, either full pathname of a file containing device names or
|
# If defined, either full pathname of a file containing device names or
|
||||||
# a ":" delimited list of device names. Root logins will be allowed only
|
# a ":" delimited list of device names. Root logins will be allowed only
|
||||||
# upon these devices.
|
# from these devices.
|
||||||
#
|
#
|
||||||
CONSOLE /etc/securetty
|
CONSOLE /etc/securetty
|
||||||
#CONSOLE console:tty01:tty02:tty03:tty04
|
#CONSOLE console:tty01:tty02:tty03:tty04
|
||||||
|
|
||||||
#
|
#
|
||||||
# If defined, all su activity is logged to this file.
|
# If defined, all su(1) activity is logged to this file.
|
||||||
#
|
#
|
||||||
#SULOG_FILE /var/log/sulog
|
#SULOG_FILE /var/log/sulog
|
||||||
|
|
||||||
@@ -82,33 +91,33 @@ MOTD_FILE /etc/motd
|
|||||||
#MOTD_FILE /etc/motd:/usr/lib/news/news-motd
|
#MOTD_FILE /etc/motd:/usr/lib/news/news-motd
|
||||||
|
|
||||||
#
|
#
|
||||||
# If defined, this file will be output before each login prompt.
|
# If defined, this file will be output before each login(1) prompt.
|
||||||
#
|
#
|
||||||
#ISSUE_FILE /etc/issue
|
#ISSUE_FILE /etc/issue
|
||||||
|
|
||||||
#
|
#
|
||||||
# If defined, file which maps tty line to TERM environment parameter.
|
# If defined, file which maps tty line to TERM environment parameter.
|
||||||
# Each line of the file is in a format something like "vt100 tty01".
|
# Each line of the file is in a format similar to "vt100 tty01".
|
||||||
#
|
#
|
||||||
#TTYTYPE_FILE /etc/ttytype
|
#TTYTYPE_FILE /etc/ttytype
|
||||||
|
|
||||||
#
|
#
|
||||||
# If defined, login failures will be logged here in a utmp format.
|
# If defined, login(1) failures will be logged here in a utmp format.
|
||||||
# last, when invoked as lastb, will read /var/log/btmp, so...
|
# last(1), when invoked as lastb(1), will read /var/log/btmp, so...
|
||||||
#
|
#
|
||||||
FTMP_FILE /var/log/btmp
|
FTMP_FILE /var/log/btmp
|
||||||
|
|
||||||
#
|
#
|
||||||
# If defined, name of file whose presence which will inhibit non-root
|
# If defined, name of file whose presence will inhibit non-root
|
||||||
# logins. The contents of this file should be a message indicating
|
# logins. The content of this file should be a message indicating
|
||||||
# why logins are inhibited.
|
# why logins are inhibited.
|
||||||
#
|
#
|
||||||
NOLOGINS_FILE /etc/nologin
|
NOLOGINS_FILE /etc/nologin
|
||||||
|
|
||||||
#
|
#
|
||||||
# If defined, the command name to display when running "su -". For
|
# If defined, the command name to display when running "su -". For
|
||||||
# example, if this is defined as "su" then a "ps" will display the
|
# example, if this is defined as "su" then ps(1) will display the
|
||||||
# command is "-su". If not defined, then "ps" would display the
|
# command as "-su". If not defined, then ps(1) will display the
|
||||||
# name of the shell actually being run, e.g. something like "-sh".
|
# name of the shell actually being run, e.g. something like "-sh".
|
||||||
#
|
#
|
||||||
SU_NAME su
|
SU_NAME su
|
||||||
@@ -158,10 +167,10 @@ ENV_PATH PATH=/bin:/usr/bin
|
|||||||
# TTYGROUP Login tty will be assigned this group ownership.
|
# TTYGROUP Login tty will be assigned this group ownership.
|
||||||
# TTYPERM Login tty will be set to this permission.
|
# TTYPERM Login tty will be set to this permission.
|
||||||
#
|
#
|
||||||
# If you have a "write" program which is "setgid" to a special group
|
# If you have a write(1) program which is "setgid" to a special group
|
||||||
# which owns the terminals, define TTYGROUP to the group number and
|
# which owns the terminals, define TTYGROUP as the number of such group
|
||||||
# TTYPERM to 0620. Otherwise leave TTYGROUP commented out and assign
|
# and TTYPERM as 0620. Otherwise leave TTYGROUP commented out and
|
||||||
# TTYPERM to either 622 or 600.
|
# set TTYPERM to either 622 or 600.
|
||||||
#
|
#
|
||||||
TTYGROUP tty
|
TTYGROUP tty
|
||||||
TTYPERM 0600
|
TTYPERM 0600
|
||||||
@@ -183,14 +192,20 @@ ERASECHAR 0177
|
|||||||
KILLCHAR 025
|
KILLCHAR 025
|
||||||
#ULIMIT 2097152
|
#ULIMIT 2097152
|
||||||
|
|
||||||
# Default initial "umask" value for non-PAM enabled systems.
|
# Default initial "umask" value used by login(1) on non-PAM enabled systems.
|
||||||
# UMASK is also used by useradd and newusers to set the mode of new home
|
# Default "umask" value for pam_umask(8) on PAM enabled systems.
|
||||||
# directories.
|
# UMASK is also used by useradd(8) and newusers(8) to set the mode for new
|
||||||
|
# home directories if HOME_MODE is not set.
|
||||||
# 022 is the default value, but 027, or even 077, could be considered
|
# 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
|
# for increased privacy. There is no One True Answer here: each sysadmin
|
||||||
# must make up her mind.
|
# must make up their mind.
|
||||||
UMASK 022
|
UMASK 022
|
||||||
|
|
||||||
|
# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new
|
||||||
|
# home directories.
|
||||||
|
# If HOME_MODE is not set, the value of UMASK is used to create the mode.
|
||||||
|
#HOME_MODE 0700
|
||||||
|
|
||||||
#
|
#
|
||||||
# Password aging controls:
|
# Password aging controls:
|
||||||
#
|
#
|
||||||
@@ -213,35 +228,43 @@ PASS_WARN_AGE 7
|
|||||||
SU_WHEEL_ONLY no
|
SU_WHEEL_ONLY no
|
||||||
|
|
||||||
#
|
#
|
||||||
# If compiled with cracklib support, where are the dictionaries
|
# If compiled with cracklib support, sets the path to the dictionaries
|
||||||
#
|
#
|
||||||
CRACKLIB_DICTPATH /var/cache/cracklib/cracklib_dict
|
CRACKLIB_DICTPATH /var/cache/cracklib/cracklib_dict
|
||||||
|
|
||||||
#
|
#
|
||||||
# Min/max values for automatic uid selection in useradd
|
# Min/max values for automatic uid selection in useradd(8)
|
||||||
#
|
#
|
||||||
UID_MIN 1000
|
UID_MIN 1000
|
||||||
UID_MAX 60000
|
UID_MAX 60000
|
||||||
# System accounts
|
# System accounts
|
||||||
SYS_UID_MIN 101
|
SYS_UID_MIN 101
|
||||||
SYS_UID_MAX 999
|
SYS_UID_MAX 999
|
||||||
|
# Extra per user uids
|
||||||
|
SUB_UID_MIN 100000
|
||||||
|
SUB_UID_MAX 600100000
|
||||||
|
SUB_UID_COUNT 65536
|
||||||
|
|
||||||
#
|
#
|
||||||
# Min/max values for automatic gid selection in groupadd
|
# Min/max values for automatic gid selection in groupadd(8)
|
||||||
#
|
#
|
||||||
GID_MIN 1000
|
GID_MIN 1000
|
||||||
GID_MAX 60000
|
GID_MAX 60000
|
||||||
# System accounts
|
# System accounts
|
||||||
SYS_GID_MIN 101
|
SYS_GID_MIN 101
|
||||||
SYS_GID_MAX 999
|
SYS_GID_MAX 999
|
||||||
|
# Extra per user group ids
|
||||||
|
SUB_GID_MIN 100000
|
||||||
|
SUB_GID_MAX 600100000
|
||||||
|
SUB_GID_COUNT 65536
|
||||||
|
|
||||||
#
|
#
|
||||||
# Max number of login retries if password is bad
|
# Max number of login(1) retries if password is bad
|
||||||
#
|
#
|
||||||
LOGIN_RETRIES 5
|
LOGIN_RETRIES 5
|
||||||
|
|
||||||
#
|
#
|
||||||
# Max time in seconds for login
|
# Max time in seconds for login(1)
|
||||||
#
|
#
|
||||||
LOGIN_TIMEOUT 60
|
LOGIN_TIMEOUT 60
|
||||||
|
|
||||||
@@ -263,12 +286,12 @@ PASS_ALWAYS_WARN yes
|
|||||||
#PASS_MAX_LEN 8
|
#PASS_MAX_LEN 8
|
||||||
|
|
||||||
#
|
#
|
||||||
# Require password before chfn/chsh can make any changes.
|
# Require password before chfn(1)/chsh(1) can make any changes.
|
||||||
#
|
#
|
||||||
CHFN_AUTH yes
|
CHFN_AUTH yes
|
||||||
|
|
||||||
#
|
#
|
||||||
# Which fields may be changed by regular users using chfn - use
|
# Which fields may be changed by regular users using chfn(1) - use
|
||||||
# any combination of letters "frwh" (full name, room number, work
|
# any combination of letters "frwh" (full name, room number, work
|
||||||
# phone, home phone). If not defined, no changes are allowed.
|
# phone, home phone). If not defined, no changes are allowed.
|
||||||
# For backward compatibility, "yes" = "rwh" and "no" = "frwh".
|
# For backward compatibility, "yes" = "rwh" and "no" = "frwh".
|
||||||
@@ -293,16 +316,19 @@ CHFN_RESTRICT rwh
|
|||||||
# Note: If you use PAM, it is recommended to use a value consistent with
|
# Note: If you use PAM, it is recommended to use a value consistent with
|
||||||
# the PAM modules configuration.
|
# the PAM modules configuration.
|
||||||
#
|
#
|
||||||
# This variable is deprecated. You should use ENCRYPT_METHOD.
|
# This variable is deprecated. You should use ENCRYPT_METHOD instead.
|
||||||
#
|
#
|
||||||
#MD5_CRYPT_ENAB no
|
#MD5_CRYPT_ENAB no
|
||||||
|
|
||||||
#
|
#
|
||||||
# Only works if compiled with ENCRYPTMETHOD_SELECT defined:
|
# Only works if compiled with ENCRYPTMETHOD_SELECT defined:
|
||||||
# If set to MD5 , MD5-based algorithm will be used for encrypting password
|
# If set to MD5, MD5-based algorithm will be used for encrypting password
|
||||||
# If set to SHA256, SHA256-based algorithm will be used for encrypting password
|
# If set to SHA256, SHA256-based algorithm will be used for encrypting password
|
||||||
# If set to SHA512, SHA512-based algorithm will be used for encrypting password
|
# If set to SHA512, SHA512-based algorithm will be used for encrypting password
|
||||||
|
# If set to BCRYPT, BCRYPT-based algorithm will be used for encrypting password
|
||||||
|
# If set to YESCRYPT, YESCRYPT-based algorithm will be used for encrypting password
|
||||||
# If set to DES, DES-based algorithm will be used for encrypting password (default)
|
# If set to DES, DES-based algorithm will be used for encrypting password (default)
|
||||||
|
# MD5 and DES should not be used for new hashes, see crypt(5) for recommendations.
|
||||||
# Overrides the MD5_CRYPT_ENAB option
|
# Overrides the MD5_CRYPT_ENAB option
|
||||||
#
|
#
|
||||||
# Note: If you use PAM, it is recommended to use a value consistent with
|
# Note: If you use PAM, it is recommended to use a value consistent with
|
||||||
@@ -314,35 +340,72 @@ CHFN_RESTRICT rwh
|
|||||||
# Only works if ENCRYPT_METHOD is set to SHA256 or SHA512.
|
# Only works if ENCRYPT_METHOD is set to SHA256 or SHA512.
|
||||||
#
|
#
|
||||||
# Define the number of SHA rounds.
|
# Define the number of SHA rounds.
|
||||||
# With a lot of rounds, it is more difficult to brute forcing the password.
|
# With a lot of rounds, it is more difficult to brute-force the password.
|
||||||
# But note also that it more CPU resources will be needed to authenticate
|
# However, more CPU resources will be needed to authenticate users if
|
||||||
# users.
|
# this value is increased.
|
||||||
#
|
#
|
||||||
# If not specified, the libc will choose the default number of rounds (5000).
|
# If not specified, the libc will choose the default number of rounds (5000),
|
||||||
# The values must be inside the 1000-999999999 range.
|
# which is orders of magnitude too low for modern hardware.
|
||||||
|
# The values must be within the 1000-999999999 range.
|
||||||
# If only one of the MIN or MAX values is set, then this value will be used.
|
# If only one of the MIN or MAX values is set, then this value will be used.
|
||||||
# If MIN > MAX, the highest value will be used.
|
# If MIN > MAX, the highest value will be used.
|
||||||
#
|
#
|
||||||
# SHA_CRYPT_MIN_ROUNDS 5000
|
#SHA_CRYPT_MIN_ROUNDS 5000
|
||||||
# SHA_CRYPT_MAX_ROUNDS 5000
|
#SHA_CRYPT_MAX_ROUNDS 5000
|
||||||
|
|
||||||
|
#
|
||||||
|
# Only works if ENCRYPT_METHOD is set to BCRYPT.
|
||||||
|
#
|
||||||
|
# Define the number of BCRYPT rounds.
|
||||||
|
# With a lot of rounds, it is more difficult to brute-force the password.
|
||||||
|
# However, more CPU resources will be needed to authenticate users if
|
||||||
|
# this value is increased.
|
||||||
|
#
|
||||||
|
# If not specified, 13 rounds will be attempted.
|
||||||
|
# If only one of the MIN or MAX values is set, then this value will be used.
|
||||||
|
# If MIN > MAX, the highest value will be used.
|
||||||
|
#
|
||||||
|
#BCRYPT_MIN_ROUNDS 13
|
||||||
|
#BCRYPT_MAX_ROUNDS 13
|
||||||
|
|
||||||
|
#
|
||||||
|
# Only works if ENCRYPT_METHOD is set to YESCRYPT.
|
||||||
|
#
|
||||||
|
# Define the YESCRYPT cost factor.
|
||||||
|
# With a higher cost factor, it is more difficult to brute-force the password.
|
||||||
|
# However, more CPU time and more memory will be needed to authenticate users
|
||||||
|
# if this value is increased.
|
||||||
|
#
|
||||||
|
# If not specified, a cost factor of 5 will be used.
|
||||||
|
# The value must be within the 1-11 range.
|
||||||
|
#
|
||||||
|
#YESCRYPT_COST_FACTOR 5
|
||||||
|
|
||||||
#
|
#
|
||||||
# List of groups to add to the user's supplementary group set
|
# List of groups to add to the user's supplementary group set
|
||||||
# when logging in on the console (as determined by the CONSOLE
|
# when logging in from the console (as determined by the CONSOLE
|
||||||
# setting). Default is none.
|
# setting). Default is none.
|
||||||
#
|
#
|
||||||
# Use with caution - it is possible for users to gain permanent
|
# Use with caution - it is possible for users to gain permanent
|
||||||
# access to these groups, even when not logged in on the console.
|
# access to these groups, even when not logged in from the console.
|
||||||
# How to do it is left as an exercise for the reader...
|
# How to do it is left as an exercise for the reader...
|
||||||
#
|
#
|
||||||
#CONSOLE_GROUPS floppy:audio:cdrom
|
#CONSOLE_GROUPS floppy:audio:cdrom
|
||||||
|
|
||||||
#
|
#
|
||||||
# Should login be allowed if we can't cd to the home directory?
|
# Should login be allowed if we can't cd to the home directory?
|
||||||
# Default in no.
|
# Default is no.
|
||||||
#
|
#
|
||||||
DEFAULT_HOME yes
|
DEFAULT_HOME yes
|
||||||
|
|
||||||
|
#
|
||||||
|
# The pwck(8) utility emits a warning for any system account with a home
|
||||||
|
# directory that does not exist. Some system accounts intentionally do
|
||||||
|
# not have a home directory. Such accounts may have this string as
|
||||||
|
# their home directory in /etc/passwd to avoid a spurious warning.
|
||||||
|
#
|
||||||
|
NONEXISTENT /nonexistent
|
||||||
|
|
||||||
#
|
#
|
||||||
# If this file exists and is readable, login environment will be
|
# If this file exists and is readable, login environment will be
|
||||||
# read from it. Every line should be in the form name=value.
|
# read from it. Every line should be in the form name=value.
|
||||||
@@ -361,14 +424,14 @@ ENVIRON_FILE /etc/environment
|
|||||||
# (examples: 022 -> 002, 077 -> 007) for non-root users, if the uid is
|
# (examples: 022 -> 002, 077 -> 007) for non-root users, if the uid is
|
||||||
# the same as gid, and username is the same as the primary group name.
|
# the same as gid, and username is the same as the primary group name.
|
||||||
#
|
#
|
||||||
# This also enables userdel to remove user groups if no members exist.
|
# This also enables userdel(8) to remove user groups if no members exist.
|
||||||
#
|
#
|
||||||
USERGROUPS_ENAB yes
|
USERGROUPS_ENAB yes
|
||||||
|
|
||||||
#
|
#
|
||||||
# If set to a non-nul number, the shadow utilities will make sure that
|
# If set to a non-zero number, the shadow utilities will make sure that
|
||||||
# groups never have more than this number of users on one line.
|
# groups never have more than this number of users on one line.
|
||||||
# This permit to support split groups (groups split into multiple lines,
|
# This permits to support split groups (groups split into multiple lines,
|
||||||
# with the same group ID, to avoid limitation of the line length in the
|
# with the same group ID, to avoid limitation of the line length in the
|
||||||
# group file).
|
# group file).
|
||||||
#
|
#
|
||||||
@@ -377,10 +440,39 @@ USERGROUPS_ENAB yes
|
|||||||
#MAX_MEMBERS_PER_GROUP 0
|
#MAX_MEMBERS_PER_GROUP 0
|
||||||
|
|
||||||
#
|
#
|
||||||
# If useradd should create home directories for users by default (non
|
# If useradd(8) should create home directories for users by default (non
|
||||||
# system users only)
|
# system users only).
|
||||||
# This option is overridden with the -M or -m flags on the useradd command
|
# This option is overridden with the -M or -m flags on the useradd(8)
|
||||||
# line.
|
# command-line.
|
||||||
#
|
#
|
||||||
#CREATE_HOME yes
|
#CREATE_HOME yes
|
||||||
|
|
||||||
|
#
|
||||||
|
# Force use shadow, even if shadow passwd & shadow group files are
|
||||||
|
# missing.
|
||||||
|
#
|
||||||
|
#FORCE_SHADOW yes
|
||||||
|
|
||||||
|
#
|
||||||
|
# Allow newuidmap and newgidmap when running under an alternative
|
||||||
|
# primary group.
|
||||||
|
#
|
||||||
|
#GRANT_AUX_GROUP_SUBIDS yes
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prevents an empty password field to be interpreted as "no authentication
|
||||||
|
# required".
|
||||||
|
# Set to "yes" to prevent for all accounts
|
||||||
|
# Set to "superuser" to prevent for UID 0 / root (default)
|
||||||
|
# Set to "no" to not prevent for any account (dangerous, historical default)
|
||||||
|
PREVENT_NO_AUTH superuser
|
||||||
|
|
||||||
|
#
|
||||||
|
# Select the HMAC cryptography algorithm.
|
||||||
|
# Used in pam_timestamp module to calculate the keyed-hash message
|
||||||
|
# authentication code.
|
||||||
|
#
|
||||||
|
# Note: It is recommended to check hmac(3) to see the possible algorithms
|
||||||
|
# that are available in your system.
|
||||||
|
#
|
||||||
|
#HMAC_CRYPTO_ALGO SHA512
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ pamd_files = \
|
|||||||
chsh \
|
chsh \
|
||||||
groupmems \
|
groupmems \
|
||||||
login \
|
login \
|
||||||
passwd \
|
passwd
|
||||||
su
|
|
||||||
|
|
||||||
pamd_acct_tools_files = \
|
pamd_acct_tools_files = \
|
||||||
chage \
|
chage \
|
||||||
@@ -29,4 +28,8 @@ pamd_DATA += $(pamd_acct_tools_files)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if WITH_SU
|
||||||
|
pamd_files += su
|
||||||
|
endif
|
||||||
|
|
||||||
EXTRA_DIST = $(pamd_files) $(pamd_acct_tools_files)
|
EXTRA_DIST = $(pamd_files) $(pamd_acct_tools_files)
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# useradd defaults file
|
|
||||||
GROUP=1000
|
|
||||||
HOME=/home
|
|
||||||
INACTIVE=-1
|
|
||||||
EXPIRE=
|
|
||||||
SHELL=/bin/bash
|
|
||||||
SKEL=/etc/skel
|
|
||||||
CREATE_MAIL_SPOOL=yes
|
|
||||||
+21
-1
@@ -5,7 +5,12 @@ DEFS =
|
|||||||
|
|
||||||
noinst_LTLIBRARIES = libshadow.la
|
noinst_LTLIBRARIES = libshadow.la
|
||||||
|
|
||||||
libshadow_la_LDFLAGS = -version-info 0:0:0
|
libshadow_la_CPPFLAGS = $(ECONF_CPPFLAGS)
|
||||||
|
if HAVE_VENDORDIR
|
||||||
|
libshadow_la_CPPFLAGS += -DVENDORDIR=\"$(VENDORDIR)\"
|
||||||
|
endif
|
||||||
|
|
||||||
|
libshadow_la_CPPFLAGS += -I$(top_srcdir)
|
||||||
|
|
||||||
libshadow_la_SOURCES = \
|
libshadow_la_SOURCES = \
|
||||||
commonio.c \
|
commonio.c \
|
||||||
@@ -14,6 +19,7 @@ libshadow_la_SOURCES = \
|
|||||||
encrypt.c \
|
encrypt.c \
|
||||||
exitcodes.h \
|
exitcodes.h \
|
||||||
faillog.h \
|
faillog.h \
|
||||||
|
fields.c \
|
||||||
fputsx.c \
|
fputsx.c \
|
||||||
getdef.c \
|
getdef.c \
|
||||||
getdef.h \
|
getdef.h \
|
||||||
@@ -27,8 +33,11 @@ libshadow_la_SOURCES = \
|
|||||||
groupio.h \
|
groupio.h \
|
||||||
gshadow.c \
|
gshadow.c \
|
||||||
lockpw.c \
|
lockpw.c \
|
||||||
|
nss.c \
|
||||||
nscd.c \
|
nscd.c \
|
||||||
nscd.h \
|
nscd.h \
|
||||||
|
sssd.c \
|
||||||
|
sssd.h \
|
||||||
pam_defs.h \
|
pam_defs.h \
|
||||||
port.c \
|
port.c \
|
||||||
port.h \
|
port.h \
|
||||||
@@ -38,6 +47,12 @@ libshadow_la_SOURCES = \
|
|||||||
pwio.c \
|
pwio.c \
|
||||||
pwio.h \
|
pwio.h \
|
||||||
pwmem.c \
|
pwmem.c \
|
||||||
|
run_part.h \
|
||||||
|
run_part.c \
|
||||||
|
subordinateio.h \
|
||||||
|
subordinateio.c \
|
||||||
|
selinux.c \
|
||||||
|
semanage.c \
|
||||||
sgetgrent.c \
|
sgetgrent.c \
|
||||||
sgetpwent.c \
|
sgetpwent.c \
|
||||||
sgetspent.c \
|
sgetspent.c \
|
||||||
@@ -47,8 +62,13 @@ libshadow_la_SOURCES = \
|
|||||||
shadowio.c \
|
shadowio.c \
|
||||||
shadowio.h \
|
shadowio.h \
|
||||||
shadowmem.c \
|
shadowmem.c \
|
||||||
|
spawn.c \
|
||||||
utent.c
|
utent.c
|
||||||
|
|
||||||
|
if WITH_TCB
|
||||||
|
libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h
|
||||||
|
endif
|
||||||
|
|
||||||
# These files are unneeded for some reason, listed in
|
# These files are unneeded for some reason, listed in
|
||||||
# order of appearance:
|
# order of appearance:
|
||||||
#
|
#
|
||||||
|
|||||||
+281
-118
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
||||||
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
|
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2011, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -45,16 +45,17 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "nscd.h"
|
#include "nscd.h"
|
||||||
#ifdef WITH_SELINUX
|
#include "sssd.h"
|
||||||
#include <selinux/selinux.h>
|
#ifdef WITH_TCB
|
||||||
#endif
|
#include <tcb.h>
|
||||||
|
#endif /* WITH_TCB */
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "commonio.h"
|
#include "commonio.h"
|
||||||
|
|
||||||
/* local function prototypes */
|
/* local function prototypes */
|
||||||
static int lrename (const char *, const char *);
|
static int lrename (const char *, const char *);
|
||||||
static int check_link_count (const char *file);
|
static int check_link_count (const char *file);
|
||||||
static int do_lock_file (const char *file, const char *lock);
|
static int do_lock_file (const char *file, const char *lock, bool log);
|
||||||
static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
|
static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *mode,
|
const char *mode,
|
||||||
@@ -132,7 +133,7 @@ static int check_link_count (const char *file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_lock_file (const char *file, const char *lock)
|
static int do_lock_file (const char *file, const char *lock, bool log)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@@ -140,8 +141,13 @@ static int do_lock_file (const char *file, const char *lock)
|
|||||||
int retval;
|
int retval;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
|
||||||
fd = open (file, O_CREAT | O_EXCL | O_WRONLY, 0600);
|
fd = open (file, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||||
if (-1 == fd) {
|
if (-1 == fd) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: %s: %s\n",
|
||||||
|
Prog, file, strerror (errno));
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +155,21 @@ static int do_lock_file (const char *file, const char *lock)
|
|||||||
snprintf (buf, sizeof buf, "%lu", (unsigned long) pid);
|
snprintf (buf, sizeof buf, "%lu", (unsigned long) pid);
|
||||||
len = (ssize_t) strlen (buf) + 1;
|
len = (ssize_t) strlen (buf) + 1;
|
||||||
if (write (fd, buf, (size_t) len) != len) {
|
if (write (fd, buf, (size_t) len) != len) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: %s file write error: %s\n",
|
||||||
|
Prog, file, strerror (errno));
|
||||||
|
}
|
||||||
|
(void) close (fd);
|
||||||
|
unlink (file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (fdatasync (fd) == -1) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: %s file sync error: %s\n",
|
||||||
|
Prog, file, strerror (errno));
|
||||||
|
}
|
||||||
(void) close (fd);
|
(void) close (fd);
|
||||||
unlink (file);
|
unlink (file);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -157,12 +178,22 @@ static int do_lock_file (const char *file, const char *lock)
|
|||||||
|
|
||||||
if (link (file, lock) == 0) {
|
if (link (file, lock) == 0) {
|
||||||
retval = check_link_count (file);
|
retval = check_link_count (file);
|
||||||
|
if ((0==retval) && log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: %s: lock file already used\n",
|
||||||
|
Prog, file);
|
||||||
|
}
|
||||||
unlink (file);
|
unlink (file);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open (lock, O_RDWR);
|
fd = open (lock, O_RDWR);
|
||||||
if (-1 == fd) {
|
if (-1 == fd) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: %s: %s\n",
|
||||||
|
Prog, lock, strerror (errno));
|
||||||
|
}
|
||||||
unlink (file);
|
unlink (file);
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -170,29 +201,60 @@ static int do_lock_file (const char *file, const char *lock)
|
|||||||
len = read (fd, buf, sizeof (buf) - 1);
|
len = read (fd, buf, sizeof (buf) - 1);
|
||||||
close (fd);
|
close (fd);
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: existing lock file %s without a PID\n",
|
||||||
|
Prog, lock);
|
||||||
|
}
|
||||||
unlink (file);
|
unlink (file);
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
if (get_pid (buf, &pid) == 0) {
|
if (get_pid (buf, &pid) == 0) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: existing lock file %s with an invalid PID '%s'\n",
|
||||||
|
Prog, lock, buf);
|
||||||
|
}
|
||||||
unlink (file);
|
unlink (file);
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (kill (pid, 0) == 0) {
|
if (kill (pid, 0) == 0) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: lock %s already used by PID %lu\n",
|
||||||
|
Prog, lock, (unsigned long) pid);
|
||||||
|
}
|
||||||
unlink (file);
|
unlink (file);
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (unlink (lock) != 0) {
|
if (unlink (lock) != 0) {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: cannot get lock %s: %s\n",
|
||||||
|
Prog, lock, strerror (errno));
|
||||||
|
}
|
||||||
unlink (file);
|
unlink (file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
if ((link (file, lock) == 0) && (check_link_count (file) != 0)) {
|
if (link (file, lock) == 0) {
|
||||||
retval = 1;
|
retval = check_link_count (file);
|
||||||
|
if ((0==retval) && log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: %s: lock file already used\n",
|
||||||
|
Prog, file);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (log) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: cannot get lock %s: %s\n",
|
||||||
|
Prog, lock, strerror (errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink (file);
|
unlink (file);
|
||||||
@@ -219,21 +281,21 @@ static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
|
|||||||
if (fchown (fileno (fp), sb->st_uid, sb->st_gid) != 0) {
|
if (fchown (fileno (fp), sb->st_uid, sb->st_gid) != 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#else
|
#else /* !HAVE_FCHOWN */
|
||||||
if (chown (name, sb->st_mode) != 0) {
|
if (chown (name, sb->st_mode) != 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* !HAVE_FCHOWN */
|
||||||
|
|
||||||
#ifdef HAVE_FCHMOD
|
#ifdef HAVE_FCHMOD
|
||||||
if (fchmod (fileno (fp), sb->st_mode & 0664) != 0) {
|
if (fchmod (fileno (fp), sb->st_mode & 0664) != 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#else
|
#else /* !HAVE_FCHMOD */
|
||||||
if (chmod (name, sb->st_mode & 0664) != 0) {
|
if (chmod (name, sb->st_mode & 0664) != 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* !HAVE_FCHMOD */
|
||||||
return fp;
|
return fp;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@@ -250,15 +312,12 @@ static int create_backup (const char *backup, FILE * fp)
|
|||||||
struct utimbuf ub;
|
struct utimbuf ub;
|
||||||
FILE *bkfp;
|
FILE *bkfp;
|
||||||
int c;
|
int c;
|
||||||
mode_t mask;
|
|
||||||
|
|
||||||
if (fstat (fileno (fp), &sb) != 0) {
|
if (fstat (fileno (fp), &sb) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask = umask (077);
|
bkfp = fopen_set_perms (backup, "w", &sb);
|
||||||
bkfp = fopen (backup, "w");
|
|
||||||
(void) umask (mask);
|
|
||||||
if (NULL == bkfp) {
|
if (NULL == bkfp) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -277,8 +336,12 @@ static int create_backup (const char *backup, FILE * fp)
|
|||||||
/* FIXME: unlink the backup file? */
|
/* FIXME: unlink the backup file? */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( (fsync (fileno (bkfp)) != 0)
|
if (fsync (fileno (bkfp)) != 0) {
|
||||||
|| (fclose (bkfp) != 0)) {
|
(void) fclose (bkfp);
|
||||||
|
/* FIXME: unlink the backup file? */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (fclose (bkfp) != 0) {
|
||||||
/* FIXME: unlink the backup file? */
|
/* FIXME: unlink the backup file? */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -315,6 +378,7 @@ static void free_linked_list (struct commonio_db *db)
|
|||||||
int commonio_setname (struct commonio_db *db, const char *name)
|
int commonio_setname (struct commonio_db *db, const char *name)
|
||||||
{
|
{
|
||||||
snprintf (db->filename, sizeof (db->filename), "%s", name);
|
snprintf (db->filename, sizeof (db->filename), "%s", name);
|
||||||
|
db->setname = true;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,54 +389,79 @@ bool commonio_present (const struct commonio_db *db)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int commonio_lock_nowait (struct commonio_db *db)
|
int commonio_lock_nowait (struct commonio_db *db, bool log)
|
||||||
{
|
{
|
||||||
char file[1024];
|
char* file = NULL;
|
||||||
char lock[1024];
|
char* lock = NULL;
|
||||||
|
size_t lock_file_len;
|
||||||
|
size_t file_len;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
if (db->locked) {
|
if (db->locked) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
file_len = strlen(db->filename) + 11;/* %lu max size */
|
||||||
snprintf (file, sizeof file, "%s.%lu",
|
lock_file_len = strlen(db->filename) + 6; /* sizeof ".lock" */
|
||||||
|
file = (char*)malloc(file_len);
|
||||||
|
if (file == NULL) {
|
||||||
|
goto cleanup_ENOMEM;
|
||||||
|
}
|
||||||
|
lock = (char*)malloc(lock_file_len);
|
||||||
|
if (lock == NULL) {
|
||||||
|
goto cleanup_ENOMEM;
|
||||||
|
}
|
||||||
|
snprintf (file, file_len, "%s.%lu",
|
||||||
db->filename, (unsigned long) getpid ());
|
db->filename, (unsigned long) getpid ());
|
||||||
snprintf (lock, sizeof lock, "%s.lock", db->filename);
|
snprintf (lock, lock_file_len, "%s.lock", db->filename);
|
||||||
if (do_lock_file (file, lock) != 0) {
|
if (do_lock_file (file, lock, log) != 0) {
|
||||||
db->locked = true;
|
db->locked = true;
|
||||||
lock_count++;
|
lock_count++;
|
||||||
return 1;
|
err = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
cleanup_ENOMEM:
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
if (lock)
|
||||||
|
free(lock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int commonio_lock (struct commonio_db *db)
|
int commonio_lock (struct commonio_db *db)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
#ifdef HAVE_LCKPWDF
|
#ifdef HAVE_LCKPWDF
|
||||||
/*
|
/*
|
||||||
* only if the system libc has a real lckpwdf() - the one from
|
* Only if the system libc has a real lckpwdf() - the one from
|
||||||
* lockpw.c calls us and would cause infinite recursion!
|
* lockpw.c calls us and would cause infinite recursion!
|
||||||
|
* It is also not used with the prefix option.
|
||||||
*/
|
*/
|
||||||
|
if (!db->setname) {
|
||||||
/*
|
/*
|
||||||
* Call lckpwdf() on the first lock.
|
* Call lckpwdf() on the first lock.
|
||||||
* If it succeeds, call *_lock() only once
|
* If it succeeds, call *_lock() only once
|
||||||
* (no retries, it should always succeed).
|
* (no retries, it should always succeed).
|
||||||
*/
|
*/
|
||||||
if (0 == lock_count) {
|
if (0 == lock_count) {
|
||||||
if (lckpwdf () == -1) {
|
if (lckpwdf () == -1) {
|
||||||
return 0; /* failure */
|
if (geteuid () != 0) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
"%s: Permission denied.\n",
|
||||||
|
Prog);
|
||||||
|
}
|
||||||
|
return 0; /* failure */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (commonio_lock_nowait (db) != 0) {
|
if (commonio_lock_nowait (db, true) != 0) {
|
||||||
return 1; /* success */
|
return 1; /* success */
|
||||||
}
|
}
|
||||||
|
|
||||||
ulckpwdf ();
|
ulckpwdf ();
|
||||||
return 0; /* failure */
|
return 0; /* failure */
|
||||||
#else
|
}
|
||||||
int i;
|
#endif /* !HAVE_LCKPWDF */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* lckpwdf() not used - do it the old way.
|
* lckpwdf() not used - do it the old way.
|
||||||
@@ -388,16 +477,17 @@ int commonio_lock (struct commonio_db *db)
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
sleep (LOCK_SLEEP); /* delay between retries */
|
sleep (LOCK_SLEEP); /* delay between retries */
|
||||||
}
|
}
|
||||||
if (commonio_lock_nowait (db) != 0) {
|
if (commonio_lock_nowait (db, i==LOCK_TRIES-1) != 0) {
|
||||||
return 1; /* success */
|
return 1; /* success */
|
||||||
}
|
}
|
||||||
/* no unnecessary retries on "permission denied" errors */
|
/* no unnecessary retries on "permission denied" errors */
|
||||||
if (geteuid () != 0) {
|
if (geteuid () != 0) {
|
||||||
|
(void) fprintf (shadow_logfd, "%s: Permission denied.\n",
|
||||||
|
Prog);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0; /* failure */
|
return 0; /* failure */
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dec_lock_count (void)
|
static void dec_lock_count (void)
|
||||||
@@ -410,11 +500,12 @@ static void dec_lock_count (void)
|
|||||||
if (nscd_need_reload) {
|
if (nscd_need_reload) {
|
||||||
nscd_flush_cache ("passwd");
|
nscd_flush_cache ("passwd");
|
||||||
nscd_flush_cache ("group");
|
nscd_flush_cache ("group");
|
||||||
|
sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
|
||||||
nscd_need_reload = false;
|
nscd_need_reload = false;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_LCKPWDF
|
#ifdef HAVE_LCKPWDF
|
||||||
ulckpwdf ();
|
ulckpwdf ();
|
||||||
#endif
|
#endif /* HAVE_LCKPWDF */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -533,6 +624,7 @@ int commonio_open (struct commonio_db *db, int mode)
|
|||||||
void *eptr = NULL;
|
void *eptr = NULL;
|
||||||
int flags = mode;
|
int flags = mode;
|
||||||
size_t buflen;
|
size_t buflen;
|
||||||
|
int fd;
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
|
|
||||||
mode &= ~O_CREAT;
|
mode &= ~O_CREAT;
|
||||||
@@ -549,11 +641,31 @@ int commonio_open (struct commonio_db *db, int mode)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
db->head = db->tail = NULL;
|
db->head = NULL;
|
||||||
|
db->tail = NULL;
|
||||||
db->cursor = NULL;
|
db->cursor = NULL;
|
||||||
db->changed = false;
|
db->changed = false;
|
||||||
|
|
||||||
db->fp = fopen (db->filename, db->readonly ? "r" : "r+");
|
fd = open (db->filename,
|
||||||
|
(db->readonly ? O_RDONLY : O_RDWR)
|
||||||
|
| O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
|
||||||
|
saved_errno = errno;
|
||||||
|
db->fp = NULL;
|
||||||
|
if (fd >= 0) {
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
if (tcb_is_suspect (fd) != 0) {
|
||||||
|
(void) close (fd);
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
db->fp = fdopen (fd, db->readonly ? "r" : "r+");
|
||||||
|
saved_errno = errno;
|
||||||
|
if (NULL == db->fp) {
|
||||||
|
(void) close (fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errno = saved_errno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If O_CREAT was specified and the file didn't exist, it will be
|
* If O_CREAT was specified and the file didn't exist, it will be
|
||||||
@@ -568,16 +680,7 @@ int commonio_open (struct commonio_db *db, int mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Do not inherit fd in spawned processes (e.g. nscd) */
|
/* Do not inherit fd in spawned processes (e.g. nscd) */
|
||||||
fcntl(fileno(db->fp), F_SETFD, FD_CLOEXEC);
|
fcntl (fileno (db->fp), F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
|
||||||
db->scontext = NULL;
|
|
||||||
if ((is_selinux_enabled () > 0) && (!db->readonly)) {
|
|
||||||
if (fgetfilecon (fileno (db->fp), &db->scontext) < 0) {
|
|
||||||
goto cleanup_errno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
buflen = BUFLEN;
|
buflen = BUFLEN;
|
||||||
buf = (char *) malloc (buflen);
|
buf = (char *) malloc (buflen);
|
||||||
@@ -663,12 +766,6 @@ int commonio_open (struct commonio_db *db, int mode)
|
|||||||
cleanup_errno:
|
cleanup_errno:
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
free_linked_list (db);
|
free_linked_list (db);
|
||||||
#ifdef WITH_SELINUX
|
|
||||||
if (db->scontext != NULL) {
|
|
||||||
freecon (db->scontext);
|
|
||||||
db->scontext = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
fclose (db->fp);
|
fclose (db->fp);
|
||||||
db->fp = NULL;
|
db->fp = NULL;
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
@@ -683,10 +780,26 @@ commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
|
|||||||
{
|
{
|
||||||
struct commonio_entry **entries, *ptr;
|
struct commonio_entry **entries, *ptr;
|
||||||
size_t n = 0, i;
|
size_t n = 0, i;
|
||||||
|
#if KEEP_NIS_AT_END
|
||||||
|
struct commonio_entry *nis = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
for (ptr = db->head; NULL != ptr; ptr = ptr->next) {
|
for (ptr = db->head;
|
||||||
|
(NULL != ptr)
|
||||||
|
#if KEEP_NIS_AT_END
|
||||||
|
&& ((NULL == ptr->line)
|
||||||
|
|| (('+' != ptr->line[0])
|
||||||
|
&& ('-' != ptr->line[0])))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
ptr = ptr->next) {
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
#if KEEP_NIS_AT_END
|
||||||
|
if (NULL != ptr) {
|
||||||
|
nis = ptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (n <= 1) {
|
if (n <= 1) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -698,18 +811,40 @@ commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
|
|||||||
}
|
}
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
for (ptr = db->head; NULL != ptr; ptr = ptr->next) {
|
for (ptr = db->head;
|
||||||
entries[n++] = ptr;
|
#if KEEP_NIS_AT_END
|
||||||
|
nis != ptr;
|
||||||
|
#else
|
||||||
|
NULL != ptr;
|
||||||
|
#endif
|
||||||
|
/*@ -nullderef @*/
|
||||||
|
ptr = ptr->next
|
||||||
|
/*@ +nullderef @*/
|
||||||
|
) {
|
||||||
|
entries[n] = ptr;
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
qsort (entries, n, sizeof (struct commonio_entry *), cmp);
|
qsort (entries, n, sizeof (struct commonio_entry *), cmp);
|
||||||
|
|
||||||
|
/* Take care of the head and tail separately */
|
||||||
db->head = entries[0];
|
db->head = entries[0];
|
||||||
db->tail = entries[--n];
|
n--;
|
||||||
|
#if KEEP_NIS_AT_END
|
||||||
|
if (NULL == nis)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
db->tail = entries[n];
|
||||||
|
}
|
||||||
db->head->prev = NULL;
|
db->head->prev = NULL;
|
||||||
db->head->next = entries[1];
|
db->head->next = entries[1];
|
||||||
db->tail->prev = entries[n - 1];
|
entries[n]->prev = entries[n - 1];
|
||||||
db->tail->next = NULL;
|
#if KEEP_NIS_AT_END
|
||||||
|
entries[n]->next = nis;
|
||||||
|
#else
|
||||||
|
entries[n]->next = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Now other elements have prev and next entries */
|
||||||
for (i = 1; i < n; i++) {
|
for (i = 1; i < n; i++) {
|
||||||
entries[i]->prev = entries[i - 1];
|
entries[i]->prev = entries[i - 1];
|
||||||
entries[i]->next = entries[i + 1];
|
entries[i]->next = entries[i + 1];
|
||||||
@@ -724,7 +859,8 @@ commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
|
|||||||
/*
|
/*
|
||||||
* Sort entries in db according to order in another.
|
* Sort entries in db according to order in another.
|
||||||
*/
|
*/
|
||||||
int commonio_sort_wrt (struct commonio_db *shadow, struct commonio_db *passwd)
|
int commonio_sort_wrt (struct commonio_db *shadow,
|
||||||
|
const struct commonio_db *passwd)
|
||||||
{
|
{
|
||||||
struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr;
|
struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr;
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -805,16 +941,11 @@ static int write_all (const struct commonio_db *db)
|
|||||||
|
|
||||||
|
|
||||||
int commonio_close (struct commonio_db *db)
|
int commonio_close (struct commonio_db *db)
|
||||||
/*@requires notnull db->fp@*/
|
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
|
||||||
/*@null@*/security_context_t old_context = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!db->isopen) {
|
if (!db->isopen) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -822,8 +953,10 @@ int commonio_close (struct commonio_db *db)
|
|||||||
db->isopen = false;
|
db->isopen = false;
|
||||||
|
|
||||||
if (!db->changed || db->readonly) {
|
if (!db->changed || db->readonly) {
|
||||||
fclose (db->fp);
|
if (NULL != db->fp) {
|
||||||
db->fp = NULL;
|
(void) fclose (db->fp);
|
||||||
|
db->fp = NULL;
|
||||||
|
}
|
||||||
goto success;
|
goto success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,27 +967,21 @@ int commonio_close (struct commonio_db *db)
|
|||||||
memzero (&sb, sizeof sb);
|
memzero (&sb, sizeof sb);
|
||||||
if (NULL != db->fp) {
|
if (NULL != db->fp) {
|
||||||
if (fstat (fileno (db->fp), &sb) != 0) {
|
if (fstat (fileno (db->fp), &sb) != 0) {
|
||||||
fclose (db->fp);
|
(void) fclose (db->fp);
|
||||||
db->fp = NULL;
|
db->fp = NULL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#ifdef WITH_SELINUX
|
|
||||||
if (db->scontext != NULL) {
|
|
||||||
if (getfscreatecon (&old_context) < 0) {
|
|
||||||
errors++;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (setfscreatecon (db->scontext) < 0) {
|
|
||||||
errors++;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/*
|
/*
|
||||||
* Create backup file.
|
* Create backup file.
|
||||||
*/
|
*/
|
||||||
snprintf (buf, sizeof buf, "%s-", db->filename);
|
snprintf (buf, sizeof buf, "%s-", db->filename);
|
||||||
|
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
if (set_selinux_file_context (db->filename, S_IFREG) != 0) {
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (create_backup (buf, db->fp) != 0) {
|
if (create_backup (buf, db->fp) != 0) {
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
@@ -863,6 +990,11 @@ int commonio_close (struct commonio_db *db)
|
|||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
if (reset_selinux_file_context () != 0) {
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (errors != 0) {
|
if (errors != 0) {
|
||||||
db->fp = NULL;
|
db->fp = NULL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -870,15 +1002,20 @@ int commonio_close (struct commonio_db *db)
|
|||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Default permissions for new [g]shadow files.
|
* Default permissions for new [g]shadow files.
|
||||||
* (passwd and group always exist...)
|
|
||||||
*/
|
*/
|
||||||
sb.st_mode = 0400;
|
sb.st_mode = db->st_mode;
|
||||||
sb.st_uid = 0;
|
sb.st_uid = db->st_uid;
|
||||||
sb.st_gid = 0;
|
sb.st_gid = db->st_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf (buf, sizeof buf, "%s+", db->filename);
|
snprintf (buf, sizeof buf, "%s+", db->filename);
|
||||||
|
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
if (set_selinux_file_context (db->filename, S_IFREG) != 0) {
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
db->fp = fopen_set_perms (buf, "w", &sb);
|
db->fp = fopen_set_perms (buf, "w", &sb);
|
||||||
if (NULL == db->fp) {
|
if (NULL == db->fp) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -895,9 +1032,9 @@ int commonio_close (struct commonio_db *db)
|
|||||||
if (fsync (fileno (db->fp)) != 0) {
|
if (fsync (fileno (db->fp)) != 0) {
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
#else
|
#else /* !HAVE_FSYNC */
|
||||||
sync ();
|
sync ();
|
||||||
#endif
|
#endif /* !HAVE_FSYNC */
|
||||||
if (fclose (db->fp) != 0) {
|
if (fclose (db->fp) != 0) {
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
@@ -913,25 +1050,18 @@ int commonio_close (struct commonio_db *db)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
if (reset_selinux_file_context () != 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
nscd_need_reload = true;
|
nscd_need_reload = true;
|
||||||
goto success;
|
goto success;
|
||||||
fail:
|
fail:
|
||||||
errors++;
|
errors++;
|
||||||
success:
|
success:
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
|
||||||
if (db->scontext != NULL) {
|
|
||||||
if (NULL != old_context) {
|
|
||||||
if (setfscreatecon (old_context) < 0) {
|
|
||||||
errors++;
|
|
||||||
}
|
|
||||||
freecon (old_context);
|
|
||||||
old_context = NULL;
|
|
||||||
}
|
|
||||||
freecon (db->scontext);
|
|
||||||
db->scontext = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
free_linked_list (db);
|
free_linked_list (db);
|
||||||
return errors == 0;
|
return errors == 0;
|
||||||
}
|
}
|
||||||
@@ -962,7 +1092,7 @@ static /*@dependent@*/ /*@null@*/struct commonio_entry *find_entry_by_name (
|
|||||||
struct commonio_db *db,
|
struct commonio_db *db,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
return next_entry_by_name(db, db->head, name);
|
return next_entry_by_name (db, db->head, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -983,7 +1113,8 @@ int commonio_update (struct commonio_db *db, const void *eptr)
|
|||||||
p = find_entry_by_name (db, db->ops->getname (eptr));
|
p = find_entry_by_name (db, db->ops->getname (eptr));
|
||||||
if (NULL != p) {
|
if (NULL != p) {
|
||||||
if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) {
|
if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) {
|
||||||
fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename);
|
fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename);
|
||||||
|
db->ops->free (nentry);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
db->ops->free (p->eptr);
|
db->ops->free (p->eptr);
|
||||||
@@ -1008,14 +1139,46 @@ int commonio_update (struct commonio_db *db, const void *eptr)
|
|||||||
|
|
||||||
#if KEEP_NIS_AT_END
|
#if KEEP_NIS_AT_END
|
||||||
add_one_entry_nis (db, p);
|
add_one_entry_nis (db, p);
|
||||||
#else
|
#else /* !KEEP_NIS_AT_END */
|
||||||
add_one_entry (db, p);
|
add_one_entry (db, p);
|
||||||
#endif
|
#endif /* !KEEP_NIS_AT_END */
|
||||||
|
|
||||||
db->changed = true;
|
db->changed = true;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_SUBIDS
|
||||||
|
int commonio_append (struct commonio_db *db, const void *eptr)
|
||||||
|
{
|
||||||
|
struct commonio_entry *p;
|
||||||
|
void *nentry;
|
||||||
|
|
||||||
|
if (!db->isopen || db->readonly) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
nentry = db->ops->dup (eptr);
|
||||||
|
if (NULL == nentry) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* new entry */
|
||||||
|
p = (struct commonio_entry *) malloc (sizeof *p);
|
||||||
|
if (NULL == p) {
|
||||||
|
db->ops->free (nentry);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->eptr = nentry;
|
||||||
|
p->line = NULL;
|
||||||
|
p->changed = true;
|
||||||
|
add_one_entry (db, p);
|
||||||
|
|
||||||
|
db->changed = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_SUBIDS */
|
||||||
|
|
||||||
void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p)
|
void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p)
|
||||||
{
|
{
|
||||||
@@ -1055,7 +1218,7 @@ int commonio_remove (struct commonio_db *db, const char *name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (next_entry_by_name (db, p->next, name) != NULL) {
|
if (next_entry_by_name (db, p->next, name) != NULL) {
|
||||||
fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename);
|
fprintf (shadow_logfd, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-13
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2008, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -31,12 +31,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
#ifndef _COMMONIO_H
|
#ifndef COMMONIO_H
|
||||||
#define _COMMONIO_H
|
#define COMMONIO_H
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
|
||||||
#include <selinux/selinux.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "defines.h" /* bool */
|
#include "defines.h" /* bool */
|
||||||
|
|
||||||
@@ -121,12 +117,19 @@ struct commonio_db {
|
|||||||
/*@dependent@*/ /*@null@*/FILE *fp;
|
/*@dependent@*/ /*@null@*/FILE *fp;
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
/*@null@*/security_context_t scontext;
|
/*@null@*/char *scontext;
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
* Default permissions and owner for newly created data file.
|
||||||
|
*/
|
||||||
|
mode_t st_mode;
|
||||||
|
uid_t st_uid;
|
||||||
|
gid_t st_gid;
|
||||||
/*
|
/*
|
||||||
* Head, tail, current position in linked list.
|
* Head, tail, current position in linked list.
|
||||||
*/
|
*/
|
||||||
/*@owned@*/ /*@null@*/struct commonio_entry *head, *tail;
|
/*@owned@*/ /*@null@*/struct commonio_entry *head;
|
||||||
|
/*@dependent@*/ /*@null@*/struct commonio_entry *tail;
|
||||||
/*@dependent@*/ /*@null@*/struct commonio_entry *cursor;
|
/*@dependent@*/ /*@null@*/struct commonio_entry *cursor;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -136,25 +139,29 @@ struct commonio_db {
|
|||||||
bool isopen:1;
|
bool isopen:1;
|
||||||
bool locked:1;
|
bool locked:1;
|
||||||
bool readonly:1;
|
bool readonly:1;
|
||||||
|
bool setname:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int commonio_setname (struct commonio_db *, const char *);
|
extern int commonio_setname (struct commonio_db *, const char *);
|
||||||
extern bool commonio_present (const struct commonio_db *db);
|
extern bool commonio_present (const struct commonio_db *db);
|
||||||
extern int commonio_lock (struct commonio_db *);
|
extern int commonio_lock (struct commonio_db *);
|
||||||
extern int commonio_lock_nowait (struct commonio_db *);
|
extern int commonio_lock_nowait (struct commonio_db *, bool log);
|
||||||
extern int commonio_open (struct commonio_db *, int);
|
extern int commonio_open (struct commonio_db *, int);
|
||||||
extern /*@observer@*/ /*@null@*/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_update (struct commonio_db *, const void *);
|
||||||
|
#ifdef ENABLE_SUBIDS
|
||||||
|
extern int commonio_append (struct commonio_db *, const void *);
|
||||||
|
#endif /* ENABLE_SUBIDS */
|
||||||
extern int commonio_remove (struct commonio_db *, const char *);
|
extern int commonio_remove (struct commonio_db *, const char *);
|
||||||
extern int commonio_rewind (struct commonio_db *);
|
extern int commonio_rewind (struct commonio_db *);
|
||||||
extern /*@observer@*/ /*@null@*/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_close (struct commonio_db *);
|
||||||
extern int commonio_unlock (struct commonio_db *);
|
extern int commonio_unlock (struct commonio_db *);
|
||||||
extern void commonio_del_entry (struct commonio_db *,
|
extern void commonio_del_entry (struct commonio_db *,
|
||||||
const struct commonio_entry *);
|
const struct commonio_entry *);
|
||||||
extern int commonio_sort_wrt (struct commonio_db *shadow,
|
extern int commonio_sort_wrt (struct commonio_db *shadow,
|
||||||
struct commonio_db *passwd);
|
const struct commonio_db *passwd);
|
||||||
extern int commonio_sort (struct commonio_db *db,
|
extern int commonio_sort (struct commonio_db *db,
|
||||||
int (*cmp) (const void *, const void *));
|
int (*cmp) (const void *, const void *));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+18
-2
@@ -4,6 +4,8 @@
|
|||||||
#ifndef _DEFINES_H_
|
#ifndef _DEFINES_H_
|
||||||
#define _DEFINES_H_
|
#define _DEFINES_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#if HAVE_STDBOOL_H
|
#if HAVE_STDBOOL_H
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
#else
|
#else
|
||||||
@@ -24,7 +26,7 @@ typedef unsigned char _Bool;
|
|||||||
|
|
||||||
/* Take care of NLS matters. */
|
/* Take care of NLS matters. */
|
||||||
#ifdef S_SPLINT_S
|
#ifdef S_SPLINT_S
|
||||||
extern char *setlocale(int categorie, const char *locale);
|
extern char *setlocale(int categories, const char *locale);
|
||||||
# define LC_ALL (6)
|
# define LC_ALL (6)
|
||||||
extern char * bindtextdomain (const char * domainname, const char * dirname);
|
extern char * bindtextdomain (const char * domainname, const char * dirname);
|
||||||
extern char * textdomain (const char * domainname);
|
extern char * textdomain (const char * domainname);
|
||||||
@@ -94,6 +96,14 @@ char *strchr (), *strrchr (), *strtok ();
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* crypt(3), crypt_gensalt(3), and their
|
||||||
|
* feature test macros may be defined in here.
|
||||||
|
*/
|
||||||
|
#if HAVE_CRYPT_H
|
||||||
|
# include <crypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if TIME_WITH_SYS_TIME
|
#if TIME_WITH_SYS_TIME
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
@@ -177,7 +187,7 @@ char *strchr (), *strrchr (), *strtok ();
|
|||||||
* --Nekral */
|
* --Nekral */
|
||||||
#define SYSLOG(x) \
|
#define SYSLOG(x) \
|
||||||
do { \
|
do { \
|
||||||
char *old_locale = setlocale(LC_ALL, NULL); \
|
char *old_locale = setlocale (LC_ALL, NULL); \
|
||||||
char *saved_locale = NULL; \
|
char *saved_locale = NULL; \
|
||||||
if (NULL != old_locale) { \
|
if (NULL != old_locale) { \
|
||||||
saved_locale = strdup (old_locale); \
|
saved_locale = strdup (old_locale); \
|
||||||
@@ -382,4 +392,10 @@ extern char *strerror ();
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SECURE_GETENV
|
||||||
|
# define shadow_getenv(name) secure_getenv(name)
|
||||||
|
# else
|
||||||
|
# define shadow_getenv(name) getenv(name)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _DEFINES_H_ */
|
#endif /* _DEFINES_H_ */
|
||||||
|
|||||||
+17
-12
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1990 - 1993, Julianne Frances Haugh
|
* Copyright (c) 1990 - 1993, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2008, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -40,38 +40,43 @@
|
|||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
char *pw_encrypt (const char *clear, const char *salt)
|
/*@exposed@*//*@null@*/char *pw_encrypt (const char *clear, const char *salt)
|
||||||
{
|
{
|
||||||
static char cipher[128];
|
static char cipher[128];
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
cp = crypt (clear, salt);
|
cp = crypt (clear, salt);
|
||||||
if (!cp) {
|
if (NULL == cp) {
|
||||||
/*
|
/*
|
||||||
* Single Unix Spec: crypt() may return a null pointer,
|
* Single Unix Spec: crypt() may return a null pointer,
|
||||||
* and set errno to indicate an error. The caller doesn't
|
* and set errno to indicate an error. In this case return
|
||||||
* expect us to return NULL, so...
|
* the NULL so the caller can handle appropriately.
|
||||||
*/
|
*/
|
||||||
perror ("crypt");
|
return NULL;
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The GNU crypt does not return NULL if the algorithm is not
|
/* Some crypt() do not return NULL if the algorithm is not
|
||||||
* supported, and return a DES encrypted password. */
|
* supported, and return a DES encrypted password. */
|
||||||
if ((NULL != salt) && (salt[0] == '$') && (strlen (cp) <= 13))
|
if ((NULL != salt) && (salt[0] == '$') && (strlen (cp) <= 13))
|
||||||
{
|
{
|
||||||
const char *method;
|
/*@observer@*/const char *method;
|
||||||
switch (salt[1])
|
switch (salt[1])
|
||||||
{
|
{
|
||||||
case '1':
|
case '1':
|
||||||
method = "MD5";
|
method = "MD5";
|
||||||
break;
|
break;
|
||||||
|
case '2':
|
||||||
|
method = "BCRYPT";
|
||||||
|
break;
|
||||||
case '5':
|
case '5':
|
||||||
method = "SHA256";
|
method = "SHA256";
|
||||||
break;
|
break;
|
||||||
case '6':
|
case '6':
|
||||||
method = "SHA512";
|
method = "SHA512";
|
||||||
break;
|
break;
|
||||||
|
case 'y':
|
||||||
|
method = "YESCRYPT";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
static char nummethod[4] = "$x$";
|
static char nummethod[4] = "$x$";
|
||||||
@@ -79,9 +84,9 @@ char *pw_encrypt (const char *clear, const char *salt)
|
|||||||
method = &nummethod[0];
|
method = &nummethod[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf (stderr,
|
(void) fprintf (shadow_logfd,
|
||||||
_("crypt method not supported by libcrypt? (%s)\n"),
|
_("crypt method not supported by libcrypt? (%s)\n"),
|
||||||
method);
|
method);
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -45,8 +45,8 @@
|
|||||||
struct faillog {
|
struct faillog {
|
||||||
short fail_cnt; /* failures since last success */
|
short fail_cnt; /* failures since last success */
|
||||||
short fail_max; /* failures before turning account off */
|
short fail_max; /* failures before turning account off */
|
||||||
char fail_line[12]; /* last failure occured here */
|
char fail_line[12]; /* last failure occurred here */
|
||||||
time_t fail_time; /* last failure occured then */
|
time_t fail_time; /* last failure occurred then */
|
||||||
/*
|
/*
|
||||||
* If nonzero, the account will be re-enabled if there are no
|
* If nonzero, the account will be re-enabled if there are no
|
||||||
* failures for fail_locktime seconds since last failure.
|
* failures for fail_locktime seconds since last failure.
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ int valid_field (const char *field, const char *illegal)
|
|||||||
const char *cp;
|
const char *cp;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
if (NULL == field) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* For each character of field, search if it appears in the list
|
/* For each character of field, search if it appears in the list
|
||||||
* of illegal characters. */
|
* of illegal characters. */
|
||||||
for (cp = field; '\0' != *cp; cp++) {
|
for (cp = field; '\0' != *cp; cp++) {
|
||||||
+186
-42
@@ -40,6 +40,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#ifdef USE_ECONF
|
||||||
|
#include <libeconf.h>
|
||||||
|
#endif
|
||||||
#include "getdef.h"
|
#include "getdef.h"
|
||||||
/*
|
/*
|
||||||
* A configuration item definition.
|
* A configuration item definition.
|
||||||
@@ -49,6 +52,43 @@ struct itemdef {
|
|||||||
/*@null@*/char *value; /* value given, or NULL if no value */
|
/*@null@*/char *value; /* value given, or NULL if no value */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PAMDEFS \
|
||||||
|
{"CHFN_AUTH", NULL}, \
|
||||||
|
{"CHSH_AUTH", NULL}, \
|
||||||
|
{"CRACKLIB_DICTPATH", NULL}, \
|
||||||
|
{"ENV_HZ", NULL}, \
|
||||||
|
{"ENVIRON_FILE", NULL}, \
|
||||||
|
{"ENV_TZ", NULL}, \
|
||||||
|
{"FAILLOG_ENAB", NULL}, \
|
||||||
|
{"FTMP_FILE", NULL}, \
|
||||||
|
{"HMAC_CRYPTO_ALGO", NULL}, \
|
||||||
|
{"ISSUE_FILE", NULL}, \
|
||||||
|
{"LASTLOG_ENAB", NULL}, \
|
||||||
|
{"LOGIN_STRING", NULL}, \
|
||||||
|
{"MAIL_CHECK_ENAB", NULL}, \
|
||||||
|
{"MOTD_FILE", NULL}, \
|
||||||
|
{"NOLOGINS_FILE", NULL}, \
|
||||||
|
{"OBSCURE_CHECKS_ENAB", NULL}, \
|
||||||
|
{"PASS_ALWAYS_WARN", NULL}, \
|
||||||
|
{"PASS_CHANGE_TRIES", NULL}, \
|
||||||
|
{"PASS_MAX_LEN", NULL}, \
|
||||||
|
{"PASS_MIN_LEN", NULL}, \
|
||||||
|
{"PORTTIME_CHECKS_ENAB", NULL}, \
|
||||||
|
{"QUOTAS_ENAB", NULL}, \
|
||||||
|
{"SU_WHEEL_ONLY", NULL}, \
|
||||||
|
{"ULIMIT", NULL},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Items used in other tools (util-linux, etc.)
|
||||||
|
*/
|
||||||
|
#define FOREIGNDEFS \
|
||||||
|
{"ALWAYS_SET_PATH", NULL}, \
|
||||||
|
{"ENV_ROOTPATH", NULL}, \
|
||||||
|
{"LOGIN_KEEP_USERNAME", NULL}, \
|
||||||
|
{"LOGIN_PLAIN_PROMPT", NULL}, \
|
||||||
|
{"MOTD_FIRSTONLY", NULL}, \
|
||||||
|
|
||||||
|
|
||||||
#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
|
#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
|
||||||
static struct itemdef def_table[] = {
|
static struct itemdef def_table[] = {
|
||||||
{"CHFN_RESTRICT", NULL},
|
{"CHFN_RESTRICT", NULL},
|
||||||
@@ -64,8 +104,10 @@ static struct itemdef def_table[] = {
|
|||||||
{"FAKE_SHELL", NULL},
|
{"FAKE_SHELL", NULL},
|
||||||
{"GID_MAX", NULL},
|
{"GID_MAX", NULL},
|
||||||
{"GID_MIN", NULL},
|
{"GID_MIN", NULL},
|
||||||
|
{"HOME_MODE", NULL},
|
||||||
{"HUSHLOGIN_FILE", NULL},
|
{"HUSHLOGIN_FILE", NULL},
|
||||||
{"KILLCHAR", NULL},
|
{"KILLCHAR", NULL},
|
||||||
|
{"LASTLOG_UID_MAX", NULL},
|
||||||
{"LOGIN_RETRIES", NULL},
|
{"LOGIN_RETRIES", NULL},
|
||||||
{"LOGIN_TIMEOUT", NULL},
|
{"LOGIN_TIMEOUT", NULL},
|
||||||
{"LOG_OK_LOGINS", NULL},
|
{"LOG_OK_LOGINS", NULL},
|
||||||
@@ -74,6 +116,7 @@ static struct itemdef def_table[] = {
|
|||||||
{"MAIL_FILE", NULL},
|
{"MAIL_FILE", NULL},
|
||||||
{"MAX_MEMBERS_PER_GROUP", NULL},
|
{"MAX_MEMBERS_PER_GROUP", NULL},
|
||||||
{"MD5_CRYPT_ENAB", NULL},
|
{"MD5_CRYPT_ENAB", NULL},
|
||||||
|
{"NONEXISTENT", NULL},
|
||||||
{"PASS_MAX_DAYS", NULL},
|
{"PASS_MAX_DAYS", NULL},
|
||||||
{"PASS_MIN_DAYS", NULL},
|
{"PASS_MIN_DAYS", NULL},
|
||||||
{"PASS_WARN_AGE", NULL},
|
{"PASS_WARN_AGE", NULL},
|
||||||
@@ -81,6 +124,19 @@ static struct itemdef def_table[] = {
|
|||||||
{"SHA_CRYPT_MAX_ROUNDS", NULL},
|
{"SHA_CRYPT_MAX_ROUNDS", NULL},
|
||||||
{"SHA_CRYPT_MIN_ROUNDS", NULL},
|
{"SHA_CRYPT_MIN_ROUNDS", NULL},
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_BCRYPT
|
||||||
|
{"BCRYPT_MAX_ROUNDS", NULL},
|
||||||
|
{"BCRYPT_MIN_ROUNDS", NULL},
|
||||||
|
#endif
|
||||||
|
#ifdef USE_YESCRYPT
|
||||||
|
{"YESCRYPT_COST_FACTOR", NULL},
|
||||||
|
#endif
|
||||||
|
{"SUB_GID_COUNT", NULL},
|
||||||
|
{"SUB_GID_MAX", NULL},
|
||||||
|
{"SUB_GID_MIN", NULL},
|
||||||
|
{"SUB_UID_COUNT", NULL},
|
||||||
|
{"SUB_UID_MAX", NULL},
|
||||||
|
{"SUB_UID_MIN", NULL},
|
||||||
{"SULOG_FILE", NULL},
|
{"SULOG_FILE", NULL},
|
||||||
{"SU_NAME", NULL},
|
{"SU_NAME", NULL},
|
||||||
{"SYS_GID_MAX", NULL},
|
{"SYS_GID_MAX", NULL},
|
||||||
@@ -96,42 +152,46 @@ static struct itemdef def_table[] = {
|
|||||||
{"USERDEL_CMD", NULL},
|
{"USERDEL_CMD", NULL},
|
||||||
{"USERGROUPS_ENAB", NULL},
|
{"USERGROUPS_ENAB", NULL},
|
||||||
#ifndef USE_PAM
|
#ifndef USE_PAM
|
||||||
{"CHFN_AUTH", NULL},
|
PAMDEFS
|
||||||
{"CHSH_AUTH", NULL},
|
|
||||||
{"CRACKLIB_DICTPATH", NULL},
|
|
||||||
{"ENV_HZ", NULL},
|
|
||||||
{"ENVIRON_FILE", NULL},
|
|
||||||
{"ENV_TZ", NULL},
|
|
||||||
{"FAILLOG_ENAB", NULL},
|
|
||||||
{"FTMP_FILE", NULL},
|
|
||||||
{"ISSUE_FILE", NULL},
|
|
||||||
{"LASTLOG_ENAB", NULL},
|
|
||||||
{"LOGIN_STRING", NULL},
|
|
||||||
{"MAIL_CHECK_ENAB", NULL},
|
|
||||||
{"MOTD_FILE", NULL},
|
|
||||||
{"NOLOGINS_FILE", NULL},
|
|
||||||
{"OBSCURE_CHECKS_ENAB", NULL},
|
|
||||||
{"PASS_ALWAYS_WARN", NULL},
|
|
||||||
{"PASS_CHANGE_TRIES", NULL},
|
|
||||||
{"PASS_MAX_LEN", NULL},
|
|
||||||
{"PASS_MIN_LEN", NULL},
|
|
||||||
{"PORTTIME_CHECKS_ENAB", NULL},
|
|
||||||
{"QUOTAS_ENAB", NULL},
|
|
||||||
{"SU_WHEEL_ONLY", NULL},
|
|
||||||
{"ULIMIT", NULL},
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_SYSLOG
|
#ifdef USE_SYSLOG
|
||||||
{"SYSLOG_SG_ENAB", NULL},
|
{"SYSLOG_SG_ENAB", NULL},
|
||||||
{"SYSLOG_SU_ENAB", NULL},
|
{"SYSLOG_SU_ENAB", NULL},
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
{"TCB_AUTH_GROUP", NULL},
|
||||||
|
{"TCB_SYMLINKS", NULL},
|
||||||
|
{"USE_TCB", NULL},
|
||||||
|
#endif
|
||||||
|
{"FORCE_SHADOW", NULL},
|
||||||
|
{"GRANT_AUX_GROUP_SUBIDS", NULL},
|
||||||
|
{"PREVENT_NO_AUTH", NULL},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NUMKNOWNDEFS (sizeof(knowndef_table)/sizeof(knowndef_table[0]))
|
||||||
|
static struct itemdef knowndef_table[] = {
|
||||||
|
#ifdef USE_PAM
|
||||||
|
PAMDEFS
|
||||||
|
#endif
|
||||||
|
FOREIGNDEFS
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef USE_ECONF
|
||||||
|
#ifdef VENDORDIR
|
||||||
|
static const char* vendordir = VENDORDIR;
|
||||||
|
#else
|
||||||
|
static const char* vendordir = NULL;
|
||||||
|
#endif
|
||||||
|
static const char* sysconfdir = "/etc";
|
||||||
|
#else
|
||||||
#ifndef LOGINDEFS
|
#ifndef LOGINDEFS
|
||||||
#define LOGINDEFS "/etc/login.defs"
|
#define LOGINDEFS "/etc/login.defs"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static char def_fname[] = LOGINDEFS; /* login config defs file */
|
static const char* def_fname = LOGINDEFS; /* login config defs file */
|
||||||
|
#endif
|
||||||
static bool def_loaded = false; /* are defs already loaded? */
|
static bool def_loaded = false; /* are defs already loaded? */
|
||||||
|
|
||||||
/* local function prototypes */
|
/* local function prototypes */
|
||||||
@@ -207,7 +267,7 @@ int getdef_num (const char *item, int dflt)
|
|||||||
if ( (getlong (d->value, &val) == 0)
|
if ( (getlong (d->value, &val) == 0)
|
||||||
|| (val > INT_MAX)
|
|| (val > INT_MAX)
|
||||||
|| (val < INT_MIN)) {
|
|| (val < INT_MIN)) {
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("configuration error - cannot parse %s value: '%s'"),
|
_("configuration error - cannot parse %s value: '%s'"),
|
||||||
item, d->value);
|
item, d->value);
|
||||||
return dflt;
|
return dflt;
|
||||||
@@ -242,7 +302,7 @@ unsigned int getdef_unum (const char *item, unsigned int dflt)
|
|||||||
if ( (getlong (d->value, &val) == 0)
|
if ( (getlong (d->value, &val) == 0)
|
||||||
|| (val < 0)
|
|| (val < 0)
|
||||||
|| (val > INT_MAX)) {
|
|| (val > INT_MAX)) {
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("configuration error - cannot parse %s value: '%s'"),
|
_("configuration error - cannot parse %s value: '%s'"),
|
||||||
item, d->value);
|
item, d->value);
|
||||||
return dflt;
|
return dflt;
|
||||||
@@ -275,7 +335,7 @@ long getdef_long (const char *item, long dflt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getlong (d->value, &val) == 0) {
|
if (getlong (d->value, &val) == 0) {
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("configuration error - cannot parse %s value: '%s'"),
|
_("configuration error - cannot parse %s value: '%s'"),
|
||||||
item, d->value);
|
item, d->value);
|
||||||
return dflt;
|
return dflt;
|
||||||
@@ -308,7 +368,7 @@ unsigned long getdef_ulong (const char *item, unsigned long dflt)
|
|||||||
|
|
||||||
if (getulong (d->value, &val) == 0) {
|
if (getulong (d->value, &val) == 0) {
|
||||||
/* FIXME: we should have a getulong */
|
/* FIXME: we should have a getulong */
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("configuration error - cannot parse %s value: '%s'"),
|
_("configuration error - cannot parse %s value: '%s'"),
|
||||||
item, d->value);
|
item, d->value);
|
||||||
return dflt;
|
return dflt;
|
||||||
@@ -346,7 +406,7 @@ int putdef_str (const char *name, const char *value)
|
|||||||
cp = strdup (value);
|
cp = strdup (value);
|
||||||
if (NULL == cp) {
|
if (NULL == cp) {
|
||||||
(void) fputs (_("Could not allocate space for config info.\n"),
|
(void) fputs (_("Could not allocate space for config info.\n"),
|
||||||
stderr);
|
shadow_logfd);
|
||||||
SYSLOG ((LOG_ERR, "could not allocate space for config info"));
|
SYSLOG ((LOG_ERR, "could not allocate space for config info"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -371,7 +431,6 @@ static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
|
|||||||
{
|
{
|
||||||
struct itemdef *ptr;
|
struct itemdef *ptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search into the table.
|
* Search into the table.
|
||||||
*/
|
*/
|
||||||
@@ -386,13 +445,51 @@ static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
|
|||||||
* Item was never found.
|
* Item was never found.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fprintf (stderr,
|
for (ptr = knowndef_table; NULL != ptr->name; ptr++) {
|
||||||
|
if (strcmp (ptr->name, name) == 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf (shadow_logfd,
|
||||||
_("configuration error - unknown item '%s' (notify administrator)\n"),
|
_("configuration error - unknown item '%s' (notify administrator)\n"),
|
||||||
name);
|
name);
|
||||||
SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name));
|
SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name));
|
||||||
|
|
||||||
|
out:
|
||||||
return (struct itemdef *) NULL;
|
return (struct itemdef *) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setdef_config_file - set the default configuration file path
|
||||||
|
*
|
||||||
|
* must be called prior to any def* calls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setdef_config_file (const char* file)
|
||||||
|
{
|
||||||
|
#ifdef USE_ECONF
|
||||||
|
size_t len;
|
||||||
|
char* cp;
|
||||||
|
|
||||||
|
len = strlen(file) + strlen(sysconfdir) + 2;
|
||||||
|
cp = malloc(len);
|
||||||
|
if (cp == NULL)
|
||||||
|
exit (13);
|
||||||
|
snprintf(cp, len, "%s/%s", file, sysconfdir);
|
||||||
|
sysconfdir = cp;
|
||||||
|
#ifdef VENDORDIR
|
||||||
|
len = strlen(file) + strlen(vendordir) + 2;
|
||||||
|
cp = malloc(len);
|
||||||
|
if (cp == NULL)
|
||||||
|
exit (13);
|
||||||
|
snprintf(cp, len, "%s/%s", file, vendordir);
|
||||||
|
vendordir = cp;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
def_fname = file;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* def_load - load configuration table
|
* def_load - load configuration table
|
||||||
*
|
*
|
||||||
@@ -401,20 +498,16 @@ static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
|
|||||||
|
|
||||||
static void def_load (void)
|
static void def_load (void)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_ECONF
|
||||||
|
econf_file *defs_file = NULL;
|
||||||
|
econf_err error;
|
||||||
|
char **keys;
|
||||||
|
size_t key_number;
|
||||||
|
#else
|
||||||
int i;
|
int i;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char buf[1024], *name, *value, *s;
|
char buf[1024], *name, *value, *s;
|
||||||
|
#endif
|
||||||
/*
|
|
||||||
* Open the configuration definitions file.
|
|
||||||
*/
|
|
||||||
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.
|
* Set the initialized flag.
|
||||||
@@ -422,6 +515,56 @@ static void def_load (void)
|
|||||||
*/
|
*/
|
||||||
def_loaded = true;
|
def_loaded = true;
|
||||||
|
|
||||||
|
#ifdef USE_ECONF
|
||||||
|
|
||||||
|
error = econf_readDirs (&defs_file, vendordir, sysconfdir, "login", "defs", " \t", "#");
|
||||||
|
if (error) {
|
||||||
|
if (error == ECONF_NOFILE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SYSLOG ((LOG_CRIT, "cannot open login definitions [%s]",
|
||||||
|
econf_errString(error)));
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = econf_getKeys(defs_file, NULL, &key_number, &keys))) {
|
||||||
|
SYSLOG ((LOG_CRIT, "cannot read login definitions [%s]",
|
||||||
|
econf_errString(error)));
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < key_number; i++) {
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
econf_getStringValue(defs_file, NULL, keys[i], &value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store the value in def_table.
|
||||||
|
*
|
||||||
|
* Ignore failures to load the login.defs file.
|
||||||
|
* The error was already reported to the user and to
|
||||||
|
* syslog. The tools will just use their default values.
|
||||||
|
*/
|
||||||
|
(void)putdef_str (keys[i], value);
|
||||||
|
}
|
||||||
|
|
||||||
|
econf_free (keys);
|
||||||
|
econf_free (defs_file);
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* Open the configuration definitions file.
|
||||||
|
*/
|
||||||
|
fp = fopen (def_fname, "r");
|
||||||
|
if (NULL == fp) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int err = errno;
|
||||||
|
SYSLOG ((LOG_CRIT, "cannot open login definitions %s [%s]",
|
||||||
|
def_fname, strerror (err)));
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go through all of the lines in the file.
|
* Go through all of the lines in the file.
|
||||||
*/
|
*/
|
||||||
@@ -471,6 +614,7 @@ static void def_load (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
(void) fclose (fp);
|
(void) fclose (fp);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ extern unsigned long getdef_ulong (const char *, unsigned long);
|
|||||||
extern unsigned int getdef_unum (const char *, unsigned int);
|
extern unsigned int getdef_unum (const char *, unsigned int);
|
||||||
extern /*@observer@*/ /*@null@*/const char *getdef_str (const char *);
|
extern /*@observer@*/ /*@null@*/const char *getdef_str (const char *);
|
||||||
extern int putdef_str (const char *, const char *);
|
extern int putdef_str (const char *, const char *);
|
||||||
|
extern void setdef_config_file (const char* file);
|
||||||
|
|
||||||
/* default UMASK value if not specified in /etc/login.defs */
|
/* default UMASK value if not specified in /etc/login.defs */
|
||||||
#define GETDEF_DEFAULT_UMASK 022
|
#define GETDEF_DEFAULT_UMASK 022
|
||||||
|
|||||||
+3
-6
@@ -44,22 +44,19 @@
|
|||||||
*/
|
*/
|
||||||
int getulong (const char *numstr, /*@out@*/unsigned long int *result)
|
int getulong (const char *numstr, /*@out@*/unsigned long int *result)
|
||||||
{
|
{
|
||||||
long long int val;
|
unsigned long int val;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
val = strtoll (numstr, &endptr, 0);
|
val = strtoul (numstr, &endptr, 0);
|
||||||
if ( ('\0' == *numstr)
|
if ( ('\0' == *numstr)
|
||||||
|| ('\0' != *endptr)
|
|| ('\0' != *endptr)
|
||||||
|| (ERANGE == errno)
|
|| (ERANGE == errno)
|
||||||
/*@+ignoresigns@*/
|
|
||||||
|| (val != (unsigned long int)val)
|
|
||||||
/*@=ignoresigns@*/
|
|
||||||
) {
|
) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = (unsigned long int)val;
|
*result = val;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+51
-11
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2001 , Michał Moskal
|
* Copyright (c) 2001 , Michał Moskal
|
||||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -80,6 +80,23 @@ static int group_put (const void *ent, FILE * file)
|
|||||||
{
|
{
|
||||||
const struct group *gr = ent;
|
const struct group *gr = ent;
|
||||||
|
|
||||||
|
if ( (NULL == gr)
|
||||||
|
|| (valid_field (gr->gr_name, ":\n") == -1)
|
||||||
|
|| (valid_field (gr->gr_passwd, ":\n") == -1)
|
||||||
|
|| (gr->gr_gid == (gid_t)-1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: fail also if gr->gr_mem == NULL ?*/
|
||||||
|
if (NULL != gr->gr_mem) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; NULL != gr->gr_mem[i]; i++) {
|
||||||
|
if (valid_field (gr->gr_mem[i], ",:\n") == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (putgrent (gr, file) == -1) ? -1 : 0;
|
return (putgrent (gr, file) == -1) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,13 +130,17 @@ static /*@owned@*/struct commonio_db group_db = {
|
|||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
NULL, /* scontext */
|
NULL, /* scontext */
|
||||||
#endif
|
#endif
|
||||||
|
0644, /* st_mode */
|
||||||
|
0, /* st_uid */
|
||||||
|
0, /* st_gid */
|
||||||
NULL, /* head */
|
NULL, /* head */
|
||||||
NULL, /* tail */
|
NULL, /* tail */
|
||||||
NULL, /* cursor */
|
NULL, /* cursor */
|
||||||
false, /* changed */
|
false, /* changed */
|
||||||
false, /* isopen */
|
false, /* isopen */
|
||||||
false, /* locked */
|
false, /* locked */
|
||||||
false /* readonly */
|
false, /* readonly */
|
||||||
|
false /* setname */
|
||||||
};
|
};
|
||||||
|
|
||||||
int gr_setdbname (const char *filename)
|
int gr_setdbname (const char *filename)
|
||||||
@@ -313,13 +334,12 @@ static /*@null@*/struct commonio_entry *merge_group_entries (
|
|||||||
|
|
||||||
/* Concatenate the 2 lines */
|
/* Concatenate the 2 lines */
|
||||||
new_line_len = strlen (gr1->line) + strlen (gr2->line) +1;
|
new_line_len = strlen (gr1->line) + strlen (gr2->line) +1;
|
||||||
new_line = (char *)malloc ((new_line_len + 1) * sizeof(char*));
|
new_line = (char *)malloc (new_line_len + 1);
|
||||||
if (NULL == new_line) {
|
if (NULL == new_line) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line);
|
snprintf(new_line, new_line_len + 1, "%s\n%s", gr1->line, gr2->line);
|
||||||
new_line[new_line_len] = '\0';
|
|
||||||
|
|
||||||
/* Concatenate the 2 list of members */
|
/* Concatenate the 2 list of members */
|
||||||
for (i=0; NULL != gptr1->gr_mem[i]; i++);
|
for (i=0; NULL != gptr1->gr_mem[i]; i++);
|
||||||
@@ -336,7 +356,7 @@ static /*@null@*/struct commonio_entry *merge_group_entries (
|
|||||||
members++;
|
members++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_members = (char **)malloc ( (members+1) * sizeof(char*) );
|
new_members = (char **)calloc ( (members+1), sizeof(char*) );
|
||||||
if (NULL == new_members) {
|
if (NULL == new_members) {
|
||||||
free (new_line);
|
free (new_line);
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
@@ -345,6 +365,8 @@ static /*@null@*/struct commonio_entry *merge_group_entries (
|
|||||||
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];
|
new_members[i] = gptr1->gr_mem[i];
|
||||||
}
|
}
|
||||||
|
/* NULL termination enforced by above calloc */
|
||||||
|
|
||||||
members = i;
|
members = i;
|
||||||
for (i=0; NULL != gptr2->gr_mem[i]; i++) {
|
for (i=0; NULL != gptr2->gr_mem[i]; i++) {
|
||||||
char **pmember = new_members;
|
char **pmember = new_members;
|
||||||
@@ -382,15 +404,19 @@ static int split_groups (unsigned int max_members)
|
|||||||
struct commonio_entry *new;
|
struct commonio_entry *new;
|
||||||
struct group *new_gptr;
|
struct group *new_gptr;
|
||||||
unsigned int members = 0;
|
unsigned int members = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
/* Check if this group must be split */
|
/* Check if this group must be split */
|
||||||
if (!gr->changed)
|
if (!gr->changed) {
|
||||||
continue;
|
continue;
|
||||||
if (NULL == gptr)
|
}
|
||||||
|
if (NULL == gptr) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
for (members = 0; NULL != gptr->gr_mem[members]; members++);
|
for (members = 0; NULL != gptr->gr_mem[members]; members++);
|
||||||
if (members <= max_members)
|
if (members <= max_members) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
new = (struct commonio_entry *) malloc (sizeof *new);
|
new = (struct commonio_entry *) malloc (sizeof *new);
|
||||||
if (NULL == new) {
|
if (NULL == new) {
|
||||||
@@ -408,9 +434,23 @@ static int split_groups (unsigned int max_members)
|
|||||||
new->changed = true;
|
new->changed = true;
|
||||||
|
|
||||||
/* Enforce the maximum number of members on gptr */
|
/* Enforce the maximum number of members on gptr */
|
||||||
gptr->gr_mem[max_members] = NULL;
|
for (i = max_members; NULL != gptr->gr_mem[i]; i++) {
|
||||||
|
free (gptr->gr_mem[i]);
|
||||||
|
gptr->gr_mem[i] = NULL;
|
||||||
|
}
|
||||||
|
/* Shift all the members */
|
||||||
/* The number of members in new_gptr will be check later */
|
/* The number of members in new_gptr will be check later */
|
||||||
new_gptr->gr_mem = &new_gptr->gr_mem[max_members];
|
for (i = 0; NULL != new_gptr->gr_mem[i + max_members]; i++) {
|
||||||
|
if (NULL != new_gptr->gr_mem[i]) {
|
||||||
|
free (new_gptr->gr_mem[i]);
|
||||||
|
}
|
||||||
|
new_gptr->gr_mem[i] = new_gptr->gr_mem[i + max_members];
|
||||||
|
new_gptr->gr_mem[i + max_members] = NULL;
|
||||||
|
}
|
||||||
|
for (; NULL != new_gptr->gr_mem[i]; i++) {
|
||||||
|
free (new_gptr->gr_mem[i]);
|
||||||
|
new_gptr->gr_mem[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* insert the new entry in the list */
|
/* insert the new entry in the list */
|
||||||
new->prev = gr;
|
new->prev = gr;
|
||||||
|
|||||||
+59
-7
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2001 , Michał Moskal
|
* Copyright (c) 2001 , Michał Moskal
|
||||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2013, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -48,25 +48,37 @@
|
|||||||
if (NULL == gr) {
|
if (NULL == gr) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*gr = *grent;
|
/* The libc might define other fields. They won't be copied. */
|
||||||
|
memset (gr, 0, sizeof *gr);
|
||||||
|
gr->gr_gid = grent->gr_gid;
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
gr->gr_name = strdup (grent->gr_name);
|
gr->gr_name = strdup (grent->gr_name);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == gr->gr_name) {
|
if (NULL == gr->gr_name) {
|
||||||
|
gr_free(gr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
gr->gr_passwd = strdup (grent->gr_passwd);
|
gr->gr_passwd = strdup (grent->gr_passwd);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == gr->gr_passwd) {
|
if (NULL == gr->gr_passwd) {
|
||||||
|
gr_free(gr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; grent->gr_mem[i]; i++);
|
for (i = 0; grent->gr_mem[i]; i++);
|
||||||
|
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
gr->gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
gr->gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == gr->gr_mem) {
|
if (NULL == gr->gr_mem) {
|
||||||
|
gr_free(gr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (i = 0; grent->gr_mem[i]; i++) {
|
for (i = 0; grent->gr_mem[i]; i++) {
|
||||||
gr->gr_mem[i] = strdup (grent->gr_mem[i]);
|
gr->gr_mem[i] = strdup (grent->gr_mem[i]);
|
||||||
if (NULL == gr->gr_mem[i]) {
|
if (NULL == gr->gr_mem[i]) {
|
||||||
|
gr_free(gr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,15 +87,55 @@
|
|||||||
return gr;
|
return gr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gr_free_members (struct group *grent)
|
||||||
|
{
|
||||||
|
if (NULL != grent->gr_mem) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; NULL != grent->gr_mem[i]; i++) {
|
||||||
|
free (grent->gr_mem[i]);
|
||||||
|
}
|
||||||
|
free (grent->gr_mem);
|
||||||
|
grent->gr_mem = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
||||||
{
|
{
|
||||||
free (grent->gr_name);
|
free (grent->gr_name);
|
||||||
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
if (NULL != grent->gr_passwd) {
|
||||||
free (grent->gr_passwd);
|
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
||||||
while (*(grent->gr_mem)) {
|
free (grent->gr_passwd);
|
||||||
free (*(grent->gr_mem));
|
|
||||||
grent->gr_mem++;
|
|
||||||
}
|
}
|
||||||
|
gr_free_members(grent);
|
||||||
free (grent);
|
free (grent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool gr_append_member(struct group *grp, char *member)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (NULL == grp->gr_mem || grp->gr_mem[0] == NULL) {
|
||||||
|
grp->gr_mem = (char **)malloc(2 * sizeof(char *));
|
||||||
|
if (!grp->gr_mem) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
grp->gr_mem[0] = strdup(member);
|
||||||
|
if (!grp->gr_mem[0]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
grp->gr_mem[1] = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; grp->gr_mem[i]; i++) ;
|
||||||
|
grp->gr_mem = realloc(grp->gr_mem, (i + 2) * sizeof(char *));
|
||||||
|
if (NULL == grp->gr_mem) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
grp->gr_mem[i] = strdup(member);
|
||||||
|
if (NULL == grp->gr_mem[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
grp->gr_mem[i + 1] = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
+3
-3
@@ -216,13 +216,13 @@ void endsgent (void)
|
|||||||
static char *buf = NULL;
|
static char *buf = NULL;
|
||||||
|
|
||||||
char *cp;
|
char *cp;
|
||||||
struct sgrp *ret;
|
|
||||||
|
|
||||||
if (0 == buflen) {
|
if (0 == buflen) {
|
||||||
buf = (char *) malloc (BUFSIZ);
|
buf = (char *) malloc (BUFSIZ);
|
||||||
if (NULL == buf) {
|
if (NULL == buf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
buflen = BUFSIZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL == fp) {
|
if (NULL == fp) {
|
||||||
@@ -230,9 +230,9 @@ void endsgent (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
while (fgetsx (buf, (int) sizeof buf, fp) == buf)
|
while (fgetsx (buf, (int) buflen, fp) == buf)
|
||||||
#else
|
#else
|
||||||
if (fgetsx (buf, (int) sizeof buf, fp) == buf)
|
if (fgetsx (buf, (int) buflen, fp) == buf)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
while ( ((cp = strrchr (buf, '\n')) == NULL)
|
while ( ((cp = strrchr (buf, '\n')) == NULL)
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@
|
|||||||
struct sgrp {
|
struct sgrp {
|
||||||
char *sg_name; /* group name */
|
char *sg_name; /* group name */
|
||||||
char *sg_passwd; /* group password */
|
char *sg_passwd; /* group password */
|
||||||
char **sg_adm; /* group administator list */
|
char **sg_adm; /* group administrator list */
|
||||||
char **sg_mem; /* group membership list */
|
char **sg_mem; /* group membership list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+26
-34
@@ -3,57 +3,49 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#ifdef USE_NSCD
|
#ifdef USE_NSCD
|
||||||
|
|
||||||
/* because of TEMP_FAILURE_RETRY */
|
|
||||||
#ifndef _GNU_SOURCE
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <features.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <spawn.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include "exitcodes.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
#include "prototypes.h"
|
||||||
#include "nscd.h"
|
#include "nscd.h"
|
||||||
|
|
||||||
#define MSG_NSCD_FLUSH_CACHE_FAILED "Failed to flush the nscd cache.\n"
|
#define MSG_NSCD_FLUSH_CACHE_FAILED "%s: Failed to flush the nscd cache.\n"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nscd_flush_cache - flush specified service buffer in nscd cache
|
* nscd_flush_cache - flush specified service buffer in nscd cache
|
||||||
*/
|
*/
|
||||||
int nscd_flush_cache (const char *service)
|
int nscd_flush_cache (const char *service)
|
||||||
{
|
{
|
||||||
pid_t pid, termpid;
|
int status, code;
|
||||||
int err, status;
|
const char *cmd = "/usr/sbin/nscd";
|
||||||
char *spawnedArgs[] = {"/usr/sbin/nscd", "nscd", "-i", service, NULL};
|
const char *spawnedArgs[] = {"nscd", "-i", service, NULL};
|
||||||
char *spawnedEnv[] = {NULL};
|
const char *spawnedEnv[] = {NULL};
|
||||||
|
|
||||||
/* spawn process */
|
if (run_command (cmd, spawnedArgs, spawnedEnv, &status) != 0) {
|
||||||
err = posix_spawn (&pid, spawnedArgs[0], NULL, NULL,
|
/* run_command writes its own more detailed message. */
|
||||||
spawnedArgs, spawnedEnv);
|
(void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||||
if(0 != err)
|
|
||||||
{
|
|
||||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
|
||||||
(void) fprintf (stderr, "posix_spawn() error=%d\n", err);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for the spawned process to exit */
|
code = WEXITSTATUS (status);
|
||||||
termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
|
if (!WIFEXITED (status)) {
|
||||||
if (-1 == termpid)
|
(void) fprintf (shadow_logfd,
|
||||||
{
|
_("%s: nscd did not terminate normally (signal %d)\n"),
|
||||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
Prog, WTERMSIG (status));
|
||||||
perror("waitpid");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (code == E_CMD_NOTFOUND) {
|
||||||
else if (termpid != pid)
|
/* nscd is not installed, or it is installed but uses an
|
||||||
{
|
interpreter that is missing. Probably the former. */
|
||||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
return 0;
|
||||||
(void) fprintf (stderr, "waitpid returned %ld != %ld\n",
|
} else if (code == 1) {
|
||||||
(long int) termpid, (long int) pid);
|
/* nscd is installed, but it isn't active. */
|
||||||
|
return 0;
|
||||||
|
} else if (code != 0) {
|
||||||
|
(void) fprintf (shadow_logfd, _("%s: nscd exited with status %d\n"),
|
||||||
|
Prog, code);
|
||||||
|
(void) fprintf (shadow_logfd, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include "../libsubid/subid.h"
|
||||||
|
|
||||||
|
#define NSSWITCH "/etc/nsswitch.conf"
|
||||||
|
|
||||||
|
// NSS plugin handling for subids
|
||||||
|
// If nsswitch has a line like
|
||||||
|
// subid: sssd
|
||||||
|
// then sssd will be consulted for subids. Unlike normal NSS dbs,
|
||||||
|
// only one db is supported at a time. That's open to debate, but
|
||||||
|
// the subids are a pretty limited resource, and local files seem
|
||||||
|
// bound to step on any other allocations leading to insecure
|
||||||
|
// conditions.
|
||||||
|
static atomic_flag nss_init_started;
|
||||||
|
static atomic_bool nss_init_completed;
|
||||||
|
|
||||||
|
static struct subid_nss_ops *subid_nss;
|
||||||
|
|
||||||
|
bool nss_is_initialized() {
|
||||||
|
return atomic_load(&nss_init_completed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nss_exit() {
|
||||||
|
if (nss_is_initialized() && subid_nss) {
|
||||||
|
dlclose(subid_nss->handle);
|
||||||
|
free(subid_nss);
|
||||||
|
subid_nss = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsswitch_path is an argument only to support testing.
|
||||||
|
void nss_init(char *nsswitch_path) {
|
||||||
|
FILE *nssfp = NULL;
|
||||||
|
char *line = NULL, *p, *token, *saveptr;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
if (atomic_flag_test_and_set(&nss_init_started)) {
|
||||||
|
// Another thread has started nss_init, wait for it to complete
|
||||||
|
while (!atomic_load(&nss_init_completed))
|
||||||
|
usleep(100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nsswitch_path)
|
||||||
|
nsswitch_path = NSSWITCH;
|
||||||
|
|
||||||
|
// read nsswitch.conf to check for a line like:
|
||||||
|
// subid: files
|
||||||
|
nssfp = fopen(nsswitch_path, "r");
|
||||||
|
if (!nssfp) {
|
||||||
|
fprintf(shadow_logfd, "Failed opening %s: %m", nsswitch_path);
|
||||||
|
atomic_store(&nss_init_completed, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ((getline(&line, &len, nssfp)) != -1) {
|
||||||
|
if (line[0] == '\0' || line[0] == '#')
|
||||||
|
continue;
|
||||||
|
if (strlen(line) < 8)
|
||||||
|
continue;
|
||||||
|
if (strncasecmp(line, "subid:", 6) != 0)
|
||||||
|
continue;
|
||||||
|
p = &line[6];
|
||||||
|
while ((*p) && isspace(*p))
|
||||||
|
p++;
|
||||||
|
if (!*p)
|
||||||
|
continue;
|
||||||
|
for (token = strtok_r(p, " \n\t", &saveptr);
|
||||||
|
token;
|
||||||
|
token = strtok_r(NULL, " \n\t", &saveptr)) {
|
||||||
|
char libname[65];
|
||||||
|
void *h;
|
||||||
|
if (strcmp(token, "files") == 0) {
|
||||||
|
subid_nss = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (strlen(token) > 50) {
|
||||||
|
fprintf(shadow_logfd, "Subid NSS module name too long (longer than 50 characters): %s\n", token);
|
||||||
|
fprintf(shadow_logfd, "Using files\n");
|
||||||
|
subid_nss = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
snprintf(libname, 64, "libsubid_%s.so", token);
|
||||||
|
h = dlopen(libname, RTLD_LAZY);
|
||||||
|
if (!h) {
|
||||||
|
fprintf(shadow_logfd, "Error opening %s: %s\n", libname, dlerror());
|
||||||
|
fprintf(shadow_logfd, "Using files\n");
|
||||||
|
subid_nss = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
subid_nss = malloc(sizeof(*subid_nss));
|
||||||
|
if (!subid_nss) {
|
||||||
|
dlclose(h);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
subid_nss->has_range = dlsym(h, "shadow_subid_has_range");
|
||||||
|
if (!subid_nss->has_range) {
|
||||||
|
fprintf(shadow_logfd, "%s did not provide @has_range@\n", libname);
|
||||||
|
dlclose(h);
|
||||||
|
free(subid_nss);
|
||||||
|
subid_nss = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
subid_nss->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges");
|
||||||
|
if (!subid_nss->list_owner_ranges) {
|
||||||
|
fprintf(shadow_logfd, "%s did not provide @list_owner_ranges@\n", libname);
|
||||||
|
dlclose(h);
|
||||||
|
free(subid_nss);
|
||||||
|
subid_nss = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners");
|
||||||
|
if (!subid_nss->find_subid_owners) {
|
||||||
|
fprintf(shadow_logfd, "%s did not provide @find_subid_owners@\n", libname);
|
||||||
|
dlclose(h);
|
||||||
|
free(subid_nss);
|
||||||
|
subid_nss = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
subid_nss->handle = h;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
fprintf(shadow_logfd, "No usable subid NSS module found, using files\n");
|
||||||
|
// subid_nss has to be null here, but to ease reviews:
|
||||||
|
free(subid_nss);
|
||||||
|
subid_nss = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
atomic_store(&nss_init_completed, true);
|
||||||
|
free(line);
|
||||||
|
if (nssfp) {
|
||||||
|
atexit(nss_exit);
|
||||||
|
fclose(nssfp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct subid_nss_ops *get_subid_nss_handle() {
|
||||||
|
nss_init(NULL);
|
||||||
|
return subid_nss;
|
||||||
|
}
|
||||||
+151
-32
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -42,6 +42,8 @@
|
|||||||
#ifndef _PROTOTYPES_H
|
#ifndef _PROTOTYPES_H
|
||||||
#define _PROTOTYPES_H
|
#define _PROTOTYPES_H
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#ifdef USE_UTMPX
|
#ifdef USE_UTMPX
|
||||||
#include <utmpx.h>
|
#include <utmpx.h>
|
||||||
@@ -57,7 +59,8 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "commonio.h"
|
#include "commonio.h"
|
||||||
|
|
||||||
extern char *Prog;
|
extern /*@observer@*/ const char *Prog; /* Program name showed in error messages */
|
||||||
|
extern FILE *shadow_logfd; /* file descripter to which error messages are printed */
|
||||||
|
|
||||||
/* addgrps.c */
|
/* addgrps.c */
|
||||||
#if defined (HAVE_SETGROUPS) && ! defined (USE_PAM)
|
#if defined (HAVE_SETGROUPS) && ! defined (USE_PAM)
|
||||||
@@ -70,27 +73,37 @@ extern int expire (const struct passwd *, /*@null@*/const struct spwd *);
|
|||||||
/* isexpired.c */
|
/* isexpired.c */
|
||||||
extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *);
|
extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *);
|
||||||
|
|
||||||
|
/* btrfs.c */
|
||||||
|
#ifdef WITH_BTRFS
|
||||||
|
extern int btrfs_create_subvolume(const char *path);
|
||||||
|
extern int btrfs_remove_subvolume(const char *path);
|
||||||
|
extern int btrfs_is_subvolume(const char *path);
|
||||||
|
extern int is_btrfs(const char *path);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* basename() renamed to Basename() to avoid libc name space confusion */
|
/* basename() renamed to Basename() to avoid libc name space confusion */
|
||||||
/* basename.c */
|
/* basename.c */
|
||||||
extern char *Basename (char *str);
|
extern /*@observer@*/const char *Basename (const char *str);
|
||||||
|
|
||||||
/* chowndir.c */
|
/* chowndir.c */
|
||||||
extern int chown_tree (const char *, uid_t, uid_t, gid_t, gid_t);
|
extern int chown_tree (const char *root,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
|
||||||
/* chowntty.c */
|
/* chowntty.c */
|
||||||
extern void chown_tty (const struct passwd *);
|
extern void chown_tty (const struct passwd *);
|
||||||
|
|
||||||
/* cleanup.c */
|
/* cleanup.c */
|
||||||
typedef void (*cleanup_function) (/*@null@*/void *arg);
|
typedef /*@null@*/void (*cleanup_function) (/*@null@*/void *arg);
|
||||||
void add_cleanup (cleanup_function pcf, /*@null@*/void *arg);
|
void add_cleanup (/*@notnull@*/cleanup_function pcf, /*@null@*/void *arg);
|
||||||
void del_cleanup (cleanup_function pcf);
|
void del_cleanup (/*@notnull@*/cleanup_function pcf);
|
||||||
void do_cleanups (void);
|
void do_cleanups (void);
|
||||||
|
|
||||||
/* cleanup_group.c */
|
/* cleanup_group.c */
|
||||||
struct cleanup_info_mod {
|
struct cleanup_info_mod {
|
||||||
char *audit_msg;
|
char *audit_msg;
|
||||||
char *action;
|
char *action;
|
||||||
char *name;
|
/*@observer@*/const char *name;
|
||||||
};
|
};
|
||||||
void cleanup_report_add_group (void *group_name);
|
void cleanup_report_add_group (void *group_name);
|
||||||
void cleanup_report_add_group_group (void *group_name);
|
void cleanup_report_add_group_group (void *group_name);
|
||||||
@@ -116,15 +129,13 @@ extern bool console (const char *);
|
|||||||
|
|
||||||
/* copydir.c */
|
/* copydir.c */
|
||||||
extern int copy_tree (const char *src_root, const char *dst_root,
|
extern int copy_tree (const char *src_root, const char *dst_root,
|
||||||
long int uid, long int gid);
|
bool copy_root,
|
||||||
extern int remove_tree (const char *root);
|
bool reset_selinux,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
#ifdef WITH_SELINUX
|
gid_t old_gid, gid_t new_gid);
|
||||||
extern int selinux_file_context (const char *dst_name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* encrypt.c */
|
/* encrypt.c */
|
||||||
extern char *pw_encrypt (const char *, const char *);
|
extern /*@exposed@*//*@null@*/char *pw_encrypt (const char *, const char *);
|
||||||
|
|
||||||
/* entry.c */
|
/* entry.c */
|
||||||
extern void pw_entry (const char *, struct passwd *);
|
extern void pw_entry (const char *, struct passwd *);
|
||||||
@@ -149,11 +160,20 @@ extern int find_new_uid (bool sys_user,
|
|||||||
uid_t *uid,
|
uid_t *uid,
|
||||||
/*@null@*/uid_t const *preferred_uid);
|
/*@null@*/uid_t const *preferred_uid);
|
||||||
|
|
||||||
|
#ifdef ENABLE_SUBIDS
|
||||||
|
/* find_new_sub_gids.c */
|
||||||
|
extern int find_new_sub_gids (gid_t *range_start, unsigned long *range_count);
|
||||||
|
|
||||||
|
/* find_new_sub_uids.c */
|
||||||
|
extern int find_new_sub_uids (uid_t *range_start, unsigned long *range_count);
|
||||||
|
#endif /* ENABLE_SUBIDS */
|
||||||
|
|
||||||
|
|
||||||
/* get_gid.c */
|
/* get_gid.c */
|
||||||
extern int get_gid (const char *gidstr, gid_t *gid);
|
extern int get_gid (const char *gidstr, gid_t *gid);
|
||||||
|
|
||||||
/* getgr_nam_gid.c */
|
/* getgr_nam_gid.c */
|
||||||
extern /*@null@*/struct group *getgr_nam_gid (const char *grname);
|
extern /*@only@*//*@null@*/struct group *getgr_nam_gid (/*@null@*/const char *grname);
|
||||||
|
|
||||||
/* getlong.c */
|
/* getlong.c */
|
||||||
extern int getlong (const char *numstr, /*@out@*/long int *result);
|
extern int getlong (const char *numstr, /*@out@*/long int *result);
|
||||||
@@ -166,6 +186,9 @@ extern int getrange (char *range,
|
|||||||
unsigned long *min, bool *has_min,
|
unsigned long *min, bool *has_min,
|
||||||
unsigned long *max, bool *has_max);
|
unsigned long *max, bool *has_max);
|
||||||
|
|
||||||
|
/* gettime.c */
|
||||||
|
extern time_t gettime ();
|
||||||
|
|
||||||
/* get_uid.c */
|
/* get_uid.c */
|
||||||
extern int get_uid (const char *uidstr, uid_t *uid);
|
extern int get_uid (const char *uidstr, uid_t *uid);
|
||||||
|
|
||||||
@@ -184,7 +207,9 @@ extern void __gr_set_changed (void);
|
|||||||
|
|
||||||
/* groupmem.c */
|
/* groupmem.c */
|
||||||
extern /*@null@*/ /*@only@*/struct group *__gr_dup (const struct group *grent);
|
extern /*@null@*/ /*@only@*/struct group *__gr_dup (const struct group *grent);
|
||||||
|
extern void gr_free_members (struct group *grent);
|
||||||
extern void gr_free (/*@out@*/ /*@only@*/struct group *grent);
|
extern void gr_free (/*@out@*/ /*@only@*/struct group *grent);
|
||||||
|
extern bool gr_append_member (struct group *grp, char *member);
|
||||||
|
|
||||||
/* hushed.c */
|
/* hushed.c */
|
||||||
extern bool hushed (const char *username);
|
extern bool hushed (const char *username);
|
||||||
@@ -236,18 +261,74 @@ extern void mailcheck (void);
|
|||||||
extern void motd (void);
|
extern void motd (void);
|
||||||
|
|
||||||
/* myname.c */
|
/* myname.c */
|
||||||
extern /*@null@*/struct passwd *get_my_pwent (void);
|
extern /*@null@*//*@only@*/struct passwd *get_my_pwent (void);
|
||||||
|
|
||||||
/* pam_pass_non_interractive.c */
|
/* nss.c */
|
||||||
|
#include <libsubid/subid.h>
|
||||||
|
extern void nss_init(char *nsswitch_path);
|
||||||
|
extern bool nss_is_initialized();
|
||||||
|
|
||||||
|
struct subid_nss_ops {
|
||||||
|
/*
|
||||||
|
* nss_has_range: does a user own a given subid range
|
||||||
|
*
|
||||||
|
* @owner: username
|
||||||
|
* @start: first subid in queried range
|
||||||
|
* @count: number of subids in queried range
|
||||||
|
* @idtype: subuid or subgid
|
||||||
|
* @result: true if @owner has been allocated the subid range.
|
||||||
|
*
|
||||||
|
* returns success if the module was able to determine an answer (true or false),
|
||||||
|
* else an error status.
|
||||||
|
*/
|
||||||
|
enum subid_status (*has_range)(const char *owner, unsigned long start, unsigned long count, enum subid_type idtype, bool *result);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nss_list_owner_ranges: list the subid ranges delegated to a user.
|
||||||
|
*
|
||||||
|
* @owner - string representing username being queried
|
||||||
|
* @id_type - subuid or subgid
|
||||||
|
* @ranges - pointer to an array of struct subid_range, or NULL. The
|
||||||
|
* returned array must be freed by the caller.
|
||||||
|
* @count - pointer to an integer into which the number of returned ranges
|
||||||
|
* is written.
|
||||||
|
|
||||||
|
* returns success if the module was able to determine an answer,
|
||||||
|
* else an error status.
|
||||||
|
*/
|
||||||
|
enum subid_status (*list_owner_ranges)(const char *owner, enum subid_type id_type, struct subid_range **ranges, int *count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nss_find_subid_owners: find uids who own a given subuid or subgid.
|
||||||
|
*
|
||||||
|
* @id - the delegated id (subuid or subgid) being queried
|
||||||
|
* @id_type - subuid or subgid
|
||||||
|
* @uids - pointer to an array of uids which will be allocated by
|
||||||
|
* nss_find_subid_owners()
|
||||||
|
* @count - number of uids found
|
||||||
|
*
|
||||||
|
* returns success if the module was able to determine an answer,
|
||||||
|
* else an error status.
|
||||||
|
*/
|
||||||
|
enum subid_status (*find_subid_owners)(unsigned long id, enum subid_type id_type, uid_t **uids, int *count);
|
||||||
|
|
||||||
|
/* The dlsym handle to close */
|
||||||
|
void *handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct subid_nss_ops *get_subid_nss_handle();
|
||||||
|
|
||||||
|
|
||||||
|
/* pam_pass_non_interactive.c */
|
||||||
#ifdef USE_PAM
|
#ifdef USE_PAM
|
||||||
extern int do_pam_passwd_non_interractive (const char *pam_service,
|
extern int do_pam_passwd_non_interactive (const char *pam_service,
|
||||||
const char *username,
|
const char *username,
|
||||||
const char* password);
|
const char* password);
|
||||||
#endif /* USE_PAM */
|
#endif /* USE_PAM */
|
||||||
|
|
||||||
/* obscure.c */
|
/* obscure.c */
|
||||||
#ifndef USE_PAM
|
#ifndef USE_PAM
|
||||||
extern int obscure (const char *, const char *, const struct passwd *);
|
extern bool obscure (const char *, const char *, const struct passwd *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* pam_pass.c */
|
/* pam_pass.c */
|
||||||
@@ -258,6 +339,21 @@ extern void do_pam_passwd (const char *user, bool silent, bool change_expired);
|
|||||||
/* port.c */
|
/* port.c */
|
||||||
extern bool isttytime (const char *, const char *, time_t);
|
extern bool isttytime (const char *, const char *, time_t);
|
||||||
|
|
||||||
|
/* prefix_flag.c */
|
||||||
|
extern const char* process_prefix_flag (const char* short_opt, int argc, char **argv);
|
||||||
|
extern struct group *prefix_getgrnam(const char *name);
|
||||||
|
extern struct group *prefix_getgrgid(gid_t gid);
|
||||||
|
extern struct passwd *prefix_getpwuid(uid_t uid);
|
||||||
|
extern struct passwd *prefix_getpwnam(const char* name);
|
||||||
|
extern struct spwd *prefix_getspnam(const char* name);
|
||||||
|
extern struct group *prefix_getgr_nam_gid(const char *grname);
|
||||||
|
extern void prefix_setpwent();
|
||||||
|
extern struct passwd* prefix_getpwent();
|
||||||
|
extern void prefix_endpwent();
|
||||||
|
extern void prefix_setgrent();
|
||||||
|
extern struct group* prefix_getgrent();
|
||||||
|
extern void prefix_endgrent();
|
||||||
|
|
||||||
/* pwd2spwd.c */
|
/* pwd2spwd.c */
|
||||||
#ifndef USE_PAM
|
#ifndef USE_PAM
|
||||||
extern struct spwd *pwd_to_spwd (const struct passwd *);
|
extern struct spwd *pwd_to_spwd (const struct passwd *);
|
||||||
@@ -280,12 +376,32 @@ extern /*@dependent@*/ /*@null@*/struct commonio_entry *__pw_get_head (void);
|
|||||||
extern /*@null@*/ /*@only@*/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);
|
extern void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent);
|
||||||
|
|
||||||
|
/* remove_tree.c */
|
||||||
|
extern int remove_tree (const char *root, bool remove_root);
|
||||||
|
|
||||||
/* rlogin.c */
|
/* rlogin.c */
|
||||||
extern int do_rlogin (const char *remote_host, char *name, size_t namelen,
|
extern int do_rlogin (const char *remote_host, char *name, size_t namelen,
|
||||||
char *term, size_t termlen);
|
char *term, size_t termlen);
|
||||||
|
|
||||||
|
/* root_flag.c */
|
||||||
|
extern void process_root_flag (const char* short_opt, int argc, char **argv);
|
||||||
|
|
||||||
/* salt.c */
|
/* salt.c */
|
||||||
extern /*@observer@*/const char *crypt_make_salt (/*@null@*/const char *meth, /*@null@*/void *arg);
|
extern /*@observer@*/const char *crypt_make_salt (/*@null@*//*@observer@*/const char *meth, /*@null@*/void *arg);
|
||||||
|
|
||||||
|
/* selinux.c */
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
extern int set_selinux_file_context (const char *dst_name, mode_t mode);
|
||||||
|
extern void reset_selinux_handle (void);
|
||||||
|
extern int reset_selinux_file_context (void);
|
||||||
|
extern int check_selinux_permit (const char *perm_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* semanage.c */
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
extern int set_seuser(const char *login_name, const char *seuser_name);
|
||||||
|
extern int del_seuser(const char *login_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* setugid.c */
|
/* setugid.c */
|
||||||
extern int setup_groups (const struct passwd *info);
|
extern int setup_groups (const struct passwd *info);
|
||||||
@@ -331,17 +447,17 @@ extern void spw_free (/*@out@*/ /*@only@*/struct spwd *spent);
|
|||||||
/* shell.c */
|
/* shell.c */
|
||||||
extern int shell (const char *file, /*@null@*/const char *arg, char *const envp[]);
|
extern int shell (const char *file, /*@null@*/const char *arg, char *const envp[]);
|
||||||
|
|
||||||
/* system.c */
|
/* spawn.c */
|
||||||
extern int safe_system (const char *command,
|
extern int run_command (const char *cmd, const char *argv[],
|
||||||
const char *argv[],
|
/*@null@*/const char *envp[], /*@out@*/int *status);
|
||||||
const char *env[],
|
|
||||||
int ignore_stderr);
|
|
||||||
|
|
||||||
/* strtoday.c */
|
/* strtoday.c */
|
||||||
extern long strtoday (const char *);
|
extern long strtoday (const char *);
|
||||||
|
|
||||||
/* suauth.c */
|
/* suauth.c */
|
||||||
extern int check_su_auth (const char *actual_id, const char *wanted_id);
|
extern int check_su_auth (const char *actual_id,
|
||||||
|
const char *wanted_id,
|
||||||
|
bool su_to_root);
|
||||||
|
|
||||||
/* sulog.c */
|
/* sulog.c */
|
||||||
extern void sulog (const char *tty,
|
extern void sulog (const char *tty,
|
||||||
@@ -357,7 +473,7 @@ extern void ttytype (const char *);
|
|||||||
|
|
||||||
/* tz.c */
|
/* tz.c */
|
||||||
#ifndef USE_PAM
|
#ifndef USE_PAM
|
||||||
extern char *tz (const char *);
|
extern /*@observer@*/const char *tz (const char *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ulimit.c */
|
/* ulimit.c */
|
||||||
@@ -367,17 +483,19 @@ extern int set_filesize_limit (int blocks);
|
|||||||
extern int user_busy (const char *name, uid_t uid);
|
extern int user_busy (const char *name, uid_t uid);
|
||||||
|
|
||||||
/* utmp.c */
|
/* utmp.c */
|
||||||
|
#ifndef USE_UTMPX
|
||||||
extern /*@null@*/struct utmp *get_current_utmp (void);
|
extern /*@null@*/struct utmp *get_current_utmp (void);
|
||||||
extern struct utmp *prepare_utmp (const char *name,
|
extern struct utmp *prepare_utmp (const char *name,
|
||||||
const char *line,
|
const char *line,
|
||||||
const char *host,
|
const char *host,
|
||||||
/*@null@*/const struct utmp *ut);
|
/*@null@*/const struct utmp *ut);
|
||||||
extern int setutmp (struct utmp *ut);
|
extern int setutmp (struct utmp *ut);
|
||||||
#ifdef USE_UTMPX
|
#else
|
||||||
|
extern /*@null@*/struct utmpx *get_current_utmp (void);
|
||||||
extern struct utmpx *prepare_utmpx (const char *name,
|
extern struct utmpx *prepare_utmpx (const char *name,
|
||||||
const char *line,
|
const char *line,
|
||||||
const char *host,
|
const char *host,
|
||||||
/*@null@*/const struct utmp *ut);
|
/*@null@*/const struct utmpx *ut);
|
||||||
extern int setutmpx (struct utmpx *utx);
|
extern int setutmpx (struct utmpx *utx);
|
||||||
#endif /* USE_UTMPX */
|
#endif /* USE_UTMPX */
|
||||||
|
|
||||||
@@ -385,9 +503,10 @@ extern int setutmpx (struct utmpx *utx);
|
|||||||
extern bool valid (const char *, const struct passwd *);
|
extern bool valid (const char *, const struct passwd *);
|
||||||
|
|
||||||
/* xmalloc.c */
|
/* xmalloc.c */
|
||||||
extern /*@maynotreturn@*/ /*@out@*//*@only@*/char *xmalloc (size_t size)
|
extern /*@maynotreturn@*/ /*@only@*//*@out@*//*@notnull@*/char *xmalloc (size_t size)
|
||||||
/*@ensures MaxSet(result) == (size - 1); @*/;
|
/*@ensures MaxSet(result) == (size - 1); @*/;
|
||||||
extern /*@maynotreturn@*/ /*@only@*/char *xstrdup (const char *);
|
extern /*@maynotreturn@*/ /*@only@*//*@notnull@*/char *xstrdup (const char *);
|
||||||
|
extern void xfree(void *ap);
|
||||||
|
|
||||||
/* xgetpwnam.c */
|
/* xgetpwnam.c */
|
||||||
extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *);
|
extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *);
|
||||||
|
|||||||
+8
-2
@@ -73,6 +73,7 @@ int pw_auth (const char *cipher,
|
|||||||
char prompt[1024];
|
char prompt[1024];
|
||||||
char *clear = NULL;
|
char *clear = NULL;
|
||||||
const char *cp;
|
const char *cp;
|
||||||
|
const char *encrypted;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
#ifdef SKEY
|
#ifdef SKEY
|
||||||
@@ -126,7 +127,7 @@ int pw_auth (const char *cipher,
|
|||||||
#ifdef SKEY
|
#ifdef SKEY
|
||||||
/*
|
/*
|
||||||
* If the user has an S/KEY entry show them the pertinent info
|
* If the user has an S/KEY entry show them the pertinent info
|
||||||
* and then we can try validating the created cyphertext and the SKEY.
|
* and then we can try validating the created ciphertext and the SKEY.
|
||||||
* If there is no SKEY information we default to not using SKEY.
|
* If there is no SKEY information we default to not using SKEY.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -177,7 +178,12 @@ int pw_auth (const char *cipher,
|
|||||||
* the results there as well.
|
* the results there as well.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retval = strcmp (pw_encrypt (input, cipher), cipher);
|
encrypted = pw_encrypt (input, cipher);
|
||||||
|
if (NULL != encrypted) {
|
||||||
|
retval = strcmp (encrypted, cipher);
|
||||||
|
} else {
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SKEY
|
#ifdef SKEY
|
||||||
/*
|
/*
|
||||||
|
|||||||
+16
-1
@@ -72,6 +72,17 @@ static int passwd_put (const void *ent, FILE * file)
|
|||||||
{
|
{
|
||||||
const struct passwd *pw = ent;
|
const struct passwd *pw = ent;
|
||||||
|
|
||||||
|
if ( (NULL == pw)
|
||||||
|
|| (valid_field (pw->pw_name, ":\n") == -1)
|
||||||
|
|| (valid_field (pw->pw_passwd, ":\n") == -1)
|
||||||
|
|| (pw->pw_uid == (uid_t)-1)
|
||||||
|
|| (pw->pw_gid == (gid_t)-1)
|
||||||
|
|| (valid_field (pw->pw_gecos, ":\n") == -1)
|
||||||
|
|| (valid_field (pw->pw_dir, ":\n") == -1)
|
||||||
|
|| (valid_field (pw->pw_shell, ":\n") == -1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return (putpwent (pw, file) == -1) ? -1 : 0;
|
return (putpwent (pw, file) == -1) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,13 +105,17 @@ static struct commonio_db passwd_db = {
|
|||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
NULL, /* scontext */
|
NULL, /* scontext */
|
||||||
#endif
|
#endif
|
||||||
|
0644, /* st_mode */
|
||||||
|
0, /* st_uid */
|
||||||
|
0, /* st_gid */
|
||||||
NULL, /* head */
|
NULL, /* head */
|
||||||
NULL, /* tail */
|
NULL, /* tail */
|
||||||
NULL, /* cursor */
|
NULL, /* cursor */
|
||||||
false, /* changed */
|
false, /* changed */
|
||||||
false, /* isopen */
|
false, /* isopen */
|
||||||
false, /* locked */
|
false, /* locked */
|
||||||
false /* readonly */
|
false, /* readonly */
|
||||||
|
false /* setname */
|
||||||
};
|
};
|
||||||
|
|
||||||
int pw_setdbname (const char *filename)
|
int pw_setdbname (const char *filename)
|
||||||
|
|||||||
+31
-9
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2001 , Michał Moskal
|
* Copyright (c) 2001 , Michał Moskal
|
||||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2013, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -48,25 +48,43 @@
|
|||||||
if (NULL == pw) {
|
if (NULL == pw) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*pw = *pwent;
|
/* The libc might define other fields. They won't be copied. */
|
||||||
|
memset (pw, 0, sizeof *pw);
|
||||||
|
pw->pw_uid = pwent->pw_uid;
|
||||||
|
pw->pw_gid = pwent->pw_gid;
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
pw->pw_name = strdup (pwent->pw_name);
|
pw->pw_name = strdup (pwent->pw_name);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == pw->pw_name) {
|
if (NULL == pw->pw_name) {
|
||||||
|
pw_free(pw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
pw->pw_passwd = strdup (pwent->pw_passwd);
|
pw->pw_passwd = strdup (pwent->pw_passwd);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == pw->pw_passwd) {
|
if (NULL == pw->pw_passwd) {
|
||||||
|
pw_free(pw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
pw->pw_gecos = strdup (pwent->pw_gecos);
|
pw->pw_gecos = strdup (pwent->pw_gecos);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == pw->pw_gecos) {
|
if (NULL == pw->pw_gecos) {
|
||||||
|
pw_free(pw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
pw->pw_dir = strdup (pwent->pw_dir);
|
pw->pw_dir = strdup (pwent->pw_dir);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == pw->pw_dir) {
|
if (NULL == pw->pw_dir) {
|
||||||
|
pw_free(pw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
pw->pw_shell = strdup (pwent->pw_shell);
|
pw->pw_shell = strdup (pwent->pw_shell);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == pw->pw_shell) {
|
if (NULL == pw->pw_shell) {
|
||||||
|
pw_free(pw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,12 +93,16 @@
|
|||||||
|
|
||||||
void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent)
|
void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent)
|
||||||
{
|
{
|
||||||
free (pwent->pw_name);
|
if (pwent != NULL) {
|
||||||
memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
|
free (pwent->pw_name);
|
||||||
free (pwent->pw_passwd);
|
if (pwent->pw_passwd) {
|
||||||
free (pwent->pw_gecos);
|
memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
|
||||||
free (pwent->pw_dir);
|
free (pwent->pw_passwd);
|
||||||
free (pwent->pw_shell);
|
}
|
||||||
free (pwent);
|
free (pwent->pw_gecos);
|
||||||
|
free (pwent->pw_dir);
|
||||||
|
free (pwent->pw_shell);
|
||||||
|
free (pwent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <lib/prototypes.h>
|
||||||
|
|
||||||
|
int run_part (char *script_path, char *name, char *action)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
int wait_status;
|
||||||
|
int pid_status;
|
||||||
|
char *args[] = { script_path, NULL };
|
||||||
|
|
||||||
|
pid=fork();
|
||||||
|
if (pid==-1) {
|
||||||
|
perror ("Could not fork");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (pid==0) {
|
||||||
|
setenv ("ACTION",action,1);
|
||||||
|
setenv ("SUBJECT",name,1);
|
||||||
|
execv (script_path,args);
|
||||||
|
perror ("execv");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_status = wait (&wait_status);
|
||||||
|
if (pid_status == pid) {
|
||||||
|
return (wait_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
perror ("waitpid");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_parts (char *directory, char *name, char *action)
|
||||||
|
{
|
||||||
|
struct dirent **namelist;
|
||||||
|
int scanlist;
|
||||||
|
int n;
|
||||||
|
int execute_result;
|
||||||
|
|
||||||
|
scanlist = scandir (directory, &namelist, 0, alphasort);
|
||||||
|
if (scanlist<0) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n=0; n<scanlist; n++) {
|
||||||
|
int path_length;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
path_length=strlen(directory) + strlen(namelist[n]->d_name) + 2;
|
||||||
|
char *s = (char*)malloc(path_length);
|
||||||
|
if (!s) {
|
||||||
|
printf ("could not allocate memory\n");
|
||||||
|
for (; n<scanlist; n++) {
|
||||||
|
free (namelist[n]);
|
||||||
|
}
|
||||||
|
free (namelist);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
snprintf (s, path_length, "%s/%s", directory, namelist[n]->d_name);
|
||||||
|
|
||||||
|
execute_result = 0;
|
||||||
|
if (stat (s, &sb) == -1) {
|
||||||
|
perror ("stat");
|
||||||
|
free (s);
|
||||||
|
for (; n<scanlist; n++) {
|
||||||
|
free (namelist[n]);
|
||||||
|
}
|
||||||
|
free (namelist);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISREG (sb.st_mode) || S_ISLNK (sb.st_mode)) {
|
||||||
|
execute_result = run_part (s, name, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (s);
|
||||||
|
|
||||||
|
if (execute_result!=0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
"%s: did not exit cleanly.\n",
|
||||||
|
namelist[n]->d_name);
|
||||||
|
for (; n<scanlist; n++) {
|
||||||
|
free (namelist[n]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free (namelist[n]);
|
||||||
|
}
|
||||||
|
free (namelist);
|
||||||
|
|
||||||
|
return (execute_result);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
int run_part (char *script_path, char *name, char *action);
|
||||||
|
int run_parts (char *directory, char *name, char *action);
|
||||||
+231
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 , Peter Vrabec <pvrabec@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>
|
||||||
|
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
#include <selinux/selinux.h>
|
||||||
|
#include <selinux/label.h>
|
||||||
|
#include "prototypes.h"
|
||||||
|
|
||||||
|
static bool selinux_checked = false;
|
||||||
|
static bool selinux_enabled;
|
||||||
|
static /*@null@*/struct selabel_handle *selabel_hnd = NULL;
|
||||||
|
|
||||||
|
static void cleanup(void)
|
||||||
|
{
|
||||||
|
if (selabel_hnd) {
|
||||||
|
selabel_close(selabel_hnd);
|
||||||
|
selabel_hnd = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_selinux_handle (void)
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set_selinux_file_context - Set the security context before any file or
|
||||||
|
* directory creation.
|
||||||
|
*
|
||||||
|
* set_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 with reset_selinux_file_context
|
||||||
|
*/
|
||||||
|
int set_selinux_file_context (const char *dst_name, mode_t mode)
|
||||||
|
{
|
||||||
|
if (!selinux_checked) {
|
||||||
|
selinux_enabled = is_selinux_enabled () > 0;
|
||||||
|
selinux_checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selinux_enabled) {
|
||||||
|
/* Get the default security context for this file */
|
||||||
|
|
||||||
|
/*@null@*/char *fcontext_raw = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (selabel_hnd == NULL) {
|
||||||
|
selabel_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
||||||
|
if (selabel_hnd == NULL) {
|
||||||
|
return security_getenforce () != 0;
|
||||||
|
}
|
||||||
|
(void) atexit(cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = selabel_lookup_raw(selabel_hnd, &fcontext_raw, dst_name, mode);
|
||||||
|
if (r < 0) {
|
||||||
|
/* No context specified for the searched path */
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return security_getenforce () != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the security context for the next created file */
|
||||||
|
r = setfscreatecon_raw (fcontext_raw);
|
||||||
|
freecon (fcontext_raw);
|
||||||
|
if (r < 0) {
|
||||||
|
return security_getenforce () != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reset_selinux_file_context - Reset the security context to the default
|
||||||
|
* policy behavior
|
||||||
|
*
|
||||||
|
* reset_selinux_file_context () should be called after the context
|
||||||
|
* was changed with set_selinux_file_context ()
|
||||||
|
*/
|
||||||
|
int reset_selinux_file_context (void)
|
||||||
|
{
|
||||||
|
if (!selinux_checked) {
|
||||||
|
selinux_enabled = is_selinux_enabled () > 0;
|
||||||
|
selinux_checked = true;
|
||||||
|
}
|
||||||
|
if (selinux_enabled) {
|
||||||
|
if (setfscreatecon_raw (NULL) != 0) {
|
||||||
|
return security_getenforce () != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log callback for libselinux internal error reporting.
|
||||||
|
*/
|
||||||
|
__attribute__((__format__ (printf, 2, 3)))
|
||||||
|
static int selinux_log_cb (int type, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
char *buf;
|
||||||
|
int r;
|
||||||
|
#ifdef WITH_AUDIT
|
||||||
|
static int selinux_audit_fd = -2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
va_start (ap, fmt);
|
||||||
|
r = vasprintf (&buf, fmt, ap);
|
||||||
|
va_end (ap);
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_AUDIT
|
||||||
|
if (-2 == selinux_audit_fd) {
|
||||||
|
selinux_audit_fd = audit_open ();
|
||||||
|
|
||||||
|
if (-1 == selinux_audit_fd) {
|
||||||
|
/* You get these only when the kernel doesn't have
|
||||||
|
* audit compiled in. */
|
||||||
|
if ( (errno != EINVAL)
|
||||||
|
&& (errno != EPROTONOSUPPORT)
|
||||||
|
&& (errno != EAFNOSUPPORT)) {
|
||||||
|
|
||||||
|
(void) fputs (_("Cannot open audit interface.\n"),
|
||||||
|
shadow_logfd);
|
||||||
|
SYSLOG ((LOG_WARN, "Cannot open audit interface."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 != selinux_audit_fd) {
|
||||||
|
if (SELINUX_AVC == type) {
|
||||||
|
if (audit_log_user_avc_message (selinux_audit_fd,
|
||||||
|
AUDIT_USER_AVC, buf, NULL, NULL,
|
||||||
|
NULL, 0) > 0) {
|
||||||
|
goto skip_syslog;
|
||||||
|
}
|
||||||
|
} else if (SELINUX_ERROR == type) {
|
||||||
|
if (audit_log_user_avc_message (selinux_audit_fd,
|
||||||
|
AUDIT_USER_SELINUX_ERR, buf, NULL, NULL,
|
||||||
|
NULL, 0) > 0) {
|
||||||
|
goto skip_syslog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SYSLOG ((LOG_WARN, "libselinux: %s", buf));
|
||||||
|
|
||||||
|
skip_syslog:
|
||||||
|
free (buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check_selinux_permit - Check whether SELinux grants the given
|
||||||
|
* operation
|
||||||
|
*
|
||||||
|
* Parameter is the SELinux permission name, e.g. rootok
|
||||||
|
*
|
||||||
|
* Returns 0 when permission is granted
|
||||||
|
* or something failed but running in
|
||||||
|
* permissive mode
|
||||||
|
*/
|
||||||
|
int check_selinux_permit (const char *perm_name)
|
||||||
|
{
|
||||||
|
char *user_context_raw;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (0 == is_selinux_enabled ()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
selinux_set_callback (SELINUX_CB_LOG, (union selinux_callback) selinux_log_cb);
|
||||||
|
|
||||||
|
if (getprevcon_raw (&user_context_raw) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: can not get previous SELinux process context: %s\n"),
|
||||||
|
Prog, strerror (errno));
|
||||||
|
SYSLOG ((LOG_WARN,
|
||||||
|
"can not get previous SELinux process context: %s",
|
||||||
|
strerror (errno)));
|
||||||
|
return (security_getenforce () != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = selinux_check_access (user_context_raw, user_context_raw, "passwd", perm_name, NULL);
|
||||||
|
freecon (user_context_raw);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !WITH_SELINUX */
|
||||||
|
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||||
|
#endif /* !WITH_SELINUX */
|
||||||
+379
@@ -0,0 +1,379 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010 , Jakub Hrozek <jhrozek@redhat.com>
|
||||||
|
* Copyright (c) 2011 , Peter Vrabec <pvrabec@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>
|
||||||
|
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <selinux/selinux.h>
|
||||||
|
#include <semanage/semanage.h>
|
||||||
|
#include "prototypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DEFAULT_SERANGE
|
||||||
|
#define DEFAULT_SERANGE "s0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void semanage_error_callback (unused void *varg,
|
||||||
|
semanage_handle_t *handle,
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char * message = NULL;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
|
||||||
|
va_start (ap, fmt);
|
||||||
|
ret = vasprintf (&message, fmt, ap);
|
||||||
|
va_end (ap);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* ENOMEM */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (semanage_msg_get_level (handle)) {
|
||||||
|
case SEMANAGE_MSG_ERR:
|
||||||
|
case SEMANAGE_MSG_WARN:
|
||||||
|
fprintf (shadow_logfd, _("[libsemanage]: %s\n"), message);
|
||||||
|
break;
|
||||||
|
case SEMANAGE_MSG_INFO:
|
||||||
|
/* nop */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free (message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static semanage_handle_t *semanage_init (void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
semanage_handle_t *handle = NULL;
|
||||||
|
|
||||||
|
handle = semanage_handle_create ();
|
||||||
|
if (NULL == handle) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Cannot create SELinux management handle\n"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
semanage_msg_set_callback (handle, semanage_error_callback, NULL);
|
||||||
|
|
||||||
|
ret = semanage_is_managed (handle);
|
||||||
|
if (ret != 1) {
|
||||||
|
fprintf (shadow_logfd, _("SELinux policy not managed\n"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_access_check (handle);
|
||||||
|
if (ret < SEMANAGE_CAN_READ) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot read SELinux policy store\n"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_connect (handle);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Cannot establish SELinux management connection\n"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_begin_transaction (handle);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot begin SELinux transaction\n"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
semanage_handle_destroy (handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int semanage_user_mod (semanage_handle_t *handle,
|
||||||
|
semanage_seuser_key_t *key,
|
||||||
|
const char *login_name,
|
||||||
|
const char *seuser_name)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
semanage_seuser_t *seuser = NULL;
|
||||||
|
|
||||||
|
semanage_seuser_query (handle, key, &seuser);
|
||||||
|
if (NULL == seuser) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not query seuser for %s\n"), login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not set serange for %s\n"), login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not set sename for %s\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_modify_local (handle, key, seuser);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not modify login mapping for %s\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
done:
|
||||||
|
semanage_seuser_free (seuser);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int semanage_user_add (semanage_handle_t *handle,
|
||||||
|
semanage_seuser_key_t *key,
|
||||||
|
const char *login_name,
|
||||||
|
const char *seuser_name)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
semanage_seuser_t *seuser = NULL;
|
||||||
|
|
||||||
|
ret = semanage_seuser_create (handle, &seuser);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Cannot create SELinux login mapping for %s\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_set_name (handle, seuser, login_name);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd, _("Could not set name for %s\n"), login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not set serange for %s\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not set SELinux user for %s\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_modify_local (handle, key, seuser);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not add login mapping for %s\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
done:
|
||||||
|
semanage_seuser_free (seuser);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int set_seuser (const char *login_name, const char *seuser_name)
|
||||||
|
{
|
||||||
|
semanage_handle_t *handle = NULL;
|
||||||
|
semanage_seuser_key_t *key = NULL;
|
||||||
|
int ret;
|
||||||
|
int seuser_exists = 0;
|
||||||
|
|
||||||
|
if (NULL == seuser_name) {
|
||||||
|
/* don't care, just let system pick the defaults */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = semanage_init ();
|
||||||
|
if (NULL == handle) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot init SELinux management\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_key_create (handle, login_name, &key);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot create SELinux user key\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_exists (handle, key, &seuser_exists);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot verify the SELinux user\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != seuser_exists) {
|
||||||
|
ret = semanage_user_mod (handle, key, login_name, seuser_name);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Cannot modify SELinux user mapping\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = semanage_user_add (handle, key, login_name, seuser_name);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Cannot add SELinux user mapping\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_commit (handle);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
reset_selinux_handle();
|
||||||
|
|
||||||
|
done:
|
||||||
|
semanage_seuser_key_free (key);
|
||||||
|
semanage_handle_destroy (handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int del_seuser (const char *login_name)
|
||||||
|
{
|
||||||
|
semanage_handle_t *handle = NULL;
|
||||||
|
semanage_seuser_key_t *key = NULL;
|
||||||
|
int ret;
|
||||||
|
int exists = 0;
|
||||||
|
|
||||||
|
handle = semanage_init ();
|
||||||
|
if (NULL == handle) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot init SELinux management\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_key_create (handle, login_name, &key);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot create SELinux user key\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_exists (handle, key, &exists);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot verify the SELinux user\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == exists) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Login mapping for %s is not defined, OK if default mapping was used\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 0; /* probably default mapping */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_exists_local (handle, key, &exists);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot verify the SELinux user\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == exists) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Login mapping for %s is defined in policy, cannot be deleted\n"),
|
||||||
|
login_name);
|
||||||
|
ret = 0; /* Login mapping defined in policy can't be deleted */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_seuser_del_local (handle, key);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Could not delete login mapping for %s"),
|
||||||
|
login_name);
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = semanage_commit (handle);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf (shadow_logfd, _("Cannot commit SELinux transaction\n"));
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
done:
|
||||||
|
semanage_handle_destroy (handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else /* !WITH_SELINUX */
|
||||||
|
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||||
|
#endif /* !WITH_SELINUX */
|
||||||
+1
-1
@@ -136,7 +136,7 @@ struct group *sgetgrent (const char *buf)
|
|||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i < (NFIELDS - 1) || *grpfields[2] == '\0') {
|
if (i < (NFIELDS - 1) || *grpfields[2] == '\0' || cp != NULL) {
|
||||||
return (struct group *) 0;
|
return (struct group *) 0;
|
||||||
}
|
}
|
||||||
grent.gr_name = grpfields[0];
|
grent.gr_name = grpfields[0];
|
||||||
|
|||||||
@@ -90,6 +90,11 @@ struct passwd *sgetpwent (const char *buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* something at the end, columns over shot */
|
||||||
|
if ( cp != NULL ) {
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There must be exactly NFIELDS colon separated fields or
|
* There must be exactly NFIELDS colon separated fields or
|
||||||
* the entry is invalid. Also, the UID and GID must be non-blank.
|
* the entry is invalid. Also, the UID and GID must be non-blank.
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ struct spwd *sgetspent (const char *string)
|
|||||||
static struct spwd spwd;
|
static struct spwd spwd;
|
||||||
char *fields[FIELDS];
|
char *fields[FIELDS];
|
||||||
char *cp;
|
char *cp;
|
||||||
char *cpp;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+57
-11
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2001 , Michał Moskal
|
* Copyright (c) 2001 , Michał Moskal
|
||||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2008, Nicolas François
|
* Copyright (c) 2007 - 2013, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "commonio.h"
|
#include "commonio.h"
|
||||||
|
#include "getdef.h"
|
||||||
#include "sgroupio.h"
|
#include "sgroupio.h"
|
||||||
|
|
||||||
/*@null@*/ /*@only@*/struct sgrp *__sgr_dup (const struct sgrp *sgent)
|
/*@null@*/ /*@only@*/struct sgrp *__sgr_dup (const struct sgrp *sgent)
|
||||||
@@ -51,13 +52,19 @@
|
|||||||
if (NULL == sg) {
|
if (NULL == sg) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*sg = *sgent;
|
/* Do the same as the other _dup function, even if we know the
|
||||||
|
* structure. */
|
||||||
|
memset (sg, 0, sizeof *sg);
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
sg->sg_name = strdup (sgent->sg_name);
|
sg->sg_name = strdup (sgent->sg_name);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == sg->sg_name) {
|
if (NULL == sg->sg_name) {
|
||||||
free (sg);
|
free (sg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
sg->sg_passwd = strdup (sgent->sg_passwd);
|
sg->sg_passwd = strdup (sgent->sg_passwd);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == sg->sg_passwd) {
|
if (NULL == sg->sg_passwd) {
|
||||||
free (sg->sg_name);
|
free (sg->sg_name);
|
||||||
free (sg);
|
free (sg);
|
||||||
@@ -65,7 +72,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; NULL != sgent->sg_adm[i]; i++);
|
for (i = 0; NULL != sgent->sg_adm[i]; i++);
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
sg->sg_adm = (char **) malloc ((i + 1) * sizeof (char *));
|
sg->sg_adm = (char **) malloc ((i + 1) * sizeof (char *));
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == sg->sg_adm) {
|
if (NULL == sg->sg_adm) {
|
||||||
free (sg->sg_passwd);
|
free (sg->sg_passwd);
|
||||||
free (sg->sg_name);
|
free (sg->sg_name);
|
||||||
@@ -88,7 +97,9 @@
|
|||||||
sg->sg_adm[i] = NULL;
|
sg->sg_adm[i] = NULL;
|
||||||
|
|
||||||
for (i = 0; NULL != sgent->sg_mem[i]; i++);
|
for (i = 0; NULL != sgent->sg_mem[i]; i++);
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
sg->sg_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
sg->sg_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == sg->sg_mem) {
|
if (NULL == sg->sg_mem) {
|
||||||
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
||||||
free (sg->sg_adm[i]);
|
free (sg->sg_adm[i]);
|
||||||
@@ -137,17 +148,20 @@ static void gshadow_free (/*@out@*/ /*@only@*/void *ent)
|
|||||||
|
|
||||||
void sgr_free (/*@out@*/ /*@only@*/struct sgrp *sgent)
|
void sgr_free (/*@out@*/ /*@only@*/struct sgrp *sgent)
|
||||||
{
|
{
|
||||||
|
size_t i;
|
||||||
free (sgent->sg_name);
|
free (sgent->sg_name);
|
||||||
memzero (sgent->sg_passwd, strlen (sgent->sg_passwd));
|
if (NULL != sgent->sg_passwd) {
|
||||||
free (sgent->sg_passwd);
|
memzero (sgent->sg_passwd, strlen (sgent->sg_passwd));
|
||||||
while (NULL != *(sgent->sg_adm)) {
|
free (sgent->sg_passwd);
|
||||||
free (*(sgent->sg_adm));
|
|
||||||
sgent->sg_adm++;
|
|
||||||
}
|
}
|
||||||
while (NULL != *(sgent->sg_mem)) {
|
for (i = 0; NULL != sgent->sg_adm[i]; i++) {
|
||||||
free (*(sgent->sg_mem));
|
free (sgent->sg_adm[i]);
|
||||||
sgent->sg_mem++;
|
|
||||||
}
|
}
|
||||||
|
free (sgent->sg_adm);
|
||||||
|
for (i = 0; NULL != sgent->sg_mem[i]; i++) {
|
||||||
|
free (sgent->sg_mem[i]);
|
||||||
|
}
|
||||||
|
free (sgent->sg_mem);
|
||||||
free (sgent);
|
free (sgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +181,32 @@ static int gshadow_put (const void *ent, FILE * file)
|
|||||||
{
|
{
|
||||||
const struct sgrp *sg = ent;
|
const struct sgrp *sg = ent;
|
||||||
|
|
||||||
|
if ( (NULL == sg)
|
||||||
|
|| (valid_field (sg->sg_name, ":\n") == -1)
|
||||||
|
|| (valid_field (sg->sg_passwd, ":\n") == -1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: fail also if sg->sg_adm == NULL ?*/
|
||||||
|
if (NULL != sg->sg_adm) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
||||||
|
if (valid_field (sg->sg_adm[i], ",:\n") == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: fail also if sg->sg_mem == NULL ?*/
|
||||||
|
if (NULL != sg->sg_mem) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; NULL != sg->sg_mem[i]; i++) {
|
||||||
|
if (valid_field (sg->sg_mem[i], ",:\n") == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (putsgent (sg, file) == -1) ? -1 : 0;
|
return (putsgent (sg, file) == -1) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,13 +229,17 @@ static struct commonio_db gshadow_db = {
|
|||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
NULL, /* scontext */
|
NULL, /* scontext */
|
||||||
#endif
|
#endif
|
||||||
|
0400, /* st_mode */
|
||||||
|
0, /* st_uid */
|
||||||
|
0, /* st_gid */
|
||||||
NULL, /* head */
|
NULL, /* head */
|
||||||
NULL, /* tail */
|
NULL, /* tail */
|
||||||
NULL, /* cursor */
|
NULL, /* cursor */
|
||||||
false, /* changed */
|
false, /* changed */
|
||||||
false, /* isopen */
|
false, /* isopen */
|
||||||
false, /* locked */
|
false, /* locked */
|
||||||
false /* readonly */
|
false, /* readonly */
|
||||||
|
false /* setname */
|
||||||
};
|
};
|
||||||
|
|
||||||
int sgr_setdbname (const char *filename)
|
int sgr_setdbname (const char *filename)
|
||||||
@@ -210,6 +254,8 @@ int sgr_setdbname (const char *filename)
|
|||||||
|
|
||||||
bool sgr_file_present (void)
|
bool sgr_file_present (void)
|
||||||
{
|
{
|
||||||
|
if (getdef_bool ("FORCE_SHADOW"))
|
||||||
|
return true;
|
||||||
return commonio_present (&gshadow_db);
|
return commonio_present (&gshadow_db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
extern int sgr_close (void);
|
extern int sgr_close (void);
|
||||||
extern bool sgr_file_present (void);
|
extern bool sgr_file_present (void);
|
||||||
extern /*@null@*/const struct sgrp *sgr_locate (const char *name);
|
extern /*@observer@*/ /*@null@*/const struct sgrp *sgr_locate (const char *name);
|
||||||
extern int sgr_lock (void);
|
extern int sgr_lock (void);
|
||||||
extern int sgr_setdbname (const char *filename);
|
extern int sgr_setdbname (const char *filename);
|
||||||
extern /*@observer@*/const char *sgr_dbname (void);
|
extern /*@observer@*/const char *sgr_dbname (void);
|
||||||
|
|||||||
+47
-30
@@ -42,10 +42,10 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
static int nis_used;
|
static bool nis_used;
|
||||||
static int nis_ignore;
|
static bool nis_ignore;
|
||||||
static enum { native, start, middle, native2 } nis_state;
|
static enum { native, start, middle, native2 } nis_state;
|
||||||
static int nis_bound;
|
static bool nis_bound;
|
||||||
static char *nis_domain;
|
static char *nis_domain;
|
||||||
static char *nis_key;
|
static char *nis_key;
|
||||||
static int nis_keylen;
|
static int nis_keylen;
|
||||||
@@ -66,12 +66,12 @@ static FILE *shadow;
|
|||||||
* __setspNIS - turn on or off NIS searches
|
* __setspNIS - turn on or off NIS searches
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void __setspNIS (int flag)
|
void __setspNIS (bool flag)
|
||||||
{
|
{
|
||||||
nis_ignore = !flag;
|
nis_ignore = !flag;
|
||||||
|
|
||||||
if (nis_ignore) {
|
if (nis_ignore) {
|
||||||
nis_used = 0;
|
nis_used = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,10 +81,11 @@ void __setspNIS (int flag)
|
|||||||
|
|
||||||
static int bind_nis (void)
|
static int bind_nis (void)
|
||||||
{
|
{
|
||||||
if (yp_get_default_domain (&nis_domain))
|
if (yp_get_default_domain (&nis_domain)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
nis_bound = 1;
|
nis_bound = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -95,10 +96,11 @@ static int bind_nis (void)
|
|||||||
|
|
||||||
void setspent (void)
|
void setspent (void)
|
||||||
{
|
{
|
||||||
if (shadow)
|
if (NULL != shadow) {
|
||||||
rewind (shadow);
|
rewind (shadow);
|
||||||
else
|
}else {
|
||||||
shadow = fopen (SHADOW_FILE, "r");
|
shadow = fopen (SHADOW_FILE, "r");
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
nis_state = native;
|
nis_state = native;
|
||||||
@@ -111,8 +113,9 @@ void setspent (void)
|
|||||||
|
|
||||||
void endspent (void)
|
void endspent (void)
|
||||||
{
|
{
|
||||||
if (shadow)
|
if (NULL != shadow) {
|
||||||
(void) fclose (shadow);
|
(void) fclose (shadow);
|
||||||
|
}
|
||||||
|
|
||||||
shadow = (FILE *) 0;
|
shadow = (FILE *) 0;
|
||||||
}
|
}
|
||||||
@@ -127,7 +130,6 @@ static struct spwd *my_sgetspent (const char *string)
|
|||||||
static struct spwd spwd;
|
static struct spwd spwd;
|
||||||
char *fields[FIELDS];
|
char *fields[FIELDS];
|
||||||
char *cp;
|
char *cp;
|
||||||
char *cpp;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -172,8 +174,9 @@ static struct spwd *my_sgetspent (const char *string)
|
|||||||
|
|
||||||
spwd.sp_namp = fields[0];
|
spwd.sp_namp = fields[0];
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
if (IS_NISCHAR (fields[0][0]))
|
if (IS_NISCHAR (fields[0][0])) {
|
||||||
nis_used = 1;
|
nis_used = true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
spwd.sp_pwdp = fields[1];
|
spwd.sp_pwdp = fields[1];
|
||||||
|
|
||||||
@@ -211,7 +214,9 @@ static struct spwd *my_sgetspent (const char *string)
|
|||||||
spwd.sp_min = -1;
|
spwd.sp_min = -1;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
} else if (spwd.sp_min < 0) {
|
} else if (spwd.sp_min < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -263,7 +268,9 @@ static struct spwd *my_sgetspent (const char *string)
|
|||||||
spwd.sp_warn = -1;
|
spwd.sp_warn = -1;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
} else if (spwd.sp_warn < 0) {
|
} else if (spwd.sp_warn < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -283,7 +290,9 @@ static struct spwd *my_sgetspent (const char *string)
|
|||||||
spwd.sp_inact = -1;
|
spwd.sp_inact = -1;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
} else if (spwd.sp_inact < 0) {
|
} else if (spwd.sp_inact < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -303,7 +312,9 @@ static struct spwd *my_sgetspent (const char *string)
|
|||||||
spwd.sp_expire = -1;
|
spwd.sp_expire = -1;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
} else if (spwd.sp_expire < 0) {
|
} else if (spwd.sp_expire < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -324,7 +335,9 @@ static struct spwd *my_sgetspent (const char *string)
|
|||||||
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
} else if (spwd.sp_flag < 0) {
|
} else if (spwd.sp_flag < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -375,10 +388,10 @@ struct spwd *getspent (void)
|
|||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
int nis_1_user = 0;
|
int nis_1_user = 0;
|
||||||
struct spwd *val;
|
struct spwd *val;
|
||||||
char buf[BUFSIZ];
|
|
||||||
#endif
|
#endif
|
||||||
if (!shadow)
|
if (NULL == shadow) {
|
||||||
setspent ();
|
setspent ();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
again:
|
again:
|
||||||
@@ -432,7 +445,7 @@ struct spwd *getspent (void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (nis_bound == 0) {
|
if (!nis_bound) {
|
||||||
if (bind_nis ()) {
|
if (bind_nis ()) {
|
||||||
nis_state = native2;
|
nis_state = native2;
|
||||||
goto again;
|
goto again;
|
||||||
@@ -440,15 +453,15 @@ struct spwd *getspent (void)
|
|||||||
}
|
}
|
||||||
if (nis_state == start) {
|
if (nis_state == start) {
|
||||||
if (yp_first (nis_domain, "shadow.bynam", &nis_key,
|
if (yp_first (nis_domain, "shadow.bynam", &nis_key,
|
||||||
&nis_keylen, &nis_val, &nis_vallen)) {
|
&nis_keylen, &nis_val, &nis_vallen)) {
|
||||||
nis_state = native2;
|
nis_state = native2;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
nis_state = middle;
|
nis_state = middle;
|
||||||
} else if (nis_state == middle) {
|
} else if (nis_state == middle) {
|
||||||
if (yp_next (nis_domain, "shadow.bynam", nis_key,
|
if (yp_next (nis_domain, "shadow.bynam", nis_key,
|
||||||
nis_keylen, &nis_key, &nis_keylen,
|
nis_keylen, &nis_key, &nis_keylen,
|
||||||
&nis_val, &nis_vallen)) {
|
&nis_val, &nis_vallen)) {
|
||||||
nis_state = native2;
|
nis_state = native2;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
@@ -469,9 +482,8 @@ struct spwd *getspnam (const char *name)
|
|||||||
struct spwd *sp;
|
struct spwd *sp;
|
||||||
|
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
char buf[BUFSIZ];
|
|
||||||
static char save_name[16];
|
static char save_name[16];
|
||||||
int nis_disabled = 0;
|
bool nis_disabled = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
setspent ();
|
setspent ();
|
||||||
@@ -481,18 +493,20 @@ struct spwd *getspnam (const char *name)
|
|||||||
* Search the shadow.byname map for this user.
|
* Search the shadow.byname map for this user.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!nis_ignore && !nis_bound)
|
if (!nis_ignore && !nis_bound) {
|
||||||
bind_nis ();
|
bind_nis ();
|
||||||
|
}
|
||||||
|
|
||||||
if (!nis_ignore && nis_bound) {
|
if (!nis_ignore && nis_bound) {
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
if (yp_match (nis_domain, "shadow.byname", name,
|
if (yp_match (nis_domain, "shadow.byname", name,
|
||||||
strlen (name), &nis_val, &nis_vallen) == 0) {
|
strlen (name), &nis_val, &nis_vallen) == 0) {
|
||||||
|
|
||||||
cp = strchr (nis_val, '\n');
|
cp = strchr (nis_val, '\n');
|
||||||
if (NULL != cp)
|
if (NULL != cp) {
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
nis_state = middle;
|
nis_state = middle;
|
||||||
sp = my_sgetspent (nis_val);
|
sp = my_sgetspent (nis_val);
|
||||||
@@ -503,8 +517,9 @@ struct spwd *getspnam (const char *name)
|
|||||||
}
|
}
|
||||||
endspent ();
|
endspent ();
|
||||||
return sp;
|
return sp;
|
||||||
} else
|
} else {
|
||||||
nis_state = native2;
|
nis_state = native2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
@@ -516,17 +531,19 @@ struct spwd *getspnam (const char *name)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (nis_used) {
|
if (nis_used) {
|
||||||
nis_ignore++;
|
nis_ignore = true;
|
||||||
nis_disabled++;
|
nis_disabled = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
while ((sp = getspent ()) != (struct spwd *) 0) {
|
while ((sp = getspent ()) != (struct spwd *) 0) {
|
||||||
if (strcmp (name, sp->sp_namp) == 0)
|
if (strcmp (name, sp->sp_namp) == 0) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef USE_NIS
|
#ifdef USE_NIS
|
||||||
if (nis_disabled)
|
if (nis_disabled) {
|
||||||
nis_ignore--;
|
nis_ignore = false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
endspent ();
|
endspent ();
|
||||||
return (sp);
|
return (sp);
|
||||||
|
|||||||
+94
-6
@@ -40,7 +40,12 @@
|
|||||||
#include <shadow.h>
|
#include <shadow.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "commonio.h"
|
#include "commonio.h"
|
||||||
|
#include "getdef.h"
|
||||||
#include "shadowio.h"
|
#include "shadowio.h"
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
#include <tcb.h>
|
||||||
|
#include "tcbfuncs.h"
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
|
||||||
static /*@null@*/ /*@only@*/void *shadow_dup (const void *ent)
|
static /*@null@*/ /*@only@*/void *shadow_dup (const void *ent)
|
||||||
{
|
{
|
||||||
@@ -72,6 +77,12 @@ static int shadow_put (const void *ent, FILE * file)
|
|||||||
{
|
{
|
||||||
const struct spwd *sp = ent;
|
const struct spwd *sp = ent;
|
||||||
|
|
||||||
|
if ( (NULL == sp)
|
||||||
|
|| (valid_field (sp->sp_namp, ":\n") == -1)
|
||||||
|
|| (valid_field (sp->sp_pwdp, ":\n") == -1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return (putspent (sp, file) == -1) ? -1 : 0;
|
return (putspent (sp, file) == -1) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,14 +104,18 @@ static struct commonio_db shadow_db = {
|
|||||||
NULL, /* fp */
|
NULL, /* fp */
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
NULL, /* scontext */
|
NULL, /* scontext */
|
||||||
#endif
|
#endif /* WITH_SELINUX */
|
||||||
|
0400, /* st_mode */
|
||||||
|
0, /* st_uid */
|
||||||
|
0, /* st_gid */
|
||||||
NULL, /* head */
|
NULL, /* head */
|
||||||
NULL, /* tail */
|
NULL, /* tail */
|
||||||
NULL, /* cursor */
|
NULL, /* cursor */
|
||||||
false, /* changed */
|
false, /* changed */
|
||||||
false, /* isopen */
|
false, /* isopen */
|
||||||
false, /* locked */
|
false, /* locked */
|
||||||
false /* readonly */
|
false, /* readonly */
|
||||||
|
false /* setname */
|
||||||
};
|
};
|
||||||
|
|
||||||
int spw_setdbname (const char *filename)
|
int spw_setdbname (const char *filename)
|
||||||
@@ -115,17 +130,52 @@ int spw_setdbname (const char *filename)
|
|||||||
|
|
||||||
bool spw_file_present (void)
|
bool spw_file_present (void)
|
||||||
{
|
{
|
||||||
|
if (getdef_bool ("FORCE_SHADOW"))
|
||||||
|
return true;
|
||||||
return commonio_present (&shadow_db);
|
return commonio_present (&shadow_db);
|
||||||
}
|
}
|
||||||
|
|
||||||
int spw_lock (void)
|
int spw_lock (void)
|
||||||
{
|
{
|
||||||
return commonio_lock (&shadow_db);
|
#ifdef WITH_TCB
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (!getdef_bool ("USE_TCB")) {
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
return commonio_lock (&shadow_db);
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
}
|
||||||
|
if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (lckpwdf_tcb (shadow_db.filename) == 0) {
|
||||||
|
shadow_db.locked = 1;
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
if (shadowtcb_gain_priv () == SHADOWTCB_FAILURE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
#endif /* WITH_TCB */
|
||||||
}
|
}
|
||||||
|
|
||||||
int spw_open (int mode)
|
int spw_open (int mode)
|
||||||
{
|
{
|
||||||
return commonio_open (&shadow_db, mode);
|
int retval = 0;
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
bool use_tcb = getdef_bool ("USE_TCB");
|
||||||
|
|
||||||
|
if (use_tcb && (shadowtcb_drop_priv () == SHADOWTCB_FAILURE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
retval = commonio_open (&shadow_db, mode);
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
if (use_tcb && (shadowtcb_gain_priv () == SHADOWTCB_FAILURE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@observer@*/ /*@null@*/const struct spwd *spw_locate (const char *name)
|
/*@observer@*/ /*@null@*/const struct spwd *spw_locate (const char *name)
|
||||||
@@ -155,12 +205,45 @@ int spw_rewind (void)
|
|||||||
|
|
||||||
int spw_close (void)
|
int spw_close (void)
|
||||||
{
|
{
|
||||||
return commonio_close (&shadow_db);
|
int retval = 0;
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
bool use_tcb = getdef_bool ("USE_TCB");
|
||||||
|
|
||||||
|
if (use_tcb && (shadowtcb_drop_priv () == SHADOWTCB_FAILURE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
retval = commonio_close (&shadow_db);
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
if (use_tcb && (shadowtcb_gain_priv () == SHADOWTCB_FAILURE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spw_unlock (void)
|
int spw_unlock (void)
|
||||||
{
|
{
|
||||||
return commonio_unlock (&shadow_db);
|
#ifdef WITH_TCB
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (!getdef_bool ("USE_TCB")) {
|
||||||
|
#endif /* WITH_TCB */
|
||||||
|
return commonio_unlock (&shadow_db);
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
}
|
||||||
|
if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ulckpwdf_tcb () == 0) {
|
||||||
|
shadow_db.locked = 0;
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
if (shadowtcb_gain_priv () == SHADOWTCB_FAILURE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
#endif /* WITH_TCB */
|
||||||
}
|
}
|
||||||
|
|
||||||
struct commonio_entry *__spw_get_head (void)
|
struct commonio_entry *__spw_get_head (void)
|
||||||
@@ -176,5 +259,10 @@ void __spw_del_entry (const struct commonio_entry *ent)
|
|||||||
/* Sort with respect to passwd ordering. */
|
/* Sort with respect to passwd ordering. */
|
||||||
int spw_sort ()
|
int spw_sort ()
|
||||||
{
|
{
|
||||||
|
#ifdef WITH_TCB
|
||||||
|
if (getdef_bool ("USE_TCB")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WITH_TCB */
|
||||||
return commonio_sort_wrt (&shadow_db, __pw_get_db ());
|
return commonio_sort_wrt (&shadow_db, __pw_get_db ());
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -31,8 +31,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
#ifndef _SHADOWIO_H
|
#ifndef SHADOWIO_H
|
||||||
#define _SHADOWIO_H
|
#define SHADOWIO_H
|
||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
|
|||||||
+26
-7
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2001 , Michał Moskal
|
* Copyright (c) 2001 , Michał Moskal
|
||||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2013, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -49,13 +49,28 @@
|
|||||||
if (NULL == sp) {
|
if (NULL == sp) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*sp = *spent;
|
/* The libc might define other fields. They won't be copied. */
|
||||||
sp->sp_namp = strdup (spent->sp_namp);
|
memset (sp, 0, sizeof *sp);
|
||||||
|
sp->sp_lstchg = spent->sp_lstchg;
|
||||||
|
sp->sp_min = spent->sp_min;
|
||||||
|
sp->sp_max = spent->sp_max;
|
||||||
|
sp->sp_warn = spent->sp_warn;
|
||||||
|
sp->sp_inact = spent->sp_inact;
|
||||||
|
sp->sp_expire = spent->sp_expire;
|
||||||
|
sp->sp_flag = spent->sp_flag;
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
|
sp->sp_namp = strdup (spent->sp_namp);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == sp->sp_namp) {
|
if (NULL == sp->sp_namp) {
|
||||||
|
free(sp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*@-mustfreeonly@*/
|
||||||
sp->sp_pwdp = strdup (spent->sp_pwdp);
|
sp->sp_pwdp = strdup (spent->sp_pwdp);
|
||||||
|
/*@=mustfreeonly@*/
|
||||||
if (NULL == sp->sp_pwdp) {
|
if (NULL == sp->sp_pwdp) {
|
||||||
|
free(sp->sp_namp);
|
||||||
|
free(sp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,9 +79,13 @@
|
|||||||
|
|
||||||
void spw_free (/*@out@*/ /*@only@*/struct spwd *spent)
|
void spw_free (/*@out@*/ /*@only@*/struct spwd *spent)
|
||||||
{
|
{
|
||||||
free (spent->sp_namp);
|
if (spent != NULL) {
|
||||||
memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
|
free (spent->sp_namp);
|
||||||
free (spent->sp_pwdp);
|
if (NULL != spent->sp_pwdp) {
|
||||||
free (spent);
|
memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
|
||||||
|
free (spent->sp_pwdp);
|
||||||
|
}
|
||||||
|
free (spent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 , Jonathan Nieder
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "exitcodes.h"
|
||||||
|
#include "prototypes.h"
|
||||||
|
|
||||||
|
int run_command (const char *cmd, const char *argv[],
|
||||||
|
/*@null@*/const char *envp[], /*@out@*/int *status)
|
||||||
|
{
|
||||||
|
pid_t pid, wpid;
|
||||||
|
|
||||||
|
if (NULL == envp) {
|
||||||
|
envp = (const char **)environ;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) fflush (stdout);
|
||||||
|
(void) fflush (shadow_logfd);
|
||||||
|
|
||||||
|
pid = fork ();
|
||||||
|
if (0 == pid) {
|
||||||
|
(void) execve (cmd, (char * const *) argv,
|
||||||
|
(char * const *) envp);
|
||||||
|
if (ENOENT == errno) {
|
||||||
|
exit (E_CMD_NOTFOUND);
|
||||||
|
}
|
||||||
|
fprintf (shadow_logfd, "%s: cannot execute %s: %s\n",
|
||||||
|
Prog, cmd, strerror (errno));
|
||||||
|
exit (E_CMD_NOEXEC);
|
||||||
|
} else if ((pid_t)-1 == pid) {
|
||||||
|
fprintf (shadow_logfd, "%s: cannot execute %s: %s\n",
|
||||||
|
Prog, cmd, strerror (errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
wpid = waitpid (pid, status, 0);
|
||||||
|
if ((pid_t)-1 == wpid && errno == ECHILD)
|
||||||
|
break;
|
||||||
|
} while ( ((pid_t)-1 == wpid && errno == EINTR)
|
||||||
|
|| ((pid_t)-1 != wpid && wpid != pid));
|
||||||
|
|
||||||
|
if ((pid_t)-1 == wpid) {
|
||||||
|
fprintf (shadow_logfd, "%s: waitpid (status: %d): %s\n",
|
||||||
|
Prog, *status, strerror (errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/* Author: Peter Vrabec <pvrabec@redhat.com> */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#ifdef USE_SSSD
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "exitcodes.h"
|
||||||
|
#include "defines.h"
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include "sssd.h"
|
||||||
|
|
||||||
|
#define MSG_SSSD_FLUSH_CACHE_FAILED "%s: Failed to flush the sssd cache."
|
||||||
|
|
||||||
|
int sssd_flush_cache (int dbflags)
|
||||||
|
{
|
||||||
|
int status, code, rv;
|
||||||
|
const char *cmd = "/usr/sbin/sss_cache";
|
||||||
|
char *sss_cache_args = NULL;
|
||||||
|
const char *spawnedArgs[] = {"sss_cache", NULL, NULL};
|
||||||
|
const char *spawnedEnv[] = {NULL};
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
sss_cache_args = malloc(4);
|
||||||
|
if (sss_cache_args == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sss_cache_args[i++] = '-';
|
||||||
|
if (dbflags & SSSD_DB_PASSWD) {
|
||||||
|
sss_cache_args[i++] = 'U';
|
||||||
|
}
|
||||||
|
if (dbflags & SSSD_DB_GROUP) {
|
||||||
|
sss_cache_args[i++] = 'G';
|
||||||
|
}
|
||||||
|
sss_cache_args[i++] = '\0';
|
||||||
|
if (i == 2) {
|
||||||
|
/* Neither passwd nor group, nothing to do */
|
||||||
|
free(sss_cache_args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
spawnedArgs[1] = sss_cache_args;
|
||||||
|
|
||||||
|
rv = run_command (cmd, spawnedArgs, spawnedEnv, &status);
|
||||||
|
free(sss_cache_args);
|
||||||
|
if (rv != 0) {
|
||||||
|
/* run_command writes its own more detailed message. */
|
||||||
|
SYSLOG ((LOG_WARN, MSG_SSSD_FLUSH_CACHE_FAILED, Prog));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
code = WEXITSTATUS (status);
|
||||||
|
if (!WIFEXITED (status)) {
|
||||||
|
SYSLOG ((LOG_WARN, "%s: sss_cache did not terminate normally (signal %d)",
|
||||||
|
Prog, WTERMSIG (status)));
|
||||||
|
return -1;
|
||||||
|
} else if (code == E_CMD_NOTFOUND) {
|
||||||
|
/* sss_cache is not installed, or it is installed but uses an
|
||||||
|
interpreter that is missing. Probably the former. */
|
||||||
|
return 0;
|
||||||
|
} else if (code != 0) {
|
||||||
|
SYSLOG ((LOG_WARN, "%s: sss_cache exited with status %d", Prog, code));
|
||||||
|
SYSLOG ((LOG_WARN, MSG_SSSD_FLUSH_CACHE_FAILED, Prog));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else /* USE_SSSD */
|
||||||
|
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||||
|
#endif /* USE_SSSD */
|
||||||
|
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef _SSSD_H_
|
||||||
|
#define _SSSD_H_
|
||||||
|
|
||||||
|
#define SSSD_DB_PASSWD 0x001
|
||||||
|
#define SSSD_DB_GROUP 0x002
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sssd_flush_cache - flush specified service buffer in sssd cache
|
||||||
|
*/
|
||||||
|
#ifdef USE_SSSD
|
||||||
|
extern int sssd_flush_cache (int dbflags);
|
||||||
|
#else
|
||||||
|
#define sssd_flush_cache(service) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+1052
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012- Eric W. Biederman
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SUBORDINATEIO_H
|
||||||
|
#define _SUBORDINATEIO_H
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_SUBIDS
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "../libsubid/subid.h"
|
||||||
|
|
||||||
|
extern int sub_uid_close(void);
|
||||||
|
extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count);
|
||||||
|
extern bool sub_uid_file_present (void);
|
||||||
|
extern bool local_sub_uid_assigned(const char *owner);
|
||||||
|
extern int sub_uid_lock (void);
|
||||||
|
extern int sub_uid_setdbname (const char *filename);
|
||||||
|
extern /*@observer@*/const char *sub_uid_dbname (void);
|
||||||
|
extern int sub_uid_open (int mode);
|
||||||
|
extern int sub_uid_unlock (void);
|
||||||
|
extern int sub_uid_add (const char *owner, uid_t start, unsigned long count);
|
||||||
|
extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
|
||||||
|
extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
|
||||||
|
extern int list_owner_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges);
|
||||||
|
extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse);
|
||||||
|
extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type);
|
||||||
|
extern int find_subid_owners(unsigned long id, enum subid_type id_type, uid_t **uids);
|
||||||
|
extern void free_subordinate_ranges(struct subordinate_range **ranges, int count);
|
||||||
|
|
||||||
|
extern int sub_gid_close(void);
|
||||||
|
extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
|
||||||
|
extern bool sub_gid_file_present (void);
|
||||||
|
extern bool local_sub_gid_assigned(const char *owner);
|
||||||
|
extern int sub_gid_lock (void);
|
||||||
|
extern int sub_gid_setdbname (const char *filename);
|
||||||
|
extern /*@observer@*/const char *sub_gid_dbname (void);
|
||||||
|
extern int sub_gid_open (int mode);
|
||||||
|
extern int sub_gid_unlock (void);
|
||||||
|
extern int sub_gid_add (const char *owner, gid_t start, unsigned long count);
|
||||||
|
extern int sub_gid_remove (const char *owner, gid_t start, unsigned long count);
|
||||||
|
extern uid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count);
|
||||||
|
#endif /* ENABLE_SUBIDS */
|
||||||
|
|
||||||
|
#endif
|
||||||
+619
@@ -0,0 +1,619 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2001 Rafal Wojtczuk, Solar Designer
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <tcb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include "getdef.h"
|
||||||
|
#include "shadowio.h"
|
||||||
|
#include "tcbfuncs.h"
|
||||||
|
|
||||||
|
#define SHADOWTCB_HASH_BY 1000
|
||||||
|
#define SHADOWTCB_LOCK_SUFFIX ".lock"
|
||||||
|
|
||||||
|
static /*@null@*//*@only@*/char *stored_tcb_user = NULL;
|
||||||
|
|
||||||
|
shadowtcb_status shadowtcb_drop_priv (void)
|
||||||
|
{
|
||||||
|
if (!getdef_bool ("USE_TCB")) {
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != stored_tcb_user) {
|
||||||
|
if (tcb_drop_priv (stored_tcb_user) == 0) {
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowtcb_status shadowtcb_gain_priv (void)
|
||||||
|
{
|
||||||
|
if (!getdef_bool ("USE_TCB")) {
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tcb_gain_priv () == 0) ? SHADOWTCB_SUCCESS : SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case something goes wrong, we return immediately, not polluting the
|
||||||
|
* code with free(). All errors are fatal, so the application is expected
|
||||||
|
* to exit soon.
|
||||||
|
*/
|
||||||
|
#define OUT_OF_MEMORY do { \
|
||||||
|
fprintf (shadow_logfd, _("%s: out of memory\n"), Prog); \
|
||||||
|
(void) fflush (shadow_logfd); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
/* Returns user's tcb directory path relative to TCB_DIR. */
|
||||||
|
static /*@null@*/ char *shadowtcb_path_rel (const char *name, uid_t uid)
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
if (!getdef_bool ("TCB_SYMLINKS") || uid < SHADOWTCB_HASH_BY) {
|
||||||
|
if (asprintf (&ret, "%s", name) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else if (uid < SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY) {
|
||||||
|
if (asprintf (&ret, ":%dK/%s",
|
||||||
|
uid / SHADOWTCB_HASH_BY, name) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (asprintf (&ret, ":%dM/:%dK/%s",
|
||||||
|
uid / (SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY),
|
||||||
|
(uid % (SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY)) / SHADOWTCB_HASH_BY,
|
||||||
|
name) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static /*@null@*/ char *shadowtcb_path_rel_existing (const char *name)
|
||||||
|
{
|
||||||
|
char *path, *rval;
|
||||||
|
struct stat st;
|
||||||
|
char link[8192];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
if (asprintf (&path, TCB_DIR "/%s", name) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (lstat (path, &st) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot stat %s: %s\n"),
|
||||||
|
Prog, path, strerror (errno));
|
||||||
|
free (path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (S_ISDIR (st.st_mode)) {
|
||||||
|
free (path);
|
||||||
|
rval = strdup (name);
|
||||||
|
if (NULL == rval) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
if (!S_ISLNK (st.st_mode)) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: %s is neither a directory, nor a symlink.\n"),
|
||||||
|
Prog, path);
|
||||||
|
free (path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ret = readlink (path, link, sizeof (link) - 1);
|
||||||
|
if (-1 == ret) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot read symbolic link %s: %s\n"),
|
||||||
|
Prog, path, strerror (errno));
|
||||||
|
free (path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free (path);
|
||||||
|
if ((size_t)ret >= sizeof(link) - 1) {
|
||||||
|
link[sizeof(link) - 1] = '\0';
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Suspiciously long symlink: %s\n"),
|
||||||
|
Prog, link);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
link[(size_t)ret] = '\0';
|
||||||
|
rval = strdup (link);
|
||||||
|
if (NULL == rval) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static /*@null@*/ char *shadowtcb_path (const char *name, uid_t uid)
|
||||||
|
{
|
||||||
|
char *ret, *rel;
|
||||||
|
|
||||||
|
rel = shadowtcb_path_rel (name, uid);
|
||||||
|
if (NULL == rel) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (asprintf (&ret, TCB_DIR "/%s", rel) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
free (rel);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free (rel);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static /*@null@*/ char *shadowtcb_path_existing (const char *name)
|
||||||
|
{
|
||||||
|
char *ret, *rel;
|
||||||
|
|
||||||
|
rel = shadowtcb_path_rel_existing (name);
|
||||||
|
if (NULL == rel) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (asprintf (&ret, TCB_DIR "/%s", rel) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
free (rel);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free (rel);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static shadowtcb_status mkdir_leading (const char *name, uid_t uid)
|
||||||
|
{
|
||||||
|
char *ind, *dir, *ptr, *path = shadowtcb_path_rel (name, uid);
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (NULL == path) {
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
ptr = path;
|
||||||
|
if (stat (TCB_DIR, &st) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot stat %s: %s\n"),
|
||||||
|
Prog, TCB_DIR, strerror (errno));
|
||||||
|
goto out_free_path;
|
||||||
|
}
|
||||||
|
while ((ind = strchr (ptr, '/'))) {
|
||||||
|
*ind = '\0';
|
||||||
|
if (asprintf (&dir, TCB_DIR "/%s", path) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if ((mkdir (dir, 0700) != 0) && (errno != EEXIST)) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot create directory %s: %s\n"),
|
||||||
|
Prog, dir, strerror (errno));
|
||||||
|
goto out_free_dir;
|
||||||
|
}
|
||||||
|
if (chown (dir, 0, st.st_gid) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change owner of %s: %s\n"),
|
||||||
|
Prog, dir, strerror (errno));
|
||||||
|
goto out_free_dir;
|
||||||
|
}
|
||||||
|
if (chmod (dir, 0711) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change mode of %s: %s\n"),
|
||||||
|
Prog, dir, strerror (errno));
|
||||||
|
goto out_free_dir;
|
||||||
|
}
|
||||||
|
free (dir);
|
||||||
|
*ind = '/';
|
||||||
|
ptr = ind + 1;
|
||||||
|
}
|
||||||
|
free (path);
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
out_free_dir:
|
||||||
|
free (dir);
|
||||||
|
out_free_path:
|
||||||
|
free (path);
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static shadowtcb_status unlink_suffs (const char *user)
|
||||||
|
{
|
||||||
|
static char *suffs[] = { "+", "-", SHADOWTCB_LOCK_SUFFIX };
|
||||||
|
char *tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if (asprintf (&tmp, TCB_FMT "%s", user, suffs[i]) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if ((unlink (tmp) != 0) && (errno != ENOENT)) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: unlink: %s: %s\n"),
|
||||||
|
Prog, tmp, strerror (errno));
|
||||||
|
free (tmp);
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
free (tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* path should be a relative existing tcb directory */
|
||||||
|
static shadowtcb_status rmdir_leading (char *path)
|
||||||
|
{
|
||||||
|
char *ind, *dir;
|
||||||
|
shadowtcb_status ret = SHADOWTCB_SUCCESS;
|
||||||
|
while ((ind = strrchr (path, '/'))) {
|
||||||
|
*ind = '\0';
|
||||||
|
if (asprintf (&dir, TCB_DIR "/%s", path) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (rmdir (dir) != 0) {
|
||||||
|
if (errno != ENOTEMPTY) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot remove directory %s: %s\n"),
|
||||||
|
Prog, dir, strerror (errno));
|
||||||
|
ret = SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
free (dir);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free (dir);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static shadowtcb_status move_dir (const char *user_newname, uid_t user_newid)
|
||||||
|
{
|
||||||
|
char *olddir = NULL, *newdir = NULL;
|
||||||
|
char *real_old_dir = NULL, *real_new_dir = NULL;
|
||||||
|
char *real_old_dir_rel = NULL, *real_new_dir_rel = NULL;
|
||||||
|
uid_t old_uid, the_newid;
|
||||||
|
struct stat oldmode;
|
||||||
|
shadowtcb_status ret = SHADOWTCB_FAILURE;
|
||||||
|
|
||||||
|
if (NULL == stored_tcb_user) {
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (asprintf (&olddir, TCB_DIR "/%s", stored_tcb_user) == -1) {
|
||||||
|
goto out_free_nomem;
|
||||||
|
}
|
||||||
|
if (stat (olddir, &oldmode) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot stat %s: %s\n"),
|
||||||
|
Prog, olddir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
old_uid = oldmode.st_uid;
|
||||||
|
the_newid = (user_newid == -1) ? old_uid : user_newid;
|
||||||
|
real_old_dir = shadowtcb_path_existing (stored_tcb_user);
|
||||||
|
if (NULL == real_old_dir) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
real_new_dir = shadowtcb_path (user_newname, the_newid);
|
||||||
|
if (NULL == real_new_dir) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (strcmp (real_old_dir, real_new_dir) == 0) {
|
||||||
|
ret = SHADOWTCB_SUCCESS;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
real_old_dir_rel = shadowtcb_path_rel_existing (stored_tcb_user);
|
||||||
|
if (NULL == real_old_dir_rel) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (mkdir_leading (user_newname, the_newid) == SHADOWTCB_FAILURE) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (rename (real_old_dir, real_new_dir) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot rename %s to %s: %s\n"),
|
||||||
|
Prog, real_old_dir, real_new_dir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (rmdir_leading (real_old_dir_rel) == SHADOWTCB_FAILURE) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if ((unlink (olddir) != 0) && (errno != ENOENT)) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot remove %s: %s\n"),
|
||||||
|
Prog, olddir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (asprintf (&newdir, TCB_DIR "/%s", user_newname) == -1) {
|
||||||
|
goto out_free_nomem;
|
||||||
|
}
|
||||||
|
real_new_dir_rel = shadowtcb_path_rel (user_newname, the_newid);
|
||||||
|
if (NULL == real_new_dir_rel) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if ( (strcmp (real_new_dir, newdir) != 0)
|
||||||
|
&& (symlink (real_new_dir_rel, newdir) != 0)) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot create symbolic link %s: %s\n"),
|
||||||
|
Prog, real_new_dir_rel, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
ret = SHADOWTCB_SUCCESS;
|
||||||
|
goto out_free;
|
||||||
|
out_free_nomem:
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
out_free:
|
||||||
|
free (olddir);
|
||||||
|
free (newdir);
|
||||||
|
free (real_old_dir);
|
||||||
|
free (real_new_dir);
|
||||||
|
free (real_old_dir_rel);
|
||||||
|
free (real_new_dir_rel);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowtcb_status shadowtcb_set_user (const char* name)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
shadowtcb_status retval;
|
||||||
|
|
||||||
|
if (!getdef_bool ("USE_TCB")) {
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != stored_tcb_user) {
|
||||||
|
free (stored_tcb_user);
|
||||||
|
}
|
||||||
|
|
||||||
|
stored_tcb_user = strdup (name);
|
||||||
|
if (NULL == stored_tcb_user) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (asprintf (&buf, TCB_FMT, name) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = (spw_setdbname (buf) != 0) ? SHADOWTCB_SUCCESS : SHADOWTCB_FAILURE;
|
||||||
|
free (buf);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tcb directory must be empty before shadowtcb_remove is called. */
|
||||||
|
shadowtcb_status shadowtcb_remove (const char *name)
|
||||||
|
{
|
||||||
|
shadowtcb_status ret = SHADOWTCB_SUCCESS;
|
||||||
|
char *path = shadowtcb_path_existing (name);
|
||||||
|
char *rel = shadowtcb_path_rel_existing (name);
|
||||||
|
if ((NULL == path) || (NULL == rel) || (rmdir (path) != 0)) {
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (rmdir_leading (rel) == SHADOWTCB_FAILURE) {
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
free (path);
|
||||||
|
free (rel);
|
||||||
|
if (asprintf (&path, TCB_DIR "/%s", name) == -1) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if ((unlink (path) != 0) && (errno != ENOENT)) {
|
||||||
|
ret = SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
free (path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowtcb_status shadowtcb_move (/*@NULL@*/const char *user_newname, uid_t user_newid)
|
||||||
|
{
|
||||||
|
struct stat dirmode, filemode;
|
||||||
|
char *tcbdir, *shadow;
|
||||||
|
shadowtcb_status ret = SHADOWTCB_FAILURE;
|
||||||
|
|
||||||
|
if (!getdef_bool ("USE_TCB")) {
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
if (NULL == stored_tcb_user) {
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (NULL == user_newname) {
|
||||||
|
user_newname = stored_tcb_user;
|
||||||
|
}
|
||||||
|
if (move_dir (user_newname, user_newid) == SHADOWTCB_FAILURE) {
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (-1 == user_newid) {
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
if ( (asprintf (&tcbdir, TCB_DIR "/%s", user_newname) == -1)
|
||||||
|
|| (asprintf (&shadow, TCB_FMT, user_newname) == -1)) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (stat (tcbdir, &dirmode) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot stat %s: %s\n"),
|
||||||
|
Prog, tcbdir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chown (tcbdir, 0, 0) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change owners of %s: %s\n"),
|
||||||
|
Prog, tcbdir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chmod (tcbdir, 0700) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change mode of %s: %s\n"),
|
||||||
|
Prog, tcbdir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (lstat (shadow, &filemode) != 0) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot lstat %s: %s\n"),
|
||||||
|
Prog, shadow, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Warning, user %s has no tcb shadow file.\n"),
|
||||||
|
Prog, user_newname);
|
||||||
|
} else {
|
||||||
|
if (!S_ISREG (filemode.st_mode) ||
|
||||||
|
filemode.st_nlink != 1) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Emergency: %s's tcb shadow is not a "
|
||||||
|
"regular file with st_nlink=1.\n"
|
||||||
|
"The account is left locked.\n"),
|
||||||
|
Prog, user_newname);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chown (shadow, user_newid, filemode.st_gid) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change owner of %s: %s\n"),
|
||||||
|
Prog, shadow, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chmod (shadow, filemode.st_mode & 07777) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change mode of %s: %s\n"),
|
||||||
|
Prog, shadow, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unlink_suffs (user_newname) == SHADOWTCB_FAILURE) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chown (tcbdir, user_newid, dirmode.st_gid) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change owner of %s: %s\n"),
|
||||||
|
Prog, tcbdir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chmod (tcbdir, dirmode.st_mode & 07777) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change mode of %s: %s\n"),
|
||||||
|
Prog, tcbdir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
ret = SHADOWTCB_SUCCESS;
|
||||||
|
out_free:
|
||||||
|
free (tcbdir);
|
||||||
|
free (shadow);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowtcb_status shadowtcb_create (const char *name, uid_t uid)
|
||||||
|
{
|
||||||
|
char *dir, *shadow;
|
||||||
|
struct stat tcbdir_stat;
|
||||||
|
gid_t shadowgid, authgid;
|
||||||
|
struct group *gr;
|
||||||
|
int fd;
|
||||||
|
shadowtcb_status ret = SHADOWTCB_FAILURE;
|
||||||
|
|
||||||
|
if (!getdef_bool ("USE_TCB")) {
|
||||||
|
return SHADOWTCB_SUCCESS;
|
||||||
|
}
|
||||||
|
if (stat (TCB_DIR, &tcbdir_stat) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot stat %s: %s\n"),
|
||||||
|
Prog, TCB_DIR, strerror (errno));
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
shadowgid = tcbdir_stat.st_gid;
|
||||||
|
authgid = shadowgid;
|
||||||
|
if (getdef_bool ("TCB_AUTH_GROUP")) {
|
||||||
|
gr = getgrnam ("auth");
|
||||||
|
if (NULL != gr) {
|
||||||
|
authgid = gr->gr_gid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (asprintf (&dir, TCB_DIR "/%s", name) == -1)
|
||||||
|
|| (asprintf (&shadow, TCB_FMT, name) == -1)) {
|
||||||
|
OUT_OF_MEMORY;
|
||||||
|
return SHADOWTCB_FAILURE;
|
||||||
|
}
|
||||||
|
if (mkdir (dir, 0700) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: mkdir: %s: %s\n"),
|
||||||
|
Prog, dir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
fd = open (shadow, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot open %s: %s\n"),
|
||||||
|
Prog, shadow, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
close (fd);
|
||||||
|
if (chown (shadow, 0, authgid) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change owner of %s: %s\n"),
|
||||||
|
Prog, shadow, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chmod (shadow, (mode_t) ((authgid == shadowgid) ? 0600 : 0640)) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change mode of %s: %s\n"),
|
||||||
|
Prog, shadow, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chown (dir, 0, authgid) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change owner of %s: %s\n"),
|
||||||
|
Prog, dir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (chmod (dir, (mode_t) ((authgid == shadowgid) ? 02700 : 02710)) != 0) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Cannot change mode of %s: %s\n"),
|
||||||
|
Prog, dir, strerror (errno));
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if ( (shadowtcb_set_user (name) == SHADOWTCB_FAILURE)
|
||||||
|
|| (shadowtcb_move (NULL, uid) == SHADOWTCB_FAILURE)) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
ret = SHADOWTCB_SUCCESS;
|
||||||
|
out_free:
|
||||||
|
free (dir);
|
||||||
|
free (shadow);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _TCBFUNCS_H
|
||||||
|
#define _TCBFUNCS_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SHADOWTCB_FAILURE = 0,
|
||||||
|
SHADOWTCB_SUCCESS = 1
|
||||||
|
} shadowtcb_status;
|
||||||
|
|
||||||
|
extern shadowtcb_status shadowtcb_drop_priv (void);
|
||||||
|
extern shadowtcb_status shadowtcb_gain_priv (void);
|
||||||
|
extern shadowtcb_status shadowtcb_set_user (const char *name);
|
||||||
|
extern shadowtcb_status shadowtcb_remove (const char *name);
|
||||||
|
extern shadowtcb_status shadowtcb_move (/*@null@*/const char *user_newname,
|
||||||
|
uid_t user_newid);
|
||||||
|
extern shadowtcb_status shadowtcb_create (const char *name, uid_t uid);
|
||||||
|
|
||||||
|
#endif
|
||||||
-19
@@ -88,25 +88,6 @@ struct utmp *getutent (void)
|
|||||||
|
|
||||||
return &utmp_buf;
|
return &utmp_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* getutline - get the utmp entry matching ut_line
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct utmp *getutline (const struct utmp *utent)
|
|
||||||
{
|
|
||||||
struct utmp save;
|
|
||||||
struct utmp *new;
|
|
||||||
|
|
||||||
save = *utent;
|
|
||||||
while (new = getutent ())
|
|
||||||
if (strncmp (new->ut_line, save.ut_line, sizeof new->ut_line))
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
return new;
|
|
||||||
|
|
||||||
return (struct utmp *) 0;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+17
-6
@@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
EXTRA_DIST = .indent.pro xgetXXbyYY.c
|
EXTRA_DIST = .indent.pro xgetXXbyYY.c
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/lib
|
AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir) $(ECONF_CPPFLAGS)
|
||||||
|
|
||||||
noinst_LIBRARIES = libmisc.a
|
noinst_LTLIBRARIES = libmisc.la
|
||||||
|
|
||||||
libmisc_a_SOURCES = \
|
libmisc_la_SOURCES = \
|
||||||
addgrps.c \
|
addgrps.c \
|
||||||
age.c \
|
age.c \
|
||||||
audit_help.c \
|
audit_help.c \
|
||||||
@@ -23,14 +23,18 @@ libmisc_a_SOURCES = \
|
|||||||
env.c \
|
env.c \
|
||||||
failure.c \
|
failure.c \
|
||||||
failure.h \
|
failure.h \
|
||||||
fields.c \
|
|
||||||
find_new_gid.c \
|
find_new_gid.c \
|
||||||
find_new_uid.c \
|
find_new_uid.c \
|
||||||
|
find_new_sub_gids.c \
|
||||||
|
find_new_sub_uids.c \
|
||||||
getdate.h \
|
getdate.h \
|
||||||
getdate.y \
|
getdate.y \
|
||||||
getgr_nam_gid.c \
|
getgr_nam_gid.c \
|
||||||
getrange.c \
|
getrange.c \
|
||||||
|
gettime.c \
|
||||||
hushed.c \
|
hushed.c \
|
||||||
|
idmapping.h \
|
||||||
|
idmapping.c \
|
||||||
isexpired.c \
|
isexpired.c \
|
||||||
limits.c \
|
limits.c \
|
||||||
list.c log.c \
|
list.c log.c \
|
||||||
@@ -40,16 +44,18 @@ libmisc_a_SOURCES = \
|
|||||||
myname.c \
|
myname.c \
|
||||||
obscure.c \
|
obscure.c \
|
||||||
pam_pass.c \
|
pam_pass.c \
|
||||||
pam_pass_non_interractive.c \
|
pam_pass_non_interactive.c \
|
||||||
|
prefix_flag.c \
|
||||||
pwd2spwd.c \
|
pwd2spwd.c \
|
||||||
pwdcheck.c \
|
pwdcheck.c \
|
||||||
pwd_init.c \
|
pwd_init.c \
|
||||||
|
remove_tree.c \
|
||||||
rlogin.c \
|
rlogin.c \
|
||||||
|
root_flag.c \
|
||||||
salt.c \
|
salt.c \
|
||||||
setugid.c \
|
setugid.c \
|
||||||
setupenv.c \
|
setupenv.c \
|
||||||
shell.c \
|
shell.c \
|
||||||
system.c \
|
|
||||||
strtoday.c \
|
strtoday.c \
|
||||||
sub.c \
|
sub.c \
|
||||||
sulog.c \
|
sulog.c \
|
||||||
@@ -66,3 +72,8 @@ libmisc_a_SOURCES = \
|
|||||||
xgetspnam.c \
|
xgetspnam.c \
|
||||||
xmalloc.c \
|
xmalloc.c \
|
||||||
yesno.c
|
yesno.c
|
||||||
|
|
||||||
|
if WITH_BTRFS
|
||||||
|
libmisc_la_SOURCES += btrfs.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
|||||||
+12
-4
@@ -57,6 +57,7 @@ int add_groups (const char *list)
|
|||||||
bool added;
|
bool added;
|
||||||
char *token;
|
char *token;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (strlen (list) >= sizeof (buf)) {
|
if (strlen (list) >= sizeof (buf)) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@@ -71,7 +72,11 @@ int add_groups (const char *list)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ngroups = getgroups (i, grouplist);
|
ngroups = getgroups (i, grouplist);
|
||||||
if ((-1 == ngroups) || (i > (size_t)ngroups)) {
|
if ( ( (-1 == ngroups)
|
||||||
|
&& (EINVAL != errno))
|
||||||
|
|| (i > (size_t)ngroups)) {
|
||||||
|
/* Unexpected failure of getgroups or successful
|
||||||
|
* reception of the groups */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* not enough room, so try allocating a larger buffer */
|
/* not enough room, so try allocating a larger buffer */
|
||||||
@@ -89,7 +94,7 @@ int add_groups (const char *list)
|
|||||||
|
|
||||||
grp = getgrnam (token); /* local, no need for xgetgrnam */
|
grp = getgrnam (token); /* local, no need for xgetgrnam */
|
||||||
if (NULL == grp) {
|
if (NULL == grp) {
|
||||||
fprintf (stderr, _("Warning: unknown group %s\n"),
|
fprintf (shadow_logfd, _("Warning: unknown group %s\n"),
|
||||||
token);
|
token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -101,7 +106,7 @@ int add_groups (const char *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ngroups >= sysconf (_SC_NGROUPS_MAX)) {
|
if (ngroups >= sysconf (_SC_NGROUPS_MAX)) {
|
||||||
fputs (_("Warning: too many groups\n"), stderr);
|
fputs (_("Warning: too many groups\n"), shadow_logfd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = (gid_t *) realloc (grouplist, (size_t)(ngroups + 1) * sizeof (GETGROUPS_T));
|
tmp = (gid_t *) realloc (grouplist, (size_t)(ngroups + 1) * sizeof (GETGROUPS_T));
|
||||||
@@ -116,9 +121,12 @@ int add_groups (const char *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (added) {
|
if (added) {
|
||||||
return setgroups ((size_t)ngroups, grouplist);
|
ret = setgroups ((size_t)ngroups, grouplist);
|
||||||
|
free (grouplist);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free (grouplist);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else /* HAVE_SETGROUPS && !USE_PAM */
|
#else /* HAVE_SETGROUPS && !USE_PAM */
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ void audit_help_open (void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(void) fputs (_("Cannot open audit interface - aborting.\n"),
|
(void) fputs (_("Cannot open audit interface - aborting.\n"),
|
||||||
stderr);
|
shadow_logfd);
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ void audit_help_open (void)
|
|||||||
* id - uid or gid that the operation is being performed on. This is used
|
* id - uid or gid that the operation is being performed on. This is used
|
||||||
* only when user is NULL.
|
* only when user is NULL.
|
||||||
*/
|
*/
|
||||||
void audit_logger (int type, const char *pgname, const char *op,
|
void audit_logger (int type, unused const char *pgname, const char *op,
|
||||||
const char *name, unsigned int id,
|
const char *name, unsigned int id,
|
||||||
shadow_audit_result result)
|
shadow_audit_result result)
|
||||||
{
|
{
|
||||||
@@ -84,7 +84,7 @@ void audit_logger (int type, const char *pgname, const char *op,
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
audit_log_acct_message (audit_fd, type, NULL, op, name, id,
|
audit_log_acct_message (audit_fd, type, NULL, op, name, id,
|
||||||
NULL, NULL, NULL, (int) result);
|
NULL, NULL, NULL, (int) result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -42,9 +42,9 @@
|
|||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
char *Basename (char *str)
|
/*@observer@*/const char *Basename (const char *str)
|
||||||
{
|
{
|
||||||
char *cp = strrchr (str, '/');
|
char *cp = strrchr (str, '/');
|
||||||
|
|
||||||
return cp ? cp + 1 : str;
|
return (NULL != cp) ? cp + 1 : str;
|
||||||
}
|
}
|
||||||
|
|||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
#include <linux/btrfs_tree.h>
|
||||||
|
#include <linux/magic.h>
|
||||||
|
#include <sys/statfs.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "prototypes.h"
|
||||||
|
|
||||||
|
static bool path_exists(const char *p)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
return stat(p, &sb) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *btrfs_cmd(void)
|
||||||
|
{
|
||||||
|
const char *btrfs_paths[] = {"/sbin/btrfs",
|
||||||
|
"/bin/btrfs", "/usr/sbin/btrfs", "/usr/bin/btrfs", NULL};
|
||||||
|
const char *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0, p = btrfs_paths[i]; p; i++, p = btrfs_paths[i])
|
||||||
|
if (path_exists(p))
|
||||||
|
return p;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int run_btrfs_subvolume_cmd(const char *subcmd, const char *arg1, const char *arg2)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
const char *cmd = btrfs_cmd();
|
||||||
|
const char *argv[] = {
|
||||||
|
"btrfs",
|
||||||
|
"subvolume",
|
||||||
|
subcmd,
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (access(cmd, X_OK)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (run_command(cmd, argv, NULL, &status))
|
||||||
|
return -1;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int btrfs_create_subvolume(const char *path)
|
||||||
|
{
|
||||||
|
return run_btrfs_subvolume_cmd("create", path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int btrfs_remove_subvolume(const char *path)
|
||||||
|
{
|
||||||
|
return run_btrfs_subvolume_cmd("delete", "-C", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Adapted from btrfsprogs */
|
||||||
|
/*
|
||||||
|
* This intentionally duplicates btrfs_util_is_subvolume_fd() instead of opening
|
||||||
|
* a file descriptor and calling it, because fstat() and fstatfs() don't accept
|
||||||
|
* file descriptors opened with O_PATH on old kernels (before v3.6 and before
|
||||||
|
* v3.12, respectively), but stat() and statfs() can be called on a path that
|
||||||
|
* the user doesn't have read or write permissions to.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 1 - btrfs subvolume
|
||||||
|
* 0 - not btrfs subvolume
|
||||||
|
* -1 - error
|
||||||
|
*/
|
||||||
|
int btrfs_is_subvolume(const char *path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = is_btrfs(path);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = stat(path, &st);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Adapted from btrfsprogs */
|
||||||
|
int is_btrfs(const char *path)
|
||||||
|
{
|
||||||
|
struct statfs sfs;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = statfs(path, &sfs);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return sfs.f_type == BTRFS_SUPER_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -46,11 +46,18 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "chkname.h"
|
#include "chkname.h"
|
||||||
|
|
||||||
|
int allow_bad_names = false;
|
||||||
|
|
||||||
static bool is_valid_name (const char *name)
|
static bool is_valid_name (const char *name)
|
||||||
{
|
{
|
||||||
|
if (allow_bad_names) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* User/group names must match [a-z_][a-z0-9_-]*[$]
|
* User/group names must match [a-z_][a-z0-9_-]*[$]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (('\0' == *name) ||
|
if (('\0' == *name) ||
|
||||||
!((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) {
|
!((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+89
-24
@@ -2,6 +2,7 @@
|
|||||||
* Copyright (c) 1992 - 1993, Julianne Frances Haugh
|
* Copyright (c) 1992 - 1993, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||||
|
* Copyright (c) 2010 - , Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -44,59 +45,92 @@
|
|||||||
*
|
*
|
||||||
* chown_dir() walks a directory tree and changes the ownership
|
* chown_dir() walks a directory tree and changes the ownership
|
||||||
* of all files owned by the provided user ID.
|
* of all files owned by the provided user ID.
|
||||||
|
*
|
||||||
|
* Only files owned (resp. group-owned) by old_uid (resp. by old_gid)
|
||||||
|
* will have their ownership (resp. group-ownership) modified, unless
|
||||||
|
* old_uid (resp. old_gid) is set to -1.
|
||||||
|
*
|
||||||
|
* new_uid and new_gid can be set to -1 to indicate that no owner or
|
||||||
|
* group-owner shall be changed.
|
||||||
*/
|
*/
|
||||||
int
|
int chown_tree (const char *root,
|
||||||
chown_tree (const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid,
|
uid_t old_uid,
|
||||||
gid_t new_gid)
|
uid_t new_uid,
|
||||||
|
gid_t old_gid,
|
||||||
|
gid_t new_gid)
|
||||||
{
|
{
|
||||||
char new_name[1024];
|
char *new_name;
|
||||||
|
size_t new_name_len;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct DIRECT *ent;
|
struct DIRECT *ent;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
|
new_name = malloc (1024);
|
||||||
|
if (NULL == new_name) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
new_name_len = 1024;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make certain the directory exists. This routine is called
|
* Make certain the directory exists. This routine is called
|
||||||
* directory by the invoker, or recursively.
|
* directly by the invoker, or recursively.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (access (root, F_OK) != 0)
|
if (access (root, F_OK) != 0) {
|
||||||
|
free (new_name);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the directory and read each entry. Every entry is tested
|
* Open the directory and read each entry. Every entry is tested
|
||||||
* to see if it is a directory, and if so this routine is called
|
* to see if it is a directory, and if so this routine is called
|
||||||
* recursively. If not, it is checked to see if it is owned by
|
* recursively. If not, it is checked to see if an ownership
|
||||||
* old user ID.
|
* shall be changed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!(dir = opendir (root)))
|
dir = opendir (root);
|
||||||
|
if (NULL == dir) {
|
||||||
|
free (new_name);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((ent = readdir (dir))) {
|
while ((ent = readdir (dir))) {
|
||||||
|
size_t ent_name_len;
|
||||||
|
uid_t tmpuid = (uid_t) -1;
|
||||||
|
gid_t tmpgid = (gid_t) -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip the "." and ".." entries
|
* Skip the "." and ".." entries
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (strcmp (ent->d_name, ".") == 0 ||
|
if ( (strcmp (ent->d_name, ".") == 0)
|
||||||
strcmp (ent->d_name, "..") == 0)
|
|| (strcmp (ent->d_name, "..") == 0)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make the filename for both the source and the
|
* Make the filename for both the source and the
|
||||||
* destination files.
|
* destination files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name)
|
ent_name_len = strlen (root) + strlen (ent->d_name) + 2;
|
||||||
break;
|
if (ent_name_len > new_name_len) {
|
||||||
|
/*@only@*/char *tmp = realloc (new_name, ent_name_len);
|
||||||
|
if (NULL == tmp) {
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
new_name = tmp;
|
||||||
|
new_name_len = ent_name_len;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf (new_name, sizeof new_name, "%s/%s", root,
|
(void) snprintf (new_name, new_name_len, "%s/%s", root, ent->d_name);
|
||||||
ent->d_name);
|
|
||||||
|
|
||||||
/* Don't follow symbolic links! */
|
/* Don't follow symbolic links! */
|
||||||
if (LSTAT (new_name, &sb) == -1)
|
if (LSTAT (new_name, &sb) == -1) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (S_ISDIR (sb.st_mode) && !S_ISLNK (sb.st_mode)) {
|
if (S_ISDIR (sb.st_mode) && !S_ISLNK (sb.st_mode)) {
|
||||||
|
|
||||||
@@ -112,25 +146,56 @@ chown_tree (const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid,
|
|||||||
}
|
}
|
||||||
#ifndef HAVE_LCHOWN
|
#ifndef HAVE_LCHOWN
|
||||||
/* don't use chown (follows symbolic links!) */
|
/* don't use chown (follows symbolic links!) */
|
||||||
if (S_ISLNK (sb.st_mode))
|
if (S_ISLNK (sb.st_mode)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (sb.st_uid == old_uid)
|
/*
|
||||||
LCHOWN (new_name, new_uid,
|
* By default, the IDs are not changed (-1).
|
||||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
*
|
||||||
|
* If the file is not owned by the user, the owner is not
|
||||||
|
* changed.
|
||||||
|
*
|
||||||
|
* If the file is not group-owned by the group, the
|
||||||
|
* group-owner is not changed.
|
||||||
|
*/
|
||||||
|
if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
|
||||||
|
tmpuid = new_uid;
|
||||||
|
}
|
||||||
|
if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
|
||||||
|
tmpgid = new_gid;
|
||||||
|
}
|
||||||
|
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
|
||||||
|
rc = LCHOWN (new_name, tmpuid, tmpgid);
|
||||||
|
if (0 != rc) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free (new_name);
|
||||||
(void) closedir (dir);
|
(void) closedir (dir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now do the root of the tree
|
* Now do the root of the tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (stat (root, &sb) == 0) {
|
if ((0 == rc) && (stat (root, &sb) == 0)) {
|
||||||
if (sb.st_uid == old_uid) {
|
uid_t tmpuid = (uid_t) -1;
|
||||||
LCHOWN (root, new_uid,
|
gid_t tmpgid = (gid_t) -1;
|
||||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
|
||||||
|
tmpuid = new_uid;
|
||||||
}
|
}
|
||||||
|
if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
|
||||||
|
tmpgid = new_gid;
|
||||||
|
}
|
||||||
|
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
|
||||||
|
rc = LCHOWN (root, tmpuid, tmpgid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -62,6 +62,7 @@ void chown_tty (const struct passwd *info)
|
|||||||
grent = getgr_nam_gid (getdef_str ("TTYGROUP"));
|
grent = getgr_nam_gid (getdef_str ("TTYGROUP"));
|
||||||
if (NULL != grent) {
|
if (NULL != grent) {
|
||||||
gid = grent->gr_gid;
|
gid = grent->gr_gid;
|
||||||
|
gr_free (grent);
|
||||||
} else {
|
} else {
|
||||||
gid = info->pw_gid;
|
gid = info->pw_gid;
|
||||||
}
|
}
|
||||||
@@ -72,10 +73,10 @@ void chown_tty (const struct passwd *info)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if ( (fchown (STDIN_FILENO, info->pw_uid, gid) != 0)
|
if ( (fchown (STDIN_FILENO, info->pw_uid, gid) != 0)
|
||||||
|| (fchmod (STDIN_FILENO, getdef_num ("TTYPERM", 0600)) != 0)) {
|
|| (fchmod (STDIN_FILENO, (mode_t)getdef_num ("TTYPERM", 0600)) != 0)) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("Unable to change owner or mode of tty stdin: %s"),
|
_("Unable to change owner or mode of tty stdin: %s"),
|
||||||
strerror (err));
|
strerror (err));
|
||||||
SYSLOG ((LOG_WARN,
|
SYSLOG ((LOG_WARN,
|
||||||
|
|||||||
+21
-5
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008 , Nicolas François
|
* Copyright (c) 2008 - 2011, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -38,8 +38,12 @@
|
|||||||
* The cleanup_functions stack.
|
* The cleanup_functions stack.
|
||||||
*/
|
*/
|
||||||
#define CLEANUP_FUNCTIONS 10
|
#define CLEANUP_FUNCTIONS 10
|
||||||
|
|
||||||
|
typedef /*@null@*/void * parg_t;
|
||||||
|
|
||||||
static cleanup_function cleanup_functions[CLEANUP_FUNCTIONS];
|
static cleanup_function cleanup_functions[CLEANUP_FUNCTIONS];
|
||||||
static void * cleanup_function_args[CLEANUP_FUNCTIONS];
|
static parg_t cleanup_function_args[CLEANUP_FUNCTIONS];
|
||||||
|
static pid_t cleanup_pid = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* - Cleanup functions shall not fail.
|
* - Cleanup functions shall not fail.
|
||||||
@@ -53,6 +57,9 @@ static void * cleanup_function_args[CLEANUP_FUNCTIONS];
|
|||||||
/*
|
/*
|
||||||
* do_cleanups - perform the actions stored in the cleanup_functions stack.
|
* do_cleanups - perform the actions stored in the cleanup_functions stack.
|
||||||
*
|
*
|
||||||
|
* Cleanup action are not executed on exit of the processes started by the
|
||||||
|
* parent (first caller of add_cleanup).
|
||||||
|
*
|
||||||
* It is intended to be used as:
|
* It is intended to be used as:
|
||||||
* atexit (do_cleanups);
|
* atexit (do_cleanups);
|
||||||
*/
|
*/
|
||||||
@@ -63,6 +70,10 @@ void do_cleanups (void)
|
|||||||
/* Make sure there were no overflow */
|
/* Make sure there were no overflow */
|
||||||
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-1]);
|
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-1]);
|
||||||
|
|
||||||
|
if (getpid () != cleanup_pid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
i = CLEANUP_FUNCTIONS;
|
i = CLEANUP_FUNCTIONS;
|
||||||
do {
|
do {
|
||||||
i--;
|
i--;
|
||||||
@@ -75,13 +86,17 @@ void do_cleanups (void)
|
|||||||
/*
|
/*
|
||||||
* add_cleanup - Add a cleanup_function to the cleanup_functions stack.
|
* add_cleanup - Add a cleanup_function to the cleanup_functions stack.
|
||||||
*/
|
*/
|
||||||
void add_cleanup (cleanup_function pcf, /*@null@*/void *arg)
|
void add_cleanup (/*@notnull@*/cleanup_function pcf, /*@null@*/void *arg)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
assert (NULL != pcf);
|
assert (NULL != pcf);
|
||||||
|
|
||||||
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-2]);
|
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-2]);
|
||||||
|
|
||||||
|
if (0 == cleanup_pid) {
|
||||||
|
cleanup_pid = getpid ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Add the cleanup_function at the end of the stack */
|
/* Add the cleanup_function at the end of the stack */
|
||||||
for (i=0; NULL != cleanup_functions[i]; i++);
|
for (i=0; NULL != cleanup_functions[i]; i++);
|
||||||
cleanup_functions[i] = pcf;
|
cleanup_functions[i] = pcf;
|
||||||
@@ -91,7 +106,7 @@ void add_cleanup (cleanup_function pcf, /*@null@*/void *arg)
|
|||||||
/*
|
/*
|
||||||
* del_cleanup - Remove a cleanup_function from the cleanup_functions stack.
|
* del_cleanup - Remove a cleanup_function from the cleanup_functions stack.
|
||||||
*/
|
*/
|
||||||
void del_cleanup (cleanup_function pcf)
|
void del_cleanup (/*@notnull@*/cleanup_function pcf)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
assert (NULL != pcf);
|
assert (NULL != pcf);
|
||||||
@@ -109,7 +124,8 @@ void del_cleanup (cleanup_function pcf)
|
|||||||
/* Move the rest of the cleanup functions */
|
/* Move the rest of the cleanup functions */
|
||||||
for (; i<CLEANUP_FUNCTIONS; i++) {
|
for (; i<CLEANUP_FUNCTIONS; i++) {
|
||||||
/* Make sure the cleanup function was specified only once */
|
/* Make sure the cleanup function was specified only once */
|
||||||
assert (cleanup_functions[i+1] != pcf);
|
assert ( (i == (CLEANUP_FUNCTIONS -1))
|
||||||
|
|| (cleanup_functions[i+1] != pcf));
|
||||||
|
|
||||||
if (i == (CLEANUP_FUNCTIONS -1)) {
|
if (i == (CLEANUP_FUNCTIONS -1)) {
|
||||||
cleanup_functions[i] = NULL;
|
cleanup_functions[i] = NULL;
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ void cleanup_report_del_group_gshadow (void *group_name)
|
|||||||
void cleanup_unlock_group (unused void *arg)
|
void cleanup_unlock_group (unused void *arg)
|
||||||
{
|
{
|
||||||
if (gr_unlock () == 0) {
|
if (gr_unlock () == 0) {
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("%s: failed to unlock %s\n"),
|
_("%s: failed to unlock %s\n"),
|
||||||
Prog, gr_dbname ());
|
Prog, gr_dbname ());
|
||||||
SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
|
SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
|
||||||
@@ -223,7 +223,7 @@ void cleanup_unlock_group (unused void *arg)
|
|||||||
void cleanup_unlock_gshadow (unused void *arg)
|
void cleanup_unlock_gshadow (unused void *arg)
|
||||||
{
|
{
|
||||||
if (sgr_unlock () == 0) {
|
if (sgr_unlock () == 0) {
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("%s: failed to unlock %s\n"),
|
_("%s: failed to unlock %s\n"),
|
||||||
Prog, sgr_dbname ());
|
Prog, sgr_dbname ());
|
||||||
SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
|
SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ void cleanup_report_add_user_shadow (void *user_name)
|
|||||||
void cleanup_unlock_passwd (unused void *arg)
|
void cleanup_unlock_passwd (unused void *arg)
|
||||||
{
|
{
|
||||||
if (pw_unlock () == 0) {
|
if (pw_unlock () == 0) {
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("%s: failed to unlock %s\n"),
|
_("%s: failed to unlock %s\n"),
|
||||||
Prog, pw_dbname ());
|
Prog, pw_dbname ());
|
||||||
SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
|
SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
|
||||||
@@ -139,7 +139,7 @@ void cleanup_unlock_passwd (unused void *arg)
|
|||||||
void cleanup_unlock_shadow (unused void *arg)
|
void cleanup_unlock_shadow (unused void *arg)
|
||||||
{
|
{
|
||||||
if (spw_unlock () == 0) {
|
if (spw_unlock () == 0) {
|
||||||
fprintf (stderr,
|
fprintf (shadow_logfd,
|
||||||
_("%s: failed to unlock %s\n"),
|
_("%s: failed to unlock %s\n"),
|
||||||
Prog, spw_dbname ());
|
Prog, spw_dbname ());
|
||||||
SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
|
SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
|
||||||
|
|||||||
+9
-5
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (c) 1991 , Chip Rosenthal
|
* Copyright (c) 1991 , Chip Rosenthal
|
||||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2008, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -50,7 +50,8 @@ static bool is_listed (const char *cfgin, const char *tty, bool def);
|
|||||||
static bool is_listed (const char *cfgin, const char *tty, bool def)
|
static bool is_listed (const char *cfgin, const char *tty, bool def)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char buf[200], *cons, *s;
|
char buf[1024], *s;
|
||||||
|
const char *cons;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the CONSOLE configuration definition isn't given,
|
* If the CONSOLE configuration definition isn't given,
|
||||||
@@ -68,13 +69,16 @@ static bool is_listed (const char *cfgin, const char *tty, bool def)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (*cons != '/') {
|
if (*cons != '/') {
|
||||||
strcpy (buf, cons);
|
char *pbuf;
|
||||||
while ((s = strtok (buf, ":")) != NULL) {
|
strncpy (buf, cons, sizeof (buf));
|
||||||
|
buf[sizeof (buf) - 1] = '\0';
|
||||||
|
pbuf = &buf[0];
|
||||||
|
while ((s = strtok (pbuf, ":")) != NULL) {
|
||||||
if (strcmp (s, tty) == 0) {
|
if (strcmp (s, tty) == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cons = NULL;
|
pbuf = NULL;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+316
-221
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
||||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2008, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -44,7 +44,19 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
#include <selinux/selinux.h>
|
#include <selinux/selinux.h>
|
||||||
#endif
|
#endif /* WITH_SELINUX */
|
||||||
|
#if defined(WITH_ACL) || defined(WITH_ATTR)
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <attr/error_context.h>
|
||||||
|
#endif /* WITH_ACL || WITH_ATTR */
|
||||||
|
#ifdef WITH_ACL
|
||||||
|
#include <acl/libacl.h>
|
||||||
|
#endif /* WITH_ACL */
|
||||||
|
#ifdef WITH_ATTR
|
||||||
|
#include <attr/libattr.h>
|
||||||
|
#endif /* WITH_ATTR */
|
||||||
|
|
||||||
|
|
||||||
static /*@null@*/const char *src_orig;
|
static /*@null@*/const char *src_orig;
|
||||||
static /*@null@*/const char *dst_orig;
|
static /*@null@*/const char *dst_orig;
|
||||||
|
|
||||||
@@ -58,66 +70,73 @@ struct link_name {
|
|||||||
static /*@exposed@*/struct link_name *links;
|
static /*@exposed@*/struct link_name *links;
|
||||||
|
|
||||||
static int copy_entry (const char *src, const char *dst,
|
static int copy_entry (const char *src, const char *dst,
|
||||||
long int uid, long int gid);
|
bool reset_selinux,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
static int copy_dir (const char *src, const char *dst,
|
static int copy_dir (const char *src, const char *dst,
|
||||||
|
bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
#ifdef S_IFLNK
|
#ifdef S_IFLNK
|
||||||
static char *readlink_malloc (const char *filename);
|
static /*@null@*/char *readlink_malloc (const char *filename);
|
||||||
static int copy_symlink (const char *src, const char *dst,
|
static int copy_symlink (const char *src, const char *dst,
|
||||||
|
unused bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid);
|
uid_t old_uid, uid_t new_uid,
|
||||||
#endif
|
gid_t old_gid, gid_t new_gid);
|
||||||
static int copy_hardlink (const char *src, const char *dst,
|
#endif /* S_IFLNK */
|
||||||
|
static int copy_hardlink (const char *dst,
|
||||||
|
unused bool reset_selinux,
|
||||||
struct link_name *lp);
|
struct link_name *lp);
|
||||||
static int copy_special (const char *dst,
|
static int copy_special (const char *src, const char *dst,
|
||||||
|
bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
static int copy_file (const char *src, const char *dst,
|
static int copy_file (const char *src, const char *dst,
|
||||||
|
bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
static int chown_if_needed (const char *dst, const struct stat *statp,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
static int lchown_if_needed (const char *dst, const struct stat *statp,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
static int fchown_if_needed (int fdst, const struct stat *statp,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#if defined(WITH_ACL) || defined(WITH_ATTR)
|
||||||
/*
|
/*
|
||||||
* selinux_file_context - Set the security context before any file or
|
* error_acl - format the error messages for the ACL and EQ libraries.
|
||||||
* directory creation.
|
|
||||||
*
|
|
||||||
* 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);
|
|
||||||
*/
|
*/
|
||||||
int selinux_file_context (const char *dst_name)
|
static void error_acl (struct error_context *ctx, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
static bool selinux_checked = false;
|
va_list ap;
|
||||||
static bool selinux_enabled;
|
|
||||||
security_context_t scontext = NULL;
|
|
||||||
|
|
||||||
if (!selinux_checked) {
|
/* ignore the case when destination does not support ACLs
|
||||||
selinux_enabled = is_selinux_enabled () > 0;
|
* or extended attributes */
|
||||||
selinux_checked = true;
|
if (ENOTSUP == errno) {
|
||||||
|
errno = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selinux_enabled) {
|
va_start (ap, fmt);
|
||||||
/* Get the default security context for this file */
|
(void) fprintf (shadow_logfd, _("%s: "), Prog);
|
||||||
if (matchpathcon (dst_name, 0, &scontext) < 0) {
|
if (vfprintf (shadow_logfd, fmt, ap) != 0) {
|
||||||
if (security_getenforce () != 0) {
|
(void) fputs (_(": "), shadow_logfd);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Set the security context for the next created file */
|
|
||||||
if (setfscreatecon (scontext) < 0) {
|
|
||||||
if (security_getenforce () != 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
freecon (scontext);
|
|
||||||
}
|
}
|
||||||
return 0;
|
(void) fprintf (shadow_logfd, "%s\n", strerror (errno));
|
||||||
|
va_end (ap);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
static struct error_context ctx = {
|
||||||
|
error_acl
|
||||||
|
};
|
||||||
|
#endif /* WITH_ACL || WITH_ATTR */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove_link - delete a link from the linked list
|
* remove_link - delete a link from the linked list
|
||||||
@@ -184,7 +203,7 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
|
|||||||
lp->ln_count = sb->st_nlink;
|
lp->ln_count = sb->st_nlink;
|
||||||
len = name_len - src_len + dst_len + 1;
|
len = name_len - src_len + dst_len + 1;
|
||||||
lp->ln_name = (char *) xmalloc (len);
|
lp->ln_name = (char *) xmalloc (len);
|
||||||
snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
|
(void) snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
|
||||||
lp->ln_next = links;
|
lp->ln_next = links;
|
||||||
links = lp;
|
links = lp;
|
||||||
|
|
||||||
@@ -196,15 +215,49 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
|
|||||||
*
|
*
|
||||||
* copy_tree() walks a directory tree and copies ordinary files
|
* copy_tree() walks a directory tree and copies ordinary files
|
||||||
* as it goes.
|
* as it goes.
|
||||||
|
*
|
||||||
|
* When reset_selinux is enabled, extended attributes (and thus
|
||||||
|
* SELinux attributes) are not copied.
|
||||||
|
*
|
||||||
|
* old_uid and new_uid are used to set the ownership of the copied
|
||||||
|
* files. Unless old_uid is set to -1, only the files owned by
|
||||||
|
* old_uid have their ownership changed to new_uid. In addition, if
|
||||||
|
* new_uid is set to -1, no ownership will be changed.
|
||||||
|
*
|
||||||
|
* The same logic applies for the group-ownership and
|
||||||
|
* old_gid/new_gid.
|
||||||
*/
|
*/
|
||||||
int copy_tree (const char *src_root, const char *dst_root,
|
int copy_tree (const char *src_root, const char *dst_root,
|
||||||
long int uid, long int gid)
|
bool copy_root, bool reset_selinux,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
bool set_orig = false;
|
bool set_orig = false;
|
||||||
struct DIRECT *ent;
|
struct DIRECT *ent;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
|
if (copy_root) {
|
||||||
|
struct stat sb;
|
||||||
|
if (access (dst_root, F_OK) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LSTAT (src_root, &sb) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISDIR (sb.st_mode)) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
"%s: %s is not a directory",
|
||||||
|
Prog, src_root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy_entry (src_root, dst_root, reset_selinux,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make certain both directories exist. This routine is called
|
* Make certain both directories exist. This routine is called
|
||||||
* after the home directory is created, or recursively after the
|
* after the home directory is created, or recursively after the
|
||||||
@@ -256,12 +309,15 @@ int copy_tree (const char *src_root, const char *dst_root,
|
|||||||
* Build the filename for both the source and
|
* Build the filename for both the source and
|
||||||
* the destination files.
|
* the destination files.
|
||||||
*/
|
*/
|
||||||
snprintf (src_name, src_len, "%s/%s",
|
(void) snprintf (src_name, src_len, "%s/%s",
|
||||||
src_root, ent->d_name);
|
src_root, ent->d_name);
|
||||||
snprintf (dst_name, dst_len, "%s/%s",
|
(void) snprintf (dst_name, dst_len, "%s/%s",
|
||||||
dst_root, ent->d_name);
|
dst_root, ent->d_name);
|
||||||
|
|
||||||
err = copy_entry (src_name, dst_name, uid, gid);
|
err = copy_entry (src_name, dst_name,
|
||||||
|
reset_selinux,
|
||||||
|
old_uid, new_uid,
|
||||||
|
old_gid, new_gid);
|
||||||
}
|
}
|
||||||
if (NULL != src_name) {
|
if (NULL != src_name) {
|
||||||
free (src_name);
|
free (src_name);
|
||||||
@@ -276,16 +332,25 @@ int copy_tree (const char *src_root, const char *dst_root,
|
|||||||
if (set_orig) {
|
if (set_orig) {
|
||||||
src_orig = NULL;
|
src_orig = NULL;
|
||||||
dst_orig = NULL;
|
dst_orig = NULL;
|
||||||
|
/* FIXME: clean links
|
||||||
|
* Since there can be hardlinks elsewhere on the device,
|
||||||
|
* we cannot check that all the hardlinks were found:
|
||||||
|
assert (NULL == links);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
/* Reset SELinux to create files with default contexts */
|
/* Reset SELinux to create files with default contexts.
|
||||||
setfscreatecon (NULL);
|
* Note that the context is only reset on exit of copy_tree (it is
|
||||||
#endif
|
* assumed that the program would quit without needing a restored
|
||||||
|
* context if copy_tree failed previously), and that copy_tree can
|
||||||
/* FIXME: with the call to remove_link, we could also check that
|
* be called recursively (hence the context is set on the
|
||||||
* no links remain in links.
|
* sub-functions of copy_entry).
|
||||||
* assert (NULL == links); */
|
*/
|
||||||
|
if (reset_selinux_file_context () != 0) {
|
||||||
|
err = -1;
|
||||||
|
}
|
||||||
|
#endif /* WITH_SELINUX */
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -300,13 +365,19 @@ int copy_tree (const char *src_root, const char *dst_root,
|
|||||||
*
|
*
|
||||||
* The access and modification time will not be modified.
|
* The access and modification time will not be modified.
|
||||||
*
|
*
|
||||||
* The permissions will be set to uid/gid.
|
* The permissions will be set to new_uid/new_gid.
|
||||||
*
|
*
|
||||||
* If uid (resp. gid) is equal to -1, the user (resp. group) will
|
* If new_uid (resp. new_gid) is equal to -1, the user (resp. group) will
|
||||||
* not be modified.
|
* not be modified.
|
||||||
|
*
|
||||||
|
* Only the files owned (resp. group-owned) by old_uid (resp.
|
||||||
|
* old_gid) will be modified, unless old_uid (resp. old_gid) is set
|
||||||
|
* to -1.
|
||||||
*/
|
*/
|
||||||
static int copy_entry (const char *src, const char *dst,
|
static int copy_entry (const char *src, const char *dst,
|
||||||
long int uid, long int gid)
|
bool reset_selinux,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
@@ -319,29 +390,30 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
#ifdef HAVE_STRUCT_STAT_ST_ATIM
|
#ifdef HAVE_STRUCT_STAT_ST_ATIM
|
||||||
mt[0].tv_sec = sb.st_atim.tv_sec;
|
mt[0].tv_sec = sb.st_atim.tv_sec;
|
||||||
mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
||||||
#else
|
#else /* !HAVE_STRUCT_STAT_ST_ATIM */
|
||||||
mt[0].tv_sec = sb.st_atime;
|
mt[0].tv_sec = sb.st_atime;
|
||||||
#ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
|
# ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
|
||||||
mt[0].tv_usec = sb.st_atimensec / 1000;
|
mt[0].tv_usec = sb.st_atimensec / 1000;
|
||||||
#else
|
# else /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
|
||||||
mt[0].tv_usec = 0;
|
mt[0].tv_usec = 0;
|
||||||
#endif
|
# endif /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
|
||||||
#endif
|
#endif /* !HAVE_STRUCT_STAT_ST_ATIM */
|
||||||
|
|
||||||
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
||||||
mt[1].tv_sec = sb.st_mtim.tv_sec;
|
mt[1].tv_sec = sb.st_mtim.tv_sec;
|
||||||
mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
|
mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
|
||||||
#else
|
#else /* !HAVE_STRUCT_STAT_ST_MTIM */
|
||||||
mt[1].tv_sec = sb.st_mtime;
|
mt[1].tv_sec = sb.st_mtime;
|
||||||
#ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
# ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||||
mt[1].tv_usec = sb.st_mtimensec / 1000;
|
mt[1].tv_usec = sb.st_mtimensec / 1000;
|
||||||
#else
|
# else /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
|
||||||
mt[1].tv_usec = 0;
|
mt[1].tv_usec = 0;
|
||||||
#endif
|
# endif /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
|
||||||
#endif
|
#endif /* !HAVE_STRUCT_STAT_ST_MTIM */
|
||||||
|
|
||||||
if (S_ISDIR (sb.st_mode)) {
|
if (S_ISDIR (sb.st_mode)) {
|
||||||
err = copy_dir (src, dst, &sb, mt, uid, gid);
|
err = copy_dir (src, dst, reset_selinux, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef S_IFLNK
|
#ifdef S_IFLNK
|
||||||
@@ -350,16 +422,17 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else if (S_ISLNK (sb.st_mode)) {
|
else if (S_ISLNK (sb.st_mode)) {
|
||||||
err = copy_symlink (src, dst, &sb, mt, uid, gid);
|
err = copy_symlink (src, dst, reset_selinux, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* S_IFLNK */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if this is a previously copied link
|
* See if this is a previously copied link
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else if ((lp = check_link (src, &sb)) != NULL) {
|
else if ((lp = check_link (src, &sb)) != NULL) {
|
||||||
err = copy_hardlink (src, dst, lp);
|
err = copy_hardlink (dst, reset_selinux, lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -369,7 +442,8 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else if (!S_ISREG (sb.st_mode)) {
|
else if (!S_ISREG (sb.st_mode)) {
|
||||||
err = copy_special (dst, &sb, mt, uid, gid);
|
err = copy_special (src, dst, reset_selinux, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -378,7 +452,8 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else {
|
else {
|
||||||
err = copy_file (src, dst, &sb, mt, uid, gid);
|
err = copy_file (src, dst, reset_selinux, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,14 +465,16 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*
|
*
|
||||||
* Copy a directory (recursively) from src to dst.
|
* Copy a directory (recursively) from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_dir (const char *src, const char *dst,
|
static int copy_dir (const char *src, const char *dst,
|
||||||
|
bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@@ -407,14 +484,33 @@ static int copy_dir (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst);
|
if (set_selinux_file_context (dst, S_IFDIR) != 0) {
|
||||||
#endif
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* WITH_SELINUX */
|
||||||
if ( (mkdir (dst, statp->st_mode) != 0)
|
if ( (mkdir (dst, statp->st_mode) != 0)
|
||||||
|| (chown (dst,
|
|| (chown_if_needed (dst, statp,
|
||||||
(uid == - 1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
(gid == - 1) ? statp->st_gid : (gid_t) gid) != 0)
|
#ifdef WITH_ACL
|
||||||
|
|| ( (perm_copy_file (src, dst, &ctx) != 0)
|
||||||
|
&& (errno != 0))
|
||||||
|
#else /* !WITH_ACL */
|
||||||
|| (chmod (dst, statp->st_mode) != 0)
|
|| (chmod (dst, statp->st_mode) != 0)
|
||||||
|| (copy_tree (src, dst, uid, gid) != 0)
|
#endif /* !WITH_ACL */
|
||||||
|
#ifdef WITH_ATTR
|
||||||
|
/*
|
||||||
|
* If the third parameter is NULL, all extended attributes
|
||||||
|
* except those that define Access Control Lists are copied.
|
||||||
|
* ACLs are excluded by default because copying them between
|
||||||
|
* file systems with and without ACL support needs some
|
||||||
|
* additional logic so that no unexpected permissions result.
|
||||||
|
*/
|
||||||
|
|| ( !reset_selinux
|
||||||
|
&& (attr_copy_file (src, dst, NULL, &ctx) != 0)
|
||||||
|
&& (errno != 0))
|
||||||
|
#endif /* WITH_ATTR */
|
||||||
|
|| (copy_tree (src, dst, false, reset_selinux,
|
||||||
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
|| (utimes (dst, mt) != 0)) {
|
|| (utimes (dst, mt) != 0)) {
|
||||||
err = -1;
|
err = -1;
|
||||||
}
|
}
|
||||||
@@ -429,11 +525,11 @@ static int copy_dir (const char *src, const char *dst,
|
|||||||
* return NULL on error.
|
* return NULL on error.
|
||||||
* The return string shall be freed by the caller.
|
* The return string shall be freed by the caller.
|
||||||
*/
|
*/
|
||||||
static char *readlink_malloc (const char *filename)
|
static /*@null@*/char *readlink_malloc (const char *filename)
|
||||||
{
|
{
|
||||||
size_t size = 1024;
|
size_t size = 1024;
|
||||||
|
|
||||||
while (1) {
|
while (true) {
|
||||||
ssize_t nchars;
|
ssize_t nchars;
|
||||||
char *buffer = (char *) malloc (size);
|
char *buffer = (char *) malloc (size);
|
||||||
if (NULL == buffer) {
|
if (NULL == buffer) {
|
||||||
@@ -443,10 +539,11 @@ static char *readlink_malloc (const char *filename)
|
|||||||
nchars = readlink (filename, buffer, size);
|
nchars = readlink (filename, buffer, size);
|
||||||
|
|
||||||
if (nchars < 0) {
|
if (nchars < 0) {
|
||||||
|
free(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (size_t) nchars < size) { /* The buffer was large enough */
|
if ((size_t) nchars < size) { /* The buffer was large enough */
|
||||||
/* readlink does not nul-terminate */
|
/* readlink does not nul-terminate */
|
||||||
buffer[nchars] = '\0';
|
buffer[nchars] = '\0';
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -463,14 +560,16 @@ static char *readlink_malloc (const char *filename)
|
|||||||
*
|
*
|
||||||
* Copy a symlink from src to dst.
|
* Copy a symlink from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_symlink (const char *src, const char *dst,
|
static int copy_symlink (const char *src, const char *dst,
|
||||||
|
unused bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
char *oldlink;
|
char *oldlink;
|
||||||
|
|
||||||
@@ -494,25 +593,33 @@ static int copy_symlink (const char *src, const char *dst,
|
|||||||
/* If src was a link to an entry of the src_orig directory itself,
|
/* 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
|
* create a link to the corresponding entry in the dst_orig
|
||||||
* directory.
|
* directory.
|
||||||
* FIXME: This may change a relative link to an absolute link
|
|
||||||
*/
|
*/
|
||||||
if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
|
if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
|
||||||
size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
|
size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
|
||||||
char *dummy = (char *) malloc (len);
|
char *dummy = (char *) xmalloc (len);
|
||||||
snprintf (dummy, len, "%s%s",
|
(void) snprintf (dummy, len, "%s%s",
|
||||||
dst_orig,
|
dst_orig,
|
||||||
oldlink + strlen (src_orig));
|
oldlink + strlen (src_orig));
|
||||||
free (oldlink);
|
free (oldlink);
|
||||||
oldlink = dummy;
|
oldlink = dummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst);
|
if (set_selinux_file_context (dst, S_IFLNK) != 0) {
|
||||||
#endif
|
free (oldlink);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* WITH_SELINUX */
|
||||||
if ( (symlink (oldlink, dst) != 0)
|
if ( (symlink (oldlink, dst) != 0)
|
||||||
|| (lchown (dst,
|
|| (lchown_if_needed (dst, statp,
|
||||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)) {
|
||||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
|
/* FIXME: there are no modes on symlinks, right?
|
||||||
|
* ACL could be copied, but this would be much more
|
||||||
|
* complex than calling perm_copy_file.
|
||||||
|
* Ditto for Extended Attributes.
|
||||||
|
* We currently only document that ACL and Extended
|
||||||
|
* Attributes are not copied.
|
||||||
|
*/
|
||||||
free (oldlink);
|
free (oldlink);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -524,12 +631,12 @@ static int copy_symlink (const char *src, const char *dst,
|
|||||||
* it returns ENOSYS on many system
|
* it returns ENOSYS on many system
|
||||||
* - not implemented
|
* - not implemented
|
||||||
*/
|
*/
|
||||||
lutimes (dst, mt);
|
(void) lutimes (dst, mt);
|
||||||
#endif
|
#endif /* HAVE_LUTIMES */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* S_IFLNK */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* copy_hardlink - copy a hardlink
|
* copy_hardlink - copy a hardlink
|
||||||
@@ -538,23 +645,18 @@ static int copy_symlink (const char *src, const char *dst,
|
|||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_hardlink (const char *src, const char *dst,
|
static int copy_hardlink (const char *dst,
|
||||||
|
unused bool reset_selinux,
|
||||||
struct link_name *lp)
|
struct link_name *lp)
|
||||||
{
|
{
|
||||||
/* TODO: selinux needed? */
|
/* FIXME: selinux, ACL, Extended Attributes needed? */
|
||||||
|
|
||||||
if (link (lp->ln_name, dst) != 0) {
|
if (link (lp->ln_name, dst) != 0) {
|
||||||
return -1;
|
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,
|
/* If the file could be unlinked, decrement the links counter,
|
||||||
* and delete the file if it was the last reference */
|
* and forget about this link if it was the last reference */
|
||||||
lp->ln_count--;
|
lp->ln_count--;
|
||||||
if (lp->ln_count <= 0) {
|
if (lp->ln_count <= 0) {
|
||||||
remove_link (lp);
|
remove_link (lp);
|
||||||
@@ -568,26 +670,46 @@ static int copy_hardlink (const char *src, const char *dst,
|
|||||||
*
|
*
|
||||||
* Copy a special file from src to dst.
|
* Copy a special file from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_special (const char *dst,
|
static int copy_special (const char *src, const char *dst,
|
||||||
|
bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst);
|
if (set_selinux_file_context (dst, statp->st_mode & S_IFMT) != 0) {
|
||||||
#endif
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* WITH_SELINUX */
|
||||||
|
|
||||||
if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
|
if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
|
||||||
|| (chown (dst,
|
|| (chown_if_needed (dst, statp,
|
||||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
#ifdef WITH_ACL
|
||||||
|
|| ( (perm_copy_file (src, dst, &ctx) != 0)
|
||||||
|
&& (errno != 0))
|
||||||
|
#else /* !WITH_ACL */
|
||||||
|| (chmod (dst, statp->st_mode & 07777) != 0)
|
|| (chmod (dst, statp->st_mode & 07777) != 0)
|
||||||
|
#endif /* !WITH_ACL */
|
||||||
|
#ifdef WITH_ATTR
|
||||||
|
/*
|
||||||
|
* If the third parameter is NULL, all extended attributes
|
||||||
|
* except those that define Access Control Lists are copied.
|
||||||
|
* ACLs are excluded by default because copying them between
|
||||||
|
* file systems with and without ACL support needs some
|
||||||
|
* additional logic so that no unexpected permissions result.
|
||||||
|
*/
|
||||||
|
|| ( !reset_selinux
|
||||||
|
&& (attr_copy_file (src, dst, NULL, &ctx) != 0)
|
||||||
|
&& (errno != 0))
|
||||||
|
#endif /* WITH_ATTR */
|
||||||
|| (utimes (dst, mt) != 0)) {
|
|| (utimes (dst, mt) != 0)) {
|
||||||
err = -1;
|
err = -1;
|
||||||
}
|
}
|
||||||
@@ -600,14 +722,16 @@ static int copy_special (const char *dst,
|
|||||||
*
|
*
|
||||||
* Copy a file from src to dst.
|
* Copy a file from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_file (const char *src, const char *dst,
|
static int copy_file (const char *src, const char *dst,
|
||||||
|
bool reset_selinux,
|
||||||
const struct stat *statp, const struct timeval mt[],
|
const struct stat *statp, const struct timeval mt[],
|
||||||
long int uid, long int gid)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int ifd;
|
int ifd;
|
||||||
@@ -620,20 +744,45 @@ static int copy_file (const char *src, const char *dst,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst);
|
if (set_selinux_file_context (dst, S_IFREG) != 0) {
|
||||||
#endif
|
(void) close (ifd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* WITH_SELINUX */
|
||||||
ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
|
ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
|
||||||
if ( (ofd < 0)
|
if ( (ofd < 0)
|
||||||
|| (fchown (ofd,
|
|| (fchown_if_needed (ofd, statp,
|
||||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
#ifdef WITH_ACL
|
||||||
|| (fchmod (ofd, statp->st_mode & 07777) != 0)) {
|
|| ( (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
|
||||||
|
&& (errno != 0))
|
||||||
|
#else /* !WITH_ACL */
|
||||||
|
|| (fchmod (ofd, statp->st_mode & 07777) != 0)
|
||||||
|
#endif /* !WITH_ACL */
|
||||||
|
#ifdef WITH_ATTR
|
||||||
|
/*
|
||||||
|
* If the third parameter is NULL, all extended attributes
|
||||||
|
* except those that define Access Control Lists are copied.
|
||||||
|
* ACLs are excluded by default because copying them between
|
||||||
|
* file systems with and without ACL support needs some
|
||||||
|
* additional logic so that no unexpected permissions result.
|
||||||
|
*/
|
||||||
|
|| ( !reset_selinux
|
||||||
|
&& (attr_copy_fd (src, ifd, dst, ofd, NULL, &ctx) != 0)
|
||||||
|
&& (errno != 0))
|
||||||
|
#endif /* WITH_ATTR */
|
||||||
|
) {
|
||||||
|
if (ofd >= 0) {
|
||||||
|
(void) close (ofd);
|
||||||
|
}
|
||||||
(void) close (ifd);
|
(void) close (ifd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
|
while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
|
||||||
if (write (ofd, buf, (size_t)cnt) != cnt) {
|
if (write (ofd, buf, (size_t)cnt) != cnt) {
|
||||||
|
(void) close (ofd);
|
||||||
|
(void) close (ifd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -642,9 +791,10 @@ static int copy_file (const char *src, const char *dst,
|
|||||||
|
|
||||||
#ifdef HAVE_FUTIMES
|
#ifdef HAVE_FUTIMES
|
||||||
if (futimes (ofd, mt) != 0) {
|
if (futimes (ofd, mt) != 0) {
|
||||||
|
(void) close (ofd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* HAVE_FUTIMES */
|
||||||
|
|
||||||
if (close (ofd) != 0) {
|
if (close (ofd) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -654,97 +804,42 @@ static int copy_file (const char *src, const char *dst,
|
|||||||
if (utimes(dst, mt) != 0) {
|
if (utimes(dst, mt) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* !HAVE_FUTIMES */
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#define def_chown_if_needed(chown_function, type_dst) \
|
||||||
* remove_tree - delete a directory tree
|
static int chown_function ## _if_needed (type_dst dst, \
|
||||||
*
|
const struct stat *statp, \
|
||||||
* remove_tree() walks a directory tree and deletes all the files
|
uid_t old_uid, uid_t new_uid, \
|
||||||
* and directories.
|
gid_t old_gid, gid_t new_gid) \
|
||||||
* At the end, it deletes the root directory itself.
|
{ \
|
||||||
*/
|
uid_t tmpuid = (uid_t) -1; \
|
||||||
|
gid_t tmpgid = (gid_t) -1; \
|
||||||
int remove_tree (const char *root)
|
\
|
||||||
{
|
/* Use new_uid if old_uid is set to -1 or if the file was \
|
||||||
char *new_name = NULL;
|
* owned by the user. */ \
|
||||||
int err = 0;
|
if (((uid_t) -1 == old_uid) || (statp->st_uid == old_uid)) { \
|
||||||
struct DIRECT *ent;
|
tmpuid = new_uid; \
|
||||||
struct stat sb;
|
} \
|
||||||
DIR *dir;
|
/* Otherwise, or if new_uid was set to -1, we keep the same \
|
||||||
|
* owner. */ \
|
||||||
/*
|
if ((uid_t) -1 == tmpuid) { \
|
||||||
* Open the source directory and read each entry. Every file
|
tmpuid = statp->st_uid; \
|
||||||
* entry in the directory is copied with the UID and GID set
|
} \
|
||||||
* to the provided values. As an added security feature only
|
\
|
||||||
* regular files (and directories ...) are copied, and no file
|
if (((gid_t) -1 == old_gid) || (statp->st_gid == old_gid)) { \
|
||||||
* is made set-ID.
|
tmpgid = new_gid; \
|
||||||
*/
|
} \
|
||||||
dir = opendir (root);
|
if ((gid_t) -1 == tmpgid) { \
|
||||||
if (NULL == dir) {
|
tmpgid = statp->st_gid; \
|
||||||
return -1;
|
} \
|
||||||
}
|
\
|
||||||
|
return chown_function (dst, tmpuid, tmpgid); \
|
||||||
while ((ent = readdir (dir))) {
|
|
||||||
size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip the "." and ".." entries
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (strcmp (ent->d_name, ".") == 0 ||
|
|
||||||
strcmp (ent->d_name, "..") == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make the filename for the current entry.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (NULL != new_name) {
|
|
||||||
free (new_name);
|
|
||||||
}
|
|
||||||
new_name = (char *) malloc (new_len);
|
|
||||||
if (NULL == new_name) {
|
|
||||||
err = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
|
|
||||||
if (LSTAT (new_name, &sb) == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISDIR (sb.st_mode)) {
|
|
||||||
/*
|
|
||||||
* Recursively delete this directory.
|
|
||||||
*/
|
|
||||||
if (remove_tree (new_name) != 0) {
|
|
||||||
err = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Delete the file.
|
|
||||||
*/
|
|
||||||
if (unlink (new_name) != 0) {
|
|
||||||
err = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (NULL != new_name) {
|
|
||||||
free (new_name);
|
|
||||||
}
|
|
||||||
(void) closedir (dir);
|
|
||||||
|
|
||||||
if (0 == err) {
|
|
||||||
if (rmdir (root) != 0) {
|
|
||||||
err = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def_chown_if_needed (chown, const char *)
|
||||||
|
def_chown_if_needed (lchown, const char *)
|
||||||
|
def_chown_if_needed (fchown, int)
|
||||||
|
|
||||||
|
|||||||
+14
-4
@@ -115,6 +115,9 @@ void addenv (const char *string, /*@null@*/const char *value)
|
|||||||
|
|
||||||
n = (size_t) (cp - newstring);
|
n = (size_t) (cp - newstring);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this environment variable is already set, change its value.
|
||||||
|
*/
|
||||||
for (i = 0; i < newenvc; i++) {
|
for (i = 0; i < newenvc; i++) {
|
||||||
if ( (strncmp (newstring, newenvp[i], n) == 0)
|
if ( (strncmp (newstring, newenvp[i], n) == 0)
|
||||||
&& (('=' == newenvp[i][n]) || ('\0' == newenvp[i][n]))) {
|
&& (('=' == newenvp[i][n]) || ('\0' == newenvp[i][n]))) {
|
||||||
@@ -128,8 +131,15 @@ void addenv (const char *string, /*@null@*/const char *value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Otherwise, save the new environment variable
|
||||||
|
*/
|
||||||
newenvp[newenvc++] = newstring;
|
newenvp[newenvc++] = newstring;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And extend the environment if needed.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether newenvc is a multiple of NEWENVP_STEP.
|
* Check whether newenvc is a multiple of NEWENVP_STEP.
|
||||||
* If so we have to resize the vector.
|
* If so we have to resize the vector.
|
||||||
@@ -143,14 +153,14 @@ void addenv (const char *string, /*@null@*/const char *value)
|
|||||||
size_t newsize;
|
size_t newsize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the resize operation succeds we can
|
* If the resize operation succeeds we can
|
||||||
* happily go on, else print a message.
|
* happily go on, else print a message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
newsize = (newenvc + NEWENVP_STEP) * sizeof (char *);
|
newsize = (newenvc + NEWENVP_STEP) * sizeof (char *);
|
||||||
__newenvp = (char **) realloc (newenvp, newsize);
|
__newenvp = (char **) realloc (newenvp, newsize);
|
||||||
|
|
||||||
if (__newenvp) {
|
if (NULL != __newenvp) {
|
||||||
/*
|
/*
|
||||||
* If this is our current environment, update
|
* If this is our current environment, update
|
||||||
* environ so that it doesn't point to some
|
* environ so that it doesn't point to some
|
||||||
@@ -161,7 +171,7 @@ void addenv (const char *string, /*@null@*/const char *value)
|
|||||||
}
|
}
|
||||||
newenvp = __newenvp;
|
newenvp = __newenvp;
|
||||||
} else {
|
} else {
|
||||||
(void) fputs (_("Environment overflow\n"), stderr);
|
(void) fputs (_("Environment overflow\n"), shadow_logfd);
|
||||||
newenvc--;
|
newenvc--;
|
||||||
free (newenvp[newenvc]);
|
free (newenvp[newenvc]);
|
||||||
}
|
}
|
||||||
@@ -251,7 +261,7 @@ void sanitize_env (void)
|
|||||||
if (strncmp (*cur, *bad, strlen (*bad)) != 0) {
|
if (strncmp (*cur, *bad, strlen (*bad)) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strchr (*cur, '/') != NULL) {
|
if (strchr (*cur, '/') == NULL) {
|
||||||
continue; /* OK */
|
continue; /* OK */
|
||||||
}
|
}
|
||||||
for (move = cur; NULL != *move; move++) {
|
for (move = cur; NULL != *move; move++) {
|
||||||
|
|||||||
+5
-3
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||||
* Copyright (c) 2002 - 2005, Tomasz Kłoczko
|
* Copyright (c) 2002 - 2005, Tomasz Kłoczko
|
||||||
* Copyright (c) 2008 , Nicolas François
|
* Copyright (c) 2008 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -98,7 +98,7 @@ void failure (uid_t uid, const char *tty, struct faillog *fl)
|
|||||||
fl->fail_cnt++;
|
fl->fail_cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy (fl->fail_line, tty, sizeof fl->fail_line);
|
strncpy (fl->fail_line, tty, sizeof (fl->fail_line) - 1);
|
||||||
(void) time (&fl->fail_time);
|
(void) time (&fl->fail_time);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -273,12 +273,14 @@ void failprint (const struct faillog *fail)
|
|||||||
lasttime++;
|
lasttime++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/*@-formatconst@*/
|
||||||
(void) printf (ngettext ("%d failure since last login.\n"
|
(void) printf (ngettext ("%d failure since last login.\n"
|
||||||
"Last was %s on %s.\n",
|
"Last was %s on %s.\n",
|
||||||
"%d failures since last login.\n"
|
"%d failures since last login.\n"
|
||||||
"Last was %s on %s.\n",
|
"Last was %s on %s.\n",
|
||||||
(unsigned long) fail->fail_cnt),
|
(unsigned long) fail->fail_cnt),
|
||||||
fail->fail_cnt, lasttime, fail->fail_line);
|
fail->fail_cnt, lasttime, fail->fail_line);
|
||||||
|
/*@=formatconst@*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -296,7 +298,7 @@ void failtmp (const char *username,
|
|||||||
#endif /* !USE_UTMPX */
|
#endif /* !USE_UTMPX */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
char *ftmp;
|
const char *ftmp;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ extern int failcheck (uid_t uid, struct faillog *fl, bool failed);
|
|||||||
extern void failprint (const struct faillog *);
|
extern void failprint (const struct faillog *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* failtmp - update the cummulative failure log
|
* failtmp - update the cumulative failure log
|
||||||
*
|
*
|
||||||
* failtmp updates the (struct utmp) formatted failure log which
|
* failtmp updates the (struct utmp) formatted failure log which
|
||||||
* maintains a record of all login failures.
|
* maintains a record of all login failures.
|
||||||
|
|||||||
+418
-104
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 2008 - 2009, Nicolas François
|
* Copyright (c) 2008 - 2011, Nicolas François
|
||||||
|
* Copyright (c) 2014, Red Hat, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -32,11 +33,123 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "groupio.h"
|
#include "groupio.h"
|
||||||
#include "getdef.h"
|
#include "getdef.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_ranges - Get the minimum and maximum ID ranges for the search
|
||||||
|
*
|
||||||
|
* This function will return the minimum and maximum ranges for IDs
|
||||||
|
*
|
||||||
|
* 0: The function completed successfully
|
||||||
|
* EINVAL: The provided ranges are impossible (such as maximum < minimum)
|
||||||
|
*
|
||||||
|
* preferred_min: The special-case minimum value for a specifically-
|
||||||
|
* requested ID, which may be lower than the standard min_id
|
||||||
|
*/
|
||||||
|
static int get_ranges (bool sys_group, gid_t *min_id, gid_t *max_id,
|
||||||
|
gid_t *preferred_min)
|
||||||
|
{
|
||||||
|
gid_t gid_def_max = 0;
|
||||||
|
|
||||||
|
if (sys_group) {
|
||||||
|
/* System groups */
|
||||||
|
|
||||||
|
/* A requested ID is allowed to be below the autoselect range */
|
||||||
|
*preferred_min = (gid_t) 1;
|
||||||
|
|
||||||
|
/* Get the minimum ID range from login.defs or default to 101 */
|
||||||
|
*min_id = (gid_t) getdef_ulong ("SYS_GID_MIN", 101UL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If SYS_GID_MAX is unspecified, we should assume it to be one
|
||||||
|
* less than the GID_MIN (which is reserved for non-system accounts)
|
||||||
|
*/
|
||||||
|
gid_def_max = (gid_t) getdef_ulong ("GID_MIN", 1000UL) - 1;
|
||||||
|
*max_id = (gid_t) getdef_ulong ("SYS_GID_MAX",
|
||||||
|
(unsigned long) gid_def_max);
|
||||||
|
|
||||||
|
/* Check that the ranges make sense */
|
||||||
|
if (*max_id < *min_id) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
_("%s: Invalid configuration: SYS_GID_MIN (%lu), "
|
||||||
|
"GID_MIN (%lu), SYS_GID_MAX (%lu)\n"),
|
||||||
|
Prog, (unsigned long) *min_id,
|
||||||
|
getdef_ulong ("GID_MIN", 1000UL),
|
||||||
|
(unsigned long) *max_id);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Non-system groups */
|
||||||
|
|
||||||
|
/* Get the values from login.defs or use reasonable defaults */
|
||||||
|
*min_id = (gid_t) getdef_ulong ("GID_MIN", 1000UL);
|
||||||
|
*max_id = (gid_t) getdef_ulong ("GID_MAX", 60000UL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The preferred minimum should match the standard ID minimum
|
||||||
|
* for non-system groups.
|
||||||
|
*/
|
||||||
|
*preferred_min = *min_id;
|
||||||
|
|
||||||
|
/* Check that the ranges make sense */
|
||||||
|
if (*max_id < *min_id) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
_("%s: Invalid configuration: GID_MIN (%lu), "
|
||||||
|
"GID_MAX (%lu)\n"),
|
||||||
|
Prog, (unsigned long) *min_id,
|
||||||
|
(unsigned long) *max_id);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check_gid - See if the requested GID is available
|
||||||
|
*
|
||||||
|
* On success, return 0
|
||||||
|
* If the ID is in use, return EEXIST
|
||||||
|
* If the ID is outside the range, return ERANGE
|
||||||
|
* In other cases, return errno from getgrgid()
|
||||||
|
*/
|
||||||
|
static int check_gid (const gid_t gid,
|
||||||
|
const gid_t gid_min,
|
||||||
|
const gid_t gid_max,
|
||||||
|
bool *used_gids)
|
||||||
|
{
|
||||||
|
/* First test that the preferred ID is in the range */
|
||||||
|
if (gid < gid_min || gid > gid_max) {
|
||||||
|
return ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether we already detected this GID
|
||||||
|
* using the gr_next() loop
|
||||||
|
*/
|
||||||
|
if (used_gids != NULL && used_gids[gid]) {
|
||||||
|
return EEXIST;
|
||||||
|
}
|
||||||
|
/* Check if the GID exists according to NSS */
|
||||||
|
errno = 0;
|
||||||
|
if (prefix_getgrgid (gid) != NULL) {
|
||||||
|
return EEXIST;
|
||||||
|
} else {
|
||||||
|
/* getgrgid() was NULL
|
||||||
|
* we have to ignore errors as temporary
|
||||||
|
* failures of remote user identity services
|
||||||
|
* would completely block user/group creation
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we've made it here, the GID must be available */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_new_gid - Find a new unused GID.
|
* find_new_gid - Find a new unused GID.
|
||||||
*
|
*
|
||||||
@@ -48,137 +161,338 @@
|
|||||||
* Return 0 on success, -1 if no unused GIDs are available.
|
* Return 0 on success, -1 if no unused GIDs are available.
|
||||||
*/
|
*/
|
||||||
int find_new_gid (bool sys_group,
|
int find_new_gid (bool sys_group,
|
||||||
gid_t *gid,
|
gid_t *gid,
|
||||||
/*@null@*/gid_t const *preferred_gid)
|
/*@null@*/gid_t const *preferred_gid)
|
||||||
{
|
{
|
||||||
const struct group *grp;
|
|
||||||
gid_t gid_min, gid_max, group_id, id;
|
|
||||||
bool *used_gids;
|
bool *used_gids;
|
||||||
|
const struct group *grp;
|
||||||
|
gid_t gid_min, gid_max, preferred_min;
|
||||||
|
gid_t id;
|
||||||
|
gid_t lowest_found, highest_found;
|
||||||
|
int result;
|
||||||
|
int nospam = 0;
|
||||||
|
|
||||||
assert (gid != NULL);
|
assert(gid != NULL);
|
||||||
|
|
||||||
if (!sys_group) {
|
/*
|
||||||
gid_min = (gid_t) getdef_ulong ("GID_MIN", 1000UL);
|
* First, figure out what ID range is appropriate for
|
||||||
gid_max = (gid_t) getdef_ulong ("GID_MAX", 60000UL);
|
* automatic assignment
|
||||||
} else {
|
*/
|
||||||
gid_min = (gid_t) getdef_ulong ("SYS_GID_MIN", 101UL);
|
result = get_ranges (sys_group, &gid_min, &gid_max, &preferred_min);
|
||||||
gid_max = (gid_t) getdef_ulong ("GID_MIN", 1000UL) - 1;
|
if (result == EINVAL) {
|
||||||
gid_max = (gid_t) getdef_ulong ("SYS_GID_MAX", (unsigned long) gid_max);
|
return -1;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if the preferred GID is available */
|
||||||
|
if (preferred_gid) {
|
||||||
|
result = check_gid (*preferred_gid, preferred_min, gid_max, NULL);
|
||||||
|
if (result == 0) {
|
||||||
|
/*
|
||||||
|
* Make sure the GID isn't queued for use already
|
||||||
|
*/
|
||||||
|
if (gr_locate_gid (*preferred_gid) == NULL) {
|
||||||
|
*gid = *preferred_gid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* gr_locate_gid() found the GID in an as-yet uncommitted
|
||||||
|
* entry. We'll proceed below and auto-set a GID.
|
||||||
|
*/
|
||||||
|
} else if (result == EEXIST || result == ERANGE) {
|
||||||
|
/*
|
||||||
|
* Continue on below. At this time, we won't
|
||||||
|
* treat these two cases differently.
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred. We should report
|
||||||
|
* this and fail the group creation.
|
||||||
|
* This differs from the automatic creation
|
||||||
|
* behavior below, since if a specific GID was
|
||||||
|
* requested and generated an error, the user is
|
||||||
|
* more likely to want to stop and address the
|
||||||
|
* issue.
|
||||||
|
*/
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Encountered error attempting to use "
|
||||||
|
"preferred GID: %s\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search the entire group file,
|
* Search the entire group file,
|
||||||
* looking for the largest unused value.
|
* looking for the next unused value.
|
||||||
|
*
|
||||||
|
* We first check the local database with gr_rewind/gr_next to find
|
||||||
|
* all local values that are in use.
|
||||||
|
*
|
||||||
|
* We then compare the next free value to all databases (local and
|
||||||
|
* remote) and iterate until we find a free one. If there are free
|
||||||
|
* values beyond the lowest (system groups) or highest (non-system
|
||||||
|
* groups), we will prefer those and avoid potentially reclaiming a
|
||||||
|
* deleted group (which can be a security issue, since it may grant
|
||||||
|
* access to files belonging to that former group).
|
||||||
|
*
|
||||||
|
* If there are no GIDs available at the end of the search, we will
|
||||||
|
* have no choice but to iterate through the range looking for gaps.
|
||||||
*
|
*
|
||||||
* 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
|
/* Create an array to hold all of the discovered GIDs */
|
||||||
* LDAP configurations (and many accounts).
|
used_gids = malloc (sizeof (bool) * (gid_max +1));
|
||||||
* Since there is a limited amount of IDs to be tested
|
if (NULL == used_gids) {
|
||||||
* for system accounts, we just check the existence
|
fprintf (shadow_logfd,
|
||||||
* of IDs with getgrgid.
|
_("%s: failed to allocate memory: %s\n"),
|
||||||
|
Prog, strerror (errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset (used_gids, false, sizeof (bool) * (gid_max + 1));
|
||||||
|
|
||||||
|
/* First look for the lowest and highest value in the local database */
|
||||||
|
(void) gr_rewind ();
|
||||||
|
highest_found = gid_min;
|
||||||
|
lowest_found = gid_max;
|
||||||
|
while ((grp = gr_next ()) != NULL) {
|
||||||
|
/*
|
||||||
|
* Does this entry have a lower GID than the lowest we've found
|
||||||
|
* so far?
|
||||||
*/
|
*/
|
||||||
group_id = gid_max;
|
if ((grp->gr_gid <= lowest_found) && (grp->gr_gid >= gid_min)) {
|
||||||
for (id = gid_max; id >= gid_min; id--) {
|
lowest_found = grp->gr_gid - 1;
|
||||||
if (getgrgid (id) != NULL) {
|
|
||||||
group_id = id - 1;
|
|
||||||
used_gids[id] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gr_rewind ();
|
/*
|
||||||
while ((grp = gr_next ()) != NULL) {
|
* Does this entry have a higher GID than the highest we've found
|
||||||
if ((grp->gr_gid <= group_id) && (grp->gr_gid >= gid_min)) {
|
* so far?
|
||||||
group_id = grp->gr_gid - 1;
|
*/
|
||||||
}
|
if ((grp->gr_gid >= highest_found) && (grp->gr_gid <= gid_max)) {
|
||||||
/* create index of used GIDs */
|
highest_found = grp->gr_gid + 1;
|
||||||
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 ();
|
/* create index of used GIDs */
|
||||||
while ((grp = gr_next ()) != NULL) {
|
if (grp->gr_gid >= gid_min
|
||||||
if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) {
|
&& grp->gr_gid <= gid_max) {
|
||||||
group_id = grp->gr_gid + 1;
|
|
||||||
}
|
used_gids[grp->gr_gid] = true;
|
||||||
/* 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 (sys_group) {
|
||||||
if (group_id == gid_min - 1) {
|
/*
|
||||||
for (group_id = gid_max; group_id >= gid_min; group_id--) {
|
* For system groups, we want to start from the
|
||||||
if (false == used_gids[group_id]) {
|
* top of the range and work downwards.
|
||||||
break;
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At the conclusion of the gr_next() search, we will either
|
||||||
|
* have a presumed-free GID or we will be at GID_MIN - 1.
|
||||||
|
*/
|
||||||
|
if (lowest_found < gid_min) {
|
||||||
|
/*
|
||||||
|
* In this case, a GID is in use at GID_MIN.
|
||||||
|
*
|
||||||
|
* We will reset the search to GID_MAX and proceed down
|
||||||
|
* through all the GIDs (skipping those we detected with
|
||||||
|
* used_gids) for a free one. It is a known issue that
|
||||||
|
* this may result in reusing a previously-deleted GID,
|
||||||
|
* so administrators should be instructed to use this
|
||||||
|
* auto-detection with care (and prefer to assign GIDs
|
||||||
|
* explicitly).
|
||||||
|
*/
|
||||||
|
lowest_found = gid_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search through all of the IDs in the range */
|
||||||
|
for (id = lowest_found; id >= gid_min; id--) {
|
||||||
|
result = check_gid (id, gid_min, gid_max, used_gids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This GID is available. Return it. */
|
||||||
|
*gid = id;
|
||||||
|
free (used_gids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This GID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique system GID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG ((LOG_ERR,
|
||||||
|
"Error checking available GIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
}
|
}
|
||||||
}
|
/*
|
||||||
if ( group_id < gid_min ) {
|
* We will continue anyway. Hopefully a later GID
|
||||||
fprintf (stderr,
|
* will work properly.
|
||||||
_("%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 we get all the way through the loop, try again from GID_MAX,
|
||||||
if (false == used_gids[group_id]) {
|
* unless that was where we previously started. (NOTE: the worst-case
|
||||||
break;
|
* scenario here is that we will run through (GID_MAX - GID_MIN - 1)
|
||||||
|
* cycles *again* if we fall into this case with lowest_found as
|
||||||
|
* GID_MAX - 1, all groups in the range in use and maintained by
|
||||||
|
* network services such as LDAP.)
|
||||||
|
*/
|
||||||
|
if (lowest_found != gid_max) {
|
||||||
|
for (id = gid_max; id >= gid_min; id--) {
|
||||||
|
result = check_gid (id, gid_min, gid_max, used_gids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This GID is available. Return it. */
|
||||||
|
*gid = id;
|
||||||
|
free (used_gids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This GID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique system GID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG ((LOG_ERR,
|
||||||
|
"Error checking available GIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We will continue anyway. Hopefully a later GID
|
||||||
|
* will work properly.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (group_id == gid_max) {
|
}
|
||||||
fprintf (stderr,
|
} else { /* !sys_group */
|
||||||
_("%s: Can't get unique GID (no more available GIDs)\n"),
|
/*
|
||||||
Prog);
|
* For non-system groups, we want to start from the
|
||||||
SYSLOG ((LOG_WARN, "no more available GID on the system"));
|
* bottom of the range and work upwards.
|
||||||
return -1;
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At the conclusion of the gr_next() search, we will either
|
||||||
|
* have a presumed-free GID or we will be at GID_MAX + 1.
|
||||||
|
*/
|
||||||
|
if (highest_found > gid_max) {
|
||||||
|
/*
|
||||||
|
* In this case, a GID is in use at GID_MAX.
|
||||||
|
*
|
||||||
|
* We will reset the search to GID_MIN and proceed up
|
||||||
|
* through all the GIDs (skipping those we detected with
|
||||||
|
* used_gids) for a free one. It is a known issue that
|
||||||
|
* this may result in reusing a previously-deleted GID,
|
||||||
|
* so administrators should be instructed to use this
|
||||||
|
* auto-detection with care (and prefer to assign GIDs
|
||||||
|
* explicitly).
|
||||||
|
*/
|
||||||
|
highest_found = gid_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search through all of the IDs in the range */
|
||||||
|
for (id = highest_found; id <= gid_max; id++) {
|
||||||
|
result = check_gid (id, gid_min, gid_max, used_gids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This GID is available. Return it. */
|
||||||
|
*gid = id;
|
||||||
|
free (used_gids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This GID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique GID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG ((LOG_ERR,
|
||||||
|
"Error checking available GIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We will continue anyway. Hopefully a later GID
|
||||||
|
* will work properly.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we get all the way through the loop, try again from GID_MIN,
|
||||||
|
* unless that was where we previously started. (NOTE: the worst-case
|
||||||
|
* scenario here is that we will run through (GID_MAX - GID_MIN - 1)
|
||||||
|
* cycles *again* if we fall into this case with highest_found as
|
||||||
|
* GID_MIN + 1, all groups in the range in use and maintained by
|
||||||
|
* network services such as LDAP.)
|
||||||
|
*/
|
||||||
|
if (highest_found != gid_min) {
|
||||||
|
for (id = gid_min; id <= gid_max; id++) {
|
||||||
|
result = check_gid (id, gid_min, gid_max, used_gids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This GID is available. Return it. */
|
||||||
|
*gid = id;
|
||||||
|
free (used_gids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This GID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique GID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG ((LOG_ERR,
|
||||||
|
"Error checking available GIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We will continue anyway. Hopefully a later GID
|
||||||
|
* will work properly.
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*gid = group_id;
|
/* The code reached here and found no available IDs in the range */
|
||||||
return 0;
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique GID (no more available GIDs)\n"),
|
||||||
|
Prog);
|
||||||
|
SYSLOG ((LOG_WARN, "no more available GIDs on the system"));
|
||||||
|
free (used_gids);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Eric Biederman
|
||||||
|
*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#ifdef ENABLE_SUBIDS
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include "subordinateio.h"
|
||||||
|
#include "getdef.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find_new_sub_gids - Find a new unused range of GIDs.
|
||||||
|
*
|
||||||
|
* If successful, find_new_sub_gids provides a range of unused
|
||||||
|
* user IDs in the [SUB_GID_MIN:SUB_GID_MAX] range.
|
||||||
|
*
|
||||||
|
* Return 0 on success, -1 if no unused GIDs are available.
|
||||||
|
*/
|
||||||
|
int find_new_sub_gids (gid_t *range_start, unsigned long *range_count)
|
||||||
|
{
|
||||||
|
unsigned long min, max;
|
||||||
|
unsigned long count;
|
||||||
|
gid_t start;
|
||||||
|
|
||||||
|
assert (range_start != NULL);
|
||||||
|
assert (range_count != NULL);
|
||||||
|
|
||||||
|
min = getdef_ulong ("SUB_GID_MIN", 100000UL);
|
||||||
|
max = getdef_ulong ("SUB_GID_MAX", 600100000UL);
|
||||||
|
count = getdef_ulong ("SUB_GID_COUNT", 65536);
|
||||||
|
|
||||||
|
if (min > max || count >= max || (min + count - 1) > max) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
_("%s: Invalid configuration: SUB_GID_MIN (%lu),"
|
||||||
|
" SUB_GID_MAX (%lu), SUB_GID_COUNT (%lu)\n"),
|
||||||
|
Prog, min, max, count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = sub_gid_find_free_range(min, max, count);
|
||||||
|
if (start == (gid_t)-1) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique subordinate GID range\n"),
|
||||||
|
Prog);
|
||||||
|
SYSLOG ((LOG_WARN, "no more available subordinate GIDs on the system"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*range_start = start;
|
||||||
|
*range_count = count;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else /* !ENABLE_SUBIDS */
|
||||||
|
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||||
|
#endif /* !ENABLE_SUBIDS */
|
||||||
|
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Eric Biederman
|
||||||
|
*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#ifdef ENABLE_SUBIDS
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include "subordinateio.h"
|
||||||
|
#include "getdef.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find_new_sub_uids - Find a new unused range of UIDs.
|
||||||
|
*
|
||||||
|
* If successful, find_new_sub_uids provides a range of unused
|
||||||
|
* user IDs in the [SUB_UID_MIN:SUB_UID_MAX] range.
|
||||||
|
*
|
||||||
|
* Return 0 on success, -1 if no unused UIDs are available.
|
||||||
|
*/
|
||||||
|
int find_new_sub_uids (uid_t *range_start, unsigned long *range_count)
|
||||||
|
{
|
||||||
|
unsigned long min, max;
|
||||||
|
unsigned long count;
|
||||||
|
uid_t start;
|
||||||
|
|
||||||
|
assert (range_start != NULL);
|
||||||
|
assert (range_count != NULL);
|
||||||
|
|
||||||
|
min = getdef_ulong ("SUB_UID_MIN", 100000UL);
|
||||||
|
max = getdef_ulong ("SUB_UID_MAX", 600100000UL);
|
||||||
|
count = getdef_ulong ("SUB_UID_COUNT", 65536);
|
||||||
|
|
||||||
|
if (min > max || count >= max || (min + count - 1) > max) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
_("%s: Invalid configuration: SUB_UID_MIN (%lu),"
|
||||||
|
" SUB_UID_MAX (%lu), SUB_UID_COUNT (%lu)\n"),
|
||||||
|
Prog, min, max, count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = sub_uid_find_free_range(min, max, count);
|
||||||
|
if (start == (uid_t)-1) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique subordinate UID range\n"),
|
||||||
|
Prog);
|
||||||
|
SYSLOG ((LOG_WARN, "no more available subordinate UIDs on the system"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*range_start = start;
|
||||||
|
*range_count = count;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else /* !ENABLE_SUBIDS */
|
||||||
|
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||||
|
#endif /* !ENABLE_SUBIDS */
|
||||||
|
|
||||||
+422
-108
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 2008 - 2009, Nicolas François
|
* Copyright (c) 2008 - 2011, Nicolas François
|
||||||
|
* Copyright (c) 2014, Red Hat, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -32,11 +33,123 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "pwio.h"
|
#include "pwio.h"
|
||||||
#include "getdef.h"
|
#include "getdef.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_ranges - Get the minimum and maximum ID ranges for the search
|
||||||
|
*
|
||||||
|
* This function will return the minimum and maximum ranges for IDs
|
||||||
|
*
|
||||||
|
* 0: The function completed successfully
|
||||||
|
* EINVAL: The provided ranges are impossible (such as maximum < minimum)
|
||||||
|
*
|
||||||
|
* preferred_min: The special-case minimum value for a specifically-
|
||||||
|
* requested ID, which may be lower than the standard min_id
|
||||||
|
*/
|
||||||
|
static int get_ranges (bool sys_user, uid_t *min_id, uid_t *max_id,
|
||||||
|
uid_t *preferred_min)
|
||||||
|
{
|
||||||
|
uid_t uid_def_max = 0;
|
||||||
|
|
||||||
|
if (sys_user) {
|
||||||
|
/* System users */
|
||||||
|
|
||||||
|
/* A requested ID is allowed to be below the autoselect range */
|
||||||
|
*preferred_min = (uid_t) 1;
|
||||||
|
|
||||||
|
/* Get the minimum ID range from login.defs or default to 101 */
|
||||||
|
*min_id = (uid_t) getdef_ulong ("SYS_UID_MIN", 101UL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If SYS_UID_MAX is unspecified, we should assume it to be one
|
||||||
|
* less than the UID_MIN (which is reserved for non-system accounts)
|
||||||
|
*/
|
||||||
|
uid_def_max = (uid_t) getdef_ulong ("UID_MIN", 1000UL) - 1;
|
||||||
|
*max_id = (uid_t) getdef_ulong ("SYS_UID_MAX",
|
||||||
|
(unsigned long) uid_def_max);
|
||||||
|
|
||||||
|
/* Check that the ranges make sense */
|
||||||
|
if (*max_id < *min_id) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
_("%s: Invalid configuration: SYS_UID_MIN (%lu), "
|
||||||
|
"UID_MIN (%lu), SYS_UID_MAX (%lu)\n"),
|
||||||
|
Prog, (unsigned long) *min_id,
|
||||||
|
getdef_ulong ("UID_MIN", 1000UL),
|
||||||
|
(unsigned long) *max_id);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Non-system users */
|
||||||
|
|
||||||
|
/* Get the values from login.defs or use reasonable defaults */
|
||||||
|
*min_id = (uid_t) getdef_ulong ("UID_MIN", 1000UL);
|
||||||
|
*max_id = (uid_t) getdef_ulong ("UID_MAX", 60000UL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The preferred minimum should match the standard ID minimum
|
||||||
|
* for non-system users.
|
||||||
|
*/
|
||||||
|
*preferred_min = *min_id;
|
||||||
|
|
||||||
|
/* Check that the ranges make sense */
|
||||||
|
if (*max_id < *min_id) {
|
||||||
|
(void) fprintf (shadow_logfd,
|
||||||
|
_("%s: Invalid configuration: UID_MIN (%lu), "
|
||||||
|
"UID_MAX (%lu)\n"),
|
||||||
|
Prog, (unsigned long) *min_id,
|
||||||
|
(unsigned long) *max_id);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check_uid - See if the requested UID is available
|
||||||
|
*
|
||||||
|
* On success, return 0
|
||||||
|
* If the ID is in use, return EEXIST
|
||||||
|
* If the ID is outside the range, return ERANGE
|
||||||
|
* In other cases, return errno from getpwuid()
|
||||||
|
*/
|
||||||
|
static int check_uid(const uid_t uid,
|
||||||
|
const uid_t uid_min,
|
||||||
|
const uid_t uid_max,
|
||||||
|
bool *used_uids)
|
||||||
|
{
|
||||||
|
/* First test that the preferred ID is in the range */
|
||||||
|
if (uid < uid_min || uid > uid_max) {
|
||||||
|
return ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether we already detected this UID
|
||||||
|
* using the pw_next() loop
|
||||||
|
*/
|
||||||
|
if (used_uids != NULL && used_uids[uid]) {
|
||||||
|
return EEXIST;
|
||||||
|
}
|
||||||
|
/* Check if the UID exists according to NSS */
|
||||||
|
errno = 0;
|
||||||
|
if (prefix_getpwuid(uid) != NULL) {
|
||||||
|
return EEXIST;
|
||||||
|
} else {
|
||||||
|
/* getpwuid() was NULL
|
||||||
|
* we have to ignore errors as temporary
|
||||||
|
* failures of remote user identity services
|
||||||
|
* would completely block user/group creation
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we've made it here, the UID must be available */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_new_uid - Find a new unused UID.
|
* find_new_uid - Find a new unused UID.
|
||||||
*
|
*
|
||||||
@@ -47,138 +160,339 @@
|
|||||||
*
|
*
|
||||||
* Return 0 on success, -1 if no unused UIDs are available.
|
* Return 0 on success, -1 if no unused UIDs are available.
|
||||||
*/
|
*/
|
||||||
int find_new_uid (bool sys_user,
|
int find_new_uid(bool sys_user,
|
||||||
uid_t *uid,
|
uid_t *uid,
|
||||||
/*@null@*/uid_t const *preferred_uid)
|
/*@null@*/uid_t const *preferred_uid)
|
||||||
{
|
{
|
||||||
const struct passwd *pwd;
|
|
||||||
uid_t uid_min, uid_max, user_id, id;
|
|
||||||
bool *used_uids;
|
bool *used_uids;
|
||||||
|
const struct passwd *pwd;
|
||||||
|
uid_t uid_min, uid_max, preferred_min;
|
||||||
|
uid_t id;
|
||||||
|
uid_t lowest_found, highest_found;
|
||||||
|
int result;
|
||||||
|
int nospam = 0;
|
||||||
|
|
||||||
assert (uid != NULL);
|
assert (uid != NULL);
|
||||||
|
|
||||||
if (!sys_user) {
|
/*
|
||||||
uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL);
|
* First, figure out what ID range is appropriate for
|
||||||
uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL);
|
* automatic assignment
|
||||||
} else {
|
*/
|
||||||
uid_min = (uid_t) getdef_ulong ("SYS_UID_MIN", 101UL);
|
result = get_ranges (sys_user, &uid_min, &uid_max, &preferred_min);
|
||||||
uid_max = (uid_t) getdef_ulong ("UID_MIN", 1000UL) - 1;
|
if (result == EINVAL) {
|
||||||
uid_max = (uid_t) getdef_ulong ("SYS_UID_MAX", (unsigned long) uid_max);
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the preferred UID is available */
|
||||||
|
if (preferred_uid) {
|
||||||
|
result = check_uid (*preferred_uid, preferred_min, uid_max, NULL);
|
||||||
|
if (result == 0) {
|
||||||
|
/*
|
||||||
|
* Make sure the UID isn't queued for use already
|
||||||
|
*/
|
||||||
|
if (pw_locate_uid (*preferred_uid) == NULL) {
|
||||||
|
*uid = *preferred_uid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* pw_locate_uid() found the UID in an as-yet uncommitted
|
||||||
|
* entry. We'll proceed below and auto-set an UID.
|
||||||
|
*/
|
||||||
|
} else if (result == EEXIST || result == ERANGE) {
|
||||||
|
/*
|
||||||
|
* Continue on below. At this time, we won't
|
||||||
|
* treat these two cases differently.
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred. We should report
|
||||||
|
* this and fail the user creation.
|
||||||
|
* This differs from the automatic creation
|
||||||
|
* behavior below, since if a specific UID was
|
||||||
|
* requested and generated an error, the user is
|
||||||
|
* more likely to want to stop and address the
|
||||||
|
* issue.
|
||||||
|
*/
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Encountered error attempting to use "
|
||||||
|
"preferred UID: %s\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search the entire passwd file,
|
||||||
|
* looking for the next unused value.
|
||||||
|
*
|
||||||
|
* We first check the local database with pw_rewind/pw_next to find
|
||||||
|
* all local values that are in use.
|
||||||
|
*
|
||||||
|
* We then compare the next free value to all databases (local and
|
||||||
|
* remote) and iterate until we find a free one. If there are free
|
||||||
|
* values beyond the lowest (system users) or highest (non-system
|
||||||
|
* users), we will prefer those and avoid potentially reclaiming a
|
||||||
|
* deleted user (which can be a security issue, since it may grant
|
||||||
|
* access to files belonging to that former user).
|
||||||
|
*
|
||||||
|
* If there are no UIDs available at the end of the search, we will
|
||||||
|
* have no choice but to iterate through the range looking for gaps.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Create an array to hold all of the discovered UIDs */
|
||||||
|
used_uids = malloc (sizeof (bool) * (uid_max +1));
|
||||||
|
if (NULL == used_uids) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: failed to allocate memory: %s\n"),
|
||||||
|
Prog, strerror (errno));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
used_uids = alloca (sizeof (bool) * (uid_max +1));
|
|
||||||
memset (used_uids, false, sizeof (bool) * (uid_max + 1));
|
memset (used_uids, false, sizeof (bool) * (uid_max + 1));
|
||||||
|
|
||||||
if ( (NULL != preferred_uid)
|
/* First look for the lowest and highest value in the local database */
|
||||||
&& (*preferred_uid >= uid_min)
|
(void) pw_rewind ();
|
||||||
&& (*preferred_uid <= uid_max)
|
highest_found = uid_min;
|
||||||
/* Check if the user exists according to NSS */
|
lowest_found = uid_max;
|
||||||
&& (getpwuid (*preferred_uid) == NULL)
|
while ((pwd = pw_next ()) != NULL) {
|
||||||
/* Check also the local database in case of uncommitted
|
/*
|
||||||
* changes */
|
* Does this entry have a lower UID than the lowest we've found
|
||||||
&& (pw_locate_uid (*preferred_uid) == NULL)) {
|
* so far?
|
||||||
*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;
|
if ((pwd->pw_uid <= lowest_found) && (pwd->pw_uid >= uid_min)) {
|
||||||
for (id = uid_max; id >= uid_min; id--) {
|
lowest_found = pwd->pw_uid - 1;
|
||||||
if (getpwuid (id) != NULL) {
|
|
||||||
user_id = id - 1;
|
|
||||||
used_uids[id] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pw_rewind ();
|
/*
|
||||||
while ((pwd = pw_next ()) != NULL) {
|
* Does this entry have a higher UID than the highest we've found
|
||||||
if ((pwd->pw_uid <= user_id) && (pwd->pw_uid >= uid_min)) {
|
* so far?
|
||||||
user_id = pwd->pw_uid - 1;
|
*/
|
||||||
}
|
if ((pwd->pw_uid >= highest_found) && (pwd->pw_uid <= uid_max)) {
|
||||||
/* create index of used UIDs */
|
highest_found = pwd->pw_uid + 1;
|
||||||
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 ();
|
/* create index of used UIDs */
|
||||||
while ((pwd = pw_next ()) != NULL) {
|
if (pwd->pw_uid >= uid_min
|
||||||
if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) {
|
&& pwd->pw_uid <= uid_max) {
|
||||||
user_id = pwd->pw_uid + 1;
|
|
||||||
}
|
used_uids[pwd->pw_uid] = true;
|
||||||
/* 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 (sys_user) {
|
||||||
if (user_id == uid_min - 1) {
|
/*
|
||||||
for (user_id = uid_max; user_id >= uid_min; user_id--) {
|
* For system users, we want to start from the
|
||||||
if (false == used_uids[user_id]) {
|
* top of the range and work downwards.
|
||||||
break;
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At the conclusion of the pw_next() search, we will either
|
||||||
|
* have a presumed-free UID or we will be at UID_MIN - 1.
|
||||||
|
*/
|
||||||
|
if (lowest_found < uid_min) {
|
||||||
|
/*
|
||||||
|
* In this case, an UID is in use at UID_MIN.
|
||||||
|
*
|
||||||
|
* We will reset the search to UID_MAX and proceed down
|
||||||
|
* through all the UIDs (skipping those we detected with
|
||||||
|
* used_uids) for a free one. It is a known issue that
|
||||||
|
* this may result in reusing a previously-deleted UID,
|
||||||
|
* so administrators should be instructed to use this
|
||||||
|
* auto-detection with care (and prefer to assign UIDs
|
||||||
|
* explicitly).
|
||||||
|
*/
|
||||||
|
lowest_found = uid_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search through all of the IDs in the range */
|
||||||
|
for (id = lowest_found; id >= uid_min; id--) {
|
||||||
|
result = check_uid (id, uid_min, uid_max, used_uids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This UID is available. Return it. */
|
||||||
|
*uid = id;
|
||||||
|
free (used_uids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This UID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique system UID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG ((LOG_ERR,
|
||||||
|
"Error checking available UIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
}
|
}
|
||||||
}
|
/*
|
||||||
if (user_id < uid_min ) {
|
* We will continue anyway. Hopefully a later UID
|
||||||
fprintf (stderr,
|
* will work properly.
|
||||||
_("%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 we get all the way through the loop, try again from UID_MAX,
|
||||||
if (false == used_uids[user_id]) {
|
* unless that was where we previously started. (NOTE: the worst-case
|
||||||
break;
|
* scenario here is that we will run through (UID_MAX - UID_MIN - 1)
|
||||||
|
* cycles *again* if we fall into this case with lowest_found as
|
||||||
|
* UID_MAX - 1, all users in the range in use and maintained by
|
||||||
|
* network services such as LDAP.)
|
||||||
|
*/
|
||||||
|
if (lowest_found != uid_max) {
|
||||||
|
for (id = uid_max; id >= uid_min; id--) {
|
||||||
|
result = check_uid (id, uid_min, uid_max, used_uids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This UID is available. Return it. */
|
||||||
|
*uid = id;
|
||||||
|
free (used_uids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This UID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique system UID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG((LOG_ERR,
|
||||||
|
"Error checking available UIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We will continue anyway. Hopefully a later UID
|
||||||
|
* will work properly.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (user_id == uid_max) {
|
}
|
||||||
fprintf (stderr,
|
} else { /* !sys_user */
|
||||||
_("%s: Can't get unique UID (no more available UIDs)\n"),
|
/*
|
||||||
Prog);
|
* For non-system users, we want to start from the
|
||||||
SYSLOG ((LOG_WARN, "no more available UID on the system"));
|
* bottom of the range and work upwards.
|
||||||
return -1;
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At the conclusion of the pw_next() search, we will either
|
||||||
|
* have a presumed-free UID or we will be at UID_MAX + 1.
|
||||||
|
*/
|
||||||
|
if (highest_found > uid_max) {
|
||||||
|
/*
|
||||||
|
* In this case, a UID is in use at UID_MAX.
|
||||||
|
*
|
||||||
|
* We will reset the search to UID_MIN and proceed up
|
||||||
|
* through all the UIDs (skipping those we detected with
|
||||||
|
* used_uids) for a free one. It is a known issue that
|
||||||
|
* this may result in reusing a previously-deleted UID,
|
||||||
|
* so administrators should be instructed to use this
|
||||||
|
* auto-detection with care (and prefer to assign UIDs
|
||||||
|
* explicitly).
|
||||||
|
*/
|
||||||
|
highest_found = uid_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search through all of the IDs in the range */
|
||||||
|
for (id = highest_found; id <= uid_max; id++) {
|
||||||
|
result = check_uid (id, uid_min, uid_max, used_uids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This UID is available. Return it. */
|
||||||
|
*uid = id;
|
||||||
|
free (used_uids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This UID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique UID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG ((LOG_ERR,
|
||||||
|
"Error checking available UIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We will continue anyway. Hopefully a later UID
|
||||||
|
* will work properly.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we get all the way through the loop, try again from UID_MIN,
|
||||||
|
* unless that was where we previously started. (NOTE: the worst-case
|
||||||
|
* scenario here is that we will run through (UID_MAX - UID_MIN - 1)
|
||||||
|
* cycles *again* if we fall into this case with highest_found as
|
||||||
|
* UID_MIN + 1, all users in the range in use and maintained by
|
||||||
|
* network services such as LDAP.)
|
||||||
|
*/
|
||||||
|
if (highest_found != uid_min) {
|
||||||
|
for (id = uid_min; id <= uid_max; id++) {
|
||||||
|
result = check_uid (id, uid_min, uid_max, used_uids);
|
||||||
|
if (result == 0) {
|
||||||
|
/* This UID is available. Return it. */
|
||||||
|
*uid = id;
|
||||||
|
free (used_uids);
|
||||||
|
return 0;
|
||||||
|
} else if (result == EEXIST) {
|
||||||
|
/* This UID is in use, we'll continue to the next */
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An unexpected error occurred.
|
||||||
|
*
|
||||||
|
* Only report it the first time to avoid spamming
|
||||||
|
* the logs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (!nospam) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique UID (%s). "
|
||||||
|
"Suppressing additional messages.\n"),
|
||||||
|
Prog, strerror (result));
|
||||||
|
SYSLOG ((LOG_ERR,
|
||||||
|
"Error checking available UIDs: %s",
|
||||||
|
strerror (result)));
|
||||||
|
nospam = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We will continue anyway. Hopefully a later UID
|
||||||
|
* will work properly.
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*uid = user_id;
|
/* The code reached here and found no available IDs in the range */
|
||||||
return 0;
|
fprintf (shadow_logfd,
|
||||||
|
_("%s: Can't get unique UID (no more available UIDs)\n"),
|
||||||
|
Prog);
|
||||||
|
SYSLOG ((LOG_WARN, "no more available UIDs on the system"));
|
||||||
|
free (used_uids);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -35,5 +35,5 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
time_t get_date (const char *, const time_t *);
|
time_t get_date (const char *p, /*@null@*/const time_t *now);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -66,7 +66,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
|
/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
|
||||||
as well as gratuitiously global symbol names, so we can have multiple
|
as well as gratuitously global symbol names, so we can have multiple
|
||||||
yacc generated parsers in the same program. Note that these are only
|
yacc generated parsers in the same program. Note that these are only
|
||||||
the variables produced by yacc. If other parser generators (bison,
|
the variables produced by yacc. If other parser generators (bison,
|
||||||
byacc, etc) produce additional global names that conflict at link time,
|
byacc, etc) produce additional global names that conflict at link time,
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
* The string may be a valid GID or a valid groupname.
|
* The string may be a valid GID or a valid groupname.
|
||||||
* If the group does not exist on the system, NULL is returned.
|
* If the group does not exist on the system, NULL is returned.
|
||||||
*/
|
*/
|
||||||
extern /*@null@*/struct group *getgr_nam_gid (const char *grname)
|
extern /*@only@*//*@null@*/struct group *getgr_nam_gid (/*@null@*/const char *grname)
|
||||||
{
|
{
|
||||||
long long int gid;
|
long long int gid;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Chris Lamb
|
||||||
|
* 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 <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "defines.h"
|
||||||
|
#include "prototypes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gettime() returns the time as the number of seconds since the Epoch
|
||||||
|
*
|
||||||
|
* Like time(), gettime() returns the time as the number of seconds since the
|
||||||
|
* Epoch, 1970-01-01 00:00:00 +0000 (UTC), except that if the SOURCE_DATE_EPOCH
|
||||||
|
* environment variable is exported it will use that instead.
|
||||||
|
*/
|
||||||
|
/*@observer@*/time_t gettime ()
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
char *source_date_epoch;
|
||||||
|
time_t fallback;
|
||||||
|
unsigned long long epoch;
|
||||||
|
|
||||||
|
fallback = time (NULL);
|
||||||
|
source_date_epoch = shadow_getenv ("SOURCE_DATE_EPOCH");
|
||||||
|
|
||||||
|
if (!source_date_epoch)
|
||||||
|
return fallback;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
epoch = strtoull (source_date_epoch, &endptr, 10);
|
||||||
|
if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
|
||||||
|
|| (errno != 0 && epoch == 0)) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n"),
|
||||||
|
strerror(errno));
|
||||||
|
} else if (endptr == source_date_epoch) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n"),
|
||||||
|
endptr);
|
||||||
|
} else if (*endptr != '\0') {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n"),
|
||||||
|
endptr);
|
||||||
|
} else if (epoch > ULONG_MAX) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu\n"),
|
||||||
|
ULONG_MAX, epoch);
|
||||||
|
} else if (epoch > fallback) {
|
||||||
|
fprintf (shadow_logfd,
|
||||||
|
_("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to the current time (%lu) but was found to be: %llu\n"),
|
||||||
|
fallback, epoch);
|
||||||
|
} else {
|
||||||
|
/* Valid */
|
||||||
|
return (time_t)epoch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
+4
-4
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (c) 1991 - 1993, Chip Rosenthal
|
* Copyright (c) 1991 - 1993, Chip Rosenthal
|
||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||||
* Copyright (c) 2008 - 2009, Nicolas François
|
* Copyright (c) 2008 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
bool hushed (const char *username)
|
bool hushed (const char *username)
|
||||||
{
|
{
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
char *hushfile;
|
const char *hushfile;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
bool found;
|
bool found;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@@ -76,7 +76,7 @@ bool hushed (const char *username)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (hushfile[0] != '/') {
|
if (hushfile[0] != '/') {
|
||||||
snprintf (buf, sizeof (buf), "%s/%s", pw->pw_dir, hushfile);
|
(void) snprintf (buf, sizeof (buf), "%s/%s", pw->pw_dir, hushfile);
|
||||||
return (access (buf, F_OK) == 0);
|
return (access (buf, F_OK) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ bool hushed (const char *username)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (found = false; !found && (fgets (buf, (int) sizeof buf, fp) == buf);) {
|
for (found = false; !found && (fgets (buf, (int) sizeof buf, fp) == buf);) {
|
||||||
buf[strlen (buf) - 1] = '\0';
|
buf[strcspn (buf, "\n")] = '\0';
|
||||||
found = (strcmp (buf, pw->pw_shell) == 0) ||
|
found = (strcmp (buf, pw->pw_shell) == 0) ||
|
||||||
(strcmp (buf, pw->pw_name) == 0);
|
(strcmp (buf, pw->pw_name) == 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Eric Biederman
|
||||||
|
* 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 <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include "idmapping.h"
|
||||||
|
#if HAVE_SYS_CAPABILITY_H
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/capability.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct map_range *get_map_ranges(int ranges, int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct map_range *mappings, *mapping;
|
||||||
|
int idx, argidx;
|
||||||
|
|
||||||
|
if (ranges < 0 || argc < 0) {
|
||||||
|
fprintf(shadow_logfd, "%s: error calculating number of arguments\n", Prog);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ranges != ((argc + 2) / 3)) {
|
||||||
|
fprintf(shadow_logfd, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ranges * 3) > argc) {
|
||||||
|
fprintf(shadow_logfd, "ranges: %u argc: %d\n",
|
||||||
|
ranges, argc);
|
||||||
|
fprintf(shadow_logfd,
|
||||||
|
_( "%s: Not enough arguments to form %u mappings\n"),
|
||||||
|
Prog, ranges);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mappings = calloc(ranges, sizeof(*mappings));
|
||||||
|
if (!mappings) {
|
||||||
|
fprintf(shadow_logfd, _( "%s: Memory allocation failure\n"),
|
||||||
|
Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gather up the ranges from the command line */
|
||||||
|
mapping = mappings;
|
||||||
|
for (idx = 0, argidx = 0; idx < ranges; idx++, argidx += 3, mapping++) {
|
||||||
|
if (!getulong(argv[argidx + 0], &mapping->upper)) {
|
||||||
|
free(mappings);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!getulong(argv[argidx + 1], &mapping->lower)) {
|
||||||
|
free(mappings);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!getulong(argv[argidx + 2], &mapping->count)) {
|
||||||
|
free(mappings);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (ULONG_MAX - mapping->upper <= mapping->count || ULONG_MAX - mapping->lower <= mapping->count) {
|
||||||
|
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (mapping->upper > UINT_MAX ||
|
||||||
|
mapping->lower > UINT_MAX ||
|
||||||
|
mapping->count > UINT_MAX) {
|
||||||
|
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (mapping->lower + mapping->count > UINT_MAX ||
|
||||||
|
mapping->upper + mapping->count > UINT_MAX) {
|
||||||
|
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (mapping->lower + mapping->count < mapping->lower ||
|
||||||
|
mapping->upper + mapping->count < mapping->upper) {
|
||||||
|
/* this one really shouldn't be possible given previous checks */
|
||||||
|
fprintf(shadow_logfd, _( "%s: subuid overflow detected.\n"), Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number of ascii digits needed to print any unsigned long in decimal.
|
||||||
|
* There are approximately 10 bits for every 3 decimal digits.
|
||||||
|
* So from bits to digits the formula is roundup((Number of bits)/10) * 3.
|
||||||
|
* For common sizes of integers this works out to:
|
||||||
|
* 2bytes --> 6 ascii estimate -> 65536 (5 real)
|
||||||
|
* 4bytes --> 12 ascii estimated -> 4294967296 (10 real)
|
||||||
|
* 8bytes --> 21 ascii estimated -> 18446744073709551616 (20 real)
|
||||||
|
* 16bytes --> 39 ascii estimated -> 340282366920938463463374607431768211456 (39 real)
|
||||||
|
*/
|
||||||
|
#define ULONG_DIGITS ((((sizeof(unsigned long) * CHAR_BIT) + 9)/10)*3)
|
||||||
|
|
||||||
|
#if HAVE_SYS_CAPABILITY_H
|
||||||
|
static inline bool maps_lower_root(int cap, int ranges, struct map_range *mappings)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
struct map_range *mapping;
|
||||||
|
|
||||||
|
if (cap != CAP_SETUID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mapping = mappings;
|
||||||
|
for (idx = 0; idx < ranges; idx++, mapping++) {
|
||||||
|
if (mapping->lower == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ruid refers to the caller's uid and is used to reset the effective uid
|
||||||
|
* back to the callers real uid.
|
||||||
|
* This clutch mainly exists for setuid-based new{g,u}idmap binaries that are
|
||||||
|
* called in contexts where all capabilities other than the necessary
|
||||||
|
* CAP_SET{G,U}ID capabilities are dropped. Since the kernel will require
|
||||||
|
* assurance that the caller holds CAP_SYS_ADMIN over the target user namespace
|
||||||
|
* the only way it can confirm is in this case is if the effective uid is
|
||||||
|
* equivalent to the uid owning the target user namespace.
|
||||||
|
* Note, we only support this when a) new{g,u}idmap is not called by root and
|
||||||
|
* b) if the caller's uid and the uid retrieved via system appropriate means
|
||||||
|
* (shadow file or other) are identical. Specifically, this does not support
|
||||||
|
* when the root user calls the new{g,u}idmap binary for an unprivileged user.
|
||||||
|
* If this is wanted: use file capabilities!
|
||||||
|
*/
|
||||||
|
void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
|
||||||
|
const char *map_file, uid_t ruid)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
struct map_range *mapping;
|
||||||
|
size_t bufsize;
|
||||||
|
char *buf, *pos;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
#if HAVE_SYS_CAPABILITY_H
|
||||||
|
int cap;
|
||||||
|
struct __user_cap_header_struct hdr = {_LINUX_CAPABILITY_VERSION_3, 0};
|
||||||
|
struct __user_cap_data_struct data[2] = {{0}};
|
||||||
|
|
||||||
|
if (strcmp(map_file, "uid_map") == 0) {
|
||||||
|
cap = CAP_SETUID;
|
||||||
|
} else if (strcmp(map_file, "gid_map") == 0) {
|
||||||
|
cap = CAP_SETGID;
|
||||||
|
} else {
|
||||||
|
fprintf(shadow_logfd, _("%s: Invalid map file %s specified\n"), Prog, map_file);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align setuid- and fscaps-based new{g,u}idmap behavior. */
|
||||||
|
if (geteuid() == 0 && geteuid() != ruid) {
|
||||||
|
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
|
||||||
|
fprintf(shadow_logfd, _("%s: Could not prctl(PR_SET_KEEPCAPS)\n"), Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seteuid(ruid) < 0) {
|
||||||
|
fprintf(shadow_logfd, _("%s: Could not seteuid to %d\n"), Prog, ruid);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lockdown new{g,u}idmap by dropping all unneeded capabilities. */
|
||||||
|
memset(data, 0, sizeof(data));
|
||||||
|
data[0].effective = CAP_TO_MASK(cap);
|
||||||
|
/*
|
||||||
|
* When uid 0 from the ancestor userns is supposed to be mapped into
|
||||||
|
* the child userns we need to retain CAP_SETFCAP.
|
||||||
|
*/
|
||||||
|
if (maps_lower_root(cap, ranges, mappings))
|
||||||
|
data[0].effective |= CAP_TO_MASK(CAP_SETFCAP);
|
||||||
|
data[0].permitted = data[0].effective;
|
||||||
|
if (capset(&hdr, data) < 0) {
|
||||||
|
fprintf(shadow_logfd, _("%s: Could not set caps\n"), Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
|
||||||
|
pos = buf = xmalloc(bufsize);
|
||||||
|
|
||||||
|
/* Build the mapping command */
|
||||||
|
mapping = mappings;
|
||||||
|
for (idx = 0; idx < ranges; idx++, mapping++) {
|
||||||
|
/* Append this range to the string that will be written */
|
||||||
|
int written = snprintf(pos, bufsize - (pos - buf),
|
||||||
|
"%lu %lu %lu\n",
|
||||||
|
mapping->upper,
|
||||||
|
mapping->lower,
|
||||||
|
mapping->count);
|
||||||
|
if ((written <= 0) || (written >= (bufsize - (pos - buf)))) {
|
||||||
|
fprintf(shadow_logfd, _("%s: snprintf failed!\n"), Prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
pos += written;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the mapping to the mapping file */
|
||||||
|
fd = openat(proc_dir_fd, map_file, O_WRONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(shadow_logfd, _("%s: open of %s failed: %s\n"),
|
||||||
|
Prog, map_file, strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (write(fd, buf, pos - buf) != (pos - buf)) {
|
||||||
|
fprintf(shadow_logfd, _("%s: write to %s failed: %s\n"),
|
||||||
|
Prog, map_file, strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 , Dan Walsh <dwalsh@redhat.com>
|
* Copyright (c) 2013 Eric Biederman
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -26,47 +26,21 @@
|
|||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#ident "$Id$"
|
#ifndef _IDMAPPING_H_
|
||||||
|
#define _IDMAPPING_H_
|
||||||
|
|
||||||
#include <stdio.h>
|
struct map_range {
|
||||||
#include <sys/wait.h>
|
unsigned long upper; /* first ID inside the namespace */
|
||||||
#include <fcntl.h>
|
unsigned long lower; /* first ID outside the namespace */
|
||||||
#include "prototypes.h"
|
unsigned long count; /* Length of the inside and outside ranges */
|
||||||
#include "defines.h"
|
};
|
||||||
|
|
||||||
int safe_system (const char *command,
|
extern struct map_range *get_map_ranges(int ranges, int argc, char **argv);
|
||||||
const char *argv[],
|
extern void write_mapping(int proc_dir_fd, int ranges,
|
||||||
const char *env[],
|
struct map_range *mappings, const char *map_file, uid_t ruid);
|
||||||
int ignore_stderr)
|
|
||||||
{
|
|
||||||
int status = -1;
|
|
||||||
int fd;
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
pid = fork();
|
extern void nss_init(char *nsswitch_path);
|
||||||
if (pid < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid) { /* Parent */
|
#endif /* _ID_MAPPING_H_ */
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
+1
-1
@@ -107,7 +107,7 @@ int isexpired (const struct passwd *pw, /*@null@*/const struct spwd *sp)
|
|||||||
|
|
||||||
if ( (-1 == sp->sp_lstchg)
|
if ( (-1 == sp->sp_lstchg)
|
||||||
|| (-1 == sp->sp_max)
|
|| (-1 == sp->sp_max)
|
||||||
|| (sp->sp_max >= (10000L * DAY / SCALE))) {
|
|| (sp->sp_max >= ((10000L * DAY) / SCALE))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+186
-72
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2008, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
/*
|
/*
|
||||||
* Separated from setup.c. --marekm
|
* Separated from setup.c. --marekm
|
||||||
* Resource limits thanks to Cristian Gafton.
|
* Resource limits thanks to Cristian Gafton.
|
||||||
|
* Enhancements of resource limit code by Thomas Orgis <thomas@orgis.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@@ -64,22 +66,46 @@
|
|||||||
* value - string value to be read
|
* value - string value to be read
|
||||||
* multiplier - value*multiplier is the actual limit
|
* multiplier - value*multiplier is the actual limit
|
||||||
*/
|
*/
|
||||||
static int
|
static int setrlimit_value (unsigned int resource,
|
||||||
setrlimit_value (unsigned int resource, const char *value,
|
const char *value,
|
||||||
unsigned int multiplier)
|
unsigned int multiplier)
|
||||||
{
|
{
|
||||||
struct rlimit rlim;
|
struct rlimit rlim;
|
||||||
long limit;
|
rlim_t limit;
|
||||||
|
|
||||||
if (getlong (value, &limit) == 0) {
|
/* The "-" is special, not belonging to a strange negative limit.
|
||||||
return 0;
|
* It is infinity, in a controlled way.
|
||||||
|
*/
|
||||||
|
if ('-' == value[0]) {
|
||||||
|
limit = RLIM_INFINITY;
|
||||||
}
|
}
|
||||||
limit *= multiplier;
|
else {
|
||||||
if (limit != (rlim_t) limit) {
|
/* We cannot use getlong here because it fails when there
|
||||||
return 0;
|
* is more to the value than just this number!
|
||||||
|
* Also, we are limited to base 10 here (hex numbers will not
|
||||||
|
* work with the limit string parser as is anyway)
|
||||||
|
*/
|
||||||
|
char *endptr;
|
||||||
|
long longlimit = strtol (value, &endptr, 10);
|
||||||
|
if ((0 == longlimit) && (value == endptr)) {
|
||||||
|
/* No argument at all. No-op.
|
||||||
|
* FIXME: We could instead throw an error, though.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
longlimit *= multiplier;
|
||||||
|
limit = (rlim_t)longlimit;
|
||||||
|
if (longlimit != limit)
|
||||||
|
{
|
||||||
|
/* FIXME: Again, silent error handling...
|
||||||
|
* Wouldn't screaming make more sense?
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rlim.rlim_cur = (rlim_t) limit;
|
|
||||||
rlim.rlim_max = (rlim_t) limit;
|
rlim.rlim_cur = limit;
|
||||||
|
rlim.rlim_max = limit;
|
||||||
if (setrlimit (resource, &rlim) != 0) {
|
if (setrlimit (resource, &rlim) != 0) {
|
||||||
return LOGIN_ERROR_RLIMIT;
|
return LOGIN_ERROR_RLIMIT;
|
||||||
}
|
}
|
||||||
@@ -138,11 +164,12 @@ static int check_logins (const char *name, const char *maxlogins)
|
|||||||
count = 0;
|
count = 0;
|
||||||
#ifdef USE_UTMPX
|
#ifdef USE_UTMPX
|
||||||
setutxent ();
|
setutxent ();
|
||||||
while ((ut = getutxent ())) {
|
while ((ut = getutxent ()))
|
||||||
#else /* !USE_UTMPX */
|
#else /* !USE_UTMPX */
|
||||||
setutent ();
|
setutent ();
|
||||||
while ((ut = getutent ())) {
|
while ((ut = getutent ()))
|
||||||
#endif /* !USE_UTMPX */
|
#endif /* !USE_UTMPX */
|
||||||
|
{
|
||||||
if (USER_PROCESS != ut->ut_type) {
|
if (USER_PROCESS != ut->ut_type) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -167,14 +194,15 @@ static int check_logins (const char *name, const char *maxlogins)
|
|||||||
* includes the user who is currently trying to log in.
|
* includes the user who is currently trying to log in.
|
||||||
*/
|
*/
|
||||||
if (count > limit) {
|
if (count > limit) {
|
||||||
SYSLOG ((LOG_WARN, "Too many logins (max %d) for %s\n",
|
SYSLOG ((LOG_WARN,
|
||||||
limit, name));
|
"Too many logins (max %lu) for %s\n",
|
||||||
|
limit, name));
|
||||||
return LOGIN_ERROR_LOGIN;
|
return LOGIN_ERROR_LOGIN;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function setup_user_limits - checks/set limits for the curent login
|
/* Function setup_user_limits - checks/set limits for the current login
|
||||||
* Original idea from Joel Katz's lshell. Ported to shadow-login
|
* Original idea from Joel Katz's lshell. Ported to shadow-login
|
||||||
* by Cristian Gafton - gafton@sorosis.ro
|
* by Cristian Gafton - gafton@sorosis.ro
|
||||||
*
|
*
|
||||||
@@ -186,17 +214,20 @@ static int check_logins (const char *name, const char *maxlogins)
|
|||||||
* [Cc]: c = RLIMIT_CORE max core file size (KB)
|
* [Cc]: c = RLIMIT_CORE max core file size (KB)
|
||||||
* [Dd]: d = RLIMIT_DATA max data size (KB)
|
* [Dd]: d = RLIMIT_DATA max data size (KB)
|
||||||
* [Ff]: f = RLIMIT_FSIZE max file size (KB)
|
* [Ff]: f = RLIMIT_FSIZE max file size (KB)
|
||||||
|
* [Ii]: i = RLIMIT_NICE max nice value (0..39 translates to 20..-19)
|
||||||
|
* [Kk]: k = file creation masK (umask)
|
||||||
|
* [Ll]: l = max number of logins for this user
|
||||||
* [Mm]: m = RLIMIT_MEMLOCK max locked-in-memory address space (KB)
|
* [Mm]: m = RLIMIT_MEMLOCK max locked-in-memory address space (KB)
|
||||||
* [Nn]: n = RLIMIT_NOFILE max number of open files
|
* [Nn]: n = RLIMIT_NOFILE max number of open files
|
||||||
|
* [Oo]: o = RLIMIT_RTPRIO max real time priority (linux/sched.h 0..MAX_RT_PRIO)
|
||||||
|
* [Pp]: p = process priority -20..20 (negative = high, positive = low)
|
||||||
* [Rr]: r = RLIMIT_RSS max resident set size (KB)
|
* [Rr]: r = RLIMIT_RSS max resident set size (KB)
|
||||||
* [Ss]: s = RLIMIT_STACK max stack size (KB)
|
* [Ss]: s = RLIMIT_STACK max stack size (KB)
|
||||||
* [Tt]: t = RLIMIT_CPU max CPU time (MIN)
|
* [Tt]: t = RLIMIT_CPU max CPU time (MIN)
|
||||||
* [Uu]: u = RLIMIT_NPROC max number of processes
|
* [Uu]: u = RLIMIT_NPROC max number of processes
|
||||||
* [Kk]: k = file creation masK (umask)
|
*
|
||||||
* [Ll]: l = max number of logins for this user
|
* NOTE: Remember to extend the "no-limits" string below when adding a new
|
||||||
* [Pp]: p = process priority -20..20 (negative = high, positive = low)
|
* limit...
|
||||||
* [Ii]: i = RLIMIT_NICE max nice value (0..39 translates to 20..-19)
|
|
||||||
* [Oo]: o = RLIMIT_RTPRIO max real time priority (linux/sched.h 0..MAX_RT_PRIO)
|
|
||||||
*
|
*
|
||||||
* Return value:
|
* Return value:
|
||||||
* 0 = okay, of course
|
* 0 = okay, of course
|
||||||
@@ -213,6 +244,24 @@ static int do_user_limits (const char *buf, const char *name)
|
|||||||
bool reported = false;
|
bool reported = false;
|
||||||
|
|
||||||
pp = buf;
|
pp = buf;
|
||||||
|
/* Skip leading whitespace. */
|
||||||
|
while ((' ' == *pp) || ('\t' == *pp)) {
|
||||||
|
pp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The special limit string "-" results in no limit for all known
|
||||||
|
* limits.
|
||||||
|
* We achieve that by parsing a full limit string, parts of it
|
||||||
|
* being ignored if a limit type is not known to the system.
|
||||||
|
* Though, there will be complaining for unknown limit types.
|
||||||
|
*/
|
||||||
|
if (strcmp (pp, "-") == 0) {
|
||||||
|
/* Remember to extend this, too, when adding new limits!
|
||||||
|
* Oh... but "unlimited" does not make sense for umask,
|
||||||
|
* or does it? (K-)
|
||||||
|
*/
|
||||||
|
pp = "A- C- D- F- I- L- M- N- O- P- R- S- T- U-";
|
||||||
|
}
|
||||||
|
|
||||||
while ('\0' != *pp) {
|
while ('\0' != *pp) {
|
||||||
switch (*pp++) {
|
switch (*pp++) {
|
||||||
@@ -223,11 +272,11 @@ static int do_user_limits (const char *buf, const char *name)
|
|||||||
retval |= setrlimit_value (RLIMIT_AS, pp, 1024);
|
retval |= setrlimit_value (RLIMIT_AS, pp, 1024);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_CPU
|
#ifdef RLIMIT_CORE
|
||||||
case 't':
|
case 'c':
|
||||||
case 'T':
|
case 'C':
|
||||||
/* RLIMIT_CPU - max CPU time (MIN) */
|
/* RLIMIT_CORE - max core file size (KB) */
|
||||||
retval |= setrlimit_value (RLIMIT_CPU, pp, 60);
|
retval |= setrlimit_value (RLIMIT_CORE, pp, 1024);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_DATA
|
#ifdef RLIMIT_DATA
|
||||||
@@ -244,20 +293,22 @@ static int do_user_limits (const char *buf, const char *name)
|
|||||||
retval |= setrlimit_value (RLIMIT_FSIZE, pp, 1024);
|
retval |= setrlimit_value (RLIMIT_FSIZE, pp, 1024);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_NPROC
|
#ifdef RLIMIT_NICE
|
||||||
case 'u':
|
case 'i':
|
||||||
case 'U':
|
case 'I':
|
||||||
/* RLIMIT_NPROC - max number of processes */
|
/* RLIMIT_NICE - max scheduling priority (0..39) */
|
||||||
retval |= setrlimit_value (RLIMIT_NPROC, pp, 1);
|
retval |= setrlimit_value (RLIMIT_NICE, pp, 1);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_CORE
|
case 'k':
|
||||||
case 'c':
|
case 'K':
|
||||||
case 'C':
|
retval |= set_umask (pp);
|
||||||
/* RLIMIT_CORE - max core file size (KB) */
|
break;
|
||||||
retval |= setrlimit_value (RLIMIT_CORE, pp, 1024);
|
case 'l':
|
||||||
|
case 'L':
|
||||||
|
/* LIMIT the number of concurrent logins */
|
||||||
|
retval |= check_logins (name, pp);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_MEMLOCK
|
#ifdef RLIMIT_MEMLOCK
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
@@ -272,6 +323,17 @@ static int do_user_limits (const char *buf, const char *name)
|
|||||||
retval |= setrlimit_value (RLIMIT_NOFILE, pp, 1);
|
retval |= setrlimit_value (RLIMIT_NOFILE, pp, 1);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RLIMIT_RTPRIO
|
||||||
|
case 'o':
|
||||||
|
case 'O':
|
||||||
|
/* RLIMIT_RTPRIO - max real time priority (0..MAX_RT_PRIO) */
|
||||||
|
retval |= setrlimit_value (RLIMIT_RTPRIO, pp, 1);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'p':
|
||||||
|
case 'P':
|
||||||
|
retval |= set_prio (pp);
|
||||||
|
break;
|
||||||
#ifdef RLIMIT_RSS
|
#ifdef RLIMIT_RSS
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'R':
|
case 'R':
|
||||||
@@ -286,35 +348,28 @@ static int do_user_limits (const char *buf, const char *name)
|
|||||||
retval |= setrlimit_value (RLIMIT_STACK, pp, 1024);
|
retval |= setrlimit_value (RLIMIT_STACK, pp, 1024);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_NICE
|
#ifdef RLIMIT_CPU
|
||||||
case 'i':
|
case 't':
|
||||||
case 'I':
|
case 'T':
|
||||||
/* RLIMIT_NICE - max scheduling priority (0..39) */
|
/* RLIMIT_CPU - max CPU time (MIN) */
|
||||||
retval |= setrlimit_value (RLIMIT_NICE, pp, 1);
|
retval |= setrlimit_value (RLIMIT_CPU, pp, 60);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_RTPRIO
|
#ifdef RLIMIT_NPROC
|
||||||
case 'o':
|
case 'u':
|
||||||
case 'O':
|
case 'U':
|
||||||
/* RLIMIT_RTPRIO - max real time priority (0..MAX_RT_PRIO) */
|
/* RLIMIT_NPROC - max number of processes */
|
||||||
retval |= setrlimit_value (RLIMIT_RTPRIO, pp, 1);
|
retval |= setrlimit_value (RLIMIT_NPROC, pp, 1);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 'k':
|
|
||||||
case 'K':
|
|
||||||
retval |= set_umask (pp);
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
case 'L':
|
|
||||||
/* LIMIT the number of concurrent logins */
|
|
||||||
retval |= check_logins (name, pp);
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
case 'P':
|
|
||||||
retval |= set_prio (pp);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
/* Only report invalid strings once */
|
/* Only report invalid strings once */
|
||||||
|
/* Note: A string can be invalid just because a
|
||||||
|
* specific (theoretically valid) setting is not
|
||||||
|
* supported by this build.
|
||||||
|
* It is just a warning in syslog anyway. The line
|
||||||
|
* is still processed
|
||||||
|
*/
|
||||||
if (!reported) {
|
if (!reported) {
|
||||||
SYSLOG ((LOG_WARN,
|
SYSLOG ((LOG_WARN,
|
||||||
"Invalid limit string: '%s'",
|
"Invalid limit string: '%s'",
|
||||||
@@ -323,13 +378,51 @@ static int do_user_limits (const char *buf, const char *name)
|
|||||||
retval |= LOGIN_ERROR_RLIMIT;
|
retval |= LOGIN_ERROR_RLIMIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* After parsing one limit setting (or just complaining
|
||||||
|
* about it), one still needs to skip its argument to
|
||||||
|
* prevent a bogus warning on trying to parse that as
|
||||||
|
* limit specification.
|
||||||
|
* So, let's skip all digits, "-" and our limited set of
|
||||||
|
* whitespace.
|
||||||
|
*/
|
||||||
|
while ( isdigit (*pp)
|
||||||
|
|| ('-' == *pp)
|
||||||
|
|| (' ' == *pp)
|
||||||
|
|| ('\t' ==*pp)) {
|
||||||
|
pp++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if user uname is in the group gname.
|
||||||
|
* Can I be sure that gr_mem contains no UID as string?
|
||||||
|
* Returns true when user is in the group, false when not.
|
||||||
|
* Any error is treated as false.
|
||||||
|
*/
|
||||||
|
static bool user_in_group (const char *uname, const char *gname)
|
||||||
|
{
|
||||||
|
struct group *groupdata;
|
||||||
|
|
||||||
|
if (uname == NULL || gname == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are not claiming to be re-entrant!
|
||||||
|
* In case of paranoia or a multithreaded login program,
|
||||||
|
* one needs to add some mess for getgrnam_r. */
|
||||||
|
groupdata = getgrnam (gname);
|
||||||
|
if (NULL == groupdata) {
|
||||||
|
SYSLOG ((LOG_WARN, "Nonexisting group `%s' in limits file.",
|
||||||
|
gname));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_on_list (groupdata->gr_mem, uname);
|
||||||
|
}
|
||||||
|
|
||||||
static int setup_user_limits (const char *uname)
|
static int setup_user_limits (const char *uname)
|
||||||
{
|
{
|
||||||
/* TODO: allow and use @group syntax --cristiang */
|
|
||||||
FILE *fil;
|
FILE *fil;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
char name[1024];
|
char name[1024];
|
||||||
@@ -351,8 +444,10 @@ static int setup_user_limits (const char *uname)
|
|||||||
}
|
}
|
||||||
/* The limits file have the following format:
|
/* The limits file have the following format:
|
||||||
* - '#' (comment) chars only as first chars on a line;
|
* - '#' (comment) chars only as first chars on a line;
|
||||||
* - username must start on first column
|
* - username must start on first column (or *, or @group)
|
||||||
* A better (smarter) checking should be done --cristiang */
|
*
|
||||||
|
* FIXME: A better (smarter) checking should be done
|
||||||
|
*/
|
||||||
while (fgets (buf, 1024, fil) != NULL) {
|
while (fgets (buf, 1024, fil) != NULL) {
|
||||||
if (('#' == buf[0]) || ('\n' == buf[0])) {
|
if (('#' == buf[0]) || ('\n' == buf[0])) {
|
||||||
continue;
|
continue;
|
||||||
@@ -364,15 +459,35 @@ static int setup_user_limits (const char *uname)
|
|||||||
* username L2 D2048 R4096
|
* username L2 D2048 R4096
|
||||||
* where spaces={' ',\t}. Also, we reject invalid limits.
|
* where spaces={' ',\t}. Also, we reject invalid limits.
|
||||||
* Imposing a limit should be done with care, so a wrong
|
* Imposing a limit should be done with care, so a wrong
|
||||||
* entry means no care anyway :-). A '-' as a limits
|
* entry means no care anyway :-).
|
||||||
* strings means no limits --cristiang */
|
*
|
||||||
if (sscanf (buf, "%s%[ACDFMNRSTULPIOacdfmnrstulpio0-9 \t-]",
|
* A '-' as a limits strings means no limits
|
||||||
name, tempbuf) == 2) {
|
*
|
||||||
|
* The username can also be:
|
||||||
|
* '*': the default limits (only the last is taken into
|
||||||
|
* account)
|
||||||
|
* @group: the limit applies to the members of the group
|
||||||
|
*
|
||||||
|
* To clarify: The first entry with matching user name rules,
|
||||||
|
* everything after it is ignored. If there is no user entry,
|
||||||
|
* the last encountered entry for a matching group rules.
|
||||||
|
* If there is no matching group entry, the default limits rule.
|
||||||
|
*/
|
||||||
|
if (sscanf (buf, "%s%[ACDFIKLMNOPRSTUacdfiklmnoprstu0-9 \t-]",
|
||||||
|
name, tempbuf) == 2) {
|
||||||
if (strcmp (name, uname) == 0) {
|
if (strcmp (name, uname) == 0) {
|
||||||
strcpy (limits, tempbuf);
|
strcpy (limits, tempbuf);
|
||||||
break;
|
break;
|
||||||
} else if (strcmp (name, "*") == 0) {
|
} else if (strcmp (name, "*") == 0) {
|
||||||
strcpy (deflimits, tempbuf);
|
strcpy (deflimits, tempbuf);
|
||||||
|
} else if (name[0] == '@') {
|
||||||
|
/* If the user is in the group, the group
|
||||||
|
* limits apply unless later a line for
|
||||||
|
* the specific user is found.
|
||||||
|
*/
|
||||||
|
if (user_in_group (uname, name+1)) {
|
||||||
|
strcpy (limits, tempbuf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,7 +507,6 @@ static int setup_user_limits (const char *uname)
|
|||||||
static void setup_usergroups (const struct passwd *info)
|
static void setup_usergroups (const struct passwd *info)
|
||||||
{
|
{
|
||||||
const struct group *grp;
|
const struct group *grp;
|
||||||
mode_t tmpmask;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if not root, and UID == GID, and username is the same as primary
|
* if not root, and UID == GID, and username is the same as primary
|
||||||
@@ -404,6 +518,7 @@ static void setup_usergroups (const struct passwd *info)
|
|||||||
grp = getgrgid (info->pw_gid);
|
grp = getgrgid (info->pw_gid);
|
||||||
if ( (NULL != grp)
|
if ( (NULL != grp)
|
||||||
&& (strcmp (info->pw_name, grp->gr_name) == 0)) {
|
&& (strcmp (info->pw_name, grp->gr_name) == 0)) {
|
||||||
|
mode_t tmpmask;
|
||||||
tmpmask = umask (0777);
|
tmpmask = umask (0777);
|
||||||
tmpmask = (tmpmask & ~070) | ((tmpmask >> 3) & 070);
|
tmpmask = (tmpmask & ~070) | ((tmpmask >> 3) & 070);
|
||||||
(void) umask (tmpmask);
|
(void) umask (tmpmask);
|
||||||
@@ -432,9 +547,8 @@ void setup_limits (const struct passwd *info)
|
|||||||
if (getdef_bool ("QUOTAS_ENAB")) {
|
if (getdef_bool ("QUOTAS_ENAB")) {
|
||||||
#ifdef LIMITS
|
#ifdef LIMITS
|
||||||
if (info->pw_uid != 0) {
|
if (info->pw_uid != 0) {
|
||||||
if (setup_user_limits (info->pw_name) &
|
if ((setup_user_limits (info->pw_name) & LOGIN_ERROR_LOGIN) != 0) {
|
||||||
LOGIN_ERROR_LOGIN) {
|
(void) fputs (_("Too many logins.\n"), shadow_logfd);
|
||||||
(void) fputs (_("Too many logins.\n"), stderr);
|
|
||||||
(void) sleep (2); /* XXX: Should be FAIL_DELAY */
|
(void) sleep (2); /* XXX: Should be FAIL_DELAY */
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-1
@@ -141,6 +141,12 @@
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Duplicate a list.
|
||||||
|
* The input list is not modified, but in order to allow the use of this
|
||||||
|
* function with list of members, the list elements are not enforced to be
|
||||||
|
* constant strings here.
|
||||||
|
*/
|
||||||
/*@only@*/ /*@out@*/char **dup_list (char *const *list)
|
/*@only@*/ /*@out@*/char **dup_list (char *const *list)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -163,6 +169,12 @@
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if member is part of the input list
|
||||||
|
* The input list is not modified, but in order to allow the use of this
|
||||||
|
* function with list of members, the list elements are not enforced to be
|
||||||
|
* constant strings here.
|
||||||
|
*/
|
||||||
bool is_on_list (char *const *list, const char *member)
|
bool is_on_list (char *const *list, const char *member)
|
||||||
{
|
{
|
||||||
assert (NULL != member);
|
assert (NULL != member);
|
||||||
@@ -187,7 +199,7 @@ bool is_on_list (char *const *list, const char *member)
|
|||||||
char *members;
|
char *members;
|
||||||
char **array;
|
char **array;
|
||||||
int i;
|
int i;
|
||||||
const char *cp;
|
char *cp;
|
||||||
char *cp2;
|
char *cp2;
|
||||||
|
|
||||||
assert (NULL != comma);
|
assert (NULL != comma);
|
||||||
@@ -229,6 +241,7 @@ bool is_on_list (char *const *list, const char *member)
|
|||||||
|
|
||||||
if ('\0' == *members) {
|
if ('\0' == *members) {
|
||||||
*array = (char *) 0;
|
*array = (char *) 0;
|
||||||
|
free (members);
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -100,9 +100,9 @@ void dolastlog (
|
|||||||
ll_time = newlog.ll_time;
|
ll_time = newlog.ll_time;
|
||||||
(void) time (&ll_time);
|
(void) time (&ll_time);
|
||||||
newlog.ll_time = ll_time;
|
newlog.ll_time = ll_time;
|
||||||
strncpy (newlog.ll_line, line, sizeof newlog.ll_line);
|
strncpy (newlog.ll_line, line, sizeof (newlog.ll_line) - 1);
|
||||||
#if HAVE_LL_HOST
|
#if HAVE_LL_HOST
|
||||||
strncpy (newlog.ll_host, host, sizeof newlog.ll_host);
|
strncpy (newlog.ll_host, host, sizeof (newlog.ll_host) - 1);
|
||||||
#endif
|
#endif
|
||||||
if ( (lseek (fd, offset, SEEK_SET) != offset)
|
if ( (lseek (fd, offset, SEEK_SET) != offset)
|
||||||
|| (write (fd, (const void *) &newlog, sizeof newlog) != (ssize_t) sizeof newlog)
|
|| (write (fd, (const void *) &newlog, sizeof newlog) != (ssize_t) sizeof newlog)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user