4
0

map.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* Owner/group mapping for tar
  2. Copyright 2015-2019 Free Software Foundation, Inc.
  3. This file is part of GNU tar.
  4. GNU tar is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. GNU tar is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include <system.h>
  15. #include "common.h"
  16. #include "wordsplit.h"
  17. #include <hash.h>
  18. #include <pwd.h>
  19. struct mapentry
  20. {
  21. uintmax_t orig_id;
  22. uintmax_t new_id;
  23. char *new_name;
  24. };
  25. static size_t
  26. map_hash (void const *entry, size_t nbuckets)
  27. {
  28. struct mapentry const *map = entry;
  29. return map->orig_id % nbuckets;
  30. }
  31. static bool
  32. map_compare (void const *entry1, void const *entry2)
  33. {
  34. struct mapentry const *map1 = entry1;
  35. struct mapentry const *map2 = entry2;
  36. return map1->orig_id == map2->orig_id;
  37. }
  38. static int
  39. parse_id (uintmax_t *retval,
  40. char const *arg, char const *what, uintmax_t maxval,
  41. char const *file, unsigned line)
  42. {
  43. uintmax_t v;
  44. char *p;
  45. errno = 0;
  46. v = strtoumax (arg, &p, 10);
  47. if (*p || errno)
  48. {
  49. error (0, 0, _("%s:%u: invalid %s: %s"), file, line, what, arg);
  50. return -1;
  51. }
  52. if (v > maxval)
  53. {
  54. error (0, 0, _("%s:%u: %s out of range: %s"), file, line, what, arg);
  55. return -1;
  56. }
  57. *retval = v;
  58. return 0;
  59. }
  60. static void
  61. map_read (Hash_table **ptab, char const *file,
  62. uintmax_t (*name_to_id) (char const *), char const *what,
  63. uintmax_t maxval)
  64. {
  65. FILE *fp;
  66. char *buf = NULL;
  67. size_t bufsize = 0;
  68. ssize_t n;
  69. struct wordsplit ws;
  70. int wsopt;
  71. unsigned line;
  72. int err = 0;
  73. fp = fopen (file, "r");
  74. if (!fp)
  75. open_fatal (file);
  76. ws.ws_comment = "#";
  77. wsopt = WRDSF_COMMENT | WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS
  78. | WRDSF_QUOTE;
  79. line = 0;
  80. while ((n = getline (&buf, &bufsize, fp)) > 0)
  81. {
  82. struct mapentry *ent;
  83. uintmax_t orig_id, new_id;
  84. char *name = NULL;
  85. char *colon;
  86. ++line;
  87. if (wordsplit (buf, &ws, wsopt))
  88. FATAL_ERROR ((0, 0, _("%s:%u: cannot split line: %s"),
  89. file, line, wordsplit_strerror (&ws)));
  90. wsopt |= WRDSF_REUSE;
  91. if (ws.ws_wordc == 0)
  92. continue;
  93. if (ws.ws_wordc != 2)
  94. {
  95. error (0, 0, _("%s:%u: malformed line"), file, line);
  96. err = 1;
  97. continue;
  98. }
  99. if (ws.ws_wordv[0][0] == '+')
  100. {
  101. if (parse_id (&orig_id, ws.ws_wordv[0]+1, what, maxval, file, line))
  102. {
  103. err = 1;
  104. continue;
  105. }
  106. }
  107. else if (name_to_id)
  108. {
  109. orig_id = name_to_id (ws.ws_wordv[0]);
  110. if (orig_id == UINTMAX_MAX)
  111. {
  112. error (0, 0, _("%s:%u: can't obtain %s of %s"),
  113. file, line, what, ws.ws_wordv[0]);
  114. err = 1;
  115. continue;
  116. }
  117. }
  118. colon = strchr (ws.ws_wordv[1], ':');
  119. if (colon)
  120. {
  121. if (colon > ws.ws_wordv[1])
  122. name = ws.ws_wordv[1];
  123. *colon++ = 0;
  124. if (parse_id (&new_id, colon, what, maxval, file, line))
  125. {
  126. err = 1;
  127. continue;
  128. }
  129. }
  130. else if (ws.ws_wordv[1][0] == '+')
  131. {
  132. if (parse_id (&new_id, ws.ws_wordv[1], what, maxval, file, line))
  133. {
  134. err = 1;
  135. continue;
  136. }
  137. }
  138. else
  139. {
  140. name = ws.ws_wordv[1];
  141. new_id = name_to_id (ws.ws_wordv[1]);
  142. if (new_id == UINTMAX_MAX)
  143. {
  144. error (0, 0, _("%s:%u: can't obtain %s of %s"),
  145. file, line, what, ws.ws_wordv[1]);
  146. err = 1;
  147. continue;
  148. }
  149. }
  150. ent = xmalloc (sizeof (*ent));
  151. ent->orig_id = orig_id;
  152. ent->new_id = new_id;
  153. ent->new_name = name ? xstrdup (name) : NULL;
  154. if (!((*ptab
  155. || (*ptab = hash_initialize (0, 0, map_hash, map_compare, 0)))
  156. && hash_insert (*ptab, ent)))
  157. xalloc_die ();
  158. }
  159. if (wsopt & WRDSF_REUSE)
  160. wordsplit_free (&ws);
  161. fclose (fp);
  162. if (err)
  163. FATAL_ERROR ((0, 0, _("errors reading map file")));
  164. }
  165. /* UID translation */
  166. static Hash_table *owner_map;
  167. static uintmax_t
  168. name_to_uid (char const *name)
  169. {
  170. struct passwd *pw = getpwnam (name);
  171. return pw ? pw->pw_uid : UINTMAX_MAX;
  172. }
  173. void
  174. owner_map_read (char const *file)
  175. {
  176. map_read (&owner_map, file, name_to_uid, "UID", TYPE_MAXIMUM (uid_t));
  177. }
  178. int
  179. owner_map_translate (uid_t uid, uid_t *new_uid, char const **new_name)
  180. {
  181. int rc = 1;
  182. if (owner_map)
  183. {
  184. struct mapentry ent, *res;
  185. ent.orig_id = uid;
  186. res = hash_lookup (owner_map, &ent);
  187. if (res)
  188. {
  189. *new_uid = res->new_id;
  190. *new_name = res->new_name;
  191. return 0;
  192. }
  193. }
  194. if (owner_option != (uid_t) -1)
  195. {
  196. *new_uid = owner_option;
  197. rc = 0;
  198. }
  199. if (owner_name_option)
  200. {
  201. *new_name = owner_name_option;
  202. rc = 0;
  203. }
  204. return rc;
  205. }
  206. /* GID translation */
  207. static Hash_table *group_map;
  208. static uintmax_t
  209. name_to_gid (char const *name)
  210. {
  211. struct group *gr = getgrnam (name);
  212. return gr ? gr->gr_gid : UINTMAX_MAX;
  213. }
  214. void
  215. group_map_read (char const *file)
  216. {
  217. map_read (&group_map, file, name_to_gid, "GID", TYPE_MAXIMUM (gid_t));
  218. }
  219. int
  220. group_map_translate (gid_t gid, gid_t *new_gid, char const **new_name)
  221. {
  222. int rc = 1;
  223. if (group_map)
  224. {
  225. struct mapentry ent, *res;
  226. ent.orig_id = gid;
  227. res = hash_lookup (group_map, &ent);
  228. if (res)
  229. {
  230. *new_gid = res->new_id;
  231. *new_name = res->new_name;
  232. return 0;
  233. }
  234. }
  235. if (group_option != (uid_t) -1)
  236. {
  237. *new_gid = group_option;
  238. rc = 0;
  239. }
  240. if (group_name_option)
  241. {
  242. *new_name = group_name_option;
  243. rc = 0;
  244. }
  245. return rc;
  246. }