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