[BACK]Return to ids.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rsync

Annotation of src/usr.bin/rsync/ids.c, Revision 1.4

1.4     ! benno       1: /*     $Id: ids.c,v 1.3 2019/02/12 19:13:03 benno Exp $ */
1.1       benno       2: /*
                      3:  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: #include <assert.h>
                     18: #include <grp.h>
                     19: #include <inttypes.h>
                     20: #include <stdio.h>
                     21: #include <stdlib.h>
                     22: #include <string.h>
                     23: #include <unistd.h>
                     24:
                     25: #include "extern.h"
                     26:
                     27: /*
                     28:  * Free a list of struct ident previously allocated with idents_gid_add().
                     29:  * Does nothing if the pointer is NULL.
                     30:  */
                     31: void
                     32: idents_free(struct ident *p, size_t sz)
                     33: {
                     34:        size_t   i;
                     35:
1.3       benno      36:        if (p == NULL)
1.1       benno      37:                return;
                     38:        for (i = 0; i < sz; i++)
                     39:                free(p[i].name);
                     40:        free(p);
                     41: }
                     42:
                     43: /*
1.3       benno      44:  * Given a list of files with the groups as set by the sender, re-assign
                     45:  * the groups from the list of remapped group identifiers.
                     46:  * Don't ever remap group wheel.
                     47:  */
                     48: void
                     49: idents_gid_assign(struct sess *sess, struct flist *fl, size_t flsz,
                     50:        const struct ident *gids, size_t gidsz)
                     51: {
                     52:        size_t   i, j;
                     53:
                     54:        for (i = 0; i < flsz; i++) {
                     55:                if (0 == fl[i].st.gid)
                     56:                        continue;
                     57:                for (j = 0; j < gidsz; j++)
                     58:                        if ((int32_t)fl[i].st.gid == gids[j].id)
                     59:                                break;
                     60:                assert(j < gidsz);
                     61:                fl[i].st.gid = gids[j].mapped;
                     62:        }
                     63: }
                     64:
                     65: /*
1.1       benno      66:  * Given a list of groups from the remote host, fill in our local
                     67:  * identifiers of the same names.
                     68:  * Use the remote numeric identifier if we can't find the group OR the
                     69:  * group has identifier zero.
1.2       benno      70:  * FIXME: what happens if we don't find the local group (we should
                     71:  * really warn about this), but the remote group identifier maps into a
                     72:  * different group name for us?
                     73:  * These are pretty unexpected things for rsync to do.
                     74:  * Another FIXME because we shouldn't let that happen even though the
                     75:  * reference rsync does.
1.1       benno      76:  */
                     77: void
                     78: idents_gid_remap(struct sess *sess, struct ident *gids, size_t gidsz)
                     79: {
1.4     ! benno      80:        size_t           i;
1.1       benno      81:        struct group    *grp;
                     82:
                     83:        for (i = 0; i < gidsz; i++) {
1.3       benno      84:                assert(gids[i].id != 0);
                     85:
1.4     ! benno      86:                /*
1.3       benno      87:                 * (1) Empty names inherit.
                     88:                 * (2) Unknown group names inherit.
                     89:                 * (3) Group wheel inherits.
                     90:                 * (4) Otherwise, use the local identifier.
                     91:                 */
                     92:
                     93:                if (gids[i].name[0] == '\0')
1.1       benno      94:                        gids[i].mapped = gids[i].id;
1.3       benno      95:                else if ((grp = getgrnam(gids[i].name)) == NULL)
                     96:                        gids[i].mapped = gids[i].id;
                     97:                else if (grp->gr_gid == 0)
1.1       benno      98:                        gids[i].mapped = gids[i].id;
                     99:                else
                    100:                        gids[i].mapped = grp->gr_gid;
1.2       benno     101:
1.1       benno     102:                LOG4(sess, "remapped group %s: %" PRId32 " -> %" PRId32,
                    103:                        gids[i].name, gids[i].id, gids[i].mapped);
                    104:        }
                    105: }
                    106:
                    107: /*
                    108:  * If "gid" is not part of the list of known groups, add it.
                    109:  * This also verifies that the group name isn't too long.
1.3       benno     110:  * Does nothing with group zero.
1.1       benno     111:  * Return zero on failure, non-zero on success.
                    112:  */
                    113: int
                    114: idents_gid_add(struct sess *sess, struct ident **gids, size_t *gidsz, gid_t gid)
                    115: {
                    116:        struct group    *grp;
                    117:        size_t           i, sz;
                    118:        void            *pp;
                    119:
1.3       benno     120:        if (gid == 0)
                    121:                return 1;
                    122:
1.1       benno     123:        for (i = 0; i < *gidsz; i++)
                    124:                if ((*gids)[i].id == (int32_t)gid)
                    125:                        return 1;
                    126:
1.4     ! benno     127:        /*
1.1       benno     128:         * Look us up in /etc/group.
                    129:         * Make sure that the group name length is sane: we transmit it
                    130:         * using a single byte.
                    131:         */
                    132:
                    133:        assert(i == *gidsz);
1.3       benno     134:        if ((grp = getgrgid(gid)) == NULL) {
1.1       benno     135:                ERR(sess, "%u: unknown gid", gid);
                    136:                return 0;
                    137:        } else if ((sz = strlen(grp->gr_name)) > UINT8_MAX) {
                    138:                ERRX(sess, "%u: group name too long: %s", gid, grp->gr_name);
                    139:                return 0;
1.3       benno     140:        } else if (sz == 0) {
1.1       benno     141:                ERRX(sess, "%u: group name zero-length", gid);
                    142:                return 0;
                    143:        }
                    144:
                    145:        /* Add the group to the array. */
                    146:
                    147:        pp = reallocarray(*gids, *gidsz + 1, sizeof(struct ident));
1.3       benno     148:        if (pp == NULL) {
1.1       benno     149:                ERR(sess, "reallocarray");
                    150:                return 0;
                    151:        }
                    152:        *gids = pp;
                    153:        (*gids)[*gidsz].id = gid;
                    154:        (*gids)[*gidsz].name = strdup(grp->gr_name);
                    155:        if (NULL == (*gids)[*gidsz].name) {
                    156:                ERR(sess, "strdup");
                    157:                return 0;
                    158:        }
                    159:
1.4     ! benno     160:        LOG4(sess, "adding group to list: %s (%u)",
1.1       benno     161:                (*gids)[*gidsz].name, (*gids)[*gidsz].id);
                    162:        (*gidsz)++;
                    163:        return 1;
                    164: }
                    165:
                    166: /*
                    167:  * Send a list of struct ident.
                    168:  * See idents_recv().
                    169:  * We should only do this if we're preserving gids/uids.
                    170:  * Return zero on failure, non-zero on success.
                    171:  */
                    172: int
1.4     ! benno     173: idents_send(struct sess *sess,
1.1       benno     174:        int fd, const struct ident *ids, size_t idsz)
                    175: {
                    176:        size_t   i, sz;
                    177:
                    178:        for (i = 0; i < idsz; i++) {
1.3       benno     179:                assert(ids[i].name != NULL);
                    180:                assert(ids[i].id != 0);
1.1       benno     181:                sz = strlen(ids[i].name);
                    182:                assert(sz > 0 && sz <= UINT8_MAX);
                    183:                if (!io_write_int(sess, fd, ids[i].id)) {
                    184:                        ERRX1(sess, "io_write_int");
                    185:                        return 0;
                    186:                } else if (!io_write_byte(sess, fd, sz)) {
                    187:                        ERRX1(sess, "io_write_byte");
                    188:                        return 0;
                    189:                } else if (!io_write_buf(sess, fd, ids[i].name, sz)) {
                    190:                        ERRX1(sess, "io_write_byte");
                    191:                        return 0;
                    192:                }
                    193:        }
                    194:
                    195:        if (!io_write_int(sess, fd, 0)) {
                    196:                ERRX1(sess, "io_write_int");
                    197:                return 0;
                    198:        }
                    199:
                    200:        return 1;
                    201: }
                    202:
                    203: /*
                    204:  * Receive a list of struct ident.
                    205:  * See idents_send().
                    206:  * We should only do this if we're preserving gids/uids.
                    207:  * Return zero on failure, non-zero on success.
                    208:  */
                    209: int
                    210: idents_recv(struct sess *sess,
                    211:        int fd, struct ident **ids, size_t *idsz)
                    212: {
                    213:        int32_t  id;
                    214:        uint8_t  sz;
                    215:        void    *pp;
                    216:
                    217:        for (;;) {
                    218:                if (!io_read_int(sess, fd, &id)) {
                    219:                        ERRX1(sess, "io_read_int");
                    220:                        return 0;
1.3       benno     221:                } else if (id == 0)
1.1       benno     222:                        break;
1.4     ! benno     223:
        !           224:                pp = reallocarray(*ids,
1.1       benno     225:                        *idsz + 1, sizeof(struct ident));
1.3       benno     226:                if (pp == NULL) {
1.1       benno     227:                        ERR(sess, "reallocarray");
                    228:                        return 0;
                    229:                }
                    230:                *ids = pp;
                    231:                memset(&(*ids)[*idsz], 0, sizeof(struct ident));
1.3       benno     232:
                    233:                /*
                    234:                 * When reading the size, warn if we get a group size of
                    235:                 * zero.
                    236:                 * The spec doesn't allow this, but we might have a
                    237:                 * noncomformant or adversarial sender.
                    238:                 */
                    239:
1.1       benno     240:                if (!io_read_byte(sess, fd, &sz)) {
                    241:                        ERRX1(sess, "io_read_byte");
                    242:                        return 0;
1.3       benno     243:                } else if (0 == sz)
                    244:                        WARNX(sess, "zero-length group name "
                    245:                                "in group list");
                    246:
1.1       benno     247:                (*ids)[*idsz].id = id;
                    248:                (*ids)[*idsz].name = calloc(sz + 1, 1);
1.3       benno     249:                if ((*ids)[*idsz].name == NULL) {
1.1       benno     250:                        ERR(sess, "calloc");
                    251:                        return 0;
                    252:                }
                    253:                if (!io_read_buf(sess, fd, (*ids)[*idsz].name, sz)) {
                    254:                        ERRX1(sess, "io_read_buf");
                    255:                        return 0;
                    256:                }
                    257:                (*idsz)++;
                    258:        }
                    259:
                    260:        return 1;
                    261: }