Annotation of embedaddon/rsync/uidlist.c, revision 1.1.1.4

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
1.1.1.4 ! misho       6:  * Copyright (C) 2004-2020 Wayne Davison
1.1       misho       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"
1.1.1.2   misho      27: #include "ifuncs.h"
                     28: #include "itypes.h"
1.1       misho      29: #include "io.h"
                     30: 
                     31: extern int am_root;
                     32: extern int preserve_uid;
                     33: extern int preserve_gid;
                     34: extern int preserve_acls;
                     35: extern int numeric_ids;
1.1.1.4 ! misho      36: extern int xmit_id0_names;
        !            37: extern pid_t namecvt_pid;
1.1.1.2   misho      38: extern gid_t our_gid;
                     39: extern char *usermap;
                     40: extern char *groupmap;
1.1       misho      41: 
                     42: #ifdef HAVE_GETGROUPS
                     43: # ifndef GETGROUPS_T
                     44: #  define GETGROUPS_T gid_t
                     45: # endif
                     46: #endif
                     47: 
1.1.1.2   misho      48: #define NFLAGS_WILD_NAME_MATCH (1<<0)
                     49: #define NFLAGS_NAME_MATCH (1<<1)
                     50: 
                     51: union name_or_id {
1.1.1.4 ! misho      52:        const char *name;
        !            53:        id_t max_id;
1.1.1.2   misho      54: };
                     55: 
1.1       misho      56: struct idlist {
                     57:        struct idlist *next;
1.1.1.2   misho      58:        union name_or_id u;
1.1       misho      59:        id_t id, id2;
                     60:        uint16 flags;
                     61: };
                     62: 
1.1.1.2   misho      63: static struct idlist *uidlist, *uidmap;
                     64: static struct idlist *gidlist, *gidmap;
                     65: 
                     66: static id_t id_parse(const char *num_str)
                     67: {
                     68:        id_t tmp, num = 0;
                     69:        const char *cp = num_str;
                     70: 
                     71:        while (*cp) {
                     72:                if (!isDigit(cp)) {
                     73:                  invalid_num:
                     74:                        rprintf(FERROR, "Invalid ID number: %s\n", num_str);
                     75:                        exit_cleanup(RERR_SYNTAX);
                     76:                }
                     77:                tmp = num * 10 + *cp++ - '0';
                     78:                if (tmp < num)
                     79:                        goto invalid_num;
                     80:                num = tmp;
                     81:        }
                     82: 
                     83:        return num;
                     84: }
1.1       misho      85: 
1.1.1.2   misho      86: static struct idlist *add_to_list(struct idlist **root, id_t id, union name_or_id noiu,
1.1       misho      87:                                  id_t id2, uint16 flags)
                     88: {
                     89:        struct idlist *node = new(struct idlist);
                     90:        node->next = *root;
1.1.1.2   misho      91:        node->u = noiu;
1.1       misho      92:        node->id = id;
                     93:        node->id2 = id2;
                     94:        node->flags = flags;
                     95:        *root = node;
                     96:        return node;
                     97: }
                     98: 
                     99: /* turn a uid into a user name */
1.1.1.4 ! misho     100: const char *uid_to_user(uid_t uid)
1.1       misho     101: {
1.1.1.4 ! misho     102:        const char *name = NULL;
        !           103: 
        !           104:        if (namecvt_pid) {
        !           105:                id_t id = uid;
        !           106:                namecvt_call("uid", &name, &id);
        !           107:        } else {
        !           108:                struct passwd *pass = getpwuid(uid);
        !           109:                if (pass)
        !           110:                        name = strdup(pass->pw_name);
        !           111:        }
        !           112: 
        !           113:        return name;
1.1       misho     114: }
                    115: 
                    116: /* turn a gid into a group name */
1.1.1.4 ! misho     117: const char *gid_to_group(gid_t gid)
1.1       misho     118: {
1.1.1.4 ! misho     119:        const char *name = NULL;
        !           120: 
        !           121:        if (namecvt_pid) {
        !           122:                id_t id = gid;
        !           123:                namecvt_call("gid", &name, &id);
        !           124:        } else {
        !           125:                struct group *grp = getgrgid(gid);
        !           126:                if (grp)
        !           127:                        name = strdup(grp->gr_name);
        !           128:        }
        !           129: 
        !           130:        return name;
1.1       misho     131: }
                    132: 
1.1.1.2   misho     133: /* Parse a user name or (optionally) a number into a uid */
                    134: int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok)
1.1       misho     135: {
1.1.1.2   misho     136:        if (!name || !*name)
                    137:                return 0;
1.1.1.4 ! misho     138: 
1.1.1.2   misho     139:        if (num_ok && name[strspn(name, "0123456789")] == '\0') {
                    140:                *uid_p = id_parse(name);
                    141:                return 1;
                    142:        }
1.1.1.4 ! misho     143: 
        !           144:        if (namecvt_pid) {
        !           145:                id_t id;
        !           146:                if (!namecvt_call("usr", &name, &id))
        !           147:                        return 0;
        !           148:                *uid_p = id;
        !           149:        } else {
        !           150:                struct passwd *pass = getpwnam(name);
        !           151:                if (!pass)
        !           152:                        return 0;
        !           153:                *uid_p = pass->pw_uid;
        !           154:        }
        !           155: 
1.1.1.2   misho     156:        return 1;
1.1       misho     157: }
                    158: 
1.1.1.2   misho     159: /* Parse a group name or (optionally) a number into a gid */
                    160: int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok)
1.1       misho     161: {
1.1.1.2   misho     162:        if (!name || !*name)
                    163:                return 0;
1.1.1.4 ! misho     164: 
1.1.1.2   misho     165:        if (num_ok && name[strspn(name, "0123456789")] == '\0') {
                    166:                *gid_p = id_parse(name);
                    167:                return 1;
                    168:        }
1.1.1.4 ! misho     169: 
        !           170:        if (namecvt_pid) {
        !           171:                id_t id;
        !           172:                if (!namecvt_call("grp", &name, &id))
        !           173:                        return 0;
        !           174:                *gid_p = id;
        !           175:        } else {
        !           176:                struct group *grp = getgrnam(name);
        !           177:                if (!grp)
        !           178:                        return 0;
        !           179:                *gid_p = grp->gr_gid;
        !           180:        }
        !           181: 
1.1.1.2   misho     182:        return 1;
1.1       misho     183: }
                    184: 
                    185: static int is_in_group(gid_t gid)
                    186: {
                    187: #ifdef HAVE_GETGROUPS
                    188:        static gid_t last_in;
                    189:        static int ngroups = -2, last_out = -1;
                    190:        static GETGROUPS_T *gidset;
                    191:        int n;
                    192: 
                    193:        if (gid == last_in && last_out >= 0)
                    194:                return last_out;
                    195:        if (ngroups < -1) {
                    196:                if ((ngroups = getgroups(0, NULL)) < 0)
                    197:                        ngroups = 0;
                    198:                gidset = new_array(GETGROUPS_T, ngroups+1);
                    199:                if (ngroups > 0)
                    200:                        ngroups = getgroups(ngroups, gidset);
                    201:                /* The default gid might not be in the list on some systems. */
                    202:                for (n = 0; n < ngroups; n++) {
1.1.1.2   misho     203:                        if (gidset[n] == our_gid)
1.1       misho     204:                                break;
                    205:                }
                    206:                if (n == ngroups)
1.1.1.2   misho     207:                        gidset[ngroups++] = our_gid;
                    208:                if (DEBUG_GTE(OWN, 2)) {
1.1       misho     209:                        int pos;
                    210:                        char *gidbuf = new_array(char, ngroups*21+32);
1.1.1.4 ! misho     211:                        pos = snprintf(gidbuf, 32, "process has %d gid%s: ", ngroups, ngroups == 1? "" : "s");
1.1       misho     212:                        for (n = 0; n < ngroups; n++) {
                    213:                                pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]);
                    214:                        }
                    215:                        rprintf(FINFO, "%s\n", gidbuf);
                    216:                        free(gidbuf);
                    217:                }
                    218:        }
                    219: 
                    220:        last_in = gid;
                    221:        for (n = 0; n < ngroups; n++) {
                    222:                if (gidset[n] == gid)
                    223:                        return last_out = 1;
                    224:        }
                    225:        return last_out = 0;
                    226: 
                    227: #else
1.1.1.2   misho     228:        return gid == our_gid;
1.1       misho     229: #endif
                    230: }
                    231: 
1.1.1.2   misho     232: /* Add a uid/gid to its list of ids.  Only called on receiving side. */
                    233: static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap,
                    234:                                  id_t id, const char *name)
1.1       misho     235: {
                    236:        struct idlist *node;
1.1.1.2   misho     237:        union name_or_id noiu;
                    238:        int flag;
                    239:        id_t id2;
1.1       misho     240: 
1.1.1.2   misho     241:        noiu.name = name; /* ensure that add_to_list() gets the raw value. */
                    242:        if (!name)
                    243:                name = "";
1.1       misho     244: 
1.1.1.2   misho     245:        for (node = idmap; node; node = node->next) {
                    246:                if (node->flags & NFLAGS_WILD_NAME_MATCH) {
                    247:                        if (!wildmatch(node->u.name, name))
                    248:                                continue;
                    249:                } else if (node->flags & NFLAGS_NAME_MATCH) {
                    250:                        if (strcmp(node->u.name, name) != 0)
                    251:                                continue;
                    252:                } else if (node->u.max_id) {
                    253:                        if (id < node->id || id > node->u.max_id)
                    254:                                continue;
                    255:                } else {
                    256:                        if (node->id != id)
                    257:                                continue;
                    258:                }
                    259:                break;
1.1       misho     260:        }
1.1.1.2   misho     261:        if (node)
                    262:                id2 = node->id2;
                    263:        else if (*name && id) {
                    264:                if (idlist_ptr == &uidlist) {
                    265:                        uid_t uid;
                    266:                        id2 = user_to_uid(name, &uid, False) ? uid : id;
                    267:                } else {
                    268:                        gid_t gid;
                    269:                        id2 = group_to_gid(name, &gid, False) ? gid : id;
                    270:                }
                    271:        } else
                    272:                id2 = id;
1.1       misho     273: 
1.1.1.2   misho     274:        flag = idlist_ptr == &gidlist && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0;
                    275:        node = add_to_list(idlist_ptr, id, noiu, id2, flag);
1.1       misho     276: 
1.1.1.2   misho     277:        if (DEBUG_GTE(OWN, 2)) {
                    278:                rprintf(FINFO, "%sid %u(%s) maps to %u\n",
                    279:                        idlist_ptr == &uidlist ? "u" : "g",
                    280:                        (unsigned)id, name, (unsigned)id2);
1.1       misho     281:        }
                    282: 
                    283:        return node;
                    284: }
                    285: 
1.1.1.4 ! misho     286: /* this function is a definite candidate for a faster algorithm */
1.1       misho     287: uid_t match_uid(uid_t uid)
                    288: {
1.1.1.2   misho     289:        static struct idlist *last = NULL;
1.1       misho     290:        struct idlist *list;
                    291: 
1.1.1.2   misho     292:        if (last && uid == last->id)
                    293:                return last->id2;
1.1       misho     294: 
                    295:        for (list = uidlist; list; list = list->next) {
                    296:                if (list->id == uid)
1.1.1.2   misho     297:                        break;
1.1       misho     298:        }
                    299: 
1.1.1.2   misho     300:        if (!list)
                    301:                list = recv_add_id(&uidlist, uidmap, uid, NULL);
                    302:        last = list;
                    303: 
                    304:        return list->id2;
1.1       misho     305: }
                    306: 
                    307: gid_t match_gid(gid_t gid, uint16 *flags_ptr)
                    308: {
                    309:        static struct idlist *last = NULL;
                    310:        struct idlist *list;
                    311: 
                    312:        if (last && gid == last->id)
                    313:                list = last;
                    314:        else {
                    315:                for (list = gidlist; list; list = list->next) {
                    316:                        if (list->id == gid)
                    317:                                break;
                    318:                }
                    319:                if (!list)
1.1.1.2   misho     320:                        list = recv_add_id(&gidlist, gidmap, gid, NULL);
1.1       misho     321:                last = list;
                    322:        }
                    323: 
                    324:        if (flags_ptr && list->flags & FLAG_SKIP_GROUP)
                    325:                *flags_ptr |= FLAG_SKIP_GROUP;
                    326:        return list->id2;
                    327: }
                    328: 
                    329: /* Add a uid to the list of uids.  Only called on sending side. */
                    330: const char *add_uid(uid_t uid)
                    331: {
                    332:        struct idlist *list;
                    333:        struct idlist *node;
1.1.1.2   misho     334:        union name_or_id noiu;
1.1       misho     335: 
                    336:        for (list = uidlist; list; list = list->next) {
                    337:                if (list->id == uid)
                    338:                        return NULL;
                    339:        }
                    340: 
1.1.1.2   misho     341:        noiu.name = uid_to_user(uid);
                    342:        node = add_to_list(&uidlist, uid, noiu, 0, 0);
                    343:        return node->u.name;
1.1       misho     344: }
                    345: 
                    346: /* Add a gid to the list of gids.  Only called on sending side. */
                    347: const char *add_gid(gid_t gid)
                    348: {
                    349:        struct idlist *list;
                    350:        struct idlist *node;
1.1.1.2   misho     351:        union name_or_id noiu;
1.1       misho     352: 
                    353:        for (list = gidlist; list; list = list->next) {
                    354:                if (list->id == gid)
                    355:                        return NULL;
                    356:        }
                    357: 
1.1.1.2   misho     358:        noiu.name = gid_to_group(gid);
                    359:        node = add_to_list(&gidlist, gid, noiu, 0, 0);
                    360:        return node->u.name;
1.1       misho     361: }
                    362: 
1.1.1.4 ! misho     363: static void send_one_name(int f, id_t id, const char *name)
1.1       misho     364: {
1.1.1.4 ! misho     365:        int len;
1.1       misho     366: 
1.1.1.4 ! misho     367:        if (!name)
        !           368:                name = "";
        !           369:        if ((len = strlen(name)) > 255) /* Impossible? */
        !           370:                len = 255;
1.1       misho     371: 
1.1.1.4 ! misho     372:        write_varint30(f, id);
        !           373:        write_byte(f, len);
        !           374:        if (len)
        !           375:                write_buf(f, name, len);
        !           376: }
        !           377: 
        !           378: static void send_one_list(int f, struct idlist *idlist, int usernames)
        !           379: {
        !           380:        struct idlist *list;
        !           381: 
        !           382:        /* we send sequences of id/byte-len/name */
        !           383:        for (list = idlist; list; list = list->next) {
        !           384:                if (list->id && list->u.name)
        !           385:                        send_one_name(f, list->id, list->u.name);
1.1       misho     386:        }
                    387: 
1.1.1.4 ! misho     388:        /* Terminate the uid list with 0 (which was excluded above).
        !           389:         * A modern rsync also sends the name of id 0. */
        !           390:        if (xmit_id0_names)
        !           391:                send_one_name(f, 0, usernames ? uid_to_user(0) : gid_to_group(0));
        !           392:        else
1.1       misho     393:                write_varint30(f, 0);
1.1.1.4 ! misho     394: }
        !           395: 
        !           396: /* send a complete uid/gid mapping to the peer */
        !           397: void send_id_lists(int f)
        !           398: {
        !           399:        if (preserve_uid || preserve_acls)
        !           400:                send_one_list(f, uidlist, 1);
        !           401: 
        !           402:        if (preserve_gid || preserve_acls)
        !           403:                send_one_list(f, gidlist, 0);
1.1       misho     404: }
                    405: 
                    406: uid_t recv_user_name(int f, uid_t uid)
                    407: {
                    408:        struct idlist *node;
                    409:        int len = read_byte(f);
1.1.1.4 ! misho     410:        char *name;
        !           411: 
        !           412:        if (len) {
        !           413:                name = new_array(char, len+1);
        !           414:                read_sbuf(f, name, len);
        !           415:                if (numeric_ids < 0) {
        !           416:                        free(name);
        !           417:                        name = NULL;
        !           418:                }
        !           419:        } else
1.1       misho     420:                name = NULL;
1.1.1.4 ! misho     421: 
1.1.1.2   misho     422:        node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */
1.1       misho     423:        return node->id2;
                    424: }
                    425: 
                    426: gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
                    427: {
                    428:        struct idlist *node;
                    429:        int len = read_byte(f);
1.1.1.4 ! misho     430:        char *name;
        !           431: 
        !           432:        if (len) {
        !           433:                name = new_array(char, len+1);
        !           434:                read_sbuf(f, name, len);
        !           435:                if (numeric_ids < 0) {
        !           436:                        free(name);
        !           437:                        name = NULL;
        !           438:                }
        !           439:        } else
1.1       misho     440:                name = NULL;
1.1.1.4 ! misho     441: 
1.1.1.2   misho     442:        node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */
1.1       misho     443:        if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
                    444:                *flags_ptr |= FLAG_SKIP_GROUP;
                    445:        return node->id2;
                    446: }
                    447: 
                    448: /* recv a complete uid/gid mapping from the peer and map the uid/gid
                    449:  * in the file list to local names */
                    450: void recv_id_list(int f, struct file_list *flist)
                    451: {
                    452:        id_t id;
                    453:        int i;
                    454: 
                    455:        if ((preserve_uid || preserve_acls) && numeric_ids <= 0) {
                    456:                /* read the uid list */
                    457:                while ((id = read_varint30(f)) != 0)
                    458:                        recv_user_name(f, id);
1.1.1.4 ! misho     459:                if (xmit_id0_names)
        !           460:                        recv_user_name(f, 0);
1.1       misho     461:        }
                    462: 
                    463:        if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {
                    464:                /* read the gid list */
                    465:                while ((id = read_varint30(f)) != 0)
                    466:                        recv_group_name(f, id, NULL);
1.1.1.4 ! misho     467:                if (xmit_id0_names)
        !           468:                        recv_group_name(f, 0, NULL);
1.1       misho     469:        }
                    470: 
                    471:        /* Now convert all the uids/gids from sender values to our values. */
                    472: #ifdef SUPPORT_ACLS
1.1.1.2   misho     473:        if (preserve_acls && (!numeric_ids || usermap || groupmap))
1.1       misho     474:                match_acl_ids();
                    475: #endif
1.1.1.2   misho     476:        if (am_root && preserve_uid && (!numeric_ids || usermap)) {
1.1       misho     477:                for (i = 0; i < flist->used; i++)
                    478:                        F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
                    479:        }
1.1.1.2   misho     480:        if (preserve_gid && (!am_root || !numeric_ids || groupmap)) {
1.1       misho     481:                for (i = 0; i < flist->used; i++) {
1.1.1.4 ! misho     482:                        F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]), &flist->files[i]->flags);
1.1       misho     483:                }
                    484:        }
                    485: }
1.1.1.2   misho     486: 
                    487: void parse_name_map(char *map, BOOL usernames)
                    488: {
                    489:        struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap;
                    490:        struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist;
                    491:        char *colon, *cp = map + strlen(map);
                    492:        union name_or_id noiu;
                    493:        id_t id1;
                    494:        uint16 flags;
                    495: 
                    496:        /* Parse the list in reverse, so the order in the struct is right. */
                    497:        while (1) {
                    498:                while (cp > map && cp[-1] != ',') cp--;
                    499:                if (!(colon = strchr(cp, ':'))) {
                    500:                        rprintf(FERROR, "No colon found in --%smap: %s\n",
                    501:                                usernames ? "user" : "group", cp);
                    502:                        exit_cleanup(RERR_SYNTAX);
                    503:                }
                    504:                if (!colon[1]) {
                    505:                        rprintf(FERROR, "No name found after colon --%smap: %s\n",
                    506:                                usernames ? "user" : "group", cp);
                    507:                        exit_cleanup(RERR_SYNTAX);
                    508:                }
                    509:                *colon = '\0';
                    510: 
                    511:                if (isDigit(cp)) {
                    512:                        char *dash = strchr(cp, '-');
                    513:                        if (strspn(cp, "0123456789-") != (size_t)(colon - cp)
                    514:                         || (dash && (!dash[1] || strchr(dash+1, '-')))) {
                    515:                                rprintf(FERROR, "Invalid number in --%smap: %s\n",
                    516:                                        usernames ? "user" : "group", cp);
                    517:                                exit_cleanup(RERR_SYNTAX);
                    518:                        }
1.1.1.3   misho     519:                        if (dash) {
                    520:                                *dash = '\0';
1.1.1.2   misho     521:                                noiu.max_id = id_parse(dash+1);
1.1.1.3   misho     522:                        } else
1.1.1.2   misho     523:                                noiu.max_id = 0;
                    524:                        flags = 0;
                    525:                        id1 = id_parse(cp);
1.1.1.3   misho     526:                        if (dash)
                    527:                                *dash = '-';
1.1.1.2   misho     528:                } else if (strpbrk(cp, "*[?")) {
                    529:                        flags = NFLAGS_WILD_NAME_MATCH;
                    530:                        noiu.name = cp;
                    531:                        id1 = 0;
                    532:                } else {
                    533:                        flags = NFLAGS_NAME_MATCH;
                    534:                        noiu.name = cp;
                    535:                        id1 = 0;
                    536:                }
                    537: 
                    538:                if (usernames) {
                    539:                        uid_t uid;
                    540:                        if (user_to_uid(colon+1, &uid, True))
                    541:                                add_to_list(idmap_ptr, id1, noiu, uid, flags);
                    542:                        else {
1.1.1.4 ! misho     543:                                rprintf(FERROR, "Unknown --usermap name on receiver: %s\n", colon+1);
1.1.1.2   misho     544:                        }
                    545:                } else {
                    546:                        gid_t gid;
                    547:                        if (group_to_gid(colon+1, &gid, True))
                    548:                                add_to_list(idmap_ptr, id1, noiu, gid, flags);
                    549:                        else {
1.1.1.4 ! misho     550:                                rprintf(FERROR, "Unknown --groupmap name on receiver: %s\n", colon+1);
1.1.1.2   misho     551:                        }
                    552:                }
                    553: 
                    554:                if (cp == map)
                    555:                        break;
                    556: 
                    557:                *--cp = '\0'; /* replace comma */
                    558:        }
                    559: 
1.1.1.4 ! misho     560:        /* If the sender isn't going to xmit the id0 name, we assume it's "root". */
        !           561:        if (!xmit_id0_names)
        !           562:                recv_add_id(idlist_ptr, *idmap_ptr, 0, numeric_ids ? NULL : "root");
1.1.1.2   misho     563: }
                    564: 
                    565: #ifdef HAVE_GETGROUPLIST
1.1.1.3   misho     566: const char *getallgroups(uid_t uid, item_list *gid_list)
1.1.1.2   misho     567: {
                    568:        struct passwd *pw;
1.1.1.3   misho     569:        gid_t *gid_array;
                    570:        int size;
                    571: 
1.1.1.2   misho     572:        if ((pw = getpwuid(uid)) == NULL)
                    573:                return "getpwuid failed";
1.1.1.3   misho     574: 
                    575:        gid_list->count = 0; /* We're overwriting any items in the list */
1.1.1.4 ! misho     576:        (void)EXPAND_ITEM_LIST(gid_list, gid_t, 32);
1.1.1.3   misho     577:        size = gid_list->malloced;
                    578: 
1.1.1.2   misho     579:        /* Get all the process's groups, with the pw_gid group first. */
1.1.1.3   misho     580:        if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0) {
                    581:                if (size > (int)gid_list->malloced) {
                    582:                        gid_list->count = gid_list->malloced;
1.1.1.4 ! misho     583:                        (void)EXPAND_ITEM_LIST(gid_list, gid_t, size);
1.1.1.3   misho     584:                        if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0)
                    585:                                size = -1;
                    586:                } else
                    587:                        size = -1;
                    588:                if (size < 0)
                    589:                        return "getgrouplist failed";
                    590:        }
                    591:        gid_list->count = size;
                    592:        gid_array = gid_list->items;
                    593: 
1.1.1.2   misho     594:        /* Paranoia: is the default group not first in the list? */
1.1.1.3   misho     595:        if (gid_array[0] != pw->pw_gid) {
1.1.1.2   misho     596:                int j;
1.1.1.3   misho     597:                for (j = 1; j < size; j++) {
                    598:                        if (gid_array[j] == pw->pw_gid)
1.1.1.2   misho     599:                                break;
                    600:                }
1.1.1.3   misho     601:                if (j == size) { /* The default group wasn't found! */
1.1.1.4 ! misho     602:                        (void)EXPAND_ITEM_LIST(gid_list, gid_t, size+1);
1.1.1.3   misho     603:                        gid_array = gid_list->items;
                    604:                }
                    605:                gid_array[j] = gid_array[0];
                    606:                gid_array[0] = pw->pw_gid;
1.1.1.2   misho     607:        }
1.1.1.3   misho     608: 
1.1.1.2   misho     609:        return NULL;
                    610: }
                    611: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>