compat_common.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Common code and structures used by name-service-switch "compat" backends.
*
* Most of the code in the "compat" backend is a perverted form of code from
* the "files" backend; this file is no exception.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <user_attr.h>
#include "compat_common.h"
#include "../../../libnsl/include/nsl_stdio_prv.h"
/*
* This should be in a header.
*/
extern int yp_get_default_domain(char **domain);
/*
* Routines to manage list of "-" users for get{pw, sp, gr}ent(). Current
* implementation is completely moronic; we use a linked list. But then
* that's what it's always done in 4.x...
*/
struct setofstrings {
char *name;
struct setofstrings *next;
/*
* === Should get smart and malloc the string and pointer as one
* object rather than two.
*/
};
typedef struct setofstrings *strset_t;
static void
{
}
*ssp = 0;
}
static boolean_t
const char *nam;
{
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
static boolean_t
const char *nam;
{
return (B_TRUE);
}
}
return (B_FALSE);
}
struct compat_backend {
int n_ops;
const char *filename;
__NSL_FILE *f;
int minbuf;
char *buf;
int linelen; /* <== Explain use, lifetime */
/* We wouldn't need all this hokey state stuff if we */
/* used another thread to implement a coroutine... */
enum {
} state;
int permit_netgroups;
const char *yp_domain;
char *netgr_buffer;
};
/*
* Lookup and enumeration routines for +@group and -@group.
*
* This code knows a lot more about lib/libc/port/gen/getnetgrent.c than
* from that file, but keep the state information per-backend-instance
* instead of just per-process.
*/
extern void _nss_initf_netgroup(nss_db_params_t *);
/*
* Should really share the db_root in getnetgrent.c in order to get the
* resource-management quotas right, but this will have to do.
*/
static DEFINE_NSS_DB_ROOT(netgr_db_root);
static boolean_t
{
return (B_FALSE);
}
}
}
static boolean_t
{
/*
* 4.x does this; ours not to reason why...
*/
}
static void
const char *netgroup;
{
/*
* ===> Need comment to explain that this first "if" is optimizing
* for the same-netgroup-as-last-time case
*/
if (be->getnetgrent_backend != 0 &&
(void *) netgroup) != NSS_SUCCESS) {
0);
be->getnetgrent_backend = 0;
}
if (be->getnetgrent_backend == 0) {
struct nss_setnetgrent_args args;
}
}
static boolean_t
char **up;
{
if (be->netgr_buffer == 0 &&
/* Out of memory */
return (B_FALSE);
}
do {
struct nss_getnetgrent_args args;
if (be->getnetgrent_backend != 0) {
NSS_DBOP_GETENT, &args);
}
} else {
return (B_FALSE);
}
} while (*up == 0);
return (B_TRUE);
}
static void
{
if (be->getnetgrent_backend != 0) {
NSS_DBOP_DESTRUCTOR, 0);
be->getnetgrent_backend = 0;
}
if (be->netgr_buffer != 0) {
be->netgr_buffer = 0;
}
}
static nss_status_t
const char *instr;
int linelen;
{
int i;
int overrides;
const char *p;
/*
* Potential optimization: only perform the field-splitting nonsense
* once per input line (at present, "+" and "+@netgroup" entries
* will cause us to do this multiple times in getent() requests).
*/
for (i = 0; i < MAXFIELDS; i++) {
fields[i] = 0;
}
const char *r = (q == 0) ? end : q;
if (len > 0) {
if (s == 0) {
break;
}
s[len] = '\0';
fields[i] = s;
overrides++;
}
if (q == 0) {
/* End of line */
break;
} else {
/* Skip the colon at (*q) */
p = q + 1;
}
}
if (overrides == 1) {
/* No real overrides, return (*args) intact */
res = NSS_SUCCESS;
} else if (overrides > 1) {
/*
* The zero'th field is always nonempty (+/-...), but at least
* one other field was also nonempty, i.e. wants to override
*/
case NSS_STR_PARSE_SUCCESS:
res = NSS_SUCCESS;
break;
case NSS_STR_PARSE_ERANGE:
res = NSS_NOTFOUND;
break;
case NSS_STR_PARSE_PARSE:
/* ===> Very likely the wrong thing to do... */
res = NSS_NOTFOUND;
break;
}
} else {
}
for (i = 0; i < MAXFIELDS; i++) {
if (fields[i] != 0) {
}
}
return (res);
}
/*ARGSUSED*/
void *dummy;
{
if (be->f == 0) {
/* Backend isn't initialized properly? */
return (NSS_UNAVAIL);
}
return (NSS_UNAVAIL);
}
} else {
__nsl_rewind(be->f);
}
/* ===> ??? nss_endent(be->db_rootp, be->db_initf, &be->db_context); */
else
/* ===> ?? netgroup stuff? */
return (NSS_SUCCESS);
}
/*ARGSUSED*/
void *dummy;
{
if (be->f != 0) {
__nsl_fclose(be->f);
be->f = 0;
}
}
/*
* Question: from the point of view of resource-freeing vs. time to
* start up again, how much should we do in endent() and how much
* in the destructor?
*/
return (NSS_SUCCESS);
}
/*ARGSUSED*/
void *dummy;
{
if (be != 0) {
if (be->f != 0) {
_nss_compat_endent(be, 0);
}
}
return (NSS_SUCCESS); /* In case anyone is dumb enough to check */
}
static int
__NSL_FILE *f;
char *buffer;
int buflen;
{
/*CONSTCOND*/
while (1) {
int linelen;
/* End of file */
return (-1);
}
/* linelen >= 1 (since fgets didn't return 0) */
/*
* ===> The code below that calls read_line() doesn't
* play by the rules; it assumes in places that
* the line is null-terminated. For now we'll
* humour it.
*/
return (linelen);
}
if (__nsl_feof(f)) {
/* Line is last line in file, and has no newline */
return (linelen);
}
/* Line too long for buffer; toss it and loop for next line */
/* ===== should syslog() in cases where previous code did */
;
}
}
}
int result = 0;
if ((attrdb != 0) &&
((op == NSS_DBOP_AUDITUSER_BYNAME) ||
(op == NSS_DBOP_USERATTR_BYNAME))) {
result = 1;
} else if ((attrdb == 0) &&
((op == NSS_DBOP_GROUP_BYNAME) ||
(op == NSS_DBOP_PASSWD_BYNAME) ||
(op == NSS_DBOP_SHADOW_BYNAME))) {
result = 1;
}
return (result);
}
/*ARGSUSED*/
int netdb;
{
int parsestat;
int (*func)();
#ifdef DEBUG
#endif /* DEBUG */
return (NSS_UNAVAIL);
}
return (res);
}
res = NSS_NOTFOUND;
/*CONSTCOND*/
while (1) {
int linelen;
/* End of file */
break;
}
/*
* Optimization: if the entry doesn't contain the
* filter string then it can't be the entry we want,
* so don't bother looking more closely at it.
*/
continue;
}
if (netdb) {
char *first;
char *last;
}
/*
* Skip leading whitespace. Normally there isn't
* any, so it's not worth calling strspn().
*/
;
}
if (*first == '\0') {
continue;
}
/*
* Found something non-blank on the line. Skip back
* over any trailing whitespace; since we know
* there's non-whitespace earlier in the line,
* checking for termination is easy.
*/
--last;
}
}
}
if (parsestat == NSS_STR_PARSE_SUCCESS) {
res = NSS_SUCCESS;
break;
}
} else if (parsestat == NSS_STR_PARSE_ERANGE) {
break;
}
}
/*
* stayopen is set to 0 by default in order to close the opened
* file. Some applications may break if it is set to 1.
*/
(void) _nss_compat_endent(be, 0);
}
if (res != NSS_SUCCESS) {
if ((op_num == NSS_DBOP_USERATTR_BYNAME) ||
(op_num == NSS_DBOP_AUDITUSER_BYNAME)) {
argp);
} else {
}
if (res != NSS_SUCCESS) {
}
}
return (res);
}
{
int parsestat;
return (NSS_UNAVAIL); /* really panic, malloc failed */
}
return (res);
}
res = NSS_NOTFOUND;
/*CONSTCOND*/
while (1) {
int linelen;
char *colon;
if (linelen < 0) {
/* End of file */
break;
}
/* Simple, wholesome, God-fearing entry */
if (parsestat == NSS_STR_PARSE_SUCCESS) {
res = NSS_SUCCESS;
break;
}
/* ===> Check the Dani logic here... */
} else if (parsestat == NSS_STR_PARSE_ERANGE) {
res = NSS_NOTFOUND;
break;
/* should we just skip this one long line ? */
} /* else if (parsestat == NSS_STR_PARSE_PARSE) */
/* don't care ! */
/* ==> ?? */ continue;
}
/*
* Process "+", "+name", "+@netgroup", "-name" or "-@netgroup"
*
* This code is optimized for lookups by name.
*
* For lookups by identifier search key cannot be matched with
* the name of the "+" or "-" entry. So nss_search() is to be
* called before extracting the name i.e. via (*be->getnamef)().
*
* But for lookups by name, search key is compared with the name
* of the "+" or "-" entry to acquire a match and thus
* unnesessary calls to nss_search() is eliminated. Also for
* matching "-" entries, calls to nss_search() is eliminated.
*/
}
/*
* Case 1:
* The entry is of the form "+@netgroup" or
* "-@netgroup". If we're performing a lookup by name,
* we can simply extract the name from the search key
* (i.e. args->key.name). If not, then we must call
* nss_search() before extracting the name via the
* get_XXname() function. i.e. (*be->getnamef)(args).
*/
if (_is_nss_lookup_by_name(0, op_num) != 0) {
/* compare then search */
if (!be->permit_netgroups ||
continue;
if (instr[0] == '+') {
/* need to search for "+" entry */
args);
continue;
}
} else {
/* search then compare */
continue;
if (!be->permit_netgroups ||
continue;
}
} /* end of case 1 */
/*
* Case 2:
* The entry is of the form "+" or "-". The former
* allows all entries from name services. The latter
* is illegal and ought to be ignored.
*/
if (instr[0] == '-')
continue;
/* need to search for "+" entry */
continue;
} /* end of case 2 */
else {
/*
* Case 3:
* The entry is of the form "+name" or "-name".
* If we're performing a lookup by name, we can simply
* extract the name from the search key
* (i.e. args->key.name). If not, then we must call
* nss_search() before extracting the name via the
* get_XXname() function. i.e. (*be->getnamef)(args).
*/
if (_is_nss_lookup_by_name(0, op_num) != 0) {
/* compare then search */
continue;
if (instr[0] == '+') {
/* need to search for "+" entry */
continue;
}
} else {
/* search then compare */
args);
continue;
!= 0)
continue;
}
} /* end of case 3 */
if (instr[0] == '-') {
/* no need to search for "-" entry */
res = NSS_NOTFOUND;
} else {
if (colon != 0)
}
break;
}
/*
* stayopen is set to 0 by default in order to close the opened
* file. Some applications may break if it is set to 1.
*/
(void) _nss_compat_endent(be, 0);
}
return (res);
}
_nss_compat_getent(be, a)
void *a;
{
char *colon = 0; /* <=== need comment re lifetime */
if (be->f == 0) {
return (res);
}
}
return (NSS_UNAVAIL); /* really panic, malloc failed */
}
/*CONSTCOND*/
while (1) {
int linelen;
char *name; /* === Need more distinctive label */
const char *savename;
/*
* In the code below...
* break means "I found one, I think" (i.e. goto the
* code after the end of the switch statement),
* continue means "Next candidate"
* (i.e. loop around to the switch statement),
* return means "I'm quite sure" (either Yes or No).
*/
case GETENT_DONE:
return (NSS_NOTFOUND);
case GETENT_ATTRDB:
return (res);
case GETENT_FILE:
if (linelen < 0) {
/* End of file */
continue;
}
*colon = '\0';
}
if (instr[0] == '-') {
} else if (be->permit_netgroups) {
name);
}
} /* Else (silently) ignore the entry */
continue;
} else if (instr[0] != '+') {
int parsestat;
/*
* Normal entry, no +/- nonsense
*/
if (colon != 0) {
*colon = ':';
}
if (parsestat == NSS_STR_PARSE_SUCCESS) {
return (NSS_SUCCESS);
}
/* ==> ?? Treat ERANGE differently ?? */
if (parsestat == NSS_STR_PARSE_ERANGE) {
return (NSS_NOTFOUND);
}
/* Skip the offending entry, get next */
continue;
/* Plain "+" */
&be->db_context);
continue;
/* "+@netgroup" */
continue;
} else {
/* "+name" */
break;
}
/* NOTREACHED */
case GETENT_ALL:
/* ==> ?? Treat ERANGE differently ?? */
&be->db_context);
continue;
}
continue;
}
name = 0; /* tell code below we've done the lookup */
break;
case GETENT_NETGROUP:
continue;
}
/* pass "name" variable to code below... */
break;
}
if (name != 0) {
continue;
}
/*
* Do a getXXXnam(name). If we were being pure,
* we'd introduce yet another function-pointer
* that the database-specific code had to supply
* to us. Instead we'll be grotty and hard-code
* the knowledge that
* (a) The username is always passwd in key.name,
* (b) NSS_DBOP_PASSWD_BYNAME ==
* NSS_DBOP_SHADOW_BYNAME ==
* NSS_DBOP_next_iter.
*/
}
/*
* Found one via "+", "+name" or "@netgroup".
* Override some fields if the /etc file says to do so.
*/
/* ==> ?? Should treat erange differently? */
continue;
}
/* 'colon' was set umpteen iterations ago in GETENT_FILE */
if (colon != 0) {
*colon = ':';
colon = 0;
}
}
}
/* We don't use this directly; we just copy the bits when we want to */
/* initialize the variable (in the compat_backend struct) that we do use */
static DEFINE_NSS_GETENT(context_initval);
int n_ops;
const char *filename;
int min_bufsize;
int netgroups;
{
return (0);
}
be->f = 0;
else
be->getnetgrent_backend = 0;
be->netgr_buffer = 0;
return ((nss_backend_t *)be);
}