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>