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

1.15    ! claudio     1: /*     $OpenBSD: ids.c,v 1.14 2021/03/22 11:25:29 claudio 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: /*
1.14      claudio    29:  * Free a list of struct ident previously allocated with idents_add().
1.1       benno      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.8       benno      48:  * If we can't find the gid in the list (when, e.g., being sent by the
                     49:  * daemon), don't try to map it.
1.3       benno      50:  */
                     51: void
1.5       florian    52: idents_assign_gid(struct sess *sess, struct flist *fl, size_t flsz,
                     53:        const struct ident *ids, size_t idsz)
1.3       benno      54: {
                     55:        size_t   i, j;
                     56:
1.7       benno      57:        assert(!sess->opts->numeric_ids);
                     58:
1.3       benno      59:        for (i = 0; i < flsz; i++) {
1.5       florian    60:                if (fl[i].st.gid == 0)
1.3       benno      61:                        continue;
1.5       florian    62:                for (j = 0; j < idsz; j++)
                     63:                        if ((int32_t)fl[i].st.gid == ids[j].id)
1.3       benno      64:                                break;
1.8       benno      65:                if (j < idsz)
                     66:                        fl[i].st.gid = ids[j].mapped;
1.3       benno      67:        }
                     68: }
                     69:
                     70: /*
1.5       florian    71:  * Like idents_assign_gid().
                     72:  */
                     73: void
                     74: idents_assign_uid(struct sess *sess, struct flist *fl, size_t flsz,
                     75:        const struct ident *ids, size_t idsz)
                     76: {
                     77:        size_t   i, j;
                     78:
1.7       benno      79:        assert(!sess->opts->numeric_ids);
                     80:
1.5       florian    81:        for (i = 0; i < flsz; i++) {
                     82:                if (fl[i].st.uid == 0)
                     83:                        continue;
                     84:                for (j = 0; j < idsz; j++)
                     85:                        if ((int32_t)fl[i].st.uid == ids[j].id)
                     86:                                break;
1.8       benno      87:                if (j < idsz)
                     88:                        fl[i].st.uid = ids[j].mapped;
1.5       florian    89:        }
                     90: }
                     91:
                     92: /*
                     93:  * Given a list of identifiers from the remote host, fill in our local
1.1       benno      94:  * identifiers of the same names.
1.6       benno      95:  * Use the remote numeric identifier if we can't find the identifier OR the
                     96:  * identifier is zero (wheel/root).
                     97:  * FIXME: we should at least warn when we can't find an identifier, use
                     98:  * the numeric id, and that numeric id is assigned to a different user.
1.1       benno      99:  */
                    100: void
1.5       florian   101: idents_remap(struct sess *sess, int isgid, struct ident *ids, size_t idsz)
1.1       benno     102: {
1.4       benno     103:        size_t           i;
1.1       benno     104:        struct group    *grp;
1.5       florian   105:        struct passwd   *usr;
1.11      deraadt   106:        uint32_t         id;
1.14      claudio   107:        int              valid;
1.6       benno     108:
1.7       benno     109:        assert(!sess->opts->numeric_ids);
1.1       benno     110:
1.5       florian   111:        for (i = 0; i < idsz; i++) {
                    112:                assert(ids[i].id != 0);
                    113:
                    114:                /* Start by getting our local representation. */
                    115:
1.11      deraadt   116:                valid = id = 0;
                    117:                if (isgid) {
                    118:                        grp = getgrnam(ids[i].name);
                    119:                        if (grp) {
                    120:                                id = grp->gr_gid;
                    121:                                valid = 1;
                    122:                        }
                    123:                } else {
                    124:                        usr = getpwnam(ids[i].name);
                    125:                        if (usr) {
                    126:                                id = usr->pw_uid;
                    127:                                valid = 1;
                    128:                        }
                    129:                }
1.3       benno     130:
1.4       benno     131:                /*
1.3       benno     132:                 * (1) Empty names inherit.
1.5       florian   133:                 * (2) Unknown identifier names inherit.
                    134:                 * (3) Wheel/root inherits.
1.3       benno     135:                 * (4) Otherwise, use the local identifier.
                    136:                 */
                    137:
1.5       florian   138:                if (ids[i].name[0] == '\0')
                    139:                        ids[i].mapped = ids[i].id;
1.11      deraadt   140:                else if (!valid)
1.5       florian   141:                        ids[i].mapped = ids[i].id;
1.1       benno     142:                else
1.5       florian   143:                        ids[i].mapped = id;
1.2       benno     144:
1.12      benno     145:                LOG4("remapped identifier %s: %d -> %d",
1.9       deraadt   146:                    ids[i].name, ids[i].id, ids[i].mapped);
1.1       benno     147:        }
                    148: }
                    149:
                    150: /*
1.5       florian   151:  * If "id" is not part of the list of known users or groups (depending
                    152:  * upon "isgid", add it.
                    153:  * This also verifies that the name isn't too long.
                    154:  * Does nothing with user/group zero.
1.1       benno     155:  * Return zero on failure, non-zero on success.
                    156:  */
                    157: int
1.13      benno     158: idents_add(int isgid, struct ident **ids, size_t *idsz, int32_t id)
1.1       benno     159: {
                    160:        struct group    *grp;
1.5       florian   161:        struct passwd   *usr;
1.1       benno     162:        size_t           i, sz;
                    163:        void            *pp;
1.5       florian   164:        const char      *name;
1.1       benno     165:
1.5       florian   166:        if (id == 0)
1.3       benno     167:                return 1;
                    168:
1.5       florian   169:        for (i = 0; i < *idsz; i++)
                    170:                if ((*ids)[i].id == id)
1.1       benno     171:                        return 1;
                    172:
1.4       benno     173:        /*
1.5       florian   174:         * Look up the reference in a type-specific way.
                    175:         * Make sure that the name length is sane: we transmit it using
                    176:         * a single byte.
1.1       benno     177:         */
                    178:
1.5       florian   179:        assert(i == *idsz);
                    180:        if (isgid) {
                    181:                if ((grp = getgrgid((gid_t)id)) == NULL) {
1.12      benno     182:                        ERR("%d: unknown gid", id);
1.5       florian   183:                        return 0;
                    184:                }
                    185:                name = grp->gr_name;
                    186:        } else {
                    187:                if ((usr = getpwuid((uid_t)id)) == NULL) {
1.12      benno     188:                        ERR("%d: unknown uid", id);
1.5       florian   189:                        return 0;
                    190:                }
                    191:                name = usr->pw_name;
                    192:        }
                    193:
                    194:        if ((sz = strlen(name)) > UINT8_MAX) {
1.12      benno     195:                ERRX("%d: name too long: %s", id, name);
1.1       benno     196:                return 0;
1.3       benno     197:        } else if (sz == 0) {
1.12      benno     198:                ERRX("%d: zero-length name", id);
1.1       benno     199:                return 0;
                    200:        }
                    201:
1.5       florian   202:        /* Add the identifier to the array. */
1.1       benno     203:
1.5       florian   204:        pp = reallocarray(*ids, *idsz + 1, sizeof(struct ident));
1.3       benno     205:        if (pp == NULL) {
1.12      benno     206:                ERR("reallocarray");
1.1       benno     207:                return 0;
                    208:        }
1.5       florian   209:        *ids = pp;
                    210:        (*ids)[*idsz].id = id;
                    211:        (*ids)[*idsz].name = strdup(name);
                    212:        if ((*ids)[*idsz].name == NULL) {
1.12      benno     213:                ERR("strdup");
1.1       benno     214:                return 0;
                    215:        }
                    216:
1.12      benno     217:        LOG4("adding identifier to list: %s (%u)",
1.9       deraadt   218:            (*ids)[*idsz].name, (*ids)[*idsz].id);
1.5       florian   219:        (*idsz)++;
1.1       benno     220:        return 1;
                    221: }
                    222:
                    223: /*
                    224:  * Send a list of struct ident.
                    225:  * See idents_recv().
                    226:  * We should only do this if we're preserving gids/uids.
                    227:  * Return zero on failure, non-zero on success.
                    228:  */
                    229: int
1.4       benno     230: idents_send(struct sess *sess,
1.1       benno     231:        int fd, const struct ident *ids, size_t idsz)
                    232: {
                    233:        size_t   i, sz;
                    234:
                    235:        for (i = 0; i < idsz; i++) {
1.3       benno     236:                assert(ids[i].name != NULL);
                    237:                assert(ids[i].id != 0);
1.1       benno     238:                sz = strlen(ids[i].name);
                    239:                assert(sz > 0 && sz <= UINT8_MAX);
1.11      deraadt   240:                if (!io_write_uint(sess, fd, ids[i].id)) {
1.12      benno     241:                        ERRX1("io_write_uint");
1.1       benno     242:                        return 0;
                    243:                } else if (!io_write_byte(sess, fd, sz)) {
1.12      benno     244:                        ERRX1("io_write_byte");
1.1       benno     245:                        return 0;
                    246:                } else if (!io_write_buf(sess, fd, ids[i].name, sz)) {
1.12      benno     247:                        ERRX1("io_write_buf");
1.1       benno     248:                        return 0;
                    249:                }
                    250:        }
                    251:
                    252:        if (!io_write_int(sess, fd, 0)) {
1.12      benno     253:                ERRX1("io_write_int");
1.1       benno     254:                return 0;
                    255:        }
                    256:
                    257:        return 1;
                    258: }
                    259:
                    260: /*
                    261:  * Receive a list of struct ident.
                    262:  * See idents_send().
                    263:  * We should only do this if we're preserving gids/uids.
                    264:  * Return zero on failure, non-zero on success.
                    265:  */
                    266: int
                    267: idents_recv(struct sess *sess,
                    268:        int fd, struct ident **ids, size_t *idsz)
                    269: {
1.14      claudio   270:        uint32_t id;
1.1       benno     271:        uint8_t  sz;
                    272:        void    *pp;
                    273:
                    274:        for (;;) {
1.11      deraadt   275:                if (!io_read_uint(sess, fd, &id)) {
1.12      benno     276:                        ERRX1("io_read_uint");
1.1       benno     277:                        return 0;
1.3       benno     278:                } else if (id == 0)
1.1       benno     279:                        break;
1.4       benno     280:
                    281:                pp = reallocarray(*ids,
1.1       benno     282:                        *idsz + 1, sizeof(struct ident));
1.3       benno     283:                if (pp == NULL) {
1.12      benno     284:                        ERR("reallocarray");
1.1       benno     285:                        return 0;
                    286:                }
                    287:                *ids = pp;
                    288:                memset(&(*ids)[*idsz], 0, sizeof(struct ident));
1.3       benno     289:
                    290:                /*
1.5       florian   291:                 * When reading the size, warn if we get a size of zero.
1.3       benno     292:                 * The spec doesn't allow this, but we might have a
                    293:                 * noncomformant or adversarial sender.
                    294:                 */
                    295:
1.1       benno     296:                if (!io_read_byte(sess, fd, &sz)) {
1.12      benno     297:                        ERRX1("io_read_byte");
1.1       benno     298:                        return 0;
1.5       florian   299:                } else if (sz == 0)
1.12      benno     300:                        WARNX("zero-length name in identifier list");
1.3       benno     301:
1.14      claudio   302:                assert(id < INT32_MAX);
1.1       benno     303:                (*ids)[*idsz].id = id;
                    304:                (*ids)[*idsz].name = calloc(sz + 1, 1);
1.3       benno     305:                if ((*ids)[*idsz].name == NULL) {
1.12      benno     306:                        ERR("calloc");
1.1       benno     307:                        return 0;
                    308:                }
                    309:                if (!io_read_buf(sess, fd, (*ids)[*idsz].name, sz)) {
1.12      benno     310:                        ERRX1("io_read_buf");
1.1       benno     311:                        return 0;
                    312:                }
                    313:                (*idsz)++;
                    314:        }
                    315:
                    316:        return 1;
                    317: }