10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51914Scasper * Common Development and Distribution License (the "License").
61914Scasper * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*8040SBaban.Kenkre@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate *
250Sstevel@tonic-gate * Common code and structures used by name-service-switch "compat" backends.
260Sstevel@tonic-gate *
270Sstevel@tonic-gate * Most of the code in the "compat" backend is a perverted form of code from
280Sstevel@tonic-gate * the "files" backend; this file is no exception.
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <ctype.h>
350Sstevel@tonic-gate #include <bsm/libbsm.h>
360Sstevel@tonic-gate #include <user_attr.h>
372830Sdjl #include <pwd.h>
382830Sdjl #include <shadow.h>
392830Sdjl #include <grp.h>
402830Sdjl #include <unistd.h> /* for GF_PATH */
412830Sdjl #include <dlfcn.h>
420Sstevel@tonic-gate #include "compat_common.h"
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate * This should be in a header.
460Sstevel@tonic-gate */
470Sstevel@tonic-gate
480Sstevel@tonic-gate extern int yp_get_default_domain(char **domain);
490Sstevel@tonic-gate
502830Sdjl /* from libc */
512830Sdjl extern int str2passwd(const char *instr, int lenstr, void *ent,
522830Sdjl char *buffer, int buflen);
532830Sdjl extern int str2spwd(const char *instr, int lenstr, void *ent,
542830Sdjl char *buffer, int buflen);
552830Sdjl extern int str2group(const char *instr, int lenstr, void *ent,
562830Sdjl char *buffer, int buflen);
572830Sdjl
582830Sdjl /* from libnsl */
592830Sdjl extern char *_strtok_escape(char *, char *, char **);
602830Sdjl
612830Sdjl /*
622830Sdjl * str2auuser_s and str2userattr_s are very simple version
632830Sdjl * of the str2auuser() and str2userattr() that can be found in
642830Sdjl * libnsl. They only copy the user name into the userstr_t
652830Sdjl * or au_user_str_t structure (so check on user name can be
662830Sdjl * performed).
672830Sdjl */
682830Sdjl static int
str2auuser_s(const char * instr,int lenstr,void * ent,char * buffer,int buflen)692830Sdjl str2auuser_s(
702830Sdjl const char *instr,
712830Sdjl int lenstr,
722830Sdjl void *ent,
732830Sdjl char *buffer,
742830Sdjl int buflen)
752830Sdjl {
762830Sdjl char *last = NULL;
772830Sdjl char *sep = KV_TOKEN_DELIMIT;
782830Sdjl au_user_str_t *au_user = (au_user_str_t *)ent;
792830Sdjl
802830Sdjl if (lenstr >= buflen)
812830Sdjl return (NSS_STR_PARSE_ERANGE);
822830Sdjl (void) strncpy(buffer, instr, buflen);
832830Sdjl au_user->au_name = _strtok_escape(buffer, sep, &last);
842830Sdjl return (0);
852830Sdjl }
862830Sdjl
872830Sdjl static int
str2userattr_s(const char * instr,int lenstr,void * ent,char * buffer,int buflen)882830Sdjl str2userattr_s(
892830Sdjl const char *instr,
902830Sdjl int lenstr,
912830Sdjl void *ent,
922830Sdjl char *buffer,
932830Sdjl int buflen)
942830Sdjl {
952830Sdjl char *last = NULL;
962830Sdjl char *sep = KV_TOKEN_DELIMIT;
972830Sdjl userstr_t *user = (userstr_t *)ent;
982830Sdjl
992830Sdjl if (lenstr >= buflen)
1002830Sdjl return (NSS_STR_PARSE_ERANGE);
1012830Sdjl (void) strncpy(buffer, instr, buflen);
1022830Sdjl user->name = _strtok_escape(buffer, sep, &last);
1032830Sdjl return (0);
1042830Sdjl }
1052830Sdjl
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate * Routines to manage list of "-" users for get{pw, sp, gr}ent(). Current
1080Sstevel@tonic-gate * implementation is completely moronic; we use a linked list. But then
1090Sstevel@tonic-gate * that's what it's always done in 4.x...
1100Sstevel@tonic-gate */
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate struct setofstrings {
1130Sstevel@tonic-gate char *name;
1140Sstevel@tonic-gate struct setofstrings *next;
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate * === Should get smart and malloc the string and pointer as one
1170Sstevel@tonic-gate * object rather than two.
1180Sstevel@tonic-gate */
1190Sstevel@tonic-gate };
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate static void
strset_free(ssp)1220Sstevel@tonic-gate strset_free(ssp)
1230Sstevel@tonic-gate strset_t *ssp;
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate strset_t cur, nxt;
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate for (cur = *ssp; cur != 0; cur = nxt) {
1280Sstevel@tonic-gate nxt = cur->next;
1290Sstevel@tonic-gate free(cur->name);
1300Sstevel@tonic-gate free(cur);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate *ssp = 0;
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate static boolean_t
strset_add(ssp,nam)1360Sstevel@tonic-gate strset_add(ssp, nam)
1370Sstevel@tonic-gate strset_t *ssp;
1380Sstevel@tonic-gate const char *nam;
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate strset_t new;
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate if (0 == (new = (strset_t)malloc(sizeof (*new)))) {
1430Sstevel@tonic-gate return (B_FALSE);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate if (0 == (new->name = malloc(strlen(nam) + 1))) {
1460Sstevel@tonic-gate free(new);
1470Sstevel@tonic-gate return (B_FALSE);
1480Sstevel@tonic-gate }
1492830Sdjl (void) strcpy(new->name, nam);
1500Sstevel@tonic-gate new->next = *ssp;
1510Sstevel@tonic-gate *ssp = new;
1520Sstevel@tonic-gate return (B_TRUE);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate static boolean_t
strset_in(ssp,nam)1560Sstevel@tonic-gate strset_in(ssp, nam)
1570Sstevel@tonic-gate const strset_t *ssp;
1580Sstevel@tonic-gate const char *nam;
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate strset_t cur;
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate for (cur = *ssp; cur != 0; cur = cur->next) {
1630Sstevel@tonic-gate if (strcmp(cur->name, nam) == 0) {
1640Sstevel@tonic-gate return (B_TRUE);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate return (B_FALSE);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate * Lookup and enumeration routines for +@group and -@group.
1720Sstevel@tonic-gate *
1730Sstevel@tonic-gate * This code knows a lot more about lib/libc/port/gen/getnetgrent.c than
1740Sstevel@tonic-gate * is really healthy. The set/get/end routines below duplicate code
1750Sstevel@tonic-gate * from that file, but keep the state information per-backend-instance
1760Sstevel@tonic-gate * instead of just per-process.
1770Sstevel@tonic-gate */
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate extern void _nss_initf_netgroup(nss_db_params_t *);
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate * Should really share the db_root in getnetgrent.c in order to get the
1820Sstevel@tonic-gate * resource-management quotas right, but this will have to do.
1830Sstevel@tonic-gate */
1840Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(netgr_db_root);
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate static boolean_t
netgr_in(compat_backend_ptr_t be,const char * group,const char * user)1870Sstevel@tonic-gate netgr_in(compat_backend_ptr_t be, const char *group, const char *user)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate if (be->yp_domain == 0) {
1900Sstevel@tonic-gate if (yp_get_default_domain((char **)&be->yp_domain) != 0) {
1910Sstevel@tonic-gate return (B_FALSE);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate return (innetgr(group, 0, user, be->yp_domain));
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate static void
netgr_set(be,netgroup)1980Sstevel@tonic-gate netgr_set(be, netgroup)
1990Sstevel@tonic-gate compat_backend_ptr_t be;
2000Sstevel@tonic-gate const char *netgroup;
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate * ===> Need comment to explain that this first "if" is optimizing
2040Sstevel@tonic-gate * for the same-netgroup-as-last-time case
2050Sstevel@tonic-gate */
2060Sstevel@tonic-gate if (be->getnetgrent_backend != 0 &&
2070Sstevel@tonic-gate NSS_INVOKE_DBOP(be->getnetgrent_backend,
2080Sstevel@tonic-gate NSS_DBOP_SETENT,
2090Sstevel@tonic-gate (void *) netgroup) != NSS_SUCCESS) {
2100Sstevel@tonic-gate NSS_INVOKE_DBOP(be->getnetgrent_backend, NSS_DBOP_DESTRUCTOR,
2110Sstevel@tonic-gate 0);
2120Sstevel@tonic-gate be->getnetgrent_backend = 0;
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate if (be->getnetgrent_backend == 0) {
2150Sstevel@tonic-gate struct nss_setnetgrent_args args;
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate args.netgroup = netgroup;
2180Sstevel@tonic-gate args.iterator = 0;
2192830Sdjl (void) nss_search(&netgr_db_root, _nss_initf_netgroup,
2200Sstevel@tonic-gate NSS_DBOP_NETGROUP_SET, &args);
2210Sstevel@tonic-gate be->getnetgrent_backend = args.iterator;
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate static boolean_t
netgr_next_u(be,up)2260Sstevel@tonic-gate netgr_next_u(be, up)
2270Sstevel@tonic-gate compat_backend_ptr_t be;
2280Sstevel@tonic-gate char **up;
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate if (be->netgr_buffer == 0 &&
2310Sstevel@tonic-gate (be->netgr_buffer = malloc(NSS_BUFLEN_NETGROUP)) == 0) {
2320Sstevel@tonic-gate /* Out of memory */
2330Sstevel@tonic-gate return (B_FALSE);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate do {
2370Sstevel@tonic-gate struct nss_getnetgrent_args args;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate args.buffer = be->netgr_buffer;
2400Sstevel@tonic-gate args.buflen = NSS_BUFLEN_NETGROUP;
2410Sstevel@tonic-gate args.status = NSS_NETGR_NO;
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate if (be->getnetgrent_backend != 0) {
2440Sstevel@tonic-gate NSS_INVOKE_DBOP(be->getnetgrent_backend,
2450Sstevel@tonic-gate NSS_DBOP_GETENT, &args);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate if (args.status == NSS_NETGR_FOUND) {
2490Sstevel@tonic-gate *up = args.retp[NSS_NETGR_USER];
2500Sstevel@tonic-gate } else {
2510Sstevel@tonic-gate return (B_FALSE);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate } while (*up == 0);
2540Sstevel@tonic-gate return (B_TRUE);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate static void
netgr_end(be)2580Sstevel@tonic-gate netgr_end(be)
2590Sstevel@tonic-gate compat_backend_ptr_t be;
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate if (be->getnetgrent_backend != 0) {
2620Sstevel@tonic-gate NSS_INVOKE_DBOP(be->getnetgrent_backend,
2630Sstevel@tonic-gate NSS_DBOP_DESTRUCTOR, 0);
2640Sstevel@tonic-gate be->getnetgrent_backend = 0;
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate if (be->netgr_buffer != 0) {
2670Sstevel@tonic-gate free(be->netgr_buffer);
2680Sstevel@tonic-gate be->netgr_buffer = 0;
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate #define MAXFIELDS 9 /* Sufficient for passwd (7), shadow (9), group (4) */
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate static nss_status_t
do_merge(be,args,instr,linelen)2760Sstevel@tonic-gate do_merge(be, args, instr, linelen)
2770Sstevel@tonic-gate compat_backend_ptr_t be;
2780Sstevel@tonic-gate nss_XbyY_args_t *args;
2790Sstevel@tonic-gate const char *instr;
2800Sstevel@tonic-gate int linelen;
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate char *fields[MAXFIELDS];
2830Sstevel@tonic-gate int i;
2840Sstevel@tonic-gate int overrides;
2850Sstevel@tonic-gate const char *p;
2860Sstevel@tonic-gate const char *end = instr + linelen;
2872830Sdjl nss_status_t res = NSS_NOTFOUND;
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate * Potential optimization: only perform the field-splitting nonsense
2910Sstevel@tonic-gate * once per input line (at present, "+" and "+@netgroup" entries
2920Sstevel@tonic-gate * will cause us to do this multiple times in getent() requests).
2930Sstevel@tonic-gate */
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate for (i = 0; i < MAXFIELDS; i++) {
2960Sstevel@tonic-gate fields[i] = 0;
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate for (p = instr, overrides = 0, i = 0; /* no test */; i++) {
2990Sstevel@tonic-gate const char *q = memchr(p, ':', end - p);
3000Sstevel@tonic-gate const char *r = (q == 0) ? end : q;
3010Sstevel@tonic-gate ssize_t len = r - p;
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate if (len > 0) {
3040Sstevel@tonic-gate char *s = malloc(len + 1);
3050Sstevel@tonic-gate if (s == 0) {
3060Sstevel@tonic-gate overrides = -1; /* Indicates "you lose" */
3070Sstevel@tonic-gate break;
3080Sstevel@tonic-gate }
3092830Sdjl (void) memcpy(s, p, len);
3100Sstevel@tonic-gate s[len] = '\0';
3110Sstevel@tonic-gate fields[i] = s;
3120Sstevel@tonic-gate overrides++;
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate if (q == 0) {
3150Sstevel@tonic-gate /* End of line */
3160Sstevel@tonic-gate break;
3170Sstevel@tonic-gate } else {
3180Sstevel@tonic-gate /* Skip the colon at (*q) */
3190Sstevel@tonic-gate p = q + 1;
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate if (overrides == 1) {
3232830Sdjl /*
3242830Sdjl * return result here if /etc file format is requested
3252830Sdjl */
3262830Sdjl if (be->return_string_data != 1) {
3272830Sdjl /* No real overrides, return (*args) intact */
3282830Sdjl res = NSS_SUCCESS;
3292830Sdjl } else {
3302830Sdjl free(fields[0]);
3312830Sdjl fields[0] = NULL;
3322830Sdjl }
3332830Sdjl }
3342830Sdjl
3352830Sdjl if (overrides > 1 || be->return_string_data == 1) {
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate * The zero'th field is always nonempty (+/-...), but at least
3380Sstevel@tonic-gate * one other field was also nonempty, i.e. wants to override
3390Sstevel@tonic-gate */
3400Sstevel@tonic-gate switch ((*be->mergef)(be, args, (const char **)fields)) {
3410Sstevel@tonic-gate case NSS_STR_PARSE_SUCCESS:
3422830Sdjl if (be->return_string_data != 1)
3432830Sdjl args->returnval = args->buf.result;
3442830Sdjl else
3452830Sdjl args->returnval = args->buf.buffer;
3460Sstevel@tonic-gate args->erange = 0;
3470Sstevel@tonic-gate res = NSS_SUCCESS;
3480Sstevel@tonic-gate break;
3490Sstevel@tonic-gate case NSS_STR_PARSE_ERANGE:
3500Sstevel@tonic-gate args->returnval = 0;
3510Sstevel@tonic-gate args->erange = 1;
3520Sstevel@tonic-gate res = NSS_NOTFOUND;
3530Sstevel@tonic-gate break;
3540Sstevel@tonic-gate case NSS_STR_PARSE_PARSE:
3550Sstevel@tonic-gate args->returnval = 0;
3560Sstevel@tonic-gate args->erange = 0;
3570Sstevel@tonic-gate /* ===> Very likely the wrong thing to do... */
3580Sstevel@tonic-gate res = NSS_NOTFOUND;
3590Sstevel@tonic-gate break;
3600Sstevel@tonic-gate }
3612830Sdjl } else if (res != NSS_SUCCESS) {
3620Sstevel@tonic-gate args->returnval = 0;
3630Sstevel@tonic-gate args->erange = 0;
3640Sstevel@tonic-gate res = NSS_UNAVAIL; /* ==> Right? */
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate for (i = 0; i < MAXFIELDS; i++) {
3680Sstevel@tonic-gate if (fields[i] != 0) {
3690Sstevel@tonic-gate free(fields[i]);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate return (res);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate /*ARGSUSED*/
3770Sstevel@tonic-gate nss_status_t
_nss_compat_setent(be,dummy)3780Sstevel@tonic-gate _nss_compat_setent(be, dummy)
3790Sstevel@tonic-gate compat_backend_ptr_t be;
3800Sstevel@tonic-gate void *dummy;
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate if (be->f == 0) {
3830Sstevel@tonic-gate if (be->filename == 0) {
3840Sstevel@tonic-gate /* Backend isn't initialized properly? */
3850Sstevel@tonic-gate return (NSS_UNAVAIL);
3860Sstevel@tonic-gate }
3871914Scasper if ((be->f = fopen(be->filename, "rF")) == 0) {
3880Sstevel@tonic-gate return (NSS_UNAVAIL);
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate } else {
3911914Scasper rewind(be->f);
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate strset_free(&be->minuses);
3940Sstevel@tonic-gate /* ===> ??? nss_endent(be->db_rootp, be->db_initf, &be->db_context); */
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate if ((strcmp(be->filename, USERATTR_FILENAME) == 0) ||
3970Sstevel@tonic-gate (strcmp(be->filename, AUDITUSER_FILENAME) == 0))
3980Sstevel@tonic-gate be->state = GETENT_ATTRDB;
3990Sstevel@tonic-gate else
4000Sstevel@tonic-gate be->state = GETENT_FILE;
4010Sstevel@tonic-gate
4023099Smichen be->return_string_data = 0;
4033099Smichen
4040Sstevel@tonic-gate /* ===> ?? netgroup stuff? */
4050Sstevel@tonic-gate return (NSS_SUCCESS);
4060Sstevel@tonic-gate }
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate /*ARGSUSED*/
4090Sstevel@tonic-gate nss_status_t
_nss_compat_endent(be,dummy)4100Sstevel@tonic-gate _nss_compat_endent(be, dummy)
4110Sstevel@tonic-gate compat_backend_ptr_t be;
4120Sstevel@tonic-gate void *dummy;
4130Sstevel@tonic-gate {
4140Sstevel@tonic-gate if (be->f != 0) {
4152830Sdjl (void) fclose(be->f);
4160Sstevel@tonic-gate be->f = 0;
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate if (be->buf != 0) {
4190Sstevel@tonic-gate free(be->buf);
4200Sstevel@tonic-gate be->buf = 0;
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate nss_endent(be->db_rootp, be->db_initf, &be->db_context);
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate be->state = GETENT_FILE; /* Probably superfluous but comforting */
4250Sstevel@tonic-gate strset_free(&be->minuses);
4260Sstevel@tonic-gate netgr_end(be);
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate /*
4290Sstevel@tonic-gate * Question: from the point of view of resource-freeing vs. time to
4300Sstevel@tonic-gate * start up again, how much should we do in endent() and how much
4310Sstevel@tonic-gate * in the destructor?
4320Sstevel@tonic-gate */
4330Sstevel@tonic-gate return (NSS_SUCCESS);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate /*ARGSUSED*/
4370Sstevel@tonic-gate nss_status_t
_nss_compat_destr(be,dummy)4380Sstevel@tonic-gate _nss_compat_destr(be, dummy)
4390Sstevel@tonic-gate compat_backend_ptr_t be;
4400Sstevel@tonic-gate void *dummy;
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate if (be != 0) {
4430Sstevel@tonic-gate if (be->f != 0) {
4442830Sdjl (void) _nss_compat_endent(be, 0);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate nss_delete(be->db_rootp);
4470Sstevel@tonic-gate nss_delete(&netgr_db_root);
4483012Smichen free(be->workarea);
4490Sstevel@tonic-gate free(be);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate return (NSS_SUCCESS); /* In case anyone is dumb enough to check */
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate static int
read_line(f,buffer,buflen)4550Sstevel@tonic-gate read_line(f, buffer, buflen)
4561914Scasper FILE *f;
4570Sstevel@tonic-gate char *buffer;
4580Sstevel@tonic-gate int buflen;
4590Sstevel@tonic-gate {
4600Sstevel@tonic-gate /*CONSTCOND*/
4610Sstevel@tonic-gate while (1) {
4620Sstevel@tonic-gate int linelen;
4630Sstevel@tonic-gate
4641914Scasper if (fgets(buffer, buflen, f) == 0) {
4650Sstevel@tonic-gate /* End of file */
4660Sstevel@tonic-gate return (-1);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate linelen = strlen(buffer);
4690Sstevel@tonic-gate /* linelen >= 1 (since fgets didn't return 0) */
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate if (buffer[linelen - 1] == '\n') {
4720Sstevel@tonic-gate /*
4730Sstevel@tonic-gate * ===> The code below that calls read_line() doesn't
4740Sstevel@tonic-gate * play by the rules; it assumes in places that
4750Sstevel@tonic-gate * the line is null-terminated. For now we'll
4760Sstevel@tonic-gate * humour it.
4770Sstevel@tonic-gate */
4780Sstevel@tonic-gate buffer[--linelen] = '\0';
4790Sstevel@tonic-gate return (linelen);
4800Sstevel@tonic-gate }
4811914Scasper if (feof(f)) {
4820Sstevel@tonic-gate /* Line is last line in file, and has no newline */
4830Sstevel@tonic-gate return (linelen);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate /* Line too long for buffer; toss it and loop for next line */
4860Sstevel@tonic-gate /* ===== should syslog() in cases where previous code did */
4871914Scasper while (fgets(buffer, buflen, f) != 0 &&
4880Sstevel@tonic-gate buffer[strlen(buffer) - 1] != '\n') {
4890Sstevel@tonic-gate ;
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate }
4922830Sdjl /*NOTREACHED*/
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate
495340Svk154806 static int
is_nss_lookup_by_name(int attrdb,nss_dbop_t op)496340Svk154806 is_nss_lookup_by_name(int attrdb, nss_dbop_t op)
497340Svk154806 {
4980Sstevel@tonic-gate int result = 0;
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate if ((attrdb != 0) &&
501340Svk154806 ((op == NSS_DBOP_AUDITUSER_BYNAME) ||
502340Svk154806 (op == NSS_DBOP_USERATTR_BYNAME))) {
5030Sstevel@tonic-gate result = 1;
5040Sstevel@tonic-gate } else if ((attrdb == 0) &&
505340Svk154806 ((op == NSS_DBOP_GROUP_BYNAME) ||
506340Svk154806 (op == NSS_DBOP_PASSWD_BYNAME) ||
507340Svk154806 (op == NSS_DBOP_SHADOW_BYNAME))) {
5080Sstevel@tonic-gate result = 1;
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate return (result);
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate /*ARGSUSED*/
5150Sstevel@tonic-gate nss_status_t
_attrdb_compat_XY_all(be,argp,netdb,check,op_num)5160Sstevel@tonic-gate _attrdb_compat_XY_all(be, argp, netdb, check, op_num)
5170Sstevel@tonic-gate compat_backend_ptr_t be;
5180Sstevel@tonic-gate nss_XbyY_args_t *argp;
5190Sstevel@tonic-gate int netdb;
5200Sstevel@tonic-gate compat_XY_check_func check;
5210Sstevel@tonic-gate nss_dbop_t op_num;
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate int parsestat;
5240Sstevel@tonic-gate int (*func)();
5250Sstevel@tonic-gate const char *filter = argp->key.name;
5260Sstevel@tonic-gate nss_status_t res;
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate #ifdef DEBUG
5290Sstevel@tonic-gate (void) fprintf(stdout, "\n[compat_common.c: _attrdb_compat_XY_all]\n");
5300Sstevel@tonic-gate #endif /* DEBUG */
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate if (be->buf == 0 &&
5330Sstevel@tonic-gate (be->buf = malloc(be->minbuf)) == 0) {
5340Sstevel@tonic-gate return (NSS_UNAVAIL);
5350Sstevel@tonic-gate }
5362830Sdjl if (check != NULL)
5372830Sdjl if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS)
5382830Sdjl return (res);
5392830Sdjl
5400Sstevel@tonic-gate res = NSS_NOTFOUND;
5410Sstevel@tonic-gate
5422830Sdjl /*
5432830Sdjl * assume a NULL buf.result pointer is an indication
5442830Sdjl * that the lookup result should be returned in /etc
5453386Smichen * file format (if called from _nss_compat_getent(),
5463386Smichen * be->return_string_data and argp->buf.result
5473386Smichen * would be set already if argp->buf.result is NULL)
5482830Sdjl */
5493386Smichen if (check != NULL) {
5503386Smichen if (argp->buf.result == NULL) {
5513386Smichen be->return_string_data = 1;
5522830Sdjl
5533386Smichen /*
5543386Smichen * the code executed later needs the result struct
5553386Smichen * as working area
5563386Smichen */
5573386Smichen argp->buf.result = be->workarea;
5583386Smichen } else
5593386Smichen be->return_string_data = 0;
5603386Smichen }
5613386Smichen
5623386Smichen /*
5633386Smichen * use an alternate str2ent function if necessary
5643386Smichen */
5653386Smichen if (be->return_string_data == 1)
5663012Smichen func = be->str2ent_alt;
5673386Smichen else
5683012Smichen func = argp->str2ent;
5692830Sdjl
5700Sstevel@tonic-gate /*CONSTCOND*/
5710Sstevel@tonic-gate while (1) {
5720Sstevel@tonic-gate int linelen;
5730Sstevel@tonic-gate char *instr = be->buf;
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate if ((linelen = read_line(be->f, instr, be->minbuf)) < 0) {
5760Sstevel@tonic-gate /* End of file */
5770Sstevel@tonic-gate argp->returnval = 0;
5780Sstevel@tonic-gate argp->erange = 0;
5790Sstevel@tonic-gate break;
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate if (filter != 0 && strstr(instr, filter) == 0) {
5820Sstevel@tonic-gate /*
5830Sstevel@tonic-gate * Optimization: if the entry doesn't contain the
5840Sstevel@tonic-gate * filter string then it can't be the entry we want,
5850Sstevel@tonic-gate * so don't bother looking more closely at it.
5860Sstevel@tonic-gate */
5870Sstevel@tonic-gate continue;
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate if (netdb) {
5900Sstevel@tonic-gate char *first;
5910Sstevel@tonic-gate char *last;
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate if ((last = strchr(instr, '#')) == 0) {
5940Sstevel@tonic-gate last = instr + linelen;
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate *last-- = '\0'; /* Nuke '\n' or #comment */
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate /*
5990Sstevel@tonic-gate * Skip leading whitespace. Normally there isn't
6000Sstevel@tonic-gate * any, so it's not worth calling strspn().
6010Sstevel@tonic-gate */
6020Sstevel@tonic-gate for (first = instr; isspace(*first); first++) {
6030Sstevel@tonic-gate ;
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate if (*first == '\0') {
6060Sstevel@tonic-gate continue;
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate /*
6090Sstevel@tonic-gate * Found something non-blank on the line. Skip back
6100Sstevel@tonic-gate * over any trailing whitespace; since we know
6110Sstevel@tonic-gate * there's non-whitespace earlier in the line,
6120Sstevel@tonic-gate * checking for termination is easy.
6130Sstevel@tonic-gate */
6140Sstevel@tonic-gate while (isspace(*last)) {
6150Sstevel@tonic-gate --last;
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate linelen = last - first + 1;
6180Sstevel@tonic-gate if (first != instr) {
6190Sstevel@tonic-gate instr = first;
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate argp->returnval = 0;
6230Sstevel@tonic-gate parsestat = (*func)(instr, linelen, argp->buf.result,
6240Sstevel@tonic-gate argp->buf.buffer, argp->buf.buflen);
6250Sstevel@tonic-gate if (parsestat == NSS_STR_PARSE_SUCCESS) {
6262830Sdjl argp->returnval = argp->buf.result;
6270Sstevel@tonic-gate if (check == 0 || (*check)(argp)) {
6282830Sdjl int len;
6292830Sdjl
6302830Sdjl if (be->return_string_data != 1) {
6312830Sdjl res = NSS_SUCCESS;
6322830Sdjl break;
6332830Sdjl }
6342830Sdjl
6352830Sdjl /* copy string data to result buffer */
6362830Sdjl argp->buf.result = NULL;
6372830Sdjl argp->returnval = argp->buf.buffer;
6382830Sdjl if ((len = strlcpy(argp->buf.buffer, instr,
6392830Sdjl argp->buf.buflen)) >=
6402830Sdjl argp->buf.buflen) {
6412830Sdjl argp->returnval = NULL;
6422830Sdjl res = NSS_NOTFOUND;
6432830Sdjl argp->erange = 1;
6442830Sdjl break;
6452830Sdjl }
6462830Sdjl
6472830Sdjl argp->returnlen = len;
6480Sstevel@tonic-gate res = NSS_SUCCESS;
6490Sstevel@tonic-gate break;
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate } else if (parsestat == NSS_STR_PARSE_ERANGE) {
6522830Sdjl res = NSS_NOTFOUND;
6530Sstevel@tonic-gate argp->erange = 1;
6540Sstevel@tonic-gate break;
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate /*
6580Sstevel@tonic-gate * stayopen is set to 0 by default in order to close the opened
6590Sstevel@tonic-gate * file. Some applications may break if it is set to 1.
6600Sstevel@tonic-gate */
6610Sstevel@tonic-gate if (check != 0 && !argp->stayopen) {
6620Sstevel@tonic-gate (void) _nss_compat_endent(be, 0);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate if (res != NSS_SUCCESS) {
6662830Sdjl /*
6672830Sdjl * tell the nss_search() and nss_getent() below
6682830Sdjl * if the result should be returned in the /etc
6692830Sdjl * file format
6702830Sdjl */
6712830Sdjl if (be->return_string_data == 1)
6722830Sdjl argp->buf.result = NULL;
6732830Sdjl
6740Sstevel@tonic-gate if ((op_num == NSS_DBOP_USERATTR_BYNAME) ||
6750Sstevel@tonic-gate (op_num == NSS_DBOP_AUDITUSER_BYNAME)) {
6760Sstevel@tonic-gate res = nss_search(be->db_rootp,
6770Sstevel@tonic-gate be->db_initf,
6780Sstevel@tonic-gate op_num,
6790Sstevel@tonic-gate argp);
6800Sstevel@tonic-gate } else {
6810Sstevel@tonic-gate res = nss_getent(be->db_rootp,
6820Sstevel@tonic-gate be->db_initf, &be->db_context, argp);
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate if (res != NSS_SUCCESS) {
6850Sstevel@tonic-gate argp->returnval = 0;
6860Sstevel@tonic-gate argp->erange = 0;
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate return (res);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate
693*8040SBaban.Kenkre@Sun.COM static int
validate_ids(compat_backend_ptr_t be,nss_XbyY_args_t * argp,char * line,int * linelenp,int buflen,int extra_chars)694*8040SBaban.Kenkre@Sun.COM validate_ids(compat_backend_ptr_t be, nss_XbyY_args_t *argp,
695*8040SBaban.Kenkre@Sun.COM char *line, int *linelenp, int buflen, int extra_chars)
696*8040SBaban.Kenkre@Sun.COM {
697*8040SBaban.Kenkre@Sun.COM if (be->return_string_data != 1) {
698*8040SBaban.Kenkre@Sun.COM struct passwd *p;
699*8040SBaban.Kenkre@Sun.COM struct group *g;
700*8040SBaban.Kenkre@Sun.COM /*
701*8040SBaban.Kenkre@Sun.COM * The data is already marshalled into
702*8040SBaban.Kenkre@Sun.COM * struct passwd or group.
703*8040SBaban.Kenkre@Sun.COM */
704*8040SBaban.Kenkre@Sun.COM if (strcmp(be->filename, PASSWD) == 0) {
705*8040SBaban.Kenkre@Sun.COM p = (struct passwd *)argp->returnval;
706*8040SBaban.Kenkre@Sun.COM if (p->pw_uid > MAXUID)
707*8040SBaban.Kenkre@Sun.COM p->pw_uid = UID_NOBODY;
708*8040SBaban.Kenkre@Sun.COM if (p->pw_gid > MAXUID)
709*8040SBaban.Kenkre@Sun.COM p->pw_gid = GID_NOBODY;
710*8040SBaban.Kenkre@Sun.COM } else if (strcmp(be->filename, GF_PATH) == 0) {
711*8040SBaban.Kenkre@Sun.COM g = (struct group *)argp->returnval;
712*8040SBaban.Kenkre@Sun.COM if (g->gr_gid > MAXUID)
713*8040SBaban.Kenkre@Sun.COM g->gr_gid = GID_NOBODY;
714*8040SBaban.Kenkre@Sun.COM }
715*8040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_SUCCESS);
716*8040SBaban.Kenkre@Sun.COM }
717*8040SBaban.Kenkre@Sun.COM
718*8040SBaban.Kenkre@Sun.COM /*
719*8040SBaban.Kenkre@Sun.COM * The data needs to be returned in string format therefore
720*8040SBaban.Kenkre@Sun.COM * validate the return string.
721*8040SBaban.Kenkre@Sun.COM */
722*8040SBaban.Kenkre@Sun.COM if (strcmp(be->filename, PASSWD) == 0)
723*8040SBaban.Kenkre@Sun.COM return (validate_passwd_ids(line, linelenp, buflen,
724*8040SBaban.Kenkre@Sun.COM extra_chars));
725*8040SBaban.Kenkre@Sun.COM else if (strcmp(be->filename, GF_PATH) == 0)
726*8040SBaban.Kenkre@Sun.COM return (validate_group_ids(line, linelenp, buflen,
727*8040SBaban.Kenkre@Sun.COM extra_chars));
728*8040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_SUCCESS);
729*8040SBaban.Kenkre@Sun.COM }
730*8040SBaban.Kenkre@Sun.COM
7310Sstevel@tonic-gate nss_status_t
_nss_compat_XY_all(be,args,check,op_num)7320Sstevel@tonic-gate _nss_compat_XY_all(be, args, check, op_num)
7330Sstevel@tonic-gate compat_backend_ptr_t be;
7340Sstevel@tonic-gate nss_XbyY_args_t *args;
7350Sstevel@tonic-gate compat_XY_check_func check;
7360Sstevel@tonic-gate nss_dbop_t op_num;
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate nss_status_t res;
7390Sstevel@tonic-gate int parsestat;
7402830Sdjl
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate if (be->buf == 0 &&
7430Sstevel@tonic-gate (be->buf = malloc(be->minbuf)) == 0) {
7440Sstevel@tonic-gate return (NSS_UNAVAIL); /* really panic, malloc failed */
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
7480Sstevel@tonic-gate return (res);
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate res = NSS_NOTFOUND;
7520Sstevel@tonic-gate
7532830Sdjl /*
7542830Sdjl * assume a NULL buf.result pointer is an indication
7552830Sdjl * that the lookup result should be returned in /etc
7562830Sdjl * file format
7572830Sdjl */
7582830Sdjl if (args->buf.result == NULL) {
7592830Sdjl
7602830Sdjl be->return_string_data = 1;
7612830Sdjl
7622830Sdjl /*
7632830Sdjl * the code executed later needs the result struct
7642830Sdjl * as working area
7652830Sdjl */
7663012Smichen args->buf.result = be->workarea;
7672830Sdjl
7683012Smichen be->str2ent_save = args->str2ent;
7693012Smichen args->str2ent = be->str2ent_alt;
7703099Smichen } else
7713099Smichen be->return_string_data = 0;
7722830Sdjl
7730Sstevel@tonic-gate /*CONSTCOND*/
7740Sstevel@tonic-gate while (1) {
7750Sstevel@tonic-gate int linelen;
7760Sstevel@tonic-gate char *instr = be->buf;
7770Sstevel@tonic-gate char *colon;
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate linelen = read_line(be->f, instr, be->minbuf);
7800Sstevel@tonic-gate if (linelen < 0) {
7810Sstevel@tonic-gate /* End of file */
7820Sstevel@tonic-gate args->returnval = 0;
7830Sstevel@tonic-gate args->erange = 0;
7840Sstevel@tonic-gate break;
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate args->returnval = 0; /* reset for both types of entries */
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate if (instr[0] != '+' && instr[0] != '-') {
7900Sstevel@tonic-gate /* Simple, wholesome, God-fearing entry */
7910Sstevel@tonic-gate parsestat = (*args->str2ent)(instr, linelen,
7920Sstevel@tonic-gate args->buf.result,
7930Sstevel@tonic-gate args->buf.buffer,
7940Sstevel@tonic-gate args->buf.buflen);
7950Sstevel@tonic-gate if (parsestat == NSS_STR_PARSE_SUCCESS) {
7960Sstevel@tonic-gate args->returnval = args->buf.result;
7970Sstevel@tonic-gate if ((*check)(args) != 0) {
7982830Sdjl int len;
799*8040SBaban.Kenkre@Sun.COM
800*8040SBaban.Kenkre@Sun.COM parsestat = validate_ids(be, args,
801*8040SBaban.Kenkre@Sun.COM instr, &linelen, be->minbuf, 1);
802*8040SBaban.Kenkre@Sun.COM if (parsestat ==
803*8040SBaban.Kenkre@Sun.COM NSS_STR_PARSE_ERANGE) {
804*8040SBaban.Kenkre@Sun.COM args->erange = 1;
805*8040SBaban.Kenkre@Sun.COM res = NSS_NOTFOUND;
806*8040SBaban.Kenkre@Sun.COM break;
807*8040SBaban.Kenkre@Sun.COM } else if (parsestat !=
808*8040SBaban.Kenkre@Sun.COM NSS_STR_PARSE_SUCCESS) {
809*8040SBaban.Kenkre@Sun.COM continue;
810*8040SBaban.Kenkre@Sun.COM }
811*8040SBaban.Kenkre@Sun.COM
8122830Sdjl if (be->return_string_data != 1) {
8132830Sdjl res = NSS_SUCCESS;
8142830Sdjl break;
8152830Sdjl }
8162830Sdjl
8172830Sdjl /*
8182830Sdjl * copy string data to
8192830Sdjl * result buffer
8202830Sdjl */
8212830Sdjl args->buf.result = NULL;
8223012Smichen args->str2ent = be->str2ent_save;
8232830Sdjl if ((len = strlcpy(args->buf.buffer,
8242830Sdjl instr, args->buf.buflen)) >=
8252830Sdjl args->buf.buflen)
8262830Sdjl parsestat =
8272830Sdjl NSS_STR_PARSE_ERANGE;
8282830Sdjl else {
8292830Sdjl args->returnval =
8302830Sdjl args->buf.buffer;
8312830Sdjl args->returnlen = len;
8322830Sdjl res = NSS_SUCCESS;
8332830Sdjl break;
8342830Sdjl }
8352830Sdjl } else
8362830Sdjl continue;
8372830Sdjl }
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate /* ===> Check the Dani logic here... */
8400Sstevel@tonic-gate
8412830Sdjl if (parsestat == NSS_STR_PARSE_ERANGE) {
8420Sstevel@tonic-gate args->erange = 1;
8430Sstevel@tonic-gate res = NSS_NOTFOUND;
8440Sstevel@tonic-gate break;
8450Sstevel@tonic-gate /* should we just skip this one long line ? */
8460Sstevel@tonic-gate } /* else if (parsestat == NSS_STR_PARSE_PARSE) */
8470Sstevel@tonic-gate /* don't care ! */
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate /* ==> ?? */ continue;
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate
8522830Sdjl
8530Sstevel@tonic-gate /*
8540Sstevel@tonic-gate * Process "+", "+name", "+@netgroup", "-name" or "-@netgroup"
8550Sstevel@tonic-gate *
8560Sstevel@tonic-gate * This code is optimized for lookups by name.
8570Sstevel@tonic-gate *
8580Sstevel@tonic-gate * For lookups by identifier search key cannot be matched with
8590Sstevel@tonic-gate * the name of the "+" or "-" entry. So nss_search() is to be
8600Sstevel@tonic-gate * called before extracting the name i.e. via (*be->getnamef)().
8610Sstevel@tonic-gate *
8620Sstevel@tonic-gate * But for lookups by name, search key is compared with the name
8630Sstevel@tonic-gate * of the "+" or "-" entry to acquire a match and thus
8640Sstevel@tonic-gate * unnesessary calls to nss_search() is eliminated. Also for
8650Sstevel@tonic-gate * matching "-" entries, calls to nss_search() is eliminated.
8660Sstevel@tonic-gate */
8670Sstevel@tonic-gate
8680Sstevel@tonic-gate if ((colon = strchr(instr, ':')) != 0) {
8690Sstevel@tonic-gate *colon = '\0'; /* terminate field to extract name */
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate if (instr[1] == '@') {
8730Sstevel@tonic-gate /*
8740Sstevel@tonic-gate * Case 1:
8750Sstevel@tonic-gate * The entry is of the form "+@netgroup" or
8760Sstevel@tonic-gate * "-@netgroup". If we're performing a lookup by name,
8770Sstevel@tonic-gate * we can simply extract the name from the search key
8780Sstevel@tonic-gate * (i.e. args->key.name). If not, then we must call
8790Sstevel@tonic-gate * nss_search() before extracting the name via the
8800Sstevel@tonic-gate * get_XXname() function. i.e. (*be->getnamef)(args).
8810Sstevel@tonic-gate */
882340Svk154806 if (is_nss_lookup_by_name(0, op_num) != 0) {
883340Svk154806 /* compare then search */
884340Svk154806 if (!be->permit_netgroups ||
885340Svk154806 !netgr_in(be, instr + 2, args->key.name))
886340Svk154806 continue;
887340Svk154806 if (instr[0] == '+') {
888340Svk154806 /* need to search for "+" entry */
8892830Sdjl (void) nss_search(be->db_rootp,
8902830Sdjl be->db_initf, op_num, args);
891340Svk154806 if (args->returnval == 0)
892340Svk154806 continue;
893340Svk154806 }
894340Svk154806 } else {
895340Svk154806 /* search then compare */
8962830Sdjl (void) nss_search(be->db_rootp,
8972830Sdjl be->db_initf, op_num, args);
8980Sstevel@tonic-gate if (args->returnval == 0)
8990Sstevel@tonic-gate continue;
900340Svk154806 if (!be->permit_netgroups ||
901340Svk154806 !netgr_in(be, instr + 2,
902340Svk154806 (*be->getnamef)(args)))
903340Svk154806 continue;
9040Sstevel@tonic-gate }
905340Svk154806 } else if (instr[1] == '\0') {
9060Sstevel@tonic-gate /*
9070Sstevel@tonic-gate * Case 2:
9080Sstevel@tonic-gate * The entry is of the form "+" or "-". The former
9090Sstevel@tonic-gate * allows all entries from name services. The latter
9100Sstevel@tonic-gate * is illegal and ought to be ignored.
9110Sstevel@tonic-gate */
9120Sstevel@tonic-gate if (instr[0] == '-')
9130Sstevel@tonic-gate continue;
9140Sstevel@tonic-gate /* need to search for "+" entry */
9152830Sdjl (void) nss_search(be->db_rootp, be->db_initf,
9162830Sdjl op_num, args);
9170Sstevel@tonic-gate if (args->returnval == 0)
9180Sstevel@tonic-gate continue;
919340Svk154806 } else {
9200Sstevel@tonic-gate /*
9210Sstevel@tonic-gate * Case 3:
9220Sstevel@tonic-gate * The entry is of the form "+name" or "-name".
9230Sstevel@tonic-gate * If we're performing a lookup by name, we can simply
9240Sstevel@tonic-gate * extract the name from the search key
9250Sstevel@tonic-gate * (i.e. args->key.name). If not, then we must call
9260Sstevel@tonic-gate * nss_search() before extracting the name via the
9270Sstevel@tonic-gate * get_XXname() function. i.e. (*be->getnamef)(args).
9280Sstevel@tonic-gate */
929340Svk154806 if (is_nss_lookup_by_name(0, op_num) != 0) {
9300Sstevel@tonic-gate /* compare then search */
9310Sstevel@tonic-gate if (strcmp(instr + 1, args->key.name) != 0)
9320Sstevel@tonic-gate continue;
9330Sstevel@tonic-gate if (instr[0] == '+') {
9340Sstevel@tonic-gate /* need to search for "+" entry */
9352830Sdjl (void) nss_search(be->db_rootp,
9362830Sdjl be->db_initf, op_num, args);
9370Sstevel@tonic-gate if (args->returnval == 0)
9380Sstevel@tonic-gate continue;
9390Sstevel@tonic-gate }
9400Sstevel@tonic-gate } else {
9410Sstevel@tonic-gate /* search then compare */
9422830Sdjl (void) nss_search(be->db_rootp,
9432830Sdjl be->db_initf, op_num, args);
9440Sstevel@tonic-gate if (args->returnval == 0)
9450Sstevel@tonic-gate continue;
9460Sstevel@tonic-gate if (strcmp(instr + 1, (*be->getnamef)(args))
947340Svk154806 != 0)
9480Sstevel@tonic-gate continue;
9490Sstevel@tonic-gate }
950340Svk154806 }
9510Sstevel@tonic-gate if (instr[0] == '-') {
9520Sstevel@tonic-gate /* no need to search for "-" entry */
9530Sstevel@tonic-gate args->returnval = 0;
9540Sstevel@tonic-gate args->erange = 0;
9550Sstevel@tonic-gate res = NSS_NOTFOUND;
9560Sstevel@tonic-gate } else {
9570Sstevel@tonic-gate if (colon != 0)
958340Svk154806 *colon = ':'; /* restoration */
9590Sstevel@tonic-gate res = do_merge(be, args, instr, linelen);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate break;
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate /*
9650Sstevel@tonic-gate * stayopen is set to 0 by default in order to close the opened
9660Sstevel@tonic-gate * file. Some applications may break if it is set to 1.
9670Sstevel@tonic-gate */
9680Sstevel@tonic-gate if (!args->stayopen) {
9690Sstevel@tonic-gate (void) _nss_compat_endent(be, 0);
9700Sstevel@tonic-gate }
9710Sstevel@tonic-gate
9722830Sdjl if (be->return_string_data == 1) {
9733012Smichen args->str2ent = be->str2ent_save;
9742830Sdjl }
9752830Sdjl
9760Sstevel@tonic-gate return (res);
9770Sstevel@tonic-gate }
9780Sstevel@tonic-gate
9790Sstevel@tonic-gate nss_status_t
_nss_compat_getent(be,a)9800Sstevel@tonic-gate _nss_compat_getent(be, a)
9810Sstevel@tonic-gate compat_backend_ptr_t be;
9820Sstevel@tonic-gate void *a;
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate nss_XbyY_args_t *args = (nss_XbyY_args_t *)a;
9850Sstevel@tonic-gate nss_status_t res;
9860Sstevel@tonic-gate char *colon = 0; /* <=== need comment re lifetime */
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate if (be->f == 0) {
9890Sstevel@tonic-gate if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
9900Sstevel@tonic-gate return (res);
9910Sstevel@tonic-gate }
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate if (be->buf == 0 &&
9950Sstevel@tonic-gate (be->buf = malloc(be->minbuf)) == 0) {
9960Sstevel@tonic-gate return (NSS_UNAVAIL); /* really panic, malloc failed */
9970Sstevel@tonic-gate }
9980Sstevel@tonic-gate
9992830Sdjl /*
10002830Sdjl * assume a NULL buf.result pointer is an indication
10012830Sdjl * that the lookup result should be returned in /etc
10022830Sdjl * file format
10032830Sdjl */
10042830Sdjl if (args->buf.result == NULL) {
10052830Sdjl be->return_string_data = 1;
10062830Sdjl
10072830Sdjl /*
10082830Sdjl * the code executed later needs the result struct
10092830Sdjl * as working area
10102830Sdjl */
10113012Smichen args->buf.result = be->workarea;
10123099Smichen } else
10133099Smichen be->return_string_data = 0;
10142830Sdjl
10150Sstevel@tonic-gate /*CONSTCOND*/
10160Sstevel@tonic-gate while (1) {
10170Sstevel@tonic-gate char *instr = be->buf;
10180Sstevel@tonic-gate int linelen;
10190Sstevel@tonic-gate char *name; /* === Need more distinctive label */
10200Sstevel@tonic-gate const char *savename;
10210Sstevel@tonic-gate
10220Sstevel@tonic-gate /*
10230Sstevel@tonic-gate * In the code below...
10240Sstevel@tonic-gate * break means "I found one, I think" (i.e. goto the
10250Sstevel@tonic-gate * code after the end of the switch statement),
10260Sstevel@tonic-gate * continue means "Next candidate"
10270Sstevel@tonic-gate * (i.e. loop around to the switch statement),
10280Sstevel@tonic-gate * return means "I'm quite sure" (either Yes or No).
10290Sstevel@tonic-gate */
10300Sstevel@tonic-gate switch (be->state) {
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate case GETENT_DONE:
10330Sstevel@tonic-gate args->returnval = 0;
10340Sstevel@tonic-gate args->erange = 0;
10350Sstevel@tonic-gate return (NSS_NOTFOUND);
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate case GETENT_ATTRDB:
10382830Sdjl args->key.name = NULL;
10390Sstevel@tonic-gate res = _attrdb_compat_XY_all(be,
10400Sstevel@tonic-gate args, 1, (compat_XY_check_func)NULL, 0);
10410Sstevel@tonic-gate return (res);
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate case GETENT_FILE:
10440Sstevel@tonic-gate linelen = read_line(be->f, instr, be->minbuf);
10450Sstevel@tonic-gate if (linelen < 0) {
10460Sstevel@tonic-gate /* End of file */
10470Sstevel@tonic-gate be->state = GETENT_DONE;
10480Sstevel@tonic-gate continue;
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate if ((colon = strchr(instr, ':')) != 0) {
10510Sstevel@tonic-gate *colon = '\0';
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate if (instr[0] == '-') {
10540Sstevel@tonic-gate if (instr[1] != '@') {
10552830Sdjl (void) strset_add(&be->minuses,
10562830Sdjl instr + 1);
10570Sstevel@tonic-gate } else if (be->permit_netgroups) {
10580Sstevel@tonic-gate netgr_set(be, instr + 2);
10590Sstevel@tonic-gate while (netgr_next_u(be, &name)) {
10602830Sdjl (void) strset_add(&be->minuses,
10610Sstevel@tonic-gate name);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate netgr_end(be);
10640Sstevel@tonic-gate } /* Else (silently) ignore the entry */
10650Sstevel@tonic-gate continue;
10660Sstevel@tonic-gate } else if (instr[0] != '+') {
10670Sstevel@tonic-gate int parsestat;
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate * Normal entry, no +/- nonsense
10700Sstevel@tonic-gate */
10710Sstevel@tonic-gate if (colon != 0) {
10720Sstevel@tonic-gate *colon = ':';
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate args->returnval = 0;
10750Sstevel@tonic-gate parsestat = (*args->str2ent)(instr, linelen,
10760Sstevel@tonic-gate args->buf.result,
10770Sstevel@tonic-gate args->buf.buffer,
10780Sstevel@tonic-gate args->buf.buflen);
10790Sstevel@tonic-gate if (parsestat == NSS_STR_PARSE_SUCCESS) {
10802830Sdjl int len;
10812830Sdjl
10822830Sdjl if (be->return_string_data != 1) {
10832830Sdjl args->returnval =
10842830Sdjl args->buf.result;
10852830Sdjl return (NSS_SUCCESS);
10862830Sdjl }
10872830Sdjl
10882830Sdjl /*
10892830Sdjl * copy string data to
10902830Sdjl * result buffer
10912830Sdjl */
10922830Sdjl args->buf.result = NULL;
10932830Sdjl args->returnval =
10942830Sdjl args->buf.buffer;
10952830Sdjl if ((len = strlcpy(args->buf.buffer,
10962830Sdjl instr, args->buf.buflen)) >=
10972830Sdjl args->buf.buflen)
10982830Sdjl parsestat =
10992830Sdjl NSS_STR_PARSE_ERANGE;
11002830Sdjl else {
11012830Sdjl args->returnlen = len;
11022830Sdjl return (NSS_SUCCESS);
11032830Sdjl }
11040Sstevel@tonic-gate }
11050Sstevel@tonic-gate /* ==> ?? Treat ERANGE differently ?? */
11060Sstevel@tonic-gate if (parsestat == NSS_STR_PARSE_ERANGE) {
11070Sstevel@tonic-gate args->returnval = 0;
11080Sstevel@tonic-gate args->erange = 1;
11090Sstevel@tonic-gate return (NSS_NOTFOUND);
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate /* Skip the offending entry, get next */
11120Sstevel@tonic-gate continue;
11130Sstevel@tonic-gate } else if (instr[1] == '\0') {
11140Sstevel@tonic-gate /* Plain "+" */
11150Sstevel@tonic-gate nss_setent(be->db_rootp, be->db_initf,
11160Sstevel@tonic-gate &be->db_context);
11170Sstevel@tonic-gate be->state = GETENT_ALL;
11180Sstevel@tonic-gate be->linelen = linelen;
11193012Smichen
11200Sstevel@tonic-gate continue;
11210Sstevel@tonic-gate } else if (instr[1] == '@') {
11220Sstevel@tonic-gate /* "+@netgroup" */
11230Sstevel@tonic-gate netgr_set(be, instr + 2);
11240Sstevel@tonic-gate be->state = GETENT_NETGROUP;
11250Sstevel@tonic-gate be->linelen = linelen;
11260Sstevel@tonic-gate continue;
11270Sstevel@tonic-gate } else {
11280Sstevel@tonic-gate /* "+name" */
11290Sstevel@tonic-gate name = instr + 1;
11300Sstevel@tonic-gate break;
11310Sstevel@tonic-gate }
11320Sstevel@tonic-gate /* NOTREACHED */
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate case GETENT_ALL:
11350Sstevel@tonic-gate linelen = be->linelen;
11360Sstevel@tonic-gate args->returnval = 0;
11373012Smichen if (be->return_string_data == 1) {
11383012Smichen be->str2ent_save = args->str2ent;
11393012Smichen args->str2ent = be->str2ent_alt;
11403012Smichen }
11413012Smichen
11422830Sdjl (void) nss_getent(be->db_rootp, be->db_initf,
11430Sstevel@tonic-gate &be->db_context, args);
11440Sstevel@tonic-gate if (args->returnval == 0) {
11450Sstevel@tonic-gate /* ==> ?? Treat ERANGE differently ?? */
11460Sstevel@tonic-gate nss_endent(be->db_rootp, be->db_initf,
11470Sstevel@tonic-gate &be->db_context);
11480Sstevel@tonic-gate be->state = GETENT_FILE;
11493012Smichen if (be->return_string_data == 1)
11503012Smichen args->str2ent = be->str2ent_save;
11510Sstevel@tonic-gate continue;
11520Sstevel@tonic-gate }
11533012Smichen if (strset_in(&be->minuses, (*be->getnamef)(args)))
11540Sstevel@tonic-gate continue;
11550Sstevel@tonic-gate name = 0; /* tell code below we've done the lookup */
11563012Smichen if (be->return_string_data == 1)
11573012Smichen args->str2ent = be->str2ent_save;
11580Sstevel@tonic-gate break;
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate case GETENT_NETGROUP:
11610Sstevel@tonic-gate linelen = be->linelen;
11620Sstevel@tonic-gate if (!netgr_next_u(be, &name)) {
11630Sstevel@tonic-gate netgr_end(be);
11640Sstevel@tonic-gate be->state = GETENT_FILE;
11650Sstevel@tonic-gate continue;
11660Sstevel@tonic-gate }
11670Sstevel@tonic-gate /* pass "name" variable to code below... */
11680Sstevel@tonic-gate break;
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate
11710Sstevel@tonic-gate if (name != 0) {
11720Sstevel@tonic-gate if (strset_in(&be->minuses, name)) {
11730Sstevel@tonic-gate continue;
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate /*
11760Sstevel@tonic-gate * Do a getXXXnam(name). If we were being pure,
11770Sstevel@tonic-gate * we'd introduce yet another function-pointer
11780Sstevel@tonic-gate * that the database-specific code had to supply
11790Sstevel@tonic-gate * to us. Instead we'll be grotty and hard-code
11800Sstevel@tonic-gate * the knowledge that
11810Sstevel@tonic-gate * (a) The username is always passwd in key.name,
11820Sstevel@tonic-gate * (b) NSS_DBOP_PASSWD_BYNAME ==
11830Sstevel@tonic-gate * NSS_DBOP_SHADOW_BYNAME ==
11840Sstevel@tonic-gate * NSS_DBOP_next_iter.
11850Sstevel@tonic-gate */
11860Sstevel@tonic-gate savename = args->key.name;
11870Sstevel@tonic-gate args->key.name = name;
11880Sstevel@tonic-gate args->returnval = 0;
11893012Smichen if (be->return_string_data == 1) {
11903012Smichen be->str2ent_save = args->str2ent;
11913012Smichen args->str2ent = be->str2ent_alt;
11923012Smichen }
11933012Smichen
11942830Sdjl (void) nss_search(be->db_rootp, be->db_initf,
11950Sstevel@tonic-gate NSS_DBOP_next_iter, args);
11963012Smichen
11973012Smichen if (be->return_string_data == 1)
11983012Smichen args->str2ent = be->str2ent_save;
11990Sstevel@tonic-gate args->key.name = savename; /* In case anyone cares */
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate /*
12020Sstevel@tonic-gate * Found one via "+", "+name" or "@netgroup".
12030Sstevel@tonic-gate * Override some fields if the /etc file says to do so.
12040Sstevel@tonic-gate */
12050Sstevel@tonic-gate if (args->returnval == 0) {
12060Sstevel@tonic-gate /* ==> ?? Should treat erange differently? */
12070Sstevel@tonic-gate continue;
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate /* 'colon' was set umpteen iterations ago in GETENT_FILE */
12100Sstevel@tonic-gate if (colon != 0) {
12110Sstevel@tonic-gate *colon = ':';
12120Sstevel@tonic-gate colon = 0;
12130Sstevel@tonic-gate }
12140Sstevel@tonic-gate return (do_merge(be, args, instr, linelen));
12150Sstevel@tonic-gate }
12162830Sdjl /*NOTREACHED*/
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate
12190Sstevel@tonic-gate /* We don't use this directly; we just copy the bits when we want to */
12200Sstevel@tonic-gate /* initialize the variable (in the compat_backend struct) that we do use */
12210Sstevel@tonic-gate static DEFINE_NSS_GETENT(context_initval);
12220Sstevel@tonic-gate
12230Sstevel@tonic-gate nss_backend_t *
_nss_compat_constr(ops,n_ops,filename,min_bufsize,rootp,initf,netgroups,getname_func,merge_func)12240Sstevel@tonic-gate _nss_compat_constr(ops, n_ops, filename, min_bufsize, rootp, initf, netgroups,
12250Sstevel@tonic-gate getname_func, merge_func)
12260Sstevel@tonic-gate compat_backend_op_t ops[];
12270Sstevel@tonic-gate int n_ops;
12280Sstevel@tonic-gate const char *filename;
12290Sstevel@tonic-gate int min_bufsize;
12300Sstevel@tonic-gate nss_db_root_t *rootp;
12310Sstevel@tonic-gate nss_db_initf_t initf;
12320Sstevel@tonic-gate int netgroups;
12330Sstevel@tonic-gate compat_get_name getname_func;
12340Sstevel@tonic-gate compat_merge_func merge_func;
12350Sstevel@tonic-gate {
12360Sstevel@tonic-gate compat_backend_ptr_t be;
12370Sstevel@tonic-gate
12380Sstevel@tonic-gate if ((be = (compat_backend_ptr_t)malloc(sizeof (*be))) == 0) {
12390Sstevel@tonic-gate return (0);
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate be->ops = ops;
12420Sstevel@tonic-gate be->n_ops = n_ops;
12430Sstevel@tonic-gate be->filename = filename;
12440Sstevel@tonic-gate be->f = 0;
12450Sstevel@tonic-gate be->minbuf = min_bufsize;
12460Sstevel@tonic-gate be->buf = 0;
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate be->db_rootp = rootp;
12490Sstevel@tonic-gate be->db_initf = initf;
12500Sstevel@tonic-gate be->db_context = context_initval;
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate be->getnamef = getname_func;
12530Sstevel@tonic-gate be->mergef = merge_func;
12540Sstevel@tonic-gate
12553012Smichen be->state = GETENT_FILE; /* i.e. do Automatic setent(); */
12563012Smichen if (strcmp(be->filename, USERATTR_FILENAME) == 0) {
12573012Smichen be->state = GETENT_ATTRDB;
12583012Smichen be->str2ent_alt = str2userattr_s;
12593012Smichen be->workarea = calloc(1, sizeof (userstr_t));
12603012Smichen } else if (strcmp(be->filename, AUDITUSER_FILENAME) == 0) {
12610Sstevel@tonic-gate be->state = GETENT_ATTRDB;
12623012Smichen be->str2ent_alt = str2auuser_s;
12633012Smichen be->workarea = calloc(1, sizeof (au_user_str_t));
12643012Smichen } else if (strcmp(be->filename, PASSWD) == 0) {
12653012Smichen be->str2ent_alt = str2passwd;
12663012Smichen be->workarea = calloc(1, sizeof (struct passwd));
12673012Smichen } else if (strcmp(be->filename, SHADOW) == 0) {
12683012Smichen be->str2ent_alt = str2spwd;
12693012Smichen be->workarea = calloc(1, sizeof (struct spwd));
12703012Smichen } else { /* group */
12713012Smichen be->str2ent_alt = str2group;
12723012Smichen be->workarea = calloc(1, sizeof (struct group));
12733012Smichen }
12743012Smichen if (be->workarea == NULL)
12753012Smichen return (NULL);
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate be->minuses = 0;
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate be->permit_netgroups = netgroups;
12800Sstevel@tonic-gate be->yp_domain = 0;
12810Sstevel@tonic-gate be->getnetgrent_backend = 0;
12820Sstevel@tonic-gate be->netgr_buffer = 0;
12832830Sdjl be->return_string_data = 0;
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate return ((nss_backend_t *)be);
12860Sstevel@tonic-gate }
1287