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