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 #endif 52 #include "namespace.h" 53 #include "reentrant.h" 54 #include "un-namespace.h" 55 #include "netdb_private.h" 56 57 static struct servdata servdata; 58 static thread_key_t servdata_key; 59 static once_t servdata_init_once = ONCE_INITIALIZER; 60 static int servdata_thr_keycreated = 0; 61 62 static void 63 servent_data_clear(struct servent_data *sed) 64 { 65 if (sed->fp) { 66 fclose(sed->fp); 67 sed->fp = NULL; 68 } 69 if (sed->key) { 70 free(sed->key); 71 sed->key = NULL; 72 } 73 } 74 75 static void 76 servdata_free(void *ptr) 77 { 78 struct servdata *sd = ptr; 79 80 if (sd == NULL) 81 return; 82 servent_data_clear(&sd->data); 83 free(sd); 84 } 85 86 static void 87 servdata_keycreate(void) 88 { 89 servdata_thr_keycreated = 90 (thr_keycreate(&servdata_key, servdata_free) == 0); 91 } 92 93 struct servdata * 94 _servdata_init(void) 95 { 96 struct servdata *sd; 97 98 if (thr_main() != 0) 99 return (&servdata); 100 if (thr_once(&servdata_init_once, servdata_keycreate) != 0 || 101 !servdata_thr_keycreated) 102 return (NULL); 103 if ((sd = thr_getspecific(servdata_key)) != NULL) 104 return (sd); 105 if ((sd = calloc(1, sizeof(*sd))) == NULL) 106 return (NULL); 107 if (thr_setspecific(servdata_key, sd) == 0) 108 return (sd); 109 free(sd); 110 return (NULL); 111 } 112 113 #ifdef YP 114 static int 115 _getservbyport_yp(struct servent_data *sed) 116 { 117 char *result; 118 int resultlen; 119 char buf[YPMAXRECORD + 2]; 120 int rv; 121 122 snprintf(buf, sizeof(buf), "%d/%s", 123 ntohs(sed->getservbyport_yp), sed->getservbyproto_yp); 124 125 sed->getservbyport_yp = 0; 126 sed->getservbyproto_yp = NULL; 127 128 if (!sed->yp_domain) { 129 if (yp_get_default_domain(&sed->yp_domain)) 130 return (0); 131 } 132 133 /* 134 * We have to be a little flexible here. Ideally you're supposed 135 * to have both a services.byname and a services.byport map, but 136 * some systems have only services.byname. FreeBSD cheats a little 137 * by putting the services.byport information in the same map as 138 * services.byname so that either case will work. We allow for both 139 * possibilities here: if there is no services.byport map, we try 140 * services.byname instead. 141 */ 142 if ((rv = yp_match(sed->yp_domain, "services.byport", buf, strlen(buf), 143 &result, &resultlen))) { 144 if (rv == YPERR_MAP) { 145 if (yp_match(sed->yp_domain, "services.byname", buf, 146 strlen(buf), &result, &resultlen)) 147 return(0); 148 } else 149 return(0); 150 } 151 152 /* getservent() expects lines terminated with \n -- make it happy */ 153 snprintf(sed->line, BUFSIZ, "%.*s\n", resultlen, result); 154 155 free(result); 156 return(1); 157 } 158 159 static int 160 _getservbyname_yp(struct servent_data *sed) 161 { 162 char *result; 163 int resultlen; 164 char buf[YPMAXRECORD + 2]; 165 166 if(!sed->yp_domain) { 167 if(yp_get_default_domain(&sed->yp_domain)) 168 return (0); 169 } 170 171 snprintf(buf, sizeof(buf), "%s/%s", sed->getservbyname_yp, 172 sed->getservbyproto_yp); 173 174 sed->getservbyname_yp = 0; 175 sed->getservbyproto_yp = NULL; 176 177 if (yp_match(sed->yp_domain, "services.byname", buf, strlen(buf), 178 &result, &resultlen)) { 179 return(0); 180 } 181 182 /* getservent() expects lines terminated with \n -- make it happy */ 183 snprintf(sed->line, BUFSIZ, "%.*s\n", resultlen, result); 184 185 free(result); 186 return(1); 187 } 188 189 static int 190 _getservent_yp(struct servent_data *sed) 191 { 192 char *lastkey, *result; 193 int resultlen; 194 int rv; 195 196 if (!sed->yp_domain) { 197 if (yp_get_default_domain(&sed->yp_domain)) 198 return (0); 199 } 200 201 if (!sed->stepping_yp) { 202 if (sed->key) 203 free(sed->key); 204 rv = yp_first(sed->yp_domain, "services.byname", &sed->key, 205 &sed->keylen, &result, &resultlen); 206 if (rv) { 207 sed->stepping_yp = 0; 208 return(0); 209 } 210 sed->stepping_yp = 1; 211 } else { 212 lastkey = sed->key; 213 rv = yp_next(sed->yp_domain, "services.byname", sed->key, 214 sed->keylen, &sed->key, &sed->keylen, &result, &resultlen); 215 free(lastkey); 216 if (rv) { 217 sed->stepping_yp = 0; 218 return (0); 219 } 220 } 221 222 /* getservent() expects lines terminated with \n -- make it happy */ 223 snprintf(sed->line, BUFSIZ, "%.*s\n", resultlen, result); 224 225 free(result); 226 227 return(1); 228 } 229 #endif 230 231 void 232 setservent_r(int f, struct servent_data *sed) 233 { 234 if (sed->fp == NULL) 235 sed->fp = fopen(_PATH_SERVICES, "r"); 236 else 237 rewind(sed->fp); 238 sed->stayopen |= f; 239 } 240 241 void 242 endservent_r(struct servent_data *sed) 243 { 244 servent_data_clear(sed); 245 sed->stayopen = 0; 246 sed->stepping_yp = 0; 247 sed->yp_domain = NULL; 248 } 249 250 int 251 getservent_r(struct servent *se, struct servent_data *sed) 252 { 253 char *p; 254 char *cp, **q, *endp; 255 long l; 256 257 #ifdef YP 258 if (sed->stepping_yp && _getservent_yp(sed)) { 259 p = sed->line; 260 goto unpack; 261 } 262 tryagain: 263 #endif 264 if (sed->fp == NULL && (sed->fp = fopen(_PATH_SERVICES, "r")) == NULL) 265 return (-1); 266 again: 267 if ((p = fgets(sed->line, BUFSIZ, sed->fp)) == NULL) 268 return (-1); 269 #ifdef YP 270 if (*p == '+' && _yp_check(NULL)) { 271 if (sed->getservbyname_yp != NULL) { 272 if (!_getservbyname_yp(sed)) 273 goto tryagain; 274 } 275 else if (sed->getservbyport_yp != 0) { 276 if (!_getservbyport_yp(sed)) 277 goto tryagain; 278 } 279 else if (!_getservent_yp(sed)) 280 goto tryagain; 281 } 282 unpack: 283 #endif 284 if (*p == '#') 285 goto again; 286 cp = strpbrk(p, "#\n"); 287 if (cp != NULL) 288 *cp = '\0'; 289 se->s_name = p; 290 p = strpbrk(p, " \t"); 291 if (p == NULL) 292 goto again; 293 *p++ = '\0'; 294 while (*p == ' ' || *p == '\t') 295 p++; 296 cp = strpbrk(p, ",/"); 297 if (cp == NULL) 298 goto again; 299 *cp++ = '\0'; 300 l = strtol(p, &endp, 10); 301 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX) 302 goto again; 303 se->s_port = htons((in_port_t)l); 304 se->s_proto = cp; 305 q = se->s_aliases = sed->aliases; 306 cp = strpbrk(cp, " \t"); 307 if (cp != NULL) 308 *cp++ = '\0'; 309 while (cp && *cp) { 310 if (*cp == ' ' || *cp == '\t') { 311 cp++; 312 continue; 313 } 314 if (q < &sed->aliases[SERVENT_MAXALIASES - 1]) 315 *q++ = cp; 316 cp = strpbrk(cp, " \t"); 317 if (cp != NULL) 318 *cp++ = '\0'; 319 } 320 *q = NULL; 321 return (0); 322 } 323 324 void 325 setservent(int f) 326 { 327 struct servdata *sd; 328 329 if ((sd = _servdata_init()) == NULL) 330 return; 331 setservent_r(f, &sd->data); 332 } 333 334 void 335 endservent(void) 336 { 337 struct servdata *sd; 338 339 if ((sd = _servdata_init()) == NULL) 340 return; 341 endservent_r(&sd->data); 342 } 343 344 struct servent * 345 getservent(void) 346 { 347 struct servdata *sd; 348 349 if ((sd = _servdata_init()) == NULL) 350 return (NULL); 351 if (getservent_r(&sd->serv, &sd->data) != 0) 352 return (NULL); 353 return (&sd->serv); 354 } 355