Annotation of embedaddon/rsync/uidlist.c, revision 1.1
1.1 ! misho 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:
! 22: /* If the source username/group does not exist on the target then use
! 23: * the numeric IDs. Never do any mapping for uid=0 or gid=0 as these
! 24: * are special. */
! 25:
! 26: #include "rsync.h"
! 27: #include "io.h"
! 28:
! 29: extern int verbose;
! 30: extern int am_root;
! 31: extern int preserve_uid;
! 32: extern int preserve_gid;
! 33: extern int preserve_acls;
! 34: extern int numeric_ids;
! 35:
! 36: #ifdef HAVE_GETGROUPS
! 37: # ifndef GETGROUPS_T
! 38: # define GETGROUPS_T gid_t
! 39: # endif
! 40: #endif
! 41:
! 42: struct idlist {
! 43: struct idlist *next;
! 44: const char *name;
! 45: id_t id, id2;
! 46: uint16 flags;
! 47: };
! 48:
! 49: static struct idlist *uidlist;
! 50: static struct idlist *gidlist;
! 51:
! 52: static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
! 53: id_t id2, uint16 flags)
! 54: {
! 55: struct idlist *node = new(struct idlist);
! 56: if (!node)
! 57: out_of_memory("add_to_list");
! 58: node->next = *root;
! 59: node->name = name;
! 60: node->id = id;
! 61: node->id2 = id2;
! 62: node->flags = flags;
! 63: *root = node;
! 64: return node;
! 65: }
! 66:
! 67: /* turn a uid into a user name */
! 68: static const char *uid_to_name(uid_t uid)
! 69: {
! 70: struct passwd *pass = getpwuid(uid);
! 71: if (pass)
! 72: return strdup(pass->pw_name);
! 73: return NULL;
! 74: }
! 75:
! 76: /* turn a gid into a group name */
! 77: static const char *gid_to_name(gid_t gid)
! 78: {
! 79: struct group *grp = getgrgid(gid);
! 80: if (grp)
! 81: return strdup(grp->gr_name);
! 82: return NULL;
! 83: }
! 84:
! 85: static uid_t map_uid(uid_t id, const char *name)
! 86: {
! 87: uid_t uid;
! 88: if (id != 0 && name_to_uid(name, &uid))
! 89: return uid;
! 90: return id;
! 91: }
! 92:
! 93: static gid_t map_gid(gid_t id, const char *name)
! 94: {
! 95: gid_t gid;
! 96: if (id != 0 && name_to_gid(name, &gid))
! 97: return gid;
! 98: return id;
! 99: }
! 100:
! 101: static int is_in_group(gid_t gid)
! 102: {
! 103: #ifdef HAVE_GETGROUPS
! 104: static gid_t last_in;
! 105: static int ngroups = -2, last_out = -1;
! 106: static GETGROUPS_T *gidset;
! 107: int n;
! 108:
! 109: if (gid == last_in && last_out >= 0)
! 110: return last_out;
! 111: if (ngroups < -1) {
! 112: gid_t mygid = MY_GID();
! 113: if ((ngroups = getgroups(0, NULL)) < 0)
! 114: ngroups = 0;
! 115: gidset = new_array(GETGROUPS_T, ngroups+1);
! 116: if (!gidset)
! 117: out_of_memory("is_in_group");
! 118: if (ngroups > 0)
! 119: ngroups = getgroups(ngroups, gidset);
! 120: /* The default gid might not be in the list on some systems. */
! 121: for (n = 0; n < ngroups; n++) {
! 122: if (gidset[n] == mygid)
! 123: break;
! 124: }
! 125: if (n == ngroups)
! 126: gidset[ngroups++] = mygid;
! 127: if (verbose > 3) {
! 128: int pos;
! 129: char *gidbuf = new_array(char, ngroups*21+32);
! 130: if (!gidbuf)
! 131: out_of_memory("is_in_group");
! 132: pos = snprintf(gidbuf, 32, "process has %d gid%s: ",
! 133: ngroups, ngroups == 1? "" : "s");
! 134: for (n = 0; n < ngroups; n++) {
! 135: pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]);
! 136: }
! 137: rprintf(FINFO, "%s\n", gidbuf);
! 138: free(gidbuf);
! 139: }
! 140: }
! 141:
! 142: last_in = gid;
! 143: for (n = 0; n < ngroups; n++) {
! 144: if (gidset[n] == gid)
! 145: return last_out = 1;
! 146: }
! 147: return last_out = 0;
! 148:
! 149: #else
! 150: static gid_t mygid = GID_NONE;
! 151: if (mygid == GID_NONE) {
! 152: mygid = MY_GID();
! 153: if (verbose > 3)
! 154: rprintf(FINFO, "process has gid %u\n", (unsigned)mygid);
! 155: }
! 156: return gid == mygid;
! 157: #endif
! 158: }
! 159:
! 160: /* Add a uid to the list of uids. Only called on receiving side. */
! 161: static struct idlist *recv_add_uid(uid_t id, const char *name)
! 162: {
! 163: uid_t id2 = name ? map_uid(id, name) : id;
! 164: struct idlist *node;
! 165:
! 166: node = add_to_list(&uidlist, id, name, id2, 0);
! 167:
! 168: if (verbose > 3) {
! 169: rprintf(FINFO, "uid %u(%s) maps to %u\n",
! 170: (unsigned)id, name ? name : "", (unsigned)id2);
! 171: }
! 172:
! 173: return node;
! 174: }
! 175:
! 176: /* Add a gid to the list of gids. Only called on receiving side. */
! 177: static struct idlist *recv_add_gid(gid_t id, const char *name)
! 178: {
! 179: gid_t id2 = name ? map_gid(id, name) : id;
! 180: struct idlist *node;
! 181:
! 182: node = add_to_list(&gidlist, id, name, id2,
! 183: !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
! 184:
! 185: if (verbose > 3) {
! 186: rprintf(FINFO, "gid %u(%s) maps to %u\n",
! 187: (unsigned)id, name ? name : "", (unsigned)id2);
! 188: }
! 189:
! 190: return node;
! 191: }
! 192:
! 193: /* this function is a definate candidate for a faster algorithm */
! 194: uid_t match_uid(uid_t uid)
! 195: {
! 196: static uid_t last_in, last_out;
! 197: struct idlist *list;
! 198:
! 199: if (uid == 0)
! 200: return 0;
! 201:
! 202: if (uid == last_in)
! 203: return last_out;
! 204:
! 205: last_in = uid;
! 206:
! 207: for (list = uidlist; list; list = list->next) {
! 208: if (list->id == uid)
! 209: return last_out = list->id2;
! 210: }
! 211:
! 212: return last_out = uid;
! 213: }
! 214:
! 215: gid_t match_gid(gid_t gid, uint16 *flags_ptr)
! 216: {
! 217: static struct idlist *last = NULL;
! 218: struct idlist *list;
! 219:
! 220: if (last && gid == last->id)
! 221: list = last;
! 222: else {
! 223: for (list = gidlist; list; list = list->next) {
! 224: if (list->id == gid)
! 225: break;
! 226: }
! 227: if (!list)
! 228: list = recv_add_gid(gid, NULL);
! 229: last = list;
! 230: }
! 231:
! 232: if (flags_ptr && list->flags & FLAG_SKIP_GROUP)
! 233: *flags_ptr |= FLAG_SKIP_GROUP;
! 234: return list->id2;
! 235: }
! 236:
! 237: /* Add a uid to the list of uids. Only called on sending side. */
! 238: const char *add_uid(uid_t uid)
! 239: {
! 240: struct idlist *list;
! 241: struct idlist *node;
! 242:
! 243: if (uid == 0) /* don't map root */
! 244: return NULL;
! 245:
! 246: for (list = uidlist; list; list = list->next) {
! 247: if (list->id == uid)
! 248: return NULL;
! 249: }
! 250:
! 251: node = add_to_list(&uidlist, uid, uid_to_name(uid), 0, 0);
! 252: return node->name;
! 253: }
! 254:
! 255: /* Add a gid to the list of gids. Only called on sending side. */
! 256: const char *add_gid(gid_t gid)
! 257: {
! 258: struct idlist *list;
! 259: struct idlist *node;
! 260:
! 261: if (gid == 0) /* don't map root */
! 262: return NULL;
! 263:
! 264: for (list = gidlist; list; list = list->next) {
! 265: if (list->id == gid)
! 266: return NULL;
! 267: }
! 268:
! 269: node = add_to_list(&gidlist, gid, gid_to_name(gid), 0, 0);
! 270: return node->name;
! 271: }
! 272:
! 273: /* send a complete uid/gid mapping to the peer */
! 274: void send_id_list(int f)
! 275: {
! 276: struct idlist *list;
! 277:
! 278: if (preserve_uid || preserve_acls) {
! 279: int len;
! 280: /* we send sequences of uid/byte-length/name */
! 281: for (list = uidlist; list; list = list->next) {
! 282: if (!list->name)
! 283: continue;
! 284: len = strlen(list->name);
! 285: write_varint30(f, list->id);
! 286: write_byte(f, len);
! 287: write_buf(f, list->name, len);
! 288: }
! 289:
! 290: /* terminate the uid list with a 0 uid. We explicitly exclude
! 291: * 0 from the list */
! 292: write_varint30(f, 0);
! 293: }
! 294:
! 295: if (preserve_gid || preserve_acls) {
! 296: int len;
! 297: for (list = gidlist; list; list = list->next) {
! 298: if (!list->name)
! 299: continue;
! 300: len = strlen(list->name);
! 301: write_varint30(f, list->id);
! 302: write_byte(f, len);
! 303: write_buf(f, list->name, len);
! 304: }
! 305: write_varint30(f, 0);
! 306: }
! 307: }
! 308:
! 309: uid_t recv_user_name(int f, uid_t uid)
! 310: {
! 311: struct idlist *node;
! 312: int len = read_byte(f);
! 313: char *name = new_array(char, len+1);
! 314: if (!name)
! 315: out_of_memory("recv_user_name");
! 316: read_sbuf(f, name, len);
! 317: if (numeric_ids < 0) {
! 318: free(name);
! 319: name = NULL;
! 320: }
! 321: node = recv_add_uid(uid, name); /* node keeps name's memory */
! 322: return node->id2;
! 323: }
! 324:
! 325: gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
! 326: {
! 327: struct idlist *node;
! 328: int len = read_byte(f);
! 329: char *name = new_array(char, len+1);
! 330: if (!name)
! 331: out_of_memory("recv_group_name");
! 332: read_sbuf(f, name, len);
! 333: if (numeric_ids < 0) {
! 334: free(name);
! 335: name = NULL;
! 336: }
! 337: node = recv_add_gid(gid, name); /* node keeps name's memory */
! 338: if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
! 339: *flags_ptr |= FLAG_SKIP_GROUP;
! 340: return node->id2;
! 341: }
! 342:
! 343: /* recv a complete uid/gid mapping from the peer and map the uid/gid
! 344: * in the file list to local names */
! 345: void recv_id_list(int f, struct file_list *flist)
! 346: {
! 347: id_t id;
! 348: int i;
! 349:
! 350: if ((preserve_uid || preserve_acls) && numeric_ids <= 0) {
! 351: /* read the uid list */
! 352: while ((id = read_varint30(f)) != 0)
! 353: recv_user_name(f, id);
! 354: }
! 355:
! 356: if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {
! 357: /* read the gid list */
! 358: while ((id = read_varint30(f)) != 0)
! 359: recv_group_name(f, id, NULL);
! 360: }
! 361:
! 362: /* Now convert all the uids/gids from sender values to our values. */
! 363: #ifdef SUPPORT_ACLS
! 364: if (preserve_acls && !numeric_ids)
! 365: match_acl_ids();
! 366: #endif
! 367: if (am_root && preserve_uid && !numeric_ids) {
! 368: for (i = 0; i < flist->used; i++)
! 369: F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
! 370: }
! 371: if (preserve_gid && (!am_root || !numeric_ids)) {
! 372: for (i = 0; i < flist->used; i++) {
! 373: F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
! 374: &flist->files[i]->flags);
! 375: }
! 376: }
! 377: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>