1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * nis/getservent.c -- "nis" backend for nsswitch "services" database 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include "nis_common.h" 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <signal.h> 38 #include <malloc.h> 39 #include <netdb.h> 40 #include <synch.h> 41 #include <ctype.h> 42 #include <rpcsvc/ypclnt.h> 43 #include <thread.h> 44 #include <sys/types.h> 45 #include <netinet/in.h> 46 47 static int 48 check_name(args) 49 nss_XbyY_args_t *args; 50 { 51 struct servent *serv = (struct servent *)args->returnval; 52 const char *name = args->key.serv.serv.name; 53 const char *proto = args->key.serv.proto; 54 char **aliasp; 55 56 if (proto != 0 && strcmp(serv->s_proto, proto) != 0) { 57 return (0); 58 } 59 if (strcmp(serv->s_name, name) == 0) { 60 return (1); 61 } 62 for (aliasp = serv->s_aliases; *aliasp != 0; aliasp++) { 63 if (strcmp(*aliasp, name) == 0) { 64 return (1); 65 } 66 } 67 return (0); 68 } 69 70 static int 71 check_name2(nss_XbyY_args_t *argp) 72 { 73 const char *limit, *linep, *keyp; 74 int name_match = 0; 75 76 linep = (const char *)argp->buf.buffer; 77 limit = linep + strlen(argp->buf.buffer); 78 keyp = argp->key.serv.serv.name; 79 80 /* compare name */ 81 while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { 82 keyp++; 83 linep++; 84 } 85 if (*keyp == '\0' && linep < limit && isspace(*linep)) { 86 if (argp->key.serv.proto == NULL) 87 return (1); 88 else 89 name_match = 1; 90 } 91 92 /* skip remainder of the name, if any */ 93 while (linep < limit && !isspace(*linep)) 94 linep++; 95 /* skip the delimiting spaces */ 96 while (linep < limit && isspace(*linep)) 97 linep++; 98 /* skip port number */ 99 while (linep < limit && !isspace(*linep) && *linep != '/') 100 linep++; 101 if (linep == limit || *linep != '/') 102 return (0); 103 104 linep++; 105 if ((keyp = argp->key.serv.proto) == NULL) { 106 /* skip protocol */ 107 while (linep < limit && !isspace(*linep)) 108 linep++; 109 } else { 110 /* compare protocol */ 111 while (*keyp && linep < limit && !isspace(*linep) && 112 *keyp == *linep) { 113 keyp++; 114 linep++; 115 } 116 /* no protocol match */ 117 if (*keyp || (linep < limit && !isspace(*linep))) 118 return (0); 119 /* protocol and name match, return */ 120 if (name_match) 121 return (1); 122 /* protocol match but name yet to be matched, so continue */ 123 } 124 125 /* compare with the aliases */ 126 while (linep < limit) { 127 /* skip the delimiting spaces */ 128 while (linep < limit && isspace(*linep)) 129 linep++; 130 131 /* compare with the alias name */ 132 keyp = argp->key.serv.serv.name; 133 while (*keyp && linep < limit && !isspace(*linep) && 134 *keyp == *linep) { 135 keyp++; 136 linep++; 137 } 138 if (*keyp == '\0' && (linep == limit || isspace(*linep))) 139 return (1); 140 141 /* skip remainder of the alias name, if any */ 142 while (linep < limit && !isspace(*linep)) 143 linep++; 144 } 145 return (0); 146 } 147 148 static mutex_t no_byname_lock = DEFAULTMUTEX; 149 static int no_byname_map = 0; 150 151 static nss_status_t 152 getbyname(be, a) 153 nis_backend_ptr_t be; 154 void *a; 155 { 156 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 157 const char *name = argp->key.serv.serv.name; 158 const char *proto = argp->key.serv.proto; 159 int no_map; 160 sigset_t oldmask, newmask; 161 162 (void) sigfillset(&newmask); 163 (void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 164 (void) mutex_lock(&no_byname_lock); 165 no_map = no_byname_map; 166 (void) mutex_unlock(&no_byname_lock); 167 (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 168 169 if (no_map == 0) { 170 int yp_status; 171 nss_status_t res; 172 173 if (proto == 0) { 174 res = _nss_nis_lookup(be, argp, 1, 175 "services.byservicename", name, &yp_status); 176 } else { 177 int len = strlen(name) + strlen(proto) + 3; 178 char *key = malloc(len); 179 180 if (key == NULL) { 181 return (NSS_UNAVAIL); 182 } 183 (void) snprintf(key, len, "%s/%s", name, proto); 184 res = _nss_nis_lookup(be, argp, 1, 185 "services.byservicename", key, &yp_status); 186 free(key); 187 } 188 189 if (yp_status == YPERR_MAP) { 190 (void) sigfillset(&newmask); 191 (void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 192 (void) mutex_lock(&no_byname_lock); 193 no_byname_map = 1; 194 (void) mutex_unlock(&no_byname_lock); 195 (void) thr_sigsetmask(SIG_SETMASK, &oldmask, 196 (sigset_t *)NULL); 197 } else /* if (res == NSS_SUCCESS) <==== */ { 198 return (res); 199 } 200 } 201 202 /* 203 * use check_anme to compare service name if nss1 or nss2 and 204 * request is not from nscd; otherwise use check_name2 205 */ 206 if (argp->buf.result != NULL) 207 return (_nss_nis_XY_all(be, argp, 1, name, check_name)); 208 else 209 return (_nss_nis_XY_all(be, argp, 1, name, check_name2)); 210 } 211 212 static int 213 check_port(args) 214 nss_XbyY_args_t *args; 215 { 216 struct servent *serv = (struct servent *)args->returnval; 217 218 /* 219 * We only resorted to _nss_nis_XY_all because proto == 0, so just... 220 */ 221 return (serv->s_port == args->key.serv.serv.port); 222 } 223 224 static int 225 check_port2(nss_XbyY_args_t *argp) 226 { 227 const char *limit, *linep, *keyp, *numstart; 228 int numlen, s_port; 229 char numbuf[12], *numend; 230 231 linep = (const char *)argp->buf.buffer; 232 limit = linep + strlen(argp->buf.buffer); 233 234 /* skip name */ 235 while (linep < limit && !isspace(*linep)) 236 linep++; 237 /* skip the delimiting spaces */ 238 while (linep < limit && isspace(*linep)) 239 linep++; 240 241 /* compare port num */ 242 numstart = linep; 243 while (linep < limit && !isspace(*linep) && *linep != '/') 244 linep++; 245 if (linep == limit || *linep != '/') 246 return (0); 247 numlen = linep - numstart; 248 if (numlen == 0 || numlen >= sizeof (numbuf)) 249 return (0); 250 (void) memcpy(numbuf, numstart, numlen); 251 numbuf[numlen] = '\0'; 252 s_port = htons((int)strtol(numbuf, &numend, 10)); 253 if (*numend != '\0') 254 return (0); 255 if (s_port == argp->key.serv.serv.port) { 256 if ((keyp = argp->key.serv.proto) == NULL) 257 return (1); 258 } else 259 return (0); 260 261 /* compare protocol */ 262 linep++; 263 while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { 264 keyp++; 265 linep++; 266 } 267 return (*keyp == '\0' && (linep == limit || isspace(*linep))); 268 } 269 270 271 static nss_status_t 272 getbyport(be, a) 273 nis_backend_ptr_t be; 274 void *a; 275 { 276 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 277 int port = ntohs(argp->key.serv.serv.port); 278 const char *proto = argp->key.serv.proto; 279 char *key; 280 nss_status_t res; 281 int len; 282 283 if (proto == 0) { 284 char portstr[12]; 285 286 (void) snprintf(portstr, 12, "%d", port); 287 /* 288 * use check_port to compare service port if nss1 or 289 * nss2 and request is not from nscd; otherwise use 290 * check_port2 291 */ 292 if (argp->buf.result != NULL) 293 return (_nss_nis_XY_all(be, argp, 1, portstr, 294 check_port)); 295 else 296 return (_nss_nis_XY_all(be, argp, 1, portstr, 297 check_port2)); 298 } 299 300 len = strlen(proto) + 14; 301 if ((key = malloc(len)) == 0) { 302 return (NSS_UNAVAIL); 303 } 304 (void) snprintf(key, len, "%d/%s", port, proto); 305 306 res = _nss_nis_lookup(be, argp, 1, "services.byname", key, 0); 307 308 free(key); 309 return (res); 310 } 311 312 static nis_backend_op_t serv_ops[] = { 313 _nss_nis_destr, 314 _nss_nis_endent, 315 _nss_nis_setent, 316 _nss_nis_getent_netdb, 317 getbyname, 318 getbyport 319 }; 320 321 /*ARGSUSED*/ 322 nss_backend_t * 323 _nss_nis_services_constr(dummy1, dummy2, dummy3) 324 const char *dummy1, *dummy2, *dummy3; 325 { 326 return (_nss_nis_constr(serv_ops, 327 sizeof (serv_ops) / sizeof (serv_ops[0]), 328 "services.byname")); 329 } 330