uidlist.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * Handle the mapping of uid/gid and user/group names between systems.
  3. *
  4. * Copyright (C) 1996 Andrew Tridgell
  5. * Copyright (C) 1996 Paul Mackerras
  6. * Copyright (C) 2004-2009 Wayne Davison
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, visit the http://fsf.org website.
  20. */
  21. /* If the source username/group does not exist on the target then use
  22. * the numeric IDs. Never do any mapping for uid=0 or gid=0 as these
  23. * are special. */
  24. #include "rsync.h"
  25. #include "io.h"
  26. extern int verbose;
  27. extern int am_root;
  28. extern int preserve_uid;
  29. extern int preserve_gid;
  30. extern int preserve_acls;
  31. extern int numeric_ids;
  32. #ifdef HAVE_GETGROUPS
  33. # ifndef GETGROUPS_T
  34. # define GETGROUPS_T gid_t
  35. # endif
  36. #endif
  37. struct idlist {
  38. struct idlist *next;
  39. const char *name;
  40. id_t id, id2;
  41. uint16 flags;
  42. };
  43. static struct idlist *uidlist;
  44. static struct idlist *gidlist;
  45. static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
  46. id_t id2, uint16 flags)
  47. {
  48. struct idlist *node = new(struct idlist);
  49. if (!node)
  50. out_of_memory("add_to_list");
  51. node->next = *root;
  52. node->name = name;
  53. node->id = id;
  54. node->id2 = id2;
  55. node->flags = flags;
  56. *root = node;
  57. return node;
  58. }
  59. /* turn a uid into a user name */
  60. static const char *uid_to_name(uid_t uid)
  61. {
  62. struct passwd *pass = getpwuid(uid);
  63. if (pass)
  64. return strdup(pass->pw_name);
  65. return NULL;
  66. }
  67. /* turn a gid into a group name */
  68. static const char *gid_to_name(gid_t gid)
  69. {
  70. struct group *grp = getgrgid(gid);
  71. if (grp)
  72. return strdup(grp->gr_name);
  73. return NULL;
  74. }
  75. static uid_t map_uid(uid_t id, const char *name)
  76. {
  77. uid_t uid;
  78. if (id != 0 && name_to_uid(name, &uid))
  79. return uid;
  80. return id;
  81. }
  82. static gid_t map_gid(gid_t id, const char *name)
  83. {
  84. gid_t gid;
  85. if (id != 0 && name_to_gid(name, &gid))
  86. return gid;
  87. return id;
  88. }
  89. static int is_in_group(gid_t gid)
  90. {
  91. #ifdef HAVE_GETGROUPS
  92. static gid_t last_in;
  93. static int ngroups = -2, last_out = -1;
  94. static GETGROUPS_T *gidset;
  95. int n;
  96. if (gid == last_in && last_out >= 0)
  97. return last_out;
  98. if (ngroups < -1) {
  99. gid_t mygid = MY_GID();
  100. if ((ngroups = getgroups(0, NULL)) < 0)
  101. ngroups = 0;
  102. gidset = new_array(GETGROUPS_T, ngroups+1);
  103. if (!gidset)
  104. out_of_memory("is_in_group");
  105. if (ngroups > 0)
  106. ngroups = getgroups(ngroups, gidset);
  107. /* The default gid might not be in the list on some systems. */
  108. for (n = 0; n < ngroups; n++) {
  109. if (gidset[n] == mygid)
  110. break;
  111. }
  112. if (n == ngroups)
  113. gidset[ngroups++] = mygid;
  114. if (verbose > 3) {
  115. int pos;
  116. char *gidbuf = new_array(char, ngroups*21+32);
  117. if (!gidbuf)
  118. out_of_memory("is_in_group");
  119. pos = snprintf(gidbuf, 32, "process has %d gid%s: ",
  120. ngroups, ngroups == 1? "" : "s");
  121. for (n = 0; n < ngroups; n++) {
  122. pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]);
  123. }
  124. rprintf(FINFO, "%s\n", gidbuf);
  125. free(gidbuf);
  126. }
  127. }
  128. last_in = gid;
  129. for (n = 0; n < ngroups; n++) {
  130. if (gidset[n] == gid)
  131. return last_out = 1;
  132. }
  133. return last_out = 0;
  134. #else
  135. static gid_t mygid = GID_NONE;
  136. if (mygid == GID_NONE) {
  137. mygid = MY_GID();
  138. if (verbose > 3)
  139. rprintf(FINFO, "process has gid %u\n", (unsigned)mygid);
  140. }
  141. return gid == mygid;
  142. #endif
  143. }
  144. /* Add a uid to the list of uids. Only called on receiving side. */
  145. static struct idlist *recv_add_uid(uid_t id, const char *name)
  146. {
  147. uid_t id2 = name ? map_uid(id, name) : id;
  148. struct idlist *node;
  149. node = add_to_list(&uidlist, id, name, id2, 0);
  150. if (verbose > 3) {
  151. rprintf(FINFO, "uid %u(%s) maps to %u\n",
  152. (unsigned)id, name ? name : "", (unsigned)id2);
  153. }
  154. return node;
  155. }
  156. /* Add a gid to the list of gids. Only called on receiving side. */
  157. static struct idlist *recv_add_gid(gid_t id, const char *name)
  158. {
  159. gid_t id2 = name ? map_gid(id, name) : id;
  160. struct idlist *node;
  161. node = add_to_list(&gidlist, id, name, id2,
  162. !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
  163. if (verbose > 3) {
  164. rprintf(FINFO, "gid %u(%s) maps to %u\n",
  165. (unsigned)id, name ? name : "", (unsigned)id2);
  166. }
  167. return node;
  168. }
  169. /* this function is a definate candidate for a faster algorithm */
  170. uid_t match_uid(uid_t uid)
  171. {
  172. static uid_t last_in, last_out;
  173. struct idlist *list;
  174. if (uid == 0)
  175. return 0;
  176. if (uid == last_in)
  177. return last_out;
  178. last_in = uid;
  179. for (list = uidlist; list; list = list->next) {
  180. if (list->id == uid)
  181. return last_out = list->id2;
  182. }
  183. return last_out = uid;
  184. }
  185. gid_t match_gid(gid_t gid, uint16 *flags_ptr)
  186. {
  187. static struct idlist *last = NULL;
  188. struct idlist *list;
  189. if (last && gid == last->id)
  190. list = last;
  191. else {
  192. for (list = gidlist; list; list = list->next) {
  193. if (list->id == gid)
  194. break;
  195. }
  196. if (!list)
  197. list = recv_add_gid(gid, NULL);
  198. last = list;
  199. }
  200. if (flags_ptr && list->flags & FLAG_SKIP_GROUP)
  201. *flags_ptr |= FLAG_SKIP_GROUP;
  202. return list->id2;
  203. }
  204. /* Add a uid to the list of uids. Only called on sending side. */
  205. const char *add_uid(uid_t uid)
  206. {
  207. struct idlist *list;
  208. struct idlist *node;
  209. if (uid == 0) /* don't map root */
  210. return NULL;
  211. for (list = uidlist; list; list = list->next) {
  212. if (list->id == uid)
  213. return NULL;
  214. }
  215. node = add_to_list(&uidlist, uid, uid_to_name(uid), 0, 0);
  216. return node->name;
  217. }
  218. /* Add a gid to the list of gids. Only called on sending side. */
  219. const char *add_gid(gid_t gid)
  220. {
  221. struct idlist *list;
  222. struct idlist *node;
  223. if (gid == 0) /* don't map root */
  224. return NULL;
  225. for (list = gidlist; list; list = list->next) {
  226. if (list->id == gid)
  227. return NULL;
  228. }
  229. node = add_to_list(&gidlist, gid, gid_to_name(gid), 0, 0);
  230. return node->name;
  231. }
  232. /* send a complete uid/gid mapping to the peer */
  233. void send_id_list(int f)
  234. {
  235. struct idlist *list;
  236. if (preserve_uid || preserve_acls) {
  237. int len;
  238. /* we send sequences of uid/byte-length/name */
  239. for (list = uidlist; list; list = list->next) {
  240. if (!list->name)
  241. continue;
  242. len = strlen(list->name);
  243. write_varint30(f, list->id);
  244. write_byte(f, len);
  245. write_buf(f, list->name, len);
  246. }
  247. /* terminate the uid list with a 0 uid. We explicitly exclude
  248. * 0 from the list */
  249. write_varint30(f, 0);
  250. }
  251. if (preserve_gid || preserve_acls) {
  252. int len;
  253. for (list = gidlist; list; list = list->next) {
  254. if (!list->name)
  255. continue;
  256. len = strlen(list->name);
  257. write_varint30(f, list->id);
  258. write_byte(f, len);
  259. write_buf(f, list->name, len);
  260. }
  261. write_varint30(f, 0);
  262. }
  263. }
  264. uid_t recv_user_name(int f, uid_t uid)
  265. {
  266. struct idlist *node;
  267. int len = read_byte(f);
  268. char *name = new_array(char, len+1);
  269. if (!name)
  270. out_of_memory("recv_user_name");
  271. read_sbuf(f, name, len);
  272. if (numeric_ids < 0) {
  273. free(name);
  274. name = NULL;
  275. }
  276. node = recv_add_uid(uid, name); /* node keeps name's memory */
  277. return node->id2;
  278. }
  279. gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
  280. {
  281. struct idlist *node;
  282. int len = read_byte(f);
  283. char *name = new_array(char, len+1);
  284. if (!name)
  285. out_of_memory("recv_group_name");
  286. read_sbuf(f, name, len);
  287. if (numeric_ids < 0) {
  288. free(name);
  289. name = NULL;
  290. }
  291. node = recv_add_gid(gid, name); /* node keeps name's memory */
  292. if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
  293. *flags_ptr |= FLAG_SKIP_GROUP;
  294. return node->id2;
  295. }
  296. /* recv a complete uid/gid mapping from the peer and map the uid/gid
  297. * in the file list to local names */
  298. void recv_id_list(int f, struct file_list *flist)
  299. {
  300. id_t id;
  301. int i;
  302. if ((preserve_uid || preserve_acls) && numeric_ids <= 0) {
  303. /* read the uid list */
  304. while ((id = read_varint30(f)) != 0)
  305. recv_user_name(f, id);
  306. }
  307. if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {
  308. /* read the gid list */
  309. while ((id = read_varint30(f)) != 0)
  310. recv_group_name(f, id, NULL);
  311. }
  312. /* Now convert all the uids/gids from sender values to our values. */
  313. #ifdef SUPPORT_ACLS
  314. if (preserve_acls && !numeric_ids)
  315. match_acl_ids();
  316. #endif
  317. if (am_root && preserve_uid && !numeric_ids) {
  318. for (i = 0; i < flist->used; i++)
  319. F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
  320. }
  321. if (preserve_gid && (!am_root || !numeric_ids)) {
  322. for (i = 0; i < flist->used; i++) {
  323. F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
  324. &flist->files[i]->flags);
  325. }
  326. }
  327. }