e14f1c3b3b
databases. - Make nsswitch support caching. Submitted by: Michael Bushkov <bushman__at__rsu.ru> Sponsored by: Google Summer of Code 2005
1049 lines
21 KiB
C
1049 lines
21 KiB
C
/* $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ */
|
|
|
|
/*
|
|
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
|
|
* unrestricted use provided that this legend is included on all tape
|
|
* media and as a part of the software program in whole or part. Users
|
|
* may copy or modify Sun RPC without charge, but are not authorized
|
|
* to license or distribute it to anyone else except as part of a product or
|
|
* program developed by the user or with the express written consent of
|
|
* Sun Microsystems, Inc.
|
|
*
|
|
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
|
|
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
|
|
*
|
|
* Sun RPC is provided with no support and without any obligation on the
|
|
* part of Sun Microsystems, Inc. to assist in its use, correction,
|
|
* modification or enhancement.
|
|
*
|
|
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
|
|
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
|
|
* OR ANY PART THEREOF.
|
|
*
|
|
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
|
|
* or profits or other special, indirect and consequential damages, even if
|
|
* Sun has been advised of the possibility of such damages.
|
|
*
|
|
* Sun Microsystems, Inc.
|
|
* 2550 Garcia Avenue
|
|
* Mountain View, California 94043
|
|
*/
|
|
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";
|
|
#endif
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
/*
|
|
* Copyright (c) 1984 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <nsswitch.h>
|
|
#include <netinet/in.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <rpc/rpc.h>
|
|
#ifdef YP
|
|
#include <rpcsvc/yp_prot.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
#endif
|
|
#include <unistd.h>
|
|
#include "namespace.h"
|
|
#include "reentrant.h"
|
|
#include "un-namespace.h"
|
|
#include "libc_private.h"
|
|
#include "nss_tls.h"
|
|
#ifdef NS_CACHING
|
|
#include "nscache.h"
|
|
#endif
|
|
|
|
#define RPCDB "/etc/rpc"
|
|
|
|
/* nsswitch declarations */
|
|
enum constants
|
|
{
|
|
SETRPCENT = 1,
|
|
ENDRPCENT = 2,
|
|
RPCENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
|
|
RPCENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
|
|
};
|
|
|
|
static const ns_src defaultsrc[] = {
|
|
{ NSSRC_FILES, NS_SUCCESS },
|
|
#ifdef YP
|
|
{ NSSRC_NIS, NS_SUCCESS },
|
|
#endif
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
/* files backend declarations */
|
|
struct files_state {
|
|
FILE *fp;
|
|
int stayopen;
|
|
};
|
|
|
|
static int files_rpcent(void *, void *, va_list);
|
|
static int files_setrpcent(void *, void *, va_list);
|
|
|
|
static void files_endstate(void *);
|
|
NSS_TLS_HANDLING(files);
|
|
|
|
/* nis backend declarations */
|
|
#ifdef YP
|
|
struct nis_state {
|
|
char domain[MAXHOSTNAMELEN];
|
|
char *current;
|
|
int currentlen;
|
|
int stepping;
|
|
int no_name_map;
|
|
};
|
|
|
|
static int nis_rpcent(void *, void *, va_list);
|
|
static int nis_setrpcent(void *, void *, va_list);
|
|
|
|
static void nis_endstate(void *);
|
|
NSS_TLS_HANDLING(nis);
|
|
#endif
|
|
|
|
/* get** wrappers for get**_r functions declarations */
|
|
struct rpcent_state {
|
|
struct rpcent rpc;
|
|
char *buffer;
|
|
size_t bufsize;
|
|
};
|
|
static void rpcent_endstate(void *);
|
|
NSS_TLS_HANDLING(rpcent);
|
|
|
|
union key {
|
|
const char *name;
|
|
int number;
|
|
};
|
|
|
|
static int wrap_getrpcbyname_r(union key, struct rpcent *, char *,
|
|
size_t, struct rpcent **);
|
|
static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *,
|
|
size_t, struct rpcent **);
|
|
static int wrap_getrpcent_r(union key, struct rpcent *, char *,
|
|
size_t, struct rpcent **);
|
|
static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *,
|
|
size_t, struct rpcent **), union key);
|
|
|
|
#ifdef NS_CACHING
|
|
static int rpc_id_func(char *, size_t *, va_list, void *);
|
|
static int rpc_marshal_func(char *, size_t *, void *, va_list, void *);
|
|
static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *);
|
|
#endif
|
|
|
|
static int
|
|
rpcent_unpack(char *p, struct rpcent *rpc, char **r_aliases,
|
|
size_t aliases_size, int *errnop)
|
|
{
|
|
char *cp, **q;
|
|
|
|
assert(p != NULL);
|
|
|
|
if (*p == '#')
|
|
return (-1);
|
|
cp = strpbrk(p, "#\n");
|
|
if (cp == NULL)
|
|
return (-1);
|
|
*cp = '\0';
|
|
cp = strpbrk(p, " \t");
|
|
if (cp == NULL)
|
|
return (-1);
|
|
*cp++ = '\0';
|
|
/* THIS STUFF IS INTERNET SPECIFIC */
|
|
rpc->r_name = p;
|
|
while (*cp == ' ' || *cp == '\t')
|
|
cp++;
|
|
rpc->r_number = atoi(cp);
|
|
q = rpc->r_aliases = r_aliases;
|
|
cp = strpbrk(cp, " \t");
|
|
if (cp != NULL)
|
|
*cp++ = '\0';
|
|
while (cp && *cp) {
|
|
if (*cp == ' ' || *cp == '\t') {
|
|
cp++;
|
|
continue;
|
|
}
|
|
if (q < &(r_aliases[aliases_size - 1]))
|
|
*q++ = cp;
|
|
else {
|
|
*errnop = ERANGE;
|
|
return -1;
|
|
}
|
|
|
|
cp = strpbrk(cp, " \t");
|
|
if (cp != NULL)
|
|
*cp++ = '\0';
|
|
}
|
|
*q = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/* files backend implementation */
|
|
static void
|
|
files_endstate(void *p)
|
|
{
|
|
FILE * f;
|
|
|
|
if (p == NULL)
|
|
return;
|
|
|
|
f = ((struct files_state *)p)->fp;
|
|
if (f != NULL)
|
|
fclose(f);
|
|
|
|
free(p);
|
|
}
|
|
|
|
static int
|
|
files_rpcent(void *retval, void *mdata, va_list ap)
|
|
{
|
|
char *name;
|
|
int number;
|
|
struct rpcent *rpc;
|
|
char *buffer;
|
|
size_t bufsize;
|
|
int *errnop;
|
|
|
|
char *line;
|
|
size_t linesize;
|
|
char **aliases;
|
|
int aliases_size;
|
|
char **rp;
|
|
|
|
struct files_state *st;
|
|
int rv;
|
|
int stayopen;
|
|
enum nss_lookup_type how;
|
|
|
|
how = (enum nss_lookup_type)mdata;
|
|
switch (how)
|
|
{
|
|
case nss_lt_name:
|
|
name = va_arg(ap, char *);
|
|
break;
|
|
case nss_lt_id:
|
|
number = va_arg(ap, int);
|
|
break;
|
|
case nss_lt_all:
|
|
break;
|
|
default:
|
|
return (NS_NOTFOUND);
|
|
}
|
|
|
|
rpc = va_arg(ap, struct rpcent *);
|
|
buffer = va_arg(ap, char *);
|
|
bufsize = va_arg(ap, size_t);
|
|
errnop = va_arg(ap, int *);
|
|
|
|
*errnop = files_getstate(&st);
|
|
if (*errnop != 0)
|
|
return (NS_UNAVAIL);
|
|
|
|
if (st->fp == NULL && (st->fp = fopen(RPCDB, "r")) == NULL) {
|
|
*errnop = errno;
|
|
return (NS_UNAVAIL);
|
|
}
|
|
|
|
if (how == nss_lt_all)
|
|
stayopen = 1;
|
|
else {
|
|
rewind(st->fp);
|
|
stayopen = st->stayopen;
|
|
}
|
|
|
|
do {
|
|
if ((line = fgetln(st->fp, &linesize)) == NULL) {
|
|
*errnop = errno;
|
|
rv = NS_RETURN;
|
|
break;
|
|
}
|
|
|
|
if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
|
|
*errnop = ERANGE;
|
|
rv = NS_RETURN;
|
|
break;
|
|
}
|
|
|
|
aliases = (char **)_ALIGN(&buffer[linesize+1]);
|
|
aliases_size = (buffer + bufsize -
|
|
(char *)aliases)/sizeof(char *);
|
|
if (aliases_size < 1) {
|
|
*errnop = ERANGE;
|
|
rv = NS_RETURN;
|
|
break;
|
|
}
|
|
|
|
memcpy(buffer, line, linesize);
|
|
buffer[linesize] = '\0';
|
|
|
|
rv = rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop);
|
|
if (rv != 0) {
|
|
if (*errnop == 0) {
|
|
rv = NS_NOTFOUND;
|
|
continue;
|
|
}
|
|
else {
|
|
rv = NS_RETURN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (how)
|
|
{
|
|
case nss_lt_name:
|
|
if (strcmp(rpc->r_name, name) == 0)
|
|
goto done;
|
|
for (rp = rpc->r_aliases; *rp != NULL; rp++) {
|
|
if (strcmp(*rp, name) == 0)
|
|
goto done;
|
|
}
|
|
rv = NS_NOTFOUND;
|
|
continue;
|
|
done:
|
|
rv = NS_SUCCESS;
|
|
break;
|
|
case nss_lt_id:
|
|
rv = (rpc->r_number == number) ? NS_SUCCESS :
|
|
NS_NOTFOUND;
|
|
break;
|
|
case nss_lt_all:
|
|
rv = NS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
} while (!(rv & NS_TERMINATE));
|
|
|
|
if (!stayopen && st->fp!=NULL) {
|
|
fclose(st->fp);
|
|
st->fp = NULL;
|
|
}
|
|
|
|
if ((rv == NS_SUCCESS) && (retval != NULL))
|
|
*((struct rpcent **)retval) = rpc;
|
|
|
|
return (rv);
|
|
}
|
|
|
|
static int
|
|
files_setrpcent(void *retval, void *mdata, va_list ap)
|
|
{
|
|
struct files_state *st;
|
|
int rv;
|
|
int f;
|
|
|
|
rv = files_getstate(&st);
|
|
if (rv != 0)
|
|
return (NS_UNAVAIL);
|
|
|
|
switch ((enum constants)mdata)
|
|
{
|
|
case SETRPCENT:
|
|
f = va_arg(ap,int);
|
|
if (st->fp == NULL)
|
|
st->fp = fopen(RPCDB, "r");
|
|
else
|
|
rewind(st->fp);
|
|
st->stayopen |= f;
|
|
break;
|
|
case ENDRPCENT:
|
|
if (st->fp != NULL) {
|
|
fclose(st->fp);
|
|
st->fp = NULL;
|
|
}
|
|
st->stayopen = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (NS_UNAVAIL);
|
|
}
|
|
|
|
/* nis backend implementation */
|
|
#ifdef YP
|
|
static void
|
|
nis_endstate(void *p)
|
|
{
|
|
if (p == NULL)
|
|
return;
|
|
|
|
free(((struct nis_state *)p)->current);
|
|
free(p);
|
|
}
|
|
|
|
static int
|
|
nis_rpcent(void *retval, void *mdata, va_list ap)
|
|
{
|
|
char *name;
|
|
int number;
|
|
struct rpcent *rpc;
|
|
char *buffer;
|
|
size_t bufsize;
|
|
int *errnop;
|
|
|
|
char **rp;
|
|
char **aliases;
|
|
int aliases_size;
|
|
|
|
char *lastkey;
|
|
char *resultbuf;
|
|
int resultbuflen;
|
|
char buf[YPMAXRECORD + 2];
|
|
|
|
struct nis_state *st;
|
|
int rv;
|
|
enum nss_lookup_type how;
|
|
int no_name_active;
|
|
|
|
how = (enum nss_lookup_type)mdata;
|
|
switch (how)
|
|
{
|
|
case nss_lt_name:
|
|
name = va_arg(ap, char *);
|
|
break;
|
|
case nss_lt_id:
|
|
number = va_arg(ap, int);
|
|
break;
|
|
case nss_lt_all:
|
|
break;
|
|
default:
|
|
return (NS_NOTFOUND);
|
|
}
|
|
|
|
rpc = va_arg(ap, struct rpcent *);
|
|
buffer = va_arg(ap, char *);
|
|
bufsize = va_arg(ap, size_t);
|
|
errnop = va_arg(ap, int *);
|
|
|
|
*errnop = nis_getstate(&st);
|
|
if (*errnop != 0)
|
|
return (NS_UNAVAIL);
|
|
|
|
if (st->domain[0] == '\0') {
|
|
if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
|
|
*errnop = errno;
|
|
return (NS_UNAVAIL);
|
|
}
|
|
}
|
|
|
|
no_name_active = 0;
|
|
do {
|
|
switch (how)
|
|
{
|
|
case nss_lt_name:
|
|
if (!st->no_name_map)
|
|
{
|
|
snprintf(buf, sizeof buf, "%s", name);
|
|
rv = yp_match(st->domain, "rpc.byname", buf,
|
|
strlen(buf), &resultbuf, &resultbuflen);
|
|
|
|
switch (rv) {
|
|
case 0:
|
|
break;
|
|
case YPERR_MAP:
|
|
st->stepping = 0;
|
|
no_name_active = 1;
|
|
how = nss_lt_all;
|
|
|
|
rv = NS_NOTFOUND;
|
|
continue;
|
|
default:
|
|
rv = NS_NOTFOUND;
|
|
goto fin;
|
|
}
|
|
} else {
|
|
st->stepping = 0;
|
|
no_name_active = 1;
|
|
how = nss_lt_all;
|
|
|
|
rv = NS_NOTFOUND;
|
|
continue;
|
|
}
|
|
break;
|
|
case nss_lt_id:
|
|
snprintf(buf, sizeof buf, "%d", number);
|
|
if (yp_match(st->domain, "rpc.bynumber", buf,
|
|
strlen(buf), &resultbuf, &resultbuflen)) {
|
|
rv = NS_NOTFOUND;
|
|
goto fin;
|
|
}
|
|
break;
|
|
case nss_lt_all:
|
|
if (!st->stepping) {
|
|
rv = yp_first(st->domain, "rpc.bynumber",
|
|
&st->current,
|
|
&st->currentlen, &resultbuf,
|
|
&resultbuflen);
|
|
if (rv) {
|
|
rv = NS_NOTFOUND;
|
|
goto fin;
|
|
}
|
|
st->stepping = 1;
|
|
} else {
|
|
lastkey = st->current;
|
|
rv = yp_next(st->domain, "rpc.bynumber",
|
|
st->current,
|
|
st->currentlen, &st->current,
|
|
&st->currentlen,
|
|
&resultbuf, &resultbuflen);
|
|
free(lastkey);
|
|
if (rv) {
|
|
st->stepping = 0;
|
|
rv = NS_NOTFOUND;
|
|
goto fin;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* we need a room for additional \n symbol */
|
|
if (bufsize <= resultbuflen + 1 + _ALIGNBYTES +
|
|
sizeof(char *)) {
|
|
*errnop = ERANGE;
|
|
rv = NS_RETURN;
|
|
break;
|
|
}
|
|
|
|
aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
|
|
aliases_size = (buffer + bufsize - (char *)aliases) /
|
|
sizeof(char *);
|
|
if (aliases_size < 1) {
|
|
*errnop = ERANGE;
|
|
rv = NS_RETURN;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* rpcent_unpack expects lines terminated with \n -- make it happy
|
|
*/
|
|
memcpy(buffer, resultbuf, resultbuflen);
|
|
buffer[resultbuflen] = '\n';
|
|
buffer[resultbuflen+1] = '\0';
|
|
free(resultbuf);
|
|
|
|
if (rpcent_unpack(buffer, rpc, aliases, aliases_size,
|
|
errnop) != 0) {
|
|
if (*errnop == 0)
|
|
rv = NS_NOTFOUND;
|
|
else
|
|
rv = NS_RETURN;
|
|
} else {
|
|
if ((how == nss_lt_all) && (no_name_active != 0)) {
|
|
if (strcmp(rpc->r_name, name) == 0)
|
|
goto done;
|
|
for (rp = rpc->r_aliases; *rp != NULL; rp++) {
|
|
if (strcmp(*rp, name) == 0)
|
|
goto done;
|
|
}
|
|
rv = NS_NOTFOUND;
|
|
continue;
|
|
done:
|
|
rv = NS_SUCCESS;
|
|
} else
|
|
rv = NS_SUCCESS;
|
|
}
|
|
|
|
} while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
|
|
|
|
fin:
|
|
if ((rv == NS_SUCCESS) && (retval != NULL))
|
|
*((struct rpcent **)retval) = rpc;
|
|
|
|
return (rv);
|
|
}
|
|
|
|
static int
|
|
nis_setrpcent(void *retval, void *mdata, va_list ap)
|
|
{
|
|
struct nis_state *st;
|
|
int rv;
|
|
|
|
rv = nis_getstate(&st);
|
|
if (rv != 0)
|
|
return (NS_UNAVAIL);
|
|
|
|
switch ((enum constants)mdata)
|
|
{
|
|
case SETRPCENT:
|
|
case ENDRPCENT:
|
|
free(st->current);
|
|
st->current = NULL;
|
|
st->stepping = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (NS_UNAVAIL);
|
|
}
|
|
#endif
|
|
|
|
#ifdef NS_CACHING
|
|
static int
|
|
rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
|
|
{
|
|
char *name;
|
|
int rpc;
|
|
|
|
size_t desired_size, size;
|
|
enum nss_lookup_type lookup_type;
|
|
int res = NS_UNAVAIL;
|
|
|
|
lookup_type = (enum nss_lookup_type)cache_mdata;
|
|
switch (lookup_type) {
|
|
case nss_lt_name:
|
|
name = va_arg(ap, char *);
|
|
|
|
size = strlen(name);
|
|
desired_size = sizeof(enum nss_lookup_type) + size + 1;
|
|
if (desired_size > *buffer_size) {
|
|
res = NS_RETURN;
|
|
goto fin;
|
|
}
|
|
|
|
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
|
|
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
|
|
|
|
res = NS_SUCCESS;
|
|
break;
|
|
case nss_lt_id:
|
|
rpc = va_arg(ap, int);
|
|
|
|
desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
|
|
if (desired_size > *buffer_size) {
|
|
res = NS_RETURN;
|
|
goto fin;
|
|
}
|
|
|
|
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
|
|
memcpy(buffer + sizeof(enum nss_lookup_type), &rpc,
|
|
sizeof(int));
|
|
|
|
res = NS_SUCCESS;
|
|
break;
|
|
default:
|
|
/* should be unreachable */
|
|
return (NS_UNAVAIL);
|
|
}
|
|
|
|
fin:
|
|
*buffer_size = desired_size;
|
|
return (res);
|
|
}
|
|
|
|
static int
|
|
rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
|
|
void *cache_mdata)
|
|
{
|
|
char *name;
|
|
int num;
|
|
struct rpcent *rpc;
|
|
char *orig_buf;
|
|
size_t orig_buf_size;
|
|
|
|
struct rpcent new_rpc;
|
|
size_t desired_size, size, aliases_size;
|
|
char *p;
|
|
char **alias;
|
|
|
|
switch ((enum nss_lookup_type)cache_mdata) {
|
|
case nss_lt_name:
|
|
name = va_arg(ap, char *);
|
|
break;
|
|
case nss_lt_id:
|
|
num = va_arg(ap, int);
|
|
break;
|
|
case nss_lt_all:
|
|
break;
|
|
default:
|
|
/* should be unreachable */
|
|
return (NS_UNAVAIL);
|
|
}
|
|
|
|
rpc = va_arg(ap, struct rpcent *);
|
|
orig_buf = va_arg(ap, char *);
|
|
orig_buf_size = va_arg(ap, size_t);
|
|
|
|
desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *);
|
|
if (rpc->r_name != NULL)
|
|
desired_size += strlen(rpc->r_name) + 1;
|
|
|
|
if (rpc->r_aliases != NULL) {
|
|
aliases_size = 0;
|
|
for (alias = rpc->r_aliases; *alias; ++alias) {
|
|
desired_size += strlen(*alias) + 1;
|
|
++aliases_size;
|
|
}
|
|
|
|
desired_size += _ALIGNBYTES + (aliases_size + 1) *
|
|
sizeof(char *);
|
|
}
|
|
|
|
if (*buffer_size < desired_size) {
|
|
/* this assignment is here for future use */
|
|
*buffer_size = desired_size;
|
|
return (NS_RETURN);
|
|
}
|
|
|
|
memcpy(&new_rpc, rpc, sizeof(struct rpcent));
|
|
|
|
*buffer_size = desired_size;
|
|
memset(buffer, 0, desired_size);
|
|
p = buffer + sizeof(struct rpcent) + sizeof(char *);
|
|
memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *));
|
|
p = (char *)_ALIGN(p);
|
|
|
|
if (new_rpc.r_name != NULL) {
|
|
size = strlen(new_rpc.r_name);
|
|
memcpy(p, new_rpc.r_name, size);
|
|
new_rpc.r_name = p;
|
|
p += size + 1;
|
|
}
|
|
|
|
if (new_rpc.r_aliases != NULL) {
|
|
p = (char *)_ALIGN(p);
|
|
memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size);
|
|
new_rpc.r_aliases = (char **)p;
|
|
p += sizeof(char *) * (aliases_size + 1);
|
|
|
|
for (alias = new_rpc.r_aliases; *alias; ++alias) {
|
|
size = strlen(*alias);
|
|
memcpy(p, *alias, size);
|
|
*alias = p;
|
|
p += size + 1;
|
|
}
|
|
}
|
|
|
|
memcpy(buffer, &new_rpc, sizeof(struct rpcent));
|
|
return (NS_SUCCESS);
|
|
}
|
|
|
|
static int
|
|
rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
|
|
void *cache_mdata)
|
|
{
|
|
char *name;
|
|
int num;
|
|
struct rpcent *rpc;
|
|
char *orig_buf;
|
|
size_t orig_buf_size;
|
|
int *ret_errno;
|
|
|
|
char *p;
|
|
char **alias;
|
|
|
|
switch ((enum nss_lookup_type)cache_mdata) {
|
|
case nss_lt_name:
|
|
name = va_arg(ap, char *);
|
|
break;
|
|
case nss_lt_id:
|
|
num = va_arg(ap, int);
|
|
break;
|
|
case nss_lt_all:
|
|
break;
|
|
default:
|
|
/* should be unreachable */
|
|
return (NS_UNAVAIL);
|
|
}
|
|
|
|
rpc = va_arg(ap, struct rpcent *);
|
|
orig_buf = va_arg(ap, char *);
|
|
orig_buf_size = va_arg(ap, size_t);
|
|
ret_errno = va_arg(ap, int *);
|
|
|
|
if (orig_buf_size <
|
|
buffer_size - sizeof(struct rpcent) - sizeof(char *)) {
|
|
*ret_errno = ERANGE;
|
|
return (NS_RETURN);
|
|
}
|
|
|
|
memcpy(rpc, buffer, sizeof(struct rpcent));
|
|
memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *));
|
|
|
|
orig_buf = (char *)_ALIGN(orig_buf);
|
|
memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) +
|
|
_ALIGN(p) - (size_t)p,
|
|
buffer_size - sizeof(struct rpcent) - sizeof(char *) -
|
|
_ALIGN(p) + (size_t)p);
|
|
p = (char *)_ALIGN(p);
|
|
|
|
NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *);
|
|
if (rpc->r_aliases != NULL) {
|
|
NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **);
|
|
|
|
for (alias = rpc->r_aliases ; *alias; ++alias)
|
|
NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
|
|
}
|
|
|
|
if (retval != NULL)
|
|
*((struct rpcent **)retval) = rpc;
|
|
|
|
return (NS_SUCCESS);
|
|
}
|
|
|
|
NSS_MP_CACHE_HANDLING(rpc);
|
|
#endif /* NS_CACHING */
|
|
|
|
|
|
/* get**_r functions implementation */
|
|
static int
|
|
getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer,
|
|
size_t bufsize, struct rpcent **result)
|
|
{
|
|
#ifdef NS_CACHING
|
|
static const nss_cache_info cache_info =
|
|
NS_COMMON_CACHE_INFO_INITIALIZER(
|
|
rpc, (void *)nss_lt_name,
|
|
rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
|
|
#endif
|
|
static const ns_dtab dtab[] = {
|
|
{ NSSRC_FILES, files_rpcent, (void *)nss_lt_name },
|
|
#ifdef YP
|
|
{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_name },
|
|
#endif
|
|
#ifdef NS_CACHING
|
|
NS_CACHE_CB(&cache_info)
|
|
#endif
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
int rv, ret_errno;
|
|
|
|
ret_errno = 0;
|
|
*result = NULL;
|
|
rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc,
|
|
name, rpc, buffer, bufsize, &ret_errno);
|
|
|
|
if (rv == NS_SUCCESS)
|
|
return (0);
|
|
else
|
|
return (ret_errno);
|
|
}
|
|
|
|
static int
|
|
getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer,
|
|
size_t bufsize, struct rpcent **result)
|
|
{
|
|
#ifdef NS_CACHING
|
|
static const nss_cache_info cache_info =
|
|
NS_COMMON_CACHE_INFO_INITIALIZER(
|
|
rpc, (void *)nss_lt_id,
|
|
rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
|
|
#endif
|
|
static const ns_dtab dtab[] = {
|
|
{ NSSRC_FILES, files_rpcent, (void *)nss_lt_id },
|
|
#ifdef YP
|
|
{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_id },
|
|
#endif
|
|
#ifdef NS_CACHING
|
|
NS_CACHE_CB(&cache_info)
|
|
#endif
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
int rv, ret_errno;
|
|
|
|
ret_errno = 0;
|
|
*result = NULL;
|
|
rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc,
|
|
number, rpc, buffer, bufsize, &ret_errno);
|
|
|
|
if (rv == NS_SUCCESS)
|
|
return (0);
|
|
else
|
|
return (ret_errno);
|
|
}
|
|
|
|
static int
|
|
getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize,
|
|
struct rpcent **result)
|
|
{
|
|
#ifdef NS_CACHING
|
|
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
|
|
rpc, (void *)nss_lt_all,
|
|
rpc_marshal_func, rpc_unmarshal_func);
|
|
#endif
|
|
static const ns_dtab dtab[] = {
|
|
{ NSSRC_FILES, files_rpcent, (void *)nss_lt_all },
|
|
#ifdef YP
|
|
{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_all },
|
|
#endif
|
|
#ifdef NS_CACHING
|
|
NS_CACHE_CB(&cache_info)
|
|
#endif
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
int rv, ret_errno;
|
|
|
|
ret_errno = 0;
|
|
*result = NULL;
|
|
rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc,
|
|
rpc, buffer, bufsize, &ret_errno);
|
|
|
|
if (rv == NS_SUCCESS)
|
|
return (0);
|
|
else
|
|
return (ret_errno);
|
|
}
|
|
|
|
/* get** wrappers for get**_r functions implementation */
|
|
static void
|
|
rpcent_endstate(void *p)
|
|
{
|
|
if (p == NULL)
|
|
return;
|
|
|
|
free(((struct rpcent_state *)p)->buffer);
|
|
free(p);
|
|
}
|
|
|
|
static int
|
|
wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer,
|
|
size_t bufsize, struct rpcent **res)
|
|
{
|
|
return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res));
|
|
}
|
|
|
|
static int
|
|
wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer,
|
|
size_t bufsize, struct rpcent **res)
|
|
{
|
|
return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res));
|
|
}
|
|
|
|
static int
|
|
wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer,
|
|
size_t bufsize, struct rpcent **res)
|
|
{
|
|
return (getrpcent_r(rpc, buffer, bufsize, res));
|
|
}
|
|
|
|
static struct rpcent *
|
|
getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **),
|
|
union key key)
|
|
{
|
|
int rv;
|
|
struct rpcent *res;
|
|
struct rpcent_state * st;
|
|
|
|
rv=rpcent_getstate(&st);
|
|
if (rv != 0) {
|
|
errno = rv;
|
|
return NULL;
|
|
}
|
|
|
|
if (st->buffer == NULL) {
|
|
st->buffer = malloc(RPCENT_STORAGE_INITIAL);
|
|
if (st->buffer == NULL)
|
|
return (NULL);
|
|
st->bufsize = RPCENT_STORAGE_INITIAL;
|
|
}
|
|
do {
|
|
rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res);
|
|
if (res == NULL && rv == ERANGE) {
|
|
free(st->buffer);
|
|
if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) {
|
|
st->buffer = NULL;
|
|
errno = ERANGE;
|
|
return (NULL);
|
|
}
|
|
st->bufsize <<= 1;
|
|
st->buffer = malloc(st->bufsize);
|
|
if (st->buffer == NULL)
|
|
return (NULL);
|
|
}
|
|
} while (res == NULL && rv == ERANGE);
|
|
if (rv != 0)
|
|
errno = rv;
|
|
|
|
return (res);
|
|
}
|
|
|
|
struct rpcent *
|
|
getrpcbyname(char *name)
|
|
{
|
|
union key key;
|
|
|
|
key.name = name;
|
|
|
|
return (getrpc(wrap_getrpcbyname_r, key));
|
|
}
|
|
|
|
struct rpcent *
|
|
getrpcbynumber(int number)
|
|
{
|
|
union key key;
|
|
|
|
key.number = number;
|
|
|
|
return (getrpc(wrap_getrpcbynumber_r, key));
|
|
}
|
|
|
|
struct rpcent *
|
|
getrpcent()
|
|
{
|
|
union key key;
|
|
|
|
key.number = 0; /* not used */
|
|
|
|
return (getrpc(wrap_getrpcent_r, key));
|
|
}
|
|
|
|
void
|
|
setrpcent(int stayopen)
|
|
{
|
|
#ifdef NS_CACHING
|
|
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
|
|
rpc, (void *)nss_lt_all,
|
|
NULL, NULL);
|
|
#endif
|
|
|
|
static const ns_dtab dtab[] = {
|
|
{ NSSRC_FILES, files_setrpcent, (void *)SETRPCENT },
|
|
#ifdef YP
|
|
{ NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT },
|
|
#endif
|
|
#ifdef NS_CACHING
|
|
NS_CACHE_CB(&cache_info)
|
|
#endif
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
|
|
(void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc,
|
|
stayopen);
|
|
}
|
|
|
|
void
|
|
endrpcent()
|
|
{
|
|
#ifdef NS_CACHING
|
|
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
|
|
rpc, (void *)nss_lt_all,
|
|
NULL, NULL);
|
|
#endif
|
|
|
|
static const ns_dtab dtab[] = {
|
|
{ NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT },
|
|
#ifdef YP
|
|
{ NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT },
|
|
#endif
|
|
#ifdef NS_CACHING
|
|
NS_CACHE_CB(&cache_info)
|
|
#endif
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
|
|
(void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endrpcent", defaultsrc);
|
|
}
|