[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.5

1.5     ! florian     1: /*     $Id: ids.c,v 1.4 2019/02/12 19:39:57 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>
1.5     ! florian    20: #include <pwd.h>
1.1       benno      21: #include <stdio.h>
                     22: #include <stdlib.h>
                     23: #include <string.h>
                     24: #include <unistd.h>
                     25:
                     26: #include "extern.h"
                     27:
                     28: /*
                     29:  * Free a list of struct ident previously allocated with idents_gid_add().
                     30:  * Does nothing if the pointer is NULL.
                     31:  */
                     32: void
                     33: idents_free(struct ident *p, size_t sz)
                     34: {
                     35:        size_t   i;
                     36:
1.3       benno      37:        if (p == NULL)
1.1       benno      38:                return;
                     39:        for (i = 0; i < sz; i++)
                     40:                free(p[i].name);
                     41:        free(p);
                     42: }
                     43:
                     44: /*
1.5     ! florian    45:  * Given a list of files with the identifiers as set by the sender,
        !            46:  * re-assign the identifiers from the list of remapped ones.
        !            47:  * Don't ever remap wheel/root.
1.3       benno      48:  */
                     49: void
1.5     ! florian    50: idents_assign_gid(struct sess *sess, struct flist *fl, size_t flsz,
        !            51:        const struct ident *ids, size_t idsz)
1.3       benno      52: {
                     53:        size_t   i, j;
                     54:
                     55:        for (i = 0; i < flsz; i++) {
1.5     ! florian    56:                if (fl[i].st.gid == 0)
1.3       benno      57:                        continue;
1.5     ! florian    58:                for (j = 0; j < idsz; j++)
        !            59:                        if ((int32_t)fl[i].st.gid == ids[j].id)
1.3       benno      60:                                break;
1.5     ! florian    61:                assert(j < idsz);
        !            62:                fl[i].st.gid = ids[j].mapped;
1.3       benno      63:        }
                     64: }
                     65:
                     66: /*
1.5     ! florian    67:  * Like idents_assign_gid().
        !            68:  */
        !            69: void
        !            70: idents_assign_uid(struct sess *sess, struct flist *fl, size_t flsz,
        !            71:        const struct ident *ids, size_t idsz)
        !            72: {
        !            73:        size_t   i, j;
        !            74:
        !            75:        for (i = 0; i < flsz; i++) {
        !            76:                if (fl[i].st.uid == 0)
        !            77:                        continue;
        !            78:                for (j = 0; j < idsz; j++)
        !            79:                        if ((int32_t)fl[i].st.uid == ids[j].id)
        !            80:                                break;
        !            81:                assert(j < idsz);
        !            82:                fl[i].st.uid = ids[j].mapped;
        !            83:        }
        !            84: }
        !            85:
        !            86: /*
        !            87:  * Given a list of identifiers from the remote host, fill in our local
1.1       benno      88:  * identifiers of the same names.
1.5     ! florian    89:  * Use the remote numeric identifier if we can't find the identifier OR
        !            90:  * the identifier is zero (wheel/root).
        !            91:  * FIXME: what happens if we don't find the local identifier (we should
        !            92:  * really warn about this), but the remote identifier maps into a
        !            93:  * different name for us?
1.2       benno      94:  * These are pretty unexpected things for rsync to do.
                     95:  * Another FIXME because we shouldn't let that happen even though the
                     96:  * reference rsync does.
1.1       benno      97:  */
                     98: void
1.5     ! florian    99: idents_remap(struct sess *sess, int isgid, struct ident *ids, size_t idsz)
1.1       benno     100: {
1.4       benno     101:        size_t           i;
1.1       benno     102:        struct group    *grp;
1.5     ! florian   103:        struct passwd   *usr;
        !           104:        int32_t          id;
1.1       benno     105:
1.5     ! florian   106:        for (i = 0; i < idsz; i++) {
        !           107:                assert(ids[i].id != 0);
        !           108:
        !           109:                /* Start by getting our local representation. */
        !           110:
        !           111:                if (isgid)
        !           112:                        id = (grp = getgrnam(ids[i].name)) == NULL ?
        !           113:                                -1 : grp->gr_gid;
        !           114:                else
        !           115:                        id = (usr = getpwnam(ids[i].name)) == NULL ?
        !           116:                                -1 : usr->pw_uid;
1.3       benno     117:
1.4       benno     118:                /*
1.3       benno     119:                 * (1) Empty names inherit.
1.5     ! florian   120:                 * (2) Unknown identifier names inherit.
        !           121:                 * (3) Wheel/root inherits.
1.3       benno     122:                 * (4) Otherwise, use the local identifier.
                    123:                 */
                    124:
1.5     ! florian   125:                if (ids[i].name[0] == '\0')
        !           126:                        ids[i].mapped = ids[i].id;
        !           127:                else if (id <= 0)
        !           128:                        ids[i].mapped = ids[i].id;
1.1       benno     129:                else
1.5     ! florian   130:                        ids[i].mapped = id;
1.2       benno     131:
1.5     ! florian   132:                LOG4(sess, "remapped identifier %s: %" PRId32 " -> %" PRId32,
        !           133:                        ids[i].name, ids[i].id, ids[i].mapped);
1.1       benno     134:        }
                    135: }
                    136:
                    137: /*
1.5     ! florian   138:  * If "id" is not part of the list of known users or groups (depending
        !           139:  * upon "isgid", add it.
        !           140:  * This also verifies that the name isn't too long.
        !           141:  * Does nothing with user/group zero.
1.1       benno     142:  * Return zero on failure, non-zero on success.
                    143:  */
                    144: int
1.5     ! florian   145: idents_add(struct sess *sess, int isgid,
        !           146:        struct ident **ids, size_t *idsz, int32_t id)
1.1       benno     147: {
                    148:        struct group    *grp;
1.5     ! florian   149:        struct passwd   *usr;
1.1       benno     150:        size_t           i, sz;
                    151:        void            *pp;
1.5     ! florian   152:        const char      *name;
1.1       benno     153:
1.5     ! florian   154:        if (id == 0)
1.3       benno     155:                return 1;
                    156:
1.5     ! florian   157:        for (i = 0; i < *idsz; i++)
        !           158:                if ((*ids)[i].id == id)
1.1       benno     159:                        return 1;
                    160:
1.4       benno     161:        /*
1.5     ! florian   162:         * Look up the reference in a type-specific way.
        !           163:         * Make sure that the name length is sane: we transmit it using
        !           164:         * a single byte.
1.1       benno     165:         */
                    166:
1.5     ! florian   167:        assert(i == *idsz);
        !           168:        if (isgid) {
        !           169:                if ((grp = getgrgid((gid_t)id)) == NULL) {
        !           170:                        ERR(sess, "%" PRId32 ": unknown gid", id);
        !           171:                        return 0;
        !           172:                }
        !           173:                name = grp->gr_name;
        !           174:        } else {
        !           175:                if ((usr = getpwuid((uid_t)id)) == NULL) {
        !           176:                        ERR(sess, "%" PRId32 ": unknown uid", id);
        !           177:                        return 0;
        !           178:                }
        !           179:                name = usr->pw_name;
        !           180:        }
        !           181:
        !           182:        if ((sz = strlen(name)) > UINT8_MAX) {
        !           183:                ERRX(sess, "%" PRId32 ": name too long: %s", id, name);
1.1       benno     184:                return 0;
1.3       benno     185:        } else if (sz == 0) {
1.5     ! florian   186:                ERRX(sess, "%" PRId32 ": zero-length name", id);
1.1       benno     187:                return 0;
                    188:        }
                    189:
1.5     ! florian   190:        /* Add the identifier to the array. */
1.1       benno     191:
1.5     ! florian   192:        pp = reallocarray(*ids, *idsz + 1, sizeof(struct ident));
1.3       benno     193:        if (pp == NULL) {
1.1       benno     194:                ERR(sess, "reallocarray");
                    195:                return 0;
                    196:        }
1.5     ! florian   197:        *ids = pp;
        !           198:        (*ids)[*idsz].id = id;
        !           199:        (*ids)[*idsz].name = strdup(name);
        !           200:        if ((*ids)[*idsz].name == NULL) {
1.1       benno     201:                ERR(sess, "strdup");
                    202:                return 0;
                    203:        }
                    204:
1.5     ! florian   205:        LOG4(sess, "adding identifier to list: %s (%u)",
        !           206:                (*ids)[*idsz].name, (*ids)[*idsz].id);
        !           207:        (*idsz)++;
1.1       benno     208:        return 1;
                    209: }
                    210:
                    211: /*
                    212:  * Send a list of struct ident.
                    213:  * See idents_recv().
                    214:  * We should only do this if we're preserving gids/uids.
                    215:  * Return zero on failure, non-zero on success.
                    216:  */
                    217: int
1.4       benno     218: idents_send(struct sess *sess,
1.1       benno     219:        int fd, const struct ident *ids, size_t idsz)
                    220: {
                    221:        size_t   i, sz;
                    222:
                    223:        for (i = 0; i < idsz; i++) {
1.3       benno     224:                assert(ids[i].name != NULL);
                    225:                assert(ids[i].id != 0);
1.1       benno     226:                sz = strlen(ids[i].name);
                    227:                assert(sz > 0 && sz <= UINT8_MAX);
                    228:                if (!io_write_int(sess, fd, ids[i].id)) {
                    229:                        ERRX1(sess, "io_write_int");
                    230:                        return 0;
                    231:                } else if (!io_write_byte(sess, fd, sz)) {
                    232:                        ERRX1(sess, "io_write_byte");
                    233:                        return 0;
                    234:                } else if (!io_write_buf(sess, fd, ids[i].name, sz)) {
                    235:                        ERRX1(sess, "io_write_byte");
                    236:                        return 0;
                    237:                }
                    238:        }
                    239:
                    240:        if (!io_write_int(sess, fd, 0)) {
                    241:                ERRX1(sess, "io_write_int");
                    242:                return 0;
                    243:        }
                    244:
                    245:        return 1;
                    246: }
                    247:
                    248: /*
                    249:  * Receive a list of struct ident.
                    250:  * See idents_send().
                    251:  * We should only do this if we're preserving gids/uids.
                    252:  * Return zero on failure, non-zero on success.
                    253:  */
                    254: int
                    255: idents_recv(struct sess *sess,
                    256:        int fd, struct ident **ids, size_t *idsz)
                    257: {
                    258:        int32_t  id;
                    259:        uint8_t  sz;
                    260:        void    *pp;
                    261:
                    262:        for (;;) {
                    263:                if (!io_read_int(sess, fd, &id)) {
                    264:                        ERRX1(sess, "io_read_int");
                    265:                        return 0;
1.3       benno     266:                } else if (id == 0)
1.1       benno     267:                        break;
1.4       benno     268:
                    269:                pp = reallocarray(*ids,
1.1       benno     270:                        *idsz + 1, sizeof(struct ident));
1.3       benno     271:                if (pp == NULL) {
1.1       benno     272:                        ERR(sess, "reallocarray");
                    273:                        return 0;
                    274:                }
                    275:                *ids = pp;
                    276:                memset(&(*ids)[*idsz], 0, sizeof(struct ident));
1.3       benno     277:
                    278:                /*
1.5     ! florian   279:                 * When reading the size, warn if we get a size of zero.
1.3       benno     280:                 * The spec doesn't allow this, but we might have a
                    281:                 * noncomformant or adversarial sender.
                    282:                 */
                    283:
1.1       benno     284:                if (!io_read_byte(sess, fd, &sz)) {
                    285:                        ERRX1(sess, "io_read_byte");
                    286:                        return 0;
1.5     ! florian   287:                } else if (sz == 0)
        !           288:                        WARNX(sess, "zero-length name "
        !           289:                                "in identifier list");
1.3       benno     290:
1.1       benno     291:                (*ids)[*idsz].id = id;
                    292:                (*ids)[*idsz].name = calloc(sz + 1, 1);
1.3       benno     293:                if ((*ids)[*idsz].name == NULL) {
1.1       benno     294:                        ERR(sess, "calloc");
                    295:                        return 0;
                    296:                }
                    297:                if (!io_read_buf(sess, fd, (*ids)[*idsz].name, sz)) {
                    298:                        ERRX1(sess, "io_read_buf");
                    299:                        return 0;
                    300:                }
                    301:                (*idsz)++;
                    302:        }
                    303:
                    304:        return 1;
                    305: }