/* * 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 * * @(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro * $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ * $FreeBSD: src/lib/libc/rpc/getrpcent.c,v 1.16 2007/05/17 03:34:33 jon Exp $ */ /* * Copyright (c) 1984 by Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef YP #include #include #endif #include #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 __unused, 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 __unused, void *mdata, va_list ap __unused) { 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 __unused, 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(void) { 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 } }; nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc, stayopen); } void endrpcent(void) { #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 } }; nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc); }