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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <exec_attr.h>
30 #include <rpcsvc/ypclnt.h>
31 #include <rpcsvc/yp_prot.h>
32 #include "nis_common.h"
33
34
35 /* extern from nis_common.c */
36 extern void massage_netdb(const char **, int *);
37 /* externs from libnsl */
38 extern int _doexeclist(nss_XbyY_args_t *);
39 extern char *_exec_wild_id(char *, const char *);
40 extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *);
41 extern char *_strtok_escape(char *, char *, char **);
42
43 typedef struct __exec_nis_args {
44 int *yp_status;
45 nss_XbyY_args_t *argp;
46 } _exec_nis_args;
47
48
49 /*
50 * check_match: returns 1 if - matching entry found and no more entries needed,
51 * or, entry cannot be found because of error;
52 * returns 0 if - no matching entry found, or,
53 * matching entry found and next match needed.
54 */
55 static int
check_match(nss_XbyY_args_t * argp,int check_policy)56 check_match(nss_XbyY_args_t *argp, int check_policy)
57 {
58 execstr_t *exec = (execstr_t *)(argp->returnval);
59 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
60 const char *name = _priv_exec->name;
61 const char *type = _priv_exec->type;
62 const char *id = _priv_exec->id;
63 const char *policy = _priv_exec->policy;
64
65 if (name && id) {
66 /*
67 * NSS_DBOP_EXECATTR_BYNAMEID searched for name and id in
68 * _exec_nis_lookup already.
69 * If we're talking to pre-Solaris9 nis servers, check policy,
70 * as policy was not a searchable column then.
71 */
72 if ((check_policy && policy &&
73 (strcmp(policy, exec->policy) != 0)) ||
74 (type && (strcmp(type, exec->type) != 0))) {
75 return (0);
76 }
77 } else if ((policy && exec->policy &&
78 (strcmp(policy, exec->policy) != 0)) ||
79 (name && exec->name && (strcmp(name, exec->name) != 0)) ||
80 (type && exec->type && (strcmp(type, exec->type) != 0)) ||
81 (id && exec->id && (strcmp(id, exec->id) != 0))) {
82 return (0);
83 }
84
85 return (1);
86 }
87
88 /*
89 * check_match_strbuf: set up the data needed by check_match()
90 * and call it to match exec_attr data in strbuf and argp->key.attrp
91 */
92 static int
check_match_strbuf(nss_XbyY_args_t * argp,char * strbuf,int check_policy)93 check_match_strbuf(nss_XbyY_args_t *argp, char *strbuf, int check_policy)
94 {
95 char *last = NULL;
96 char *sep = KV_TOKEN_DELIMIT;
97 execstr_t exec;
98 execstr_t *execp = &exec;
99 void *sp;
100 int rc;
101
102 /*
103 * Remove newline that yp_match puts at the
104 * end of the entry it retrieves from the map.
105 */
106 if (strbuf[argp->returnlen] == '\n') {
107 strbuf[argp->returnlen] = '\0';
108 }
109
110 execp->name = _strtok_escape(strbuf, sep, &last);
111 execp->policy = _strtok_escape(NULL, sep, &last);
112 execp->type = _strtok_escape(NULL, sep, &last);
113 execp->res1 = _strtok_escape(NULL, sep, &last);
114 execp->res2 = _strtok_escape(NULL, sep, &last);
115 execp->id = _strtok_escape(NULL, sep, &last);
116
117 sp = argp->returnval;
118 argp->returnval = execp;
119 rc = check_match(argp, check_policy);
120 argp->returnval = sp;
121 free(strbuf);
122
123 return (rc);
124 }
125
126 static nss_status_t
_exec_nis_parse(const char * instr,int instr_len,nss_XbyY_args_t * argp,int check_policy)127 _exec_nis_parse(const char *instr,
128 int instr_len,
129 nss_XbyY_args_t *argp,
130 int check_policy)
131 {
132 int parse_stat;
133 nss_status_t res;
134 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
135 char *strbuf;
136 int check_matched;
137
138 argp->returnval = NULL;
139 argp->returnlen = 0;
140 parse_stat = (*argp->str2ent)(instr, instr_len, argp->buf.result,
141 argp->buf.buffer, argp->buf.buflen);
142 switch (parse_stat) {
143 case NSS_STR_PARSE_SUCCESS:
144 argp->returnlen = instr_len;
145 /* if exec_attr file format requested */
146 if (argp->buf.result == NULL) {
147 argp->returnval = argp->buf.buffer;
148 if ((strbuf = strdup(instr)) == NULL)
149 res = NSS_UNAVAIL;
150 check_matched = check_match_strbuf(argp,
151 strbuf, check_policy);
152 } else {
153 argp->returnval = argp->buf.result;
154 check_matched = check_match(argp, check_policy);
155 }
156 if (check_matched) {
157 res = NSS_SUCCESS;
158 if (IS_GET_ALL(_priv_exec->search_flag)) {
159 if (_doexeclist(argp) == 0) {
160 res = NSS_UNAVAIL;
161 }
162 }
163 } else {
164 res = NSS_NOTFOUND;
165 }
166 break;
167 case NSS_STR_PARSE_ERANGE:
168 argp->erange = 1;
169 res = NSS_NOTFOUND;
170 break;
171 default:
172 res = NSS_UNAVAIL;
173 break;
174 }
175
176 return (res);
177 }
178
179 /*
180 * This is the callback for yp_all. It returns 0 to indicate that it wants to
181 * be called again for further key-value pairs, or returns non-zero to stop the
182 * flow of key-value pairs. If it returns a non-zero value, it is not called
183 * again. The functional value of yp_all is then 0.
184 */
185 /*ARGSUSED*/
186 static int
_exec_nis_cb(int instatus,char * inkey,int inkeylen,char * inval,int invallen,void * indata)187 _exec_nis_cb(int instatus,
188 char *inkey,
189 int inkeylen,
190 char *inval,
191 int invallen,
192 void *indata)
193 {
194 int check_policy = 1; /* always check policy for yp_all */
195 int stop_cb;
196 const char *filter;
197 nss_status_t res;
198 _exec_nis_args *eargp = (_exec_nis_args *)indata;
199 nss_XbyY_args_t *argp = eargp->argp;
200 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
201
202 if (instatus != YP_TRUE) {
203 /*
204 * If we have no more data to look at, we want to
205 * keep yp_status from previous key/value pair
206 * that we processed.
207 * If this is the 1st time we enter this callback,
208 * yp_status is already set to YPERR_YPERR
209 * (see _exec_nis_lookup() for when this callback
210 * and arguments are set initially).
211 */
212 if (instatus != YP_NOMORE) {
213 *(eargp->yp_status) = YPERR_YPERR;
214 }
215 return (0); /* yp_all may decide otherwise... */
216 }
217
218 filter = (_priv_exec->name) ? _priv_exec->name : _priv_exec->id;
219
220 /*
221 * yp_all does not null terminate the entry it retrieves from the
222 * map, unlike yp_match. so we do it explicitly here.
223 */
224 inval[invallen] = '\0';
225
226 /*
227 * Optimization: if the entry doesn't contain the filter string then
228 * it can't be the entry we want, so don't bother looking more closely
229 * at it.
230 */
231 if ((_priv_exec->policy &&
232 (strstr(inval, _priv_exec->policy) == NULL)) ||
233 (strstr(inval, filter) == NULL)) {
234 *(eargp->yp_status) = YPERR_KEY;
235 return (0);
236 }
237
238 res = _exec_nis_parse(inval, invallen, argp, check_policy);
239
240 switch (res) {
241 case NSS_SUCCESS:
242 *(eargp->yp_status) = 0;
243 stop_cb = IS_GET_ONE(_priv_exec->search_flag);
244 break;
245 case NSS_UNAVAIL:
246 *(eargp->yp_status) = YPERR_KEY;
247 stop_cb = 1;
248 break;
249 default:
250 *(eargp->yp_status) = YPERR_YPERR;
251 stop_cb = 0;
252 break;
253 }
254
255 return (stop_cb);
256 }
257
258 static nss_status_t
_exec_nis_lookup(nis_backend_ptr_t be,nss_XbyY_args_t * argp,int getby_flag)259 _exec_nis_lookup(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
260 {
261 int ypstatus;
262 nss_status_t res = NSS_SUCCESS;
263 nss_status_t ypres;
264 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
265
266 if (getby_flag == NSS_DBOP_EXECATTR_BYNAMEID) {
267 int check_policy = 0;
268 int vallen;
269 char *val;
270 char key[MAX_INPUT];
271
272 /*
273 * Try using policy as part of search key. If that fails,
274 * (it will, in case of pre-Solaris9 nis server where policy
275 * was not searchable), try again without using policy.
276 */
277 if (snprintf(key, MAX_INPUT, "%s%s%s%s%s", _priv_exec->name,
278 KV_TOKEN_DELIMIT, _priv_exec->policy, KV_TOKEN_DELIMIT,
279 _priv_exec->id) >= MAX_INPUT)
280 return (NSS_NOTFOUND);
281 do {
282 ypres = _nss_nis_ypmatch(be->domain, NIS_MAP_EXECATTR,
283 key, &val, &vallen, &ypstatus);
284 if ((check_policy == 0) && (ypstatus == YPERR_KEY)) {
285 (void) snprintf(key, MAX_INPUT, "%s%s%s",
286 _priv_exec->name, KV_TOKEN_DELIMIT,
287 _priv_exec->id);
288 check_policy = 1;
289 continue;
290 } else if (ypres != NSS_SUCCESS) {
291 res = ypres;
292 break;
293 } else {
294 char *val_save = val;
295
296 massage_netdb((const char **)&val, &vallen);
297 res = _exec_nis_parse((const char *)val,
298 vallen, argp, check_policy);
299 free(val_save);
300 break;
301 }
302 } while (res == NSS_SUCCESS);
303 } else {
304 int ypstat = YPERR_YPERR;
305 struct ypall_callback cback;
306 _exec_nis_args eargs;
307
308 eargs.yp_status = &ypstat;
309 eargs.argp = argp;
310
311 cback.foreach = _exec_nis_cb;
312 cback.data = (void *)&eargs;
313
314 /*
315 * Instead of calling yp_all() doing hard lookup, we use
316 * the alternative function, __yp_all_cflookup(), to
317 * perform soft lookup when binding to nis servers with
318 * time-out control. Other than that, these two functions
319 * do exactly the same thing.
320 */
321 ypstatus = __yp_all_cflookup((char *)(be->domain),
322 (char *)(be->enum_map), &cback, 0);
323
324 /*
325 * For GET_ALL, check if we found anything at all.
326 */
327 if (_priv_exec->head_exec != NULL)
328 return (NSS_SUCCESS);
329
330 switch (ypstat) {
331 case 0:
332 res = NSS_SUCCESS;
333 break;
334 case YPERR_BUSY:
335 res = NSS_TRYAGAIN;
336 break;
337 case YPERR_KEY:
338 /*
339 * If no such key, return NSS_NOTFOUND
340 * as this looks more relevant; it will
341 * also help libnsl to try with another
342 * policy (see _getexecprof()).
343 */
344 res = NSS_NOTFOUND;
345 break;
346 default:
347 res = NSS_UNAVAIL;
348 break;
349 }
350
351 }
352
353 return (res);
354 }
355
356 /*
357 * If search for exact match for id failed, get_wild checks if we have
358 * a wild-card entry for that id.
359 */
360 static nss_status_t
get_wild(nis_backend_ptr_t be,nss_XbyY_args_t * argp,int getby_flag)361 get_wild(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
362 {
363 const char *orig_id;
364 char *old_id = NULL;
365 char *wild_id = NULL;
366 nss_status_t res = NSS_NOTFOUND;
367 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
368
369 orig_id = _priv_exec->id;
370 old_id = strdup(_priv_exec->id);
371 wild_id = old_id;
372 while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) {
373 _priv_exec->id = wild_id;
374 res = _exec_nis_lookup(be, argp, getby_flag);
375 if (res == NSS_SUCCESS)
376 break;
377 }
378 _priv_exec->id = orig_id;
379 if (old_id)
380 free(old_id);
381
382 return (res);
383 }
384
385
386 static nss_status_t
getbynam(nis_backend_ptr_t be,void * a)387 getbynam(nis_backend_ptr_t be, void *a)
388 {
389 nss_status_t res;
390 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
391
392 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAME);
393
394 _exec_cleanup(res, argp);
395
396 return (res);
397 }
398
399 static nss_status_t
getbyid(nis_backend_ptr_t be,void * a)400 getbyid(nis_backend_ptr_t be, void *a)
401 {
402 nss_status_t res;
403 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
404 /*LINTED*/
405 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
406
407 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYID);
408
409 if (res != NSS_SUCCESS)
410 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID);
411
412 _exec_cleanup(res, argp);
413
414 return (res);
415 }
416
417
418 static nss_status_t
getbynameid(nis_backend_ptr_t be,void * a)419 getbynameid(nis_backend_ptr_t be, void *a)
420 {
421 nss_status_t res;
422 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
423 /*LINTED*/
424 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
425
426 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
427
428 if (res != NSS_SUCCESS)
429 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
430
431 _exec_cleanup(res, argp);
432
433 return (res);
434 }
435
436
437 static nis_backend_op_t execattr_ops[] = {
438 _nss_nis_destr,
439 _nss_nis_endent,
440 _nss_nis_setent,
441 _nss_nis_getent_netdb,
442 getbynam,
443 getbyid,
444 getbynameid
445 };
446
447 /*ARGSUSED*/
448 nss_backend_t *
_nss_nis_exec_attr_constr(const char * dummy1,const char * dummy2,const char * dummy3,const char * dummy4,const char * dummy5,const char * dummy6,const char * dummy7)449 _nss_nis_exec_attr_constr(const char *dummy1,
450 const char *dummy2,
451 const char *dummy3,
452 const char *dummy4,
453 const char *dummy5,
454 const char *dummy6,
455 const char *dummy7)
456 {
457 return (_nss_nis_constr(execattr_ops,
458 sizeof (execattr_ops)/sizeof (execattr_ops[0]),
459 NIS_MAP_EXECATTR));
460 }
461