1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if defined(LIBC_SCCS) && !defined(lint) 35 static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93"; 36 #endif /* LIBC_SCCS and not lint */ 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/types.h> 41 #include <sys/socket.h> 42 #include <arpa/inet.h> 43 #include <netdb.h> 44 #include <stdio.h> 45 #include <string.h> 46 #include <stdlib.h> 47 #ifdef YP 48 #include <rpc/rpc.h> 49 #include <rpcsvc/yp_prot.h> 50 #include <rpcsvc/ypclnt.h> 51 static int serv_stepping_yp = 0; 52 #endif 53 #include "libc_private.h" 54 55 #define MAXALIASES 35 56 57 static FILE *servf = NULL; 58 static char line[BUFSIZ+1]; 59 static struct servent serv; 60 static char *serv_aliases[MAXALIASES]; 61 int _serv_stayopen; 62 63 #ifdef YP 64 char *___getservbyname_yp = NULL; 65 char *___getservbyproto_yp = NULL; 66 int ___getservbyport_yp = 0; 67 static char *yp_domain = NULL; 68 69 static int 70 _getservbyport_yp(line) 71 char *line; 72 { 73 char *result; 74 int resultlen; 75 char buf[YPMAXRECORD + 2]; 76 int rv; 77 78 snprintf(buf, sizeof(buf), "%d/%s", ntohs(___getservbyport_yp), 79 ___getservbyproto_yp); 80 81 ___getservbyport_yp = 0; 82 ___getservbyproto_yp = NULL; 83 84 if(!yp_domain) { 85 if(yp_get_default_domain(&yp_domain)) 86 return (0); 87 } 88 89 /* 90 * We have to be a little flexible here. Ideally you're supposed 91 * to have both a services.byname and a services.byport map, but 92 * some systems have only services.byname. FreeBSD cheats a little 93 * by putting the services.byport information in the same map as 94 * services.byname so that either case will work. We allow for both 95 * possibilities here: if there is no services.byport map, we try 96 * services.byname instead. 97 */ 98 if ((rv = yp_match(yp_domain, "services.byport", buf, strlen(buf), 99 &result, &resultlen))) { 100 if (rv == YPERR_MAP) { 101 if (yp_match(yp_domain, "services.byname", buf, 102 strlen(buf), &result, &resultlen)) 103 return(0); 104 } else 105 return(0); 106 } 107 108 /* getservent() expects lines terminated with \n -- make it happy */ 109 snprintf(line, BUFSIZ, "%.*s\n", resultlen, result); 110 111 free(result); 112 return(1); 113 } 114 115 static int 116 _getservbyname_yp(line) 117 char *line; 118 { 119 char *result; 120 int resultlen; 121 char buf[YPMAXRECORD + 2]; 122 123 if(!yp_domain) { 124 if(yp_get_default_domain(&yp_domain)) 125 return (0); 126 } 127 128 snprintf(buf, sizeof(buf), "%s/%s", ___getservbyname_yp, 129 ___getservbyproto_yp); 130 131 ___getservbyname_yp = 0; 132 ___getservbyproto_yp = NULL; 133 134 if (yp_match(yp_domain, "services.byname", buf, strlen(buf), 135 &result, &resultlen)) { 136 return(0); 137 } 138 139 /* getservent() expects lines terminated with \n -- make it happy */ 140 snprintf(line, BUFSIZ, "%.*s\n", resultlen, result); 141 142 free(result); 143 return(1); 144 } 145 146 static int 147 _getservent_yp(line) 148 char *line; 149 { 150 static char *key = NULL; 151 static int keylen; 152 char *lastkey, *result; 153 int resultlen; 154 int rv; 155 156 if(!yp_domain) { 157 if(yp_get_default_domain(&yp_domain)) 158 return (0); 159 } 160 161 if (!serv_stepping_yp) { 162 if (key) 163 free(key); 164 if ((rv = yp_first(yp_domain, "services.byname", &key, &keylen, 165 &result, &resultlen))) { 166 serv_stepping_yp = 0; 167 return(0); 168 } 169 serv_stepping_yp = 1; 170 } else { 171 lastkey = key; 172 rv = yp_next(yp_domain, "services.byname", key, keylen, &key, 173 &keylen, &result, &resultlen); 174 free(lastkey); 175 if (rv) { 176 serv_stepping_yp = 0; 177 return (0); 178 } 179 } 180 181 /* getservent() expects lines terminated with \n -- make it happy */ 182 snprintf(line, BUFSIZ, "%.*s\n", resultlen, result); 183 184 free(result); 185 186 return(1); 187 } 188 #endif 189 190 void 191 setservent(f) 192 int f; 193 { 194 if (servf == NULL) 195 servf = fopen(_PATH_SERVICES, "r" ); 196 else 197 rewind(servf); 198 _serv_stayopen |= f; 199 } 200 201 void 202 endservent() 203 { 204 if (servf) { 205 fclose(servf); 206 servf = NULL; 207 } 208 _serv_stayopen = 0; 209 } 210 211 struct servent * 212 getservent() 213 { 214 char *p; 215 char *cp, **q; 216 217 #ifdef YP 218 if (serv_stepping_yp && _getservent_yp(line)) { 219 p = (char *)&line; 220 goto unpack; 221 } 222 tryagain: 223 #endif 224 if (servf == NULL && (servf = fopen(_PATH_SERVICES, "r" )) == NULL) 225 return (NULL); 226 again: 227 if ((p = fgets(line, BUFSIZ, servf)) == NULL) 228 return (NULL); 229 #ifdef YP 230 if (*p == '+' && _yp_check(NULL)) { 231 if (___getservbyname_yp != NULL) { 232 if (!_getservbyname_yp(line)) 233 goto tryagain; 234 } 235 else if (___getservbyport_yp != 0) { 236 if (!_getservbyport_yp(line)) 237 goto tryagain; 238 } 239 else if (!_getservent_yp(line)) 240 goto tryagain; 241 } 242 unpack: 243 #endif 244 if (*p == '#') 245 goto again; 246 cp = strpbrk(p, "#\n"); 247 if (cp == NULL) 248 goto again; 249 *cp = '\0'; 250 serv.s_name = p; 251 p = strpbrk(p, " \t"); 252 if (p == NULL) 253 goto again; 254 *p++ = '\0'; 255 while (*p == ' ' || *p == '\t') 256 p++; 257 cp = strpbrk(p, ",/"); 258 if (cp == NULL) 259 goto again; 260 *cp++ = '\0'; 261 serv.s_port = htons((u_short)atoi(p)); 262 serv.s_proto = cp; 263 q = serv.s_aliases = serv_aliases; 264 cp = strpbrk(cp, " \t"); 265 if (cp != NULL) 266 *cp++ = '\0'; 267 while (cp && *cp) { 268 if (*cp == ' ' || *cp == '\t') { 269 cp++; 270 continue; 271 } 272 if (q < &serv_aliases[MAXALIASES - 1]) 273 *q++ = cp; 274 cp = strpbrk(cp, " \t"); 275 if (cp != NULL) 276 *cp++ = '\0'; 277 } 278 *q = NULL; 279 return (&serv); 280 } 281