[BACK]Return to sftp-usergroup.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/sftp-usergroup.c, Revision 1.1

1.1     ! djm         1: /*
        !             2:  * Copyright (c) 2022 Damien Miller <djm@mindrot.org>
        !             3:  *
        !             4:  * Permission to use, copy, modify, and distribute this software for any
        !             5:  * purpose with or without fee is hereby granted, provided that the above
        !             6:  * copyright notice and this permission notice appear in all copies.
        !             7:  *
        !             8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !             9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            15:  */
        !            16:
        !            17: /* sftp client user/group lookup and caching */
        !            18:
        !            19: #include <sys/types.h>
        !            20: #include <sys/tree.h>
        !            21:
        !            22: #include <glob.h>
        !            23: #include <stdlib.h>
        !            24: #include <stdarg.h>
        !            25: #include <string.h>
        !            26:
        !            27: #include "log.h"
        !            28: #include "xmalloc.h"
        !            29:
        !            30: #include "sftp-common.h"
        !            31: #include "sftp-client.h"
        !            32: #include "sftp-usergroup.h"
        !            33:
        !            34: /* Tree of id, name */
        !            35: struct idname {
        !            36:         u_int id;
        !            37:        char *name;
        !            38:         RB_ENTRY(idname) entry;
        !            39:        /* XXX implement bounded cache as TAILQ */
        !            40: };
        !            41: static int
        !            42: idname_cmp(struct idname *a, struct idname *b)
        !            43: {
        !            44:        if (a->id == b->id)
        !            45:                return 0;
        !            46:        return a->id > b->id ? 1 : -1;
        !            47: }
        !            48: RB_HEAD(idname_tree, idname);
        !            49: RB_GENERATE_STATIC(idname_tree, idname, entry, idname_cmp)
        !            50:
        !            51: static struct idname_tree user_idname = RB_INITIALIZER(&user_idname);
        !            52: static struct idname_tree group_idname = RB_INITIALIZER(&group_idname);
        !            53:
        !            54: static void
        !            55: idname_free(struct idname *idname)
        !            56: {
        !            57:        if (idname == NULL)
        !            58:                return;
        !            59:        free(idname->name);
        !            60:        free(idname);
        !            61: }
        !            62:
        !            63: static void
        !            64: idname_enter(struct idname_tree *tree, u_int id, const char *name)
        !            65: {
        !            66:        struct idname *idname;
        !            67:
        !            68:        if ((idname = xcalloc(1, sizeof(*idname))) == NULL)
        !            69:                fatal_f("alloc");
        !            70:        idname->id = id;
        !            71:        idname->name = xstrdup(name);
        !            72:        if (RB_INSERT(idname_tree, tree, idname) != NULL)
        !            73:                idname_free(idname);
        !            74: }
        !            75:
        !            76: static const char *
        !            77: idname_lookup(struct idname_tree *tree, u_int id)
        !            78: {
        !            79:        struct idname idname, *found;
        !            80:
        !            81:        memset(&idname, 0, sizeof(idname));
        !            82:        idname.id = id;
        !            83:        if ((found = RB_FIND(idname_tree, tree, &idname)) != NULL)
        !            84:                return found->name;
        !            85:        return NULL;
        !            86: }
        !            87:
        !            88: static void
        !            89: freenames(char **names, u_int nnames)
        !            90: {
        !            91:        u_int i;
        !            92:
        !            93:        if (names == NULL)
        !            94:                return;
        !            95:        for (i = 0; i < nnames; i++)
        !            96:                free(names[i]);
        !            97:        free(names);
        !            98: }
        !            99:
        !           100: static void
        !           101: lookup_and_record(struct sftp_conn *conn,
        !           102:     u_int *uids, u_int nuids, u_int *gids, u_int ngids)
        !           103: {
        !           104:        int r;
        !           105:        u_int i;
        !           106:        char **usernames = NULL, **groupnames = NULL;
        !           107:
        !           108:        if ((r = do_get_users_groups_by_id(conn, uids, nuids, gids, ngids,
        !           109:            &usernames, &groupnames)) != 0) {
        !           110:                debug_fr(r, "do_get_users_groups_by_id");
        !           111:                return;
        !           112:        }
        !           113:        for (i = 0; i < nuids; i++) {
        !           114:                if (usernames[i] == NULL) {
        !           115:                        debug3_f("uid %u not resolved", uids[i]);
        !           116:                        continue;
        !           117:                }
        !           118:                debug3_f("record uid %u => \"%s\"", uids[i], usernames[i]);
        !           119:                idname_enter(&user_idname, uids[i], usernames[i]);
        !           120:        }
        !           121:        for (i = 0; i < ngids; i++) {
        !           122:                if (groupnames[i] == NULL) {
        !           123:                        debug3_f("gid %u not resolved", gids[i]);
        !           124:                        continue;
        !           125:                }
        !           126:                debug3_f("record gid %u => \"%s\"", gids[i], groupnames[i]);
        !           127:                idname_enter(&group_idname, gids[i], groupnames[i]);
        !           128:        }
        !           129:        freenames(usernames, nuids);
        !           130:        freenames(groupnames, ngids);
        !           131: }
        !           132:
        !           133: static int
        !           134: has_id(u_int id, u_int *ids, u_int nids)
        !           135: {
        !           136:        u_int i;
        !           137:
        !           138:        if (nids == 0)
        !           139:                return 0;
        !           140:
        !           141:        /* XXX O(N^2) */
        !           142:        for (i = 0; i < nids; i++) {
        !           143:                if (ids[i] == id)
        !           144:                        break;
        !           145:        }
        !           146:        return i < nids;
        !           147: }
        !           148:
        !           149: static void
        !           150: collect_ids_from_glob(glob_t *g, int user, u_int **idsp, u_int *nidsp)
        !           151: {
        !           152:        u_int id, i, n = 0, *ids = NULL;
        !           153:
        !           154:        for (i = 0; g->gl_pathv[i] != NULL; i++) {
        !           155:                if (user) {
        !           156:                        if (ruser_name(g->gl_statv[i]->st_uid) != NULL)
        !           157:                                continue; /* Already seen */
        !           158:                        id = (u_int)g->gl_statv[i]->st_uid;
        !           159:                } else {
        !           160:                        if (rgroup_name(g->gl_statv[i]->st_gid) != NULL)
        !           161:                                continue; /* Already seen */
        !           162:                        id = (u_int)g->gl_statv[i]->st_gid;
        !           163:                }
        !           164:                if (has_id(id, ids, n))
        !           165:                        continue;
        !           166:                ids = xrecallocarray(ids, n, n + 1, sizeof(*ids));
        !           167:                ids[n++] = id;
        !           168:        }
        !           169:        *idsp = ids;
        !           170:        *nidsp = n;
        !           171: }
        !           172:
        !           173: void
        !           174: get_remote_user_groups_from_glob(struct sftp_conn *conn, glob_t *g)
        !           175: {
        !           176:        u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
        !           177:
        !           178:        if (!can_get_users_groups_by_id(conn))
        !           179:                return;
        !           180:
        !           181:        collect_ids_from_glob(g, 1, &uids, &nuids);
        !           182:        collect_ids_from_glob(g, 0, &gids, &ngids);
        !           183:        lookup_and_record(conn, uids, nuids, gids, ngids);
        !           184:        free(uids);
        !           185:        free(gids);
        !           186: }
        !           187:
        !           188: static void
        !           189: collect_ids_from_dirents(SFTP_DIRENT **d, int user, u_int **idsp, u_int *nidsp)
        !           190: {
        !           191:        u_int id, i, n = 0, *ids = NULL;
        !           192:
        !           193:        for (i = 0; d[i] != NULL; i++) {
        !           194:                if (user) {
        !           195:                        if (ruser_name((uid_t)(d[i]->a.uid)) != NULL)
        !           196:                                continue; /* Already seen */
        !           197:                        id = d[i]->a.uid;
        !           198:                } else {
        !           199:                        if (rgroup_name((gid_t)(d[i]->a.gid)) != NULL)
        !           200:                                continue; /* Already seen */
        !           201:                        id = d[i]->a.gid;
        !           202:                }
        !           203:                if (has_id(id, ids, n))
        !           204:                        continue;
        !           205:                ids = xrecallocarray(ids, n, n + 1, sizeof(*ids));
        !           206:                ids[n++] = id;
        !           207:        }
        !           208:        *idsp = ids;
        !           209:        *nidsp = n;
        !           210: }
        !           211:
        !           212: void
        !           213: get_remote_user_groups_from_dirents(struct sftp_conn *conn, SFTP_DIRENT **d)
        !           214: {
        !           215:        u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
        !           216:
        !           217:        if (!can_get_users_groups_by_id(conn))
        !           218:                return;
        !           219:
        !           220:        collect_ids_from_dirents(d, 1, &uids, &nuids);
        !           221:        collect_ids_from_dirents(d, 0, &gids, &ngids);
        !           222:        lookup_and_record(conn, uids, nuids, gids, ngids);
        !           223:        free(uids);
        !           224:        free(gids);
        !           225: }
        !           226:
        !           227: const char *
        !           228: ruser_name(uid_t uid)
        !           229: {
        !           230:        return idname_lookup(&user_idname, (u_int)uid);
        !           231: }
        !           232:
        !           233: const char *
        !           234: rgroup_name(uid_t gid)
        !           235: {
        !           236:        return idname_lookup(&group_idname, (u_int)gid);
        !           237: }
        !           238: