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 <secdb.h>
27 #include <exec_attr.h>
28 #include "ldap_common.h"
29
30
31 /* exec_attr attributes filters */
32 #define ISWILD(x) (x == NULL) ? "*" : x
33 #define _EXEC_NAME "cn"
34 #define _EXEC_POLICY "SolarisKernelSecurityPolicy"
35 #define _EXEC_TYPE "SolarisProfileType"
36 #define _EXEC_RES1 "SolarisAttrRes1"
37 #define _EXEC_RES2 "SolarisAttrRes2"
38 #define _EXEC_ID "SolarisProfileId"
39 #define _EXEC_ATTRS "SolarisAttrKeyValue"
40 #define _EXEC_GETEXECNAME "(&(objectClass=SolarisExecAttr)(cn=%s)"\
41 "(SolarisKernelSecurityPolicy=%s)"\
42 "(SolarisProfileType=%s))"
43 #define _EXEC_GETEXECNAME_SSD "(&(%%s)(cn=%s)"\
44 "(SolarisKernelSecurityPolicy=%s)"\
45 "(SolarisProfileType=%s))"
46 #define _EXEC_GETEXECID "(&(objectClass=SolarisExecAttr)"\
47 "(SolarisProfileId=%s)"\
48 "(SolarisKernelSecurityPolicy=%s)"\
49 "(SolarisProfileType=%s))"
50 #define _EXEC_GETEXECID_SSD "(&(%%s)"\
51 "(SolarisProfileId=%s)"\
52 "(SolarisKernelSecurityPolicy=%s)"\
53 "(SolarisProfileType=%s))"
54 #define _EXEC_GETEXECNAMEID "(&(objectClass=SolarisExecAttr)(cn=%s)"\
55 "(SolarisProfileId=%s)"\
56 "(SolarisKernelSecurityPolicy=%s)"\
57 "(SolarisProfileType=%s))"
58 #define _EXEC_GETEXECNAMEID_SSD "(&(%%s)(cn=%s)"\
59 "(SolarisProfileId=%s)"\
60 "(SolarisKernelSecurityPolicy=%s)"\
61 "(SolarisProfileType=%s))"
62
63
64 /* from libnsl */
65 extern int _doexeclist(nss_XbyY_args_t *);
66 extern char *_exec_wild_id(char *, const char *);
67 extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *);
68
69
70 static const char *exec_attrs[] = {
71 _EXEC_NAME,
72 _EXEC_POLICY,
73 _EXEC_TYPE,
74 _EXEC_RES1,
75 _EXEC_RES2,
76 _EXEC_ID,
77 _EXEC_ATTRS,
78 (char *)NULL
79 };
80
81
82 #ifdef DEBUG
83 static void
_print_execstr(execstr_t * exec)84 _print_execstr(execstr_t *exec)
85 {
86
87 (void) fprintf(stdout, " exec-name: [%s]\n", exec->name);
88 if (exec->policy != (char *)NULL) {
89 (void) fprintf(stdout, " policy: [%s]\n", exec->policy);
90 }
91 if (exec->type != (char *)NULL) {
92 (void) fprintf(stdout, " type: [%s]\n", exec->type);
93 }
94 if (exec->res1 != (char *)NULL) {
95 (void) fprintf(stdout, " res1: [%s]\n", exec->res1);
96 }
97 if (exec->res2 != (char *)NULL) {
98 (void) fprintf(stdout, " res2: [%s]\n", exec->res2);
99 }
100 if (exec->id != (char *)NULL) {
101 (void) fprintf(stdout, " id: [%s]\n", exec->id);
102 }
103 if (exec->attr != (char *)NULL) {
104 (void) fprintf(stdout, " attr: [%s]\n", exec->attr);
105 }
106 if (exec->next != (execstr_t *)NULL) {
107 (void) fprintf(stdout, " next: [%s]\n", exec->next->name);
108 (void) fprintf(stdout, "\n");
109 _print_execstr(exec->next);
110 }
111 }
112 #endif /* DEBUG */
113
114
115 static int
_exec_ldap_exec2ent(ns_ldap_entry_t * entry,nss_XbyY_args_t * argp)116 _exec_ldap_exec2ent(ns_ldap_entry_t *entry, nss_XbyY_args_t *argp)
117 {
118
119 int i;
120 unsigned long len = 0L;
121 int buflen = (int)0;
122 char *nullstring = (char *)NULL;
123 char *buffer = (char *)NULL;
124 char *ceiling = (char *)NULL;
125 execstr_t *exec = (execstr_t *)NULL;
126 ns_ldap_attr_t *attrptr;
127
128 buffer = argp->buf.buffer;
129 buflen = (size_t)argp->buf.buflen;
130 (void) memset(argp->buf.buffer, 0, buflen);
131 exec = (execstr_t *)(argp->buf.result);
132 ceiling = buffer + buflen;
133 exec->name = (char *)NULL;
134 exec->policy = (char *)NULL;
135 exec->type = (char *)NULL;
136 exec->res1 = (char *)NULL;
137 exec->res2 = (char *)NULL;
138 exec->id = (char *)NULL;
139 exec->attr = (char *)NULL;
140
141 for (i = 0; i < entry->attr_count; i++) {
142 attrptr = entry->attr_pair[i];
143 if (attrptr == NULL) {
144 return ((int)NSS_STR_PARSE_PARSE);
145 }
146 if (strcasecmp(attrptr->attrname, _EXEC_NAME) == 0) {
147 if ((attrptr->attrvalue[0] == NULL) ||
148 (len = strlen(attrptr->attrvalue[0])) < 1) {
149 return ((int)NSS_STR_PARSE_PARSE);
150 }
151 exec->name = buffer;
152 buffer += len + 1;
153 if (buffer >= ceiling) {
154 return ((int)NSS_STR_PARSE_ERANGE);
155 }
156 (void) strcpy(exec->name, attrptr->attrvalue[0]);
157 continue;
158 }
159 if (strcasecmp(attrptr->attrname, _EXEC_POLICY) == 0) {
160 if ((attrptr->attrvalue[0] == NULL) ||
161 (len = strlen(attrptr->attrvalue[0])) < 1) {
162 exec->policy = nullstring;
163 } else {
164 exec->policy = buffer;
165 buffer += len + 1;
166 if (buffer >= ceiling) {
167 return ((int)NSS_STR_PARSE_ERANGE);
168 }
169 (void) strcpy(exec->policy,
170 attrptr->attrvalue[0]);
171 }
172 continue;
173 }
174 if (strcasecmp(attrptr->attrname, _EXEC_TYPE) == 0) {
175 if ((attrptr->attrvalue[0] == NULL) ||
176 (len = strlen(attrptr->attrvalue[0])) < 1) {
177 exec->type = nullstring;
178 } else {
179 exec->type = buffer;
180 buffer += len + 1;
181 if (buffer >= ceiling) {
182 return ((int)NSS_STR_PARSE_ERANGE);
183 }
184 (void) strcpy(exec->type,
185 attrptr->attrvalue[0]);
186 }
187 continue;
188 }
189 if (strcasecmp(attrptr->attrname, _EXEC_RES1) == 0) {
190 if ((attrptr->attrvalue[0] == NULL) ||
191 (len = strlen(attrptr->attrvalue[0])) < 1) {
192 exec->res1 = nullstring;
193 } else {
194 exec->res1 = buffer;
195 buffer += len + 1;
196 if (buffer >= ceiling) {
197 return ((int)NSS_STR_PARSE_ERANGE);
198 }
199 (void) strcpy(exec->res1,
200 attrptr->attrvalue[0]);
201 }
202 continue;
203 }
204 if (strcasecmp(attrptr->attrname, _EXEC_RES2) == 0) {
205 if ((attrptr->attrvalue[0] == NULL) ||
206 (len = strlen(attrptr->attrvalue[0])) < 1) {
207 exec->res2 = nullstring;
208 } else {
209 exec->res2 = buffer;
210 buffer += len + 1;
211 if (buffer >= ceiling) {
212 return ((int)NSS_STR_PARSE_ERANGE);
213 }
214 (void) strcpy(exec->res2,
215 attrptr->attrvalue[0]);
216 }
217 continue;
218 }
219 if (strcasecmp(attrptr->attrname, _EXEC_ID) == 0) {
220 if ((attrptr->attrvalue[0] == NULL) ||
221 (len = strlen(attrptr->attrvalue[0])) < 1) {
222 exec->id = nullstring;
223 } else {
224 exec->id = buffer;
225 buffer += len + 1;
226 if (buffer >= ceiling) {
227 return ((int)NSS_STR_PARSE_ERANGE);
228 }
229 (void) strcpy(exec->id, attrptr->attrvalue[0]);
230 }
231 continue;
232 }
233 if (strcasecmp(attrptr->attrname, _EXEC_ATTRS) == 0) {
234 if ((attrptr->attrvalue[0] == NULL) ||
235 (len = strlen(attrptr->attrvalue[0])) < 1) {
236 exec->attr = nullstring;
237 } else {
238 exec->attr = buffer;
239 buffer += len + 1;
240 if (buffer >= ceiling) {
241 return ((int)NSS_STR_PARSE_ERANGE);
242 }
243 (void) strcpy(exec->attr,
244 attrptr->attrvalue[0]);
245 }
246 continue;
247 }
248 }
249
250 exec->next = (execstr_t *)NULL;
251
252 #ifdef DEBUG
253 (void) fprintf(stdout, "\n[getexecattr.c: _exec_ldap_exec2ent]\n");
254 _print_execstr(exec);
255 #endif /* DEBUG */
256
257 return ((int)NSS_STR_PARSE_SUCCESS);
258 }
259
260
261 /*
262 * place the results from ldap object structure into the file format
263 * returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE}
264 */
265 static int
_nss_ldap_exec2str(ldap_backend_ptr be,nss_XbyY_args_t * argp)266 _nss_ldap_exec2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
267 {
268 int status = NSS_STR_PARSE_SUCCESS;
269 ns_ldap_result_t *result = be->result;
270 int len;
271 char *buffer, **name, **policy, **type;
272 char **res1, **res2, **id, **attr;
273 char *policy_str, *type_str, *res1_str, *res2_str;
274 char *id_str, *attr_str;
275
276 if (result == NULL)
277 return (NSS_STR_PARSE_PARSE);
278
279 (void) memset(argp->buf.buffer, 0, argp->buf.buflen);
280
281 name = __ns_ldap_getAttr(result->entry, _EXEC_NAME);
282 if (name == NULL || name[0] == NULL ||
283 (strlen(name[0]) < 1)) {
284 status = NSS_STR_PARSE_PARSE;
285 goto result_exec2str;
286 }
287
288 policy = __ns_ldap_getAttr(result->entry, _EXEC_POLICY);
289
290 if (policy == NULL || policy[0] == NULL)
291 policy_str = _NO_VALUE;
292 else
293 policy_str = policy[0];
294
295 type = __ns_ldap_getAttr(result->entry, _EXEC_TYPE);
296 if (type == NULL || type[0] == NULL)
297 type_str = _NO_VALUE;
298 else
299 type_str = type[0];
300
301 res1 = __ns_ldap_getAttr(result->entry, _EXEC_RES1);
302 if (res1 == NULL || res1[0] == NULL)
303 res1_str = _NO_VALUE;
304 else
305 res1_str = res1[0];
306
307 res2 = __ns_ldap_getAttr(result->entry, _EXEC_RES2);
308 if (res2 == NULL || res2[0] == NULL)
309 res2_str = _NO_VALUE;
310 else
311 res2_str = res2[0];
312
313 id = __ns_ldap_getAttr(result->entry, _EXEC_ID);
314 if (id == NULL || id[0] == NULL)
315 id_str = _NO_VALUE;
316 else
317 id_str = id[0];
318
319 attr = __ns_ldap_getAttr(result->entry, _EXEC_ATTRS);
320 if (attr == NULL || attr[0] == NULL)
321 attr_str = _NO_VALUE;
322 else
323 attr_str = attr[0];
324
325 /* 7 = 6 ':' + 1 '\0' */
326 len = strlen(name[0]) + strlen(policy_str) + strlen(type_str) +
327 strlen(res1_str) + strlen(res2_str) + strlen(id_str) +
328 strlen(attr_str) + 7;
329
330 if (len > argp->buf.buflen) {
331 status = NSS_STR_PARSE_ERANGE;
332 goto result_exec2str;
333 }
334 if (argp->buf.result != NULL) {
335 if ((be->buffer = calloc(1, len)) == NULL) {
336 status = NSS_STR_PARSE_PARSE;
337 goto result_exec2str;
338 }
339 buffer = be->buffer;
340 } else
341 buffer = argp->buf.buffer;
342
343 (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s",
344 name[0], policy_str, type_str, res1_str,
345 res2_str, id_str, attr_str);
346 /* The front end marshaller does not need the trailing null */
347 if (argp->buf.result != NULL)
348 be->buflen = strlen(buffer);
349 result_exec2str:
350 (void) __ns_ldap_freeResult(&be->result);
351 return (status);
352 }
353
354
355 static nss_status_t
_exec_process_val(ldap_backend_ptr be,nss_XbyY_args_t * argp)356 _exec_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp)
357 {
358 int status;
359 nss_status_t nss_stat = NSS_UNAVAIL;
360 ns_ldap_attr_t *attrptr;
361 ns_ldap_entry_t *entry;
362 ns_ldap_result_t *result = be->result;
363 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
364
365 argp->returnval = NULL;
366 attrptr = getattr(result, 0);
367 if (attrptr == NULL) {
368 (void) __ns_ldap_freeResult(&be->result);
369 return (nss_stat);
370 }
371 for (entry = result->entry; entry != NULL; entry = entry->next) {
372 status = _exec_ldap_exec2ent(entry, argp);
373 switch (status) {
374 case NSS_STR_PARSE_SUCCESS:
375 argp->returnval = argp->buf.result;
376 nss_stat = NSS_SUCCESS;
377 if (IS_GET_ALL(_priv_exec->search_flag)) {
378 if (_doexeclist(argp) == 0) {
379 nss_stat = NSS_UNAVAIL;
380 }
381 }
382 break;
383 case NSS_STR_PARSE_ERANGE:
384 argp->erange = 1;
385 nss_stat = NSS_NOTFOUND;
386 break;
387 case NSS_STR_PARSE_PARSE:
388 nss_stat = NSS_NOTFOUND;
389 break;
390 default:
391 nss_stat = NSS_UNAVAIL;
392 break;
393 }
394
395 if (IS_GET_ONE(_priv_exec->search_flag) ||
396 (nss_stat != NSS_SUCCESS)) {
397 break;
398 }
399 }
400
401 return (nss_stat);
402 }
403
404
405 /*
406 * Check if we have either an exact match or a wild-card entry for that id.
407 */
408 static nss_status_t
get_wild(ldap_backend_ptr be,nss_XbyY_args_t * argp,int getby_flag)409 get_wild(ldap_backend_ptr be, nss_XbyY_args_t *argp, int getby_flag)
410 {
411 char *dup_id = NULL;
412 char *wild_id;
413 char searchfilter[SEARCHFILTERLEN];
414 char userdata[SEARCHFILTERLEN];
415 char name[SEARCHFILTERLEN];
416 char id[SEARCHFILTERLEN];
417 int ret;
418 nss_status_t nss_stat = NSS_NOTFOUND;
419 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
420 const char *policy = _priv_exec->policy;
421 const char *type = _priv_exec->type;
422
423 if (strpbrk(policy, "*()\\") != NULL ||
424 type != NULL && strpbrk(type, "*()\\") != NULL)
425 return ((nss_status_t)NSS_NOTFOUND);
426
427 if (_priv_exec->id != NULL)
428 dup_id = strdup(_priv_exec->id);
429
430 switch (getby_flag) {
431 case NSS_DBOP_EXECATTR_BYNAMEID:
432 if (_ldap_filter_name(name, _priv_exec->name,
433 sizeof (name)) != 0)
434 goto go_out;
435 break;
436 }
437
438 wild_id = dup_id;
439 do {
440 if (wild_id != NULL) {
441 if (_ldap_filter_name(id, wild_id, sizeof (id)) != 0)
442 goto go_out;
443 } else
444 (void) strlcpy(id, "*", sizeof (id));
445
446 switch (getby_flag) {
447 case NSS_DBOP_EXECATTR_BYID:
448 ret = snprintf(searchfilter, sizeof (searchfilter),
449 _EXEC_GETEXECID, id, policy, ISWILD(type));
450 if (ret >= sizeof (searchfilter) || ret < 0)
451 goto go_out;
452 ret = snprintf(userdata, sizeof (userdata),
453 _EXEC_GETEXECID_SSD, id, policy, ISWILD(type));
454 if (ret >= sizeof (userdata) || ret < 0)
455 goto go_out;
456 break;
457
458 case NSS_DBOP_EXECATTR_BYNAMEID:
459 ret = snprintf(searchfilter, sizeof (searchfilter),
460 _EXEC_GETEXECNAMEID, name, id,
461 policy, ISWILD(type));
462 if (ret >= sizeof (searchfilter) || ret < 0)
463 goto go_out;
464 ret = snprintf(userdata, sizeof (userdata),
465 _EXEC_GETEXECNAMEID_SSD, name, id,
466 policy, ISWILD(type));
467 if (ret >= sizeof (userdata) || ret < 0)
468 goto go_out;
469 break;
470
471 default:
472 goto go_out;
473 }
474 nss_stat = _nss_ldap_nocb_lookup(be, argp, _EXECATTR,
475 searchfilter, NULL, _merge_SSD_filter, userdata);
476 if (nss_stat == NSS_SUCCESS)
477 break;
478 } while ((wild_id = _exec_wild_id(wild_id, type)) != NULL);
479
480 go_out:
481 free(dup_id);
482
483 return (nss_stat);
484 }
485
486 static nss_status_t
exec_attr_process_val(ldap_backend_ptr be,nss_XbyY_args_t * argp)487 exec_attr_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp) {
488
489 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
490 int stat, nss_stat = NSS_SUCCESS;
491
492 if (IS_GET_ONE(_priv_exec->search_flag)) {
493 /* ns_ldap_entry_t -> file format */
494 stat = (*be->ldapobj2str)(be, argp);
495
496 if (stat == NSS_STR_PARSE_SUCCESS) {
497 if (argp->buf.result != NULL) {
498 /* file format -> execstr_t */
499 stat = (*argp->str2ent)(be->buffer,
500 be->buflen,
501 argp->buf.result,
502 argp->buf.buffer,
503 argp->buf.buflen);
504 if (stat == NSS_STR_PARSE_SUCCESS) {
505 argp->returnval = argp->buf.result;
506 argp->returnlen = 1; /* irrelevant */
507 nss_stat = NSS_SUCCESS;
508 } else {
509 argp->returnval = NULL;
510 argp->returnlen = 0;
511 nss_stat = NSS_NOTFOUND;
512 }
513 } else {
514 /* return file format in argp->buf.buffer */
515 argp->returnval = argp->buf.buffer;
516 argp->returnlen = strlen(argp->buf.buffer);
517 nss_stat = NSS_SUCCESS;
518 }
519 } else {
520 argp->returnval = NULL;
521 argp->returnlen = 0;
522 nss_stat = NSS_NOTFOUND;
523 }
524 } else {
525 /* GET_ALL */
526 nss_stat = _exec_process_val(be, argp);
527 _exec_cleanup(nss_stat, argp);
528 }
529
530 return (nss_stat);
531
532 }
533
534 static nss_status_t
getbynam(ldap_backend_ptr be,void * a)535 getbynam(ldap_backend_ptr be, void *a)
536 {
537 char searchfilter[SEARCHFILTERLEN];
538 char userdata[SEARCHFILTERLEN];
539 char name[SEARCHFILTERLEN];
540 int ret;
541 nss_status_t nss_stat;
542 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
543 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
544 const char *policy = _priv_exec->policy;
545 const char *type = _priv_exec->type;
546
547 if (strpbrk(policy, "*()\\") != NULL ||
548 type != NULL && strpbrk(type, "*()\\") != NULL ||
549 _ldap_filter_name(name, _priv_exec->name, sizeof (name)) != 0)
550 return ((nss_status_t)NSS_NOTFOUND);
551 ret = snprintf(searchfilter, sizeof (searchfilter),
552 _EXEC_GETEXECNAME, name, policy, ISWILD(type));
553 if (ret >= sizeof (searchfilter) || ret < 0)
554 return ((nss_status_t)NSS_NOTFOUND);
555 ret = snprintf(userdata, sizeof (userdata),
556 _EXEC_GETEXECNAME_SSD, name, policy, ISWILD(type));
557 if (ret >= sizeof (userdata) || ret < 0)
558 return ((nss_status_t)NSS_NOTFOUND);
559
560 nss_stat = _nss_ldap_nocb_lookup(be, argp, _EXECATTR,
561 searchfilter, NULL, _merge_SSD_filter, userdata);
562
563 if (nss_stat == NSS_SUCCESS)
564 nss_stat = exec_attr_process_val(be, argp);
565
566 return (nss_stat);
567 }
568
569 static nss_status_t
getbyid(ldap_backend_ptr be,void * a)570 getbyid(ldap_backend_ptr be, void *a)
571 {
572 nss_status_t nss_stat = NSS_SUCCESS;
573 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
574
575 nss_stat = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID);
576
577 if (nss_stat == NSS_SUCCESS)
578 nss_stat = exec_attr_process_val(be, argp);
579
580 return (nss_stat);
581 }
582
583
584 static nss_status_t
getbynameid(ldap_backend_ptr be,void * a)585 getbynameid(ldap_backend_ptr be, void *a)
586 {
587 nss_status_t nss_stat;
588 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
589
590 nss_stat = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
591
592 if (nss_stat == NSS_SUCCESS)
593 nss_stat = exec_attr_process_val(be, argp);
594
595 return (nss_stat);
596 }
597
598
599 static ldap_backend_op_t execattr_ops[] = {
600 _nss_ldap_destr,
601 _nss_ldap_endent,
602 _nss_ldap_setent,
603 _nss_ldap_getent,
604 getbynam,
605 getbyid,
606 getbynameid
607 };
608
609
610 /*ARGSUSED0*/
611 nss_backend_t *
_nss_ldap_exec_attr_constr(const char * dummy1,const char * dummy2,const char * dummy3,const char * dummy4,const char * dummy5,const char * dummy6,const char * dummy7)612 _nss_ldap_exec_attr_constr(const char *dummy1,
613 const char *dummy2,
614 const char *dummy3,
615 const char *dummy4,
616 const char *dummy5,
617 const char *dummy6,
618 const char *dummy7)
619 {
620 #ifdef DEBUG
621 (void) fprintf(stdout,
622 "\n[getexecattr.c: _nss_ldap_exec_attr_constr]\n");
623 #endif
624 return ((nss_backend_t *)_nss_ldap_constr(execattr_ops,
625 sizeof (execattr_ops)/sizeof (execattr_ops[0]), _EXECATTR,
626 exec_attrs, _nss_ldap_exec2str));
627 }
628