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/param.h> 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <arpa/inet.h> 44 #include <errno.h> 45 #include <limits.h> 46 #include <netdb.h> 47 #include <stdio.h> 48 #include <string.h> 49 #include <stdlib.h> 50 #ifdef YP 51 #include <rpc/rpc.h> 52 #include <rpcsvc/yp_prot.h> 53 #include <rpcsvc/ypclnt.h> 54 #endif 55 #include "namespace.h" 56 #include "reentrant.h" 57 #include "un-namespace.h" 58 #include "netdb_private.h" 59 60 NETDB_THREAD_ALLOC(servent_data) 61 NETDB_THREAD_ALLOC(servdata) 62 63 static void 64 servent_data_clear(struct servent_data *sed) 65 { 66 if (sed->fp) { 67 fclose(sed->fp); 68 sed->fp = NULL; 69 } 70 #ifdef YP 71 free(sed->yp_key); 72 sed->yp_key = NULL; 73 #endif 74 } 75 76 static void 77 servent_data_free(void *ptr) 78 { 79 struct servent_data *sed = ptr; 80 81 servent_data_clear(sed); 82 free(sed); 83 } 84 85 static void 86 servdata_free(void *ptr) 87 { 88 free(ptr); 89 } 90 91 int 92 __copy_servent(struct servent *se, struct servent *sptr, char *buf, 93 size_t buflen) 94 { 95 char *cp; 96 int i, n; 97 int numptr, len; 98 99 /* Find out the amount of space required to store the answer. */ 100 numptr = 1; /* NULL ptr */ 101 len = (char *)ALIGN(buf) - buf; 102 for (i = 0; se->s_aliases[i]; i++, numptr++) { 103 len += strlen(se->s_aliases[i]) + 1; 104 } 105 len += strlen(se->s_name) + 1; 106 len += strlen(se->s_proto) + 1; 107 len += numptr * sizeof(char*); 108 109 if (len > (int)buflen) { 110 errno = ERANGE; 111 return (-1); 112 } 113 114 /* copy port value */ 115 sptr->s_port = se->s_port; 116 117 cp = (char *)ALIGN(buf) + numptr * sizeof(char *); 118 119 /* copy official name */ 120 n = strlen(se->s_name) + 1; 121 strcpy(cp, se->s_name); 122 sptr->s_name = cp; 123 cp += n; 124 125 /* copy aliases */ 126 sptr->s_aliases = (char **)ALIGN(buf); 127 for (i = 0 ; se->s_aliases[i]; i++) { 128 n = strlen(se->s_aliases[i]) + 1; 129 strcpy(cp, se->s_aliases[i]); 130 sptr->s_aliases[i] = cp; 131 cp += n; 132 } 133 sptr->s_aliases[i] = NULL; 134 135 /* copy proto */ 136 n = strlen(se->s_proto) + 1; 137 strcpy(cp, se->s_proto); 138 sptr->s_proto = cp; 139 cp += n; 140 141 return (0); 142 } 143 144 #ifdef YP 145 static int 146 _getservbyport_yp(struct servent_data *sed) 147 { 148 char *result; 149 int resultlen; 150 char buf[YPMAXRECORD + 2]; 151 int rv; 152 153 snprintf(buf, sizeof(buf), "%d/%s", ntohs(sed->yp_port), 154 sed->yp_proto); 155 156 sed->yp_port = 0; 157 sed->yp_proto = NULL; 158 159 if (!sed->yp_domain) { 160 if (yp_get_default_domain(&sed->yp_domain)) 161 return (0); 162 } 163 164 /* 165 * We have to be a little flexible here. Ideally you're supposed 166 * to have both a services.byname and a services.byport map, but 167 * some systems have only services.byname. FreeBSD cheats a little 168 * by putting the services.byport information in the same map as 169 * services.byname so that either case will work. We allow for both 170 * possibilities here: if there is no services.byport map, we try 171 * services.byname instead. 172 */ 173 if ((rv = yp_match(sed->yp_domain, "services.byport", buf, strlen(buf), 174 &result, &resultlen))) { 175 if (rv == YPERR_MAP) { 176 if (yp_match(sed->yp_domain, "services.byname", buf, 177 strlen(buf), &result, &resultlen)) 178 return(0); 179 } else 180 return(0); 181 } 182 183 /* getservent() expects lines terminated with \n -- make it happy */ 184 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result); 185 186 free(result); 187 return(1); 188 } 189 190 static int 191 _getservbyname_yp(struct servent_data *sed) 192 { 193 char *result; 194 int resultlen; 195 char buf[YPMAXRECORD + 2]; 196 197 if(!sed->yp_domain) { 198 if(yp_get_default_domain(&sed->yp_domain)) 199 return (0); 200 } 201 202 snprintf(buf, sizeof(buf), "%s/%s", sed->yp_name, sed->yp_proto); 203 204 sed->yp_name = 0; 205 sed->yp_proto = NULL; 206 207 if (yp_match(sed->yp_domain, "services.byname", buf, strlen(buf), 208 &result, &resultlen)) { 209 return(0); 210 } 211 212 /* getservent() expects lines terminated with \n -- make it happy */ 213 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result); 214 215 free(result); 216 return(1); 217 } 218 219 static int 220 _getservent_yp(struct servent_data *sed) 221 { 222 char *lastkey, *result; 223 int resultlen; 224 int rv; 225 226 if (!sed->yp_domain) { 227 if (yp_get_default_domain(&sed->yp_domain)) 228 return (0); 229 } 230 231 if (!sed->yp_stepping) { 232 free(sed->yp_key); 233 rv = yp_first(sed->yp_domain, "services.byname", &sed->yp_key, 234 &sed->yp_keylen, &result, &resultlen); 235 if (rv) { 236 sed->yp_stepping = 0; 237 return(0); 238 } 239 sed->yp_stepping = 1; 240 } else { 241 lastkey = sed->yp_key; 242 rv = yp_next(sed->yp_domain, "services.byname", sed->yp_key, 243 sed->yp_keylen, &sed->yp_key, &sed->yp_keylen, &result, 244 &resultlen); 245 free(lastkey); 246 if (rv) { 247 sed->yp_stepping = 0; 248 return (0); 249 } 250 } 251 252 /* getservent() expects lines terminated with \n -- make it happy */ 253 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result); 254 255 free(result); 256 257 return(1); 258 } 259 #endif 260 261 void 262 __setservent_p(int f, struct servent_data *sed) 263 { 264 if (sed->fp == NULL) 265 sed->fp = fopen(_PATH_SERVICES, "r"); 266 else 267 rewind(sed->fp); 268 sed->stayopen |= f; 269 } 270 271 void 272 __endservent_p(struct servent_data *sed) 273 { 274 servent_data_clear(sed); 275 sed->stayopen = 0; 276 #ifdef YP 277 sed->yp_stepping = 0; 278 sed->yp_domain = NULL; 279 #endif 280 } 281 282 int 283 __getservent_p(struct servent *se, struct servent_data *sed) 284 { 285 char *p; 286 char *cp, **q, *endp; 287 long l; 288 289 #ifdef YP 290 if (sed->yp_stepping && _getservent_yp(sed)) { 291 p = sed->line; 292 goto unpack; 293 } 294 tryagain: 295 #endif 296 if (sed->fp == NULL && (sed->fp = fopen(_PATH_SERVICES, "r")) == NULL) 297 return (-1); 298 again: 299 if ((p = fgets(sed->line, sizeof sed->line, sed->fp)) == NULL) 300 return (-1); 301 #ifdef YP 302 if (*p == '+' && _yp_check(NULL)) { 303 if (sed->yp_name != NULL) { 304 if (!_getservbyname_yp(sed)) 305 goto tryagain; 306 } 307 else if (sed->yp_port != 0) { 308 if (!_getservbyport_yp(sed)) 309 goto tryagain; 310 } 311 else if (!_getservent_yp(sed)) 312 goto tryagain; 313 } 314 unpack: 315 #endif 316 if (*p == '#') 317 goto again; 318 cp = strpbrk(p, "#\n"); 319 if (cp != NULL) 320 *cp = '\0'; 321 se->s_name = p; 322 p = strpbrk(p, " \t"); 323 if (p == NULL) 324 goto again; 325 *p++ = '\0'; 326 while (*p == ' ' || *p == '\t') 327 p++; 328 cp = strpbrk(p, ",/"); 329 if (cp == NULL) 330 goto again; 331 *cp++ = '\0'; 332 l = strtol(p, &endp, 10); 333 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX) 334 goto again; 335 se->s_port = htons((in_port_t)l); 336 se->s_proto = cp; 337 q = se->s_aliases = sed->aliases; 338 cp = strpbrk(cp, " \t"); 339 if (cp != NULL) 340 *cp++ = '\0'; 341 while (cp && *cp) { 342 if (*cp == ' ' || *cp == '\t') { 343 cp++; 344 continue; 345 } 346 if (q < &sed->aliases[_MAXALIASES - 1]) 347 *q++ = cp; 348 cp = strpbrk(cp, " \t"); 349 if (cp != NULL) 350 *cp++ = '\0'; 351 } 352 *q = NULL; 353 return (0); 354 } 355 356 int 357 getservent_r(struct servent *sptr, char *buffer, size_t buflen, 358 struct servent **result) 359 { 360 struct servent se; 361 struct servent_data *sed; 362 363 if ((sed = __servent_data_init()) == NULL) 364 return (-1); 365 366 if (__getservent_p(&se, sed) != 0) 367 return (-1); 368 if (__copy_servent(&se, sptr, buffer, buflen) != 0) 369 return (-1); 370 *result = sptr; 371 return (0); 372 } 373 374 void 375 setservent(int f) 376 { 377 struct servent_data *sed; 378 379 if ((sed = __servent_data_init()) == NULL) 380 return; 381 __setservent_p(f, sed); 382 } 383 384 void 385 endservent(void) 386 { 387 struct servent_data *sed; 388 389 if ((sed = __servent_data_init()) == NULL) 390 return; 391 __endservent_p(sed); 392 } 393 394 struct servent * 395 getservent(void) 396 { 397 struct servdata *sd; 398 struct servent *rval; 399 400 if ((sd = __servdata_init()) == NULL) 401 return (NULL); 402 if (getservent_r(&sd->serv, sd->data, sizeof(sd->data), &rval) != 0) 403 return (NULL); 404 return (rval); 405 } 406