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
check_name(args)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
check_name2(nss_XbyY_args_t * argp)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
getbyname(be,a)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
check_port(args)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
check_port2(nss_XbyY_args_t * argp)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
getbyport(be,a)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 *
_nss_nis_services_constr(dummy1,dummy2,dummy3)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