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 #ifdef YP 70 free(sed->yp_key); 71 sed->yp_key = NULL; 72 #endif 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", ntohs(sed->yp_port), 123 sed->yp_proto); 124 125 sed->yp_port = 0; 126 sed->yp_proto = 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, sizeof sed->line, "%.*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->yp_name, sed->yp_proto); 172 173 sed->yp_name = 0; 174 sed->yp_proto = NULL; 175 176 if (yp_match(sed->yp_domain, "services.byname", buf, strlen(buf), 177 &result, &resultlen)) { 178 return(0); 179 } 180 181 /* getservent() expects lines terminated with \n -- make it happy */ 182 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result); 183 184 free(result); 185 return(1); 186 } 187 188 static int 189 _getservent_yp(struct servent_data *sed) 190 { 191 char *lastkey, *result; 192 int resultlen; 193 int rv; 194 195 if (!sed->yp_domain) { 196 if (yp_get_default_domain(&sed->yp_domain)) 197 return (0); 198 } 199 200 if (!sed->yp_stepping) { 201 free(sed->yp_key); 202 rv = yp_first(sed->yp_domain, "services.byname", &sed->yp_key, 203 &sed->yp_keylen, &result, &resultlen); 204 if (rv) { 205 sed->yp_stepping = 0; 206 return(0); 207 } 208 sed->yp_stepping = 1; 209 } else { 210 lastkey = sed->yp_key; 211 rv = yp_next(sed->yp_domain, "services.byname", sed->yp_key, 212 sed->yp_keylen, &sed->yp_key, &sed->yp_keylen, &result, 213 &resultlen); 214 free(lastkey); 215 if (rv) { 216 sed->yp_stepping = 0; 217 return (0); 218 } 219 } 220 221 /* getservent() expects lines terminated with \n -- make it happy */ 222 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result); 223 224 free(result); 225 226 return(1); 227 } 228 #endif 229 230 void 231 setservent_r(int f, struct servent_data *sed) 232 { 233 if (sed->fp == NULL) 234 sed->fp = fopen(_PATH_SERVICES, "r"); 235 else 236 rewind(sed->fp); 237 sed->stayopen |= f; 238 } 239 240 void 241 endservent_r(struct servent_data *sed) 242 { 243 servent_data_clear(sed); 244 sed->stayopen = 0; 245 #ifdef YP 246 sed->yp_stepping = 0; 247 sed->yp_domain = NULL; 248 #endif 249 } 250 251 int 252 getservent_r(struct servent *se, struct servent_data *sed) 253 { 254 char *p; 255 char *cp, **q, *endp; 256 long l; 257 258 #ifdef YP 259 if (sed->yp_stepping && _getservent_yp(sed)) { 260 p = sed->line; 261 goto unpack; 262 } 263 tryagain: 264 #endif 265 if (sed->fp == NULL && (sed->fp = fopen(_PATH_SERVICES, "r")) == NULL) 266 return (-1); 267 again: 268 if ((p = fgets(sed->line, sizeof sed->line, sed->fp)) == NULL) 269 return (-1); 270 #ifdef YP 271 if (*p == '+' && _yp_check(NULL)) { 272 if (sed->yp_name != NULL) { 273 if (!_getservbyname_yp(sed)) 274 goto tryagain; 275 } 276 else if (sed->yp_port != 0) { 277 if (!_getservbyport_yp(sed)) 278 goto tryagain; 279 } 280 else if (!_getservent_yp(sed)) 281 goto tryagain; 282 } 283 unpack: 284 #endif 285 if (*p == '#') 286 goto again; 287 cp = strpbrk(p, "#\n"); 288 if (cp != NULL) 289 *cp = '\0'; 290 se->s_name = p; 291 p = strpbrk(p, " \t"); 292 if (p == NULL) 293 goto again; 294 *p++ = '\0'; 295 while (*p == ' ' || *p == '\t') 296 p++; 297 cp = strpbrk(p, ",/"); 298 if (cp == NULL) 299 goto again; 300 *cp++ = '\0'; 301 l = strtol(p, &endp, 10); 302 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX) 303 goto again; 304 se->s_port = htons((in_port_t)l); 305 se->s_proto = cp; 306 q = se->s_aliases = sed->aliases; 307 cp = strpbrk(cp, " \t"); 308 if (cp != NULL) 309 *cp++ = '\0'; 310 while (cp && *cp) { 311 if (*cp == ' ' || *cp == '\t') { 312 cp++; 313 continue; 314 } 315 if (q < &sed->aliases[_MAXALIASES - 1]) 316 *q++ = cp; 317 cp = strpbrk(cp, " \t"); 318 if (cp != NULL) 319 *cp++ = '\0'; 320 } 321 *q = NULL; 322 return (0); 323 } 324 325 void 326 setservent(int f) 327 { 328 struct servdata *sd; 329 330 if ((sd = __servdata_init()) == NULL) 331 return; 332 setservent_r(f, &sd->data); 333 } 334 335 void 336 endservent(void) 337 { 338 struct servdata *sd; 339 340 if ((sd = __servdata_init()) == NULL) 341 return; 342 endservent_r(&sd->data); 343 } 344 345 struct servent * 346 getservent(void) 347 { 348 struct servdata *sd; 349 350 if ((sd = __servdata_init()) == NULL) 351 return (NULL); 352 if (getservent_r(&sd->serv, &sd->data) != 0) 353 return (NULL); 354 return (&sd->serv); 355 } 356