1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * getgrent.c 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate * 28*0Sstevel@tonic-gate * lib/nsswitch/compat/getgrent.c -- name-service-switch backend for getgrnam() 29*0Sstevel@tonic-gate * et al that does 4.x compatibility. It looks in /etc/group; if it finds 30*0Sstevel@tonic-gate * group entries there that begin with "+" or "-", it consults other 31*0Sstevel@tonic-gate * services. By default it uses NIS (YP), but the user can override this 32*0Sstevel@tonic-gate * with a "group_compat" entry in /etc/nsswitch.conf, e.g. 33*0Sstevel@tonic-gate * group_compat: nisplus 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * This code tries to produce the same results as the 4.x code, even when 36*0Sstevel@tonic-gate * the latter seems ill thought-out. Bug-compatible, in other words. 37*0Sstevel@tonic-gate * Though we do try to be more reasonable about the format of "+" and "-" 38*0Sstevel@tonic-gate * entries here, i.e. you don't have to pad them with spurious colons and 39*0Sstevel@tonic-gate * bogus uid/gid values. 40*0Sstevel@tonic-gate * 41*0Sstevel@tonic-gate * Caveats: 42*0Sstevel@tonic-gate * - More than one source may be specified, with the usual switch semantics, 43*0Sstevel@tonic-gate * but having multiple sources here is definitely odd. 44*0Sstevel@tonic-gate * - People who recursively specify "compat" deserve what they get. 45*0Sstevel@tonic-gate */ 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate #include <grp.h> 50*0Sstevel@tonic-gate #include <stdlib.h> 51*0Sstevel@tonic-gate #include <unistd.h> /* for GF_PATH */ 52*0Sstevel@tonic-gate #include <strings.h> 53*0Sstevel@tonic-gate #include "compat_common.h" 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root); 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate static void 58*0Sstevel@tonic-gate _nss_initf_group_compat(p) 59*0Sstevel@tonic-gate nss_db_params_t *p; 60*0Sstevel@tonic-gate { 61*0Sstevel@tonic-gate p->name = NSS_DBNAM_GROUP; 62*0Sstevel@tonic-gate p->config_name = NSS_DBNAM_GROUP_COMPAT; 63*0Sstevel@tonic-gate p->default_config = NSS_DEFCONF_GROUP_COMPAT; 64*0Sstevel@tonic-gate } 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate static const char * 67*0Sstevel@tonic-gate get_grname(argp) 68*0Sstevel@tonic-gate nss_XbyY_args_t *argp; 69*0Sstevel@tonic-gate { 70*0Sstevel@tonic-gate struct group *g = (struct group *)argp->returnval; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate return (g->gr_name); 73*0Sstevel@tonic-gate } 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static int 76*0Sstevel@tonic-gate check_grname(argp) 77*0Sstevel@tonic-gate nss_XbyY_args_t *argp; 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate struct group *g = (struct group *)argp->returnval; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate return (strcmp(g->gr_name, argp->key.name) == 0); 82*0Sstevel@tonic-gate } 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate static nss_status_t 85*0Sstevel@tonic-gate getbyname(be, a) 86*0Sstevel@tonic-gate compat_backend_ptr_t be; 87*0Sstevel@tonic-gate void *a; 88*0Sstevel@tonic-gate { 89*0Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate return (_nss_compat_XY_all(be, argp, check_grname, 92*0Sstevel@tonic-gate NSS_DBOP_GROUP_BYNAME)); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate static int 96*0Sstevel@tonic-gate check_grgid(argp) 97*0Sstevel@tonic-gate nss_XbyY_args_t *argp; 98*0Sstevel@tonic-gate { 99*0Sstevel@tonic-gate struct group *g = (struct group *)argp->returnval; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate return (g->gr_gid == argp->key.gid); 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate static nss_status_t 105*0Sstevel@tonic-gate getbygid(be, a) 106*0Sstevel@tonic-gate compat_backend_ptr_t be; 107*0Sstevel@tonic-gate void *a; 108*0Sstevel@tonic-gate { 109*0Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate return (_nss_compat_XY_all(be, argp, check_grgid, 112*0Sstevel@tonic-gate NSS_DBOP_GROUP_BYGID)); 113*0Sstevel@tonic-gate } 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate static nss_status_t 116*0Sstevel@tonic-gate getbymember(be, a) 117*0Sstevel@tonic-gate compat_backend_ptr_t be; 118*0Sstevel@tonic-gate void *a; 119*0Sstevel@tonic-gate { 120*0Sstevel@tonic-gate struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a; 121*0Sstevel@tonic-gate int numgids = argp->numgids; 122*0Sstevel@tonic-gate int maxgids = argp->maxgids; 123*0Sstevel@tonic-gate gid_t *gid_array = argp->gid_array; 124*0Sstevel@tonic-gate struct nss_XbyY_args grargs; 125*0Sstevel@tonic-gate struct group *g; 126*0Sstevel@tonic-gate nss_XbyY_buf_t *gb = NULL, *b = NULL; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* 129*0Sstevel@tonic-gate * Generic implementation: enumerate using getent(), then check each 130*0Sstevel@tonic-gate * group returned by getent() to see whether it contains the user. 131*0Sstevel@tonic-gate * There are much faster ways, but at least this one gets the right 132*0Sstevel@tonic-gate * answer. 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate if (numgids >= maxgids) { 135*0Sstevel@tonic-gate /* full gid_array; nobody should have bothered to call us */ 136*0Sstevel@tonic-gate return (NSS_SUCCESS); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate b = NSS_XbyY_ALLOC(&gb, sizeof (struct group), NSS_BUFLEN_GROUP); 140*0Sstevel@tonic-gate if (b == 0) 141*0Sstevel@tonic-gate return (NSS_UNAVAIL); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate NSS_XbyY_INIT(&grargs, gb->result, gb->buffer, gb->buflen, 144*0Sstevel@tonic-gate argp->str2ent); 145*0Sstevel@tonic-gate g = (struct group *)gb->result; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate (void) _nss_compat_setent(be, 0); 148*0Sstevel@tonic-gate while (_nss_compat_getent(be, &grargs) == NSS_SUCCESS) { 149*0Sstevel@tonic-gate char **mem; 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate if (grargs.returnval == 0) { 152*0Sstevel@tonic-gate continue; 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate for (mem = g->gr_mem; *mem != 0; mem++) { 155*0Sstevel@tonic-gate if (strcmp(*mem, argp->username) == 0) { 156*0Sstevel@tonic-gate int gid = g->gr_gid; 157*0Sstevel@tonic-gate int i; 158*0Sstevel@tonic-gate for (i = 0; i < numgids; i++) { 159*0Sstevel@tonic-gate if (gid == gid_array[i]) { 160*0Sstevel@tonic-gate break; 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate if (i == numgids) { 164*0Sstevel@tonic-gate gid_array[numgids++] = gid; 165*0Sstevel@tonic-gate argp->numgids = numgids; 166*0Sstevel@tonic-gate if (numgids >= maxgids) { 167*0Sstevel@tonic-gate /* filled the gid_array */ 168*0Sstevel@tonic-gate (void) _nss_compat_endent(be, 169*0Sstevel@tonic-gate 0); 170*0Sstevel@tonic-gate NSS_XbyY_FREE(&gb); 171*0Sstevel@tonic-gate return (NSS_SUCCESS); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate /* Done with this group, try next */ 174*0Sstevel@tonic-gate break; 175*0Sstevel@tonic-gate } 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate (void) _nss_compat_endent(be, 0); 180*0Sstevel@tonic-gate NSS_XbyY_FREE(&gb); 181*0Sstevel@tonic-gate return (NSS_NOTFOUND); /* Really means "gid_array not full yet" */ 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /*ARGSUSED*/ 185*0Sstevel@tonic-gate static int 186*0Sstevel@tonic-gate merge_grents(be, argp, fields) 187*0Sstevel@tonic-gate compat_backend_ptr_t be; 188*0Sstevel@tonic-gate nss_XbyY_args_t *argp; 189*0Sstevel@tonic-gate const char **fields; 190*0Sstevel@tonic-gate { 191*0Sstevel@tonic-gate struct group *g = (struct group *)argp->buf.result; 192*0Sstevel@tonic-gate char *buf; 193*0Sstevel@tonic-gate char *s; 194*0Sstevel@tonic-gate int parsestat; 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate /* 197*0Sstevel@tonic-gate * We're allowed to override the passwd (has anyone ever actually used 198*0Sstevel@tonic-gate * the passwd in a group entry?) and the membership list, but not 199*0Sstevel@tonic-gate * the groupname or the gid. 200*0Sstevel@tonic-gate * That's what the SunOS 4.x code did; who are we to question it... 201*0Sstevel@tonic-gate * 202*0Sstevel@tonic-gate * Efficiency is heartlessly abandoned in the quest for simplicity. 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate if (fields[1] == 0 && fields[3] == 0) { 205*0Sstevel@tonic-gate /* No legal overrides, leave *argp unscathed */ 206*0Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate if ((buf = malloc(NSS_LINELEN_GROUP)) == 0) { 209*0Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 210*0Sstevel@tonic-gate /* Really "out of memory", but PARSE_PARSE will have to do */ 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate s = buf; 213*0Sstevel@tonic-gate (void) snprintf(s, NSS_LINELEN_GROUP, "%s:%s:%d:", 214*0Sstevel@tonic-gate g->gr_name, 215*0Sstevel@tonic-gate fields[1] != 0 ? fields[1] : g->gr_passwd, 216*0Sstevel@tonic-gate g->gr_gid); 217*0Sstevel@tonic-gate s += strlen(s); 218*0Sstevel@tonic-gate if (fields[3] != 0) { 219*0Sstevel@tonic-gate strcpy(s, fields[3]); 220*0Sstevel@tonic-gate s += strlen(s); 221*0Sstevel@tonic-gate } else { 222*0Sstevel@tonic-gate char **memp; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate for (memp = g->gr_mem; *memp != 0; memp++) { 225*0Sstevel@tonic-gate size_t len = strlen(*memp); 226*0Sstevel@tonic-gate if (s + len + 1 <= buf + NSS_LINELEN_GROUP) { 227*0Sstevel@tonic-gate if (memp != g->gr_mem) { 228*0Sstevel@tonic-gate *s++ = ','; 229*0Sstevel@tonic-gate } 230*0Sstevel@tonic-gate (void) memcpy(s, *memp, len); 231*0Sstevel@tonic-gate s += len; 232*0Sstevel@tonic-gate } else { 233*0Sstevel@tonic-gate free(buf); 234*0Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate parsestat = (*argp->str2ent)(buf, s - buf, 239*0Sstevel@tonic-gate argp->buf.result, 240*0Sstevel@tonic-gate argp->buf.buffer, 241*0Sstevel@tonic-gate argp->buf.buflen); 242*0Sstevel@tonic-gate free(buf); 243*0Sstevel@tonic-gate return (parsestat); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate static compat_backend_op_t group_ops[] = { 247*0Sstevel@tonic-gate _nss_compat_destr, 248*0Sstevel@tonic-gate _nss_compat_endent, 249*0Sstevel@tonic-gate _nss_compat_setent, 250*0Sstevel@tonic-gate _nss_compat_getent, 251*0Sstevel@tonic-gate getbyname, 252*0Sstevel@tonic-gate getbygid, 253*0Sstevel@tonic-gate getbymember 254*0Sstevel@tonic-gate }; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate /*ARGSUSED*/ 257*0Sstevel@tonic-gate nss_backend_t * 258*0Sstevel@tonic-gate _nss_compat_group_constr(dummy1, dummy2, dummy3) 259*0Sstevel@tonic-gate const char *dummy1, *dummy2, *dummy3; 260*0Sstevel@tonic-gate { 261*0Sstevel@tonic-gate return (_nss_compat_constr(group_ops, 262*0Sstevel@tonic-gate sizeof (group_ops) / sizeof (group_ops[0]), 263*0Sstevel@tonic-gate GF_PATH, 264*0Sstevel@tonic-gate NSS_LINELEN_GROUP, 265*0Sstevel@tonic-gate &db_root, 266*0Sstevel@tonic-gate _nss_initf_group_compat, 267*0Sstevel@tonic-gate 0, 268*0Sstevel@tonic-gate get_grname, 269*0Sstevel@tonic-gate merge_grents)); 270*0Sstevel@tonic-gate } 271