kill tsol ("Trusted Solaris") aka TX ("Trusted Extensions")
[unleashed.git] / usr / src / cmd / ldap / ns_ldap / ldaplist.c
blobeaa84cbc8b319de07fc8609391316f11b1dccfa3
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <libintl.h>
30 #include <strings.h>
31 #include <locale.h>
32 #include <syslog.h>
34 #include "standalone.h"
36 extern char *set_filter(char **, char *, char **);
37 extern char *set_filter_publickey(char **, char *, int, char **);
38 extern void _printResult(ns_ldap_result_t *);
39 extern void printMapping();
41 int listflag = 0;
45 static struct database_t {
46 const char *database;
47 const char *sortattr;
48 }databaselist[] = {
49 { NS_LDAP_TYPE_HOSTS, "cn" },
50 { NS_LDAP_TYPE_IPNODES, "cn" },
51 { NS_LDAP_TYPE_RPC, "cn" },
52 { NS_LDAP_TYPE_PROTOCOLS, "cn" },
53 { NS_LDAP_TYPE_NETWORKS, "ipnetworknumber" },
54 { NS_LDAP_TYPE_SERVICES, "cn" },
55 { NS_LDAP_TYPE_GROUP, "gidnumber" },
56 { NS_LDAP_TYPE_NETMASKS, "ipnetworknumber"},
57 { NS_LDAP_TYPE_ETHERS, "cn" },
58 { NS_LDAP_TYPE_NETGROUP, "cn" },
59 { NS_LDAP_TYPE_BOOTPARAMS, "cn" },
60 { NS_LDAP_TYPE_PUBLICKEY, "cn" },
61 { NS_LDAP_TYPE_PASSWD, "uid" },
62 { NS_LDAP_TYPE_SHADOW, "uid" },
63 { NS_LDAP_TYPE_ALIASES, "cn" },
64 { NS_LDAP_TYPE_AUTOMOUNT, "automountKey" },
65 { NS_LDAP_TYPE_USERATTR, "uid" },
66 { NS_LDAP_TYPE_PROFILE, "cn" },
67 { NS_LDAP_TYPE_EXECATTR, "cn" },
68 { NS_LDAP_TYPE_AUTHATTR, "cn" },
69 { NS_LDAP_TYPE_AUUSER, "uid" },
70 { NS_LDAP_TYPE_PROJECT, "SolarisProjectName" },
71 { 0, 0 }
75 void
76 usage(char *msg) {
77 if (msg)
78 (void) fprintf(stderr, "%s\n", msg);
80 (void) fprintf(stderr,
81 gettext(
82 "\n"
83 "usage: ldaplist [-dlv] [-h LDAP_server[:serverPort] [-M domainName]\n"
84 "[-N profileName] [-a authenticationMethod] [-P certifPath]\n"
85 "[-D bindDN] [-w bindPassword] [-j passwdFile]]\n"
86 "[<database> [<key>] ...]\n\n"
87 "usage: ldaplist -h\n"
88 "\n"
89 "usage: ldaplist -g\n\n"
90 "\tOptions:\n"
91 "\t -l list all the attributes found in entry.\n"
92 "\t By default, it lists only the DNs.\n"
93 "\t -d list attributes for the database instead of its entries\n"
94 "\t -v print out the LDAP search filter.\n"
95 "\t -g list the database mappings.\n"
96 "\t -h An address (or a name) and a port of the LDAP server in\n"
97 "\t which the entries will be stored. The default value for\n"
98 "\t the port is 389 (or 636 for TLS connections).\n"
99 "\t -M The name of a domain served by the specified server.\n"
100 "\t If not specified, the default domain name will be used.\n"
101 "\t -N Specifies a DUAProfile name.\n"
102 "\t The default value is \"default\".\n"
103 "\t -a Specifies an authentication method.\n"
104 "\t -P The certificate path for the location of the certificate\n"
105 "\t database.\n"
106 "\t -D Specifies an entry which has read permission to\n"
107 "\t the requested database.\n"
108 "\t -w Password to be used for authenticating the bindDN.\n"
109 "\t -j File containing the password for bindDN or SSL key db.\n"
110 "\t<database> is the database to be searched in. Standard system\n"
111 "\tdatabases are:\n"
112 "\t\tpassword, printers, group, hosts, ethers, networks, netmasks,\n"
113 "\t\trpc, bootparams, protocols, services, netgroup, auto_*.\n"
114 "\tNon-standard system databases can be specified as follows:\n"
115 "\t\tby specific container: ou=<dbname> or\n"
116 "\t\tby default container: <dbname>. In this case, 'nismapname'\n"
117 "\t\twill be used, thus mapping this to nismapname=<dbname>.\n"
118 "\t<key> is the key to search in the database. For the standard\n"
119 "\tdatabases, the search type for the key is predefined. You can\n"
120 "\toverride this by specifying <type>=<key>.\n"
121 "\nNOTE: The old -h option printing the mapping information is "
122 "deprecated.\nFor backward compatibility the following mode is "
123 "available:\nldaplist -h\n"));
124 exit(1);
128 * This is a generic filter call back function for
129 * merging the filter from service search descriptor with
130 * an existing search filter. This routine expects userdata
131 * contain a format string with a single %s in it, and will
132 * use the format string with sprintf() to insert the SSD filter.
134 * This routine is passed to the __ns_ldap_list() or
135 * __ns_ldap_firstEntry() APIs as the filter call back
136 * together with the userdata. For example,
137 * the "ldaplist hosts sys1" processing may call __ns_ldap_list()
138 * with "(&(objectClass=ipHost)(cn=sys1))" as filter, this function
139 * as the filter call back, and "(&(%s)(cn=sys1))" as the
140 * userdata, this routine will in turn gets call to produce
141 * "(&(department=sds)(cn=sys1))" as the real search
142 * filter, if the input SSD contains a filter "department=sds".
144 static int
145 merge_SSD_filter(const ns_ldap_search_desc_t *desc,
146 char **realfilter,
147 const void *userdata)
149 int len;
150 char *checker;
152 /* sanity check */
153 if (realfilter == NULL)
154 return (NS_LDAP_INVALID_PARAM);
155 *realfilter = NULL;
157 if (desc == NULL || desc->filter == NULL ||
158 userdata == NULL)
159 return (NS_LDAP_INVALID_PARAM);
161 /* Parameter check. We only want one %s here, otherwise bail. */
162 len = 0; /* Reuse 'len' as "Number of %s hits"... */
163 checker = (char *)userdata;
164 do {
165 checker = strchr(checker, '%');
166 if (checker != NULL) {
167 if (len > 0 || *(checker + 1) != 's')
168 return (NS_LDAP_INVALID_PARAM);
169 len++; /* Got our %s. */
170 checker += 2;
171 } else if (len != 1)
172 return (NS_LDAP_INVALID_PARAM);
173 } while (checker != NULL);
175 len = strlen(userdata) + strlen(desc->filter) + 1;
177 *realfilter = (char *)malloc(len);
178 if (*realfilter == NULL)
179 return (NS_LDAP_MEMORY);
181 (void) sprintf(*realfilter, (char *)userdata,
182 desc->filter);
184 return (NS_LDAP_SUCCESS);
187 /* returns 0=success, 1=error */
189 list(char *database, char *ldapfilter, char **ldapattribute,
190 char **err, char *userdata)
192 ns_ldap_result_t *result;
193 ns_ldap_error_t *errorp;
194 int rc;
195 char buf[500];
196 const char *sort = NULL;
197 int i;
199 if (database) {
200 for (i = 0; databaselist[i].database; i++) {
201 if (strcmp(databaselist[i].database, database) == 0) {
202 sort = databaselist[i].sortattr;
203 break;
205 if (strcmp(databaselist[i].database,
206 NS_LDAP_TYPE_AUTOMOUNT) == 0 &&
207 strncmp(database, NS_LDAP_TYPE_AUTOMOUNT,
208 sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0) {
209 sort = databaselist[i].sortattr;
210 break;
215 *err = NULL;
216 buf[0] = '\0';
217 rc = __ns_ldap_list_sort(database, (const char *)ldapfilter,
218 sort, merge_SSD_filter, (const char **)ldapattribute, NULL,
219 listflag, &result, &errorp, NULL, userdata);
220 if (rc != NS_LDAP_SUCCESS) {
221 char *p;
222 (void) __ns_ldap_err2str(rc, &p);
223 if (errorp && errorp->message) {
224 (void) snprintf(buf, sizeof (buf), "%s (%s)",
225 p, errorp->message);
226 (void) __ns_ldap_freeError(&errorp);
227 } else
228 (void) snprintf(buf, sizeof (buf), "%s\n", p);
229 *err = strdup(buf);
230 return (rc);
233 _printResult(result);
234 (void) __ns_ldap_freeResult(&result);
235 return (0);
240 switch_err(int rc)
242 switch (rc) {
243 case NS_LDAP_SUCCESS:
244 return (0);
245 case NS_LDAP_NOTFOUND:
246 return (1);
248 return (2);
252 main(int argc, char **argv)
255 extern int optind;
256 char *database = NULL;
257 char *ldapfilter = NULL;
258 char *attribute = "dn";
259 char **key = NULL;
260 char **ldapattribute = NULL;
261 char *buffer[100];
262 char *err = NULL;
263 char *p;
264 int index = 1;
265 int c;
266 int rc;
267 int verbose = 0;
268 char *udata = NULL;
270 ns_standalone_conf_t standalone_cfg = standaloneDefaults;
271 ns_ldap_error_t *errorp = NULL;
272 char *authmech = NULL;
273 ns_auth_t auth = {NS_LDAP_AUTH_NONE,
274 NS_LDAP_TLS_NONE,
275 NS_LDAP_SASL_NONE,
276 NS_LDAP_SASLOPT_NONE};
278 (void) setlocale(LC_ALL, "");
279 (void) textdomain(TEXT_DOMAIN);
281 openlog("ldaplist", LOG_PID, LOG_USER);
283 if (argc == 2 &&
284 strlen(argv[1]) == 2 && strncmp(argv[1], "-h", 2) == 0) {
285 /* preserve backwards compatability, support old -h option */
286 (void) printMapping();
287 exit(0);
290 while ((c = getopt(argc, argv, "h:M:N:P:r:a:D:w:j:dgvl")) != EOF) {
291 switch (c) {
292 case 'd':
293 listflag |= NS_LDAP_SCOPE_BASE;
294 break;
295 case 'g':
296 (void) printMapping();
297 exit(0);
298 break; /* Never reached */
299 case 'l':
300 attribute = "NULL";
301 break;
302 case 'v':
303 verbose = 1;
304 break;
305 case 'M':
306 standalone_cfg.type = NS_LDAP_SERVER;
307 standalone_cfg.SA_DOMAIN = optarg;
308 break;
309 case 'h':
310 standalone_cfg.type = NS_LDAP_SERVER;
311 if (separatePort(optarg,
312 &standalone_cfg.SA_SERVER,
313 &standalone_cfg.SA_PORT) > 0) {
314 exit(1);
316 break;
317 case 'P':
318 standalone_cfg.type = NS_LDAP_SERVER;
319 standalone_cfg.SA_CERT_PATH = optarg;
320 break;
321 case 'N':
322 standalone_cfg.type = NS_LDAP_SERVER;
323 standalone_cfg.SA_PROFILE_NAME = optarg;
324 break;
325 case 'D':
326 standalone_cfg.type = NS_LDAP_SERVER;
327 standalone_cfg.SA_BIND_DN = strdup(optarg);
328 break;
329 case 'w':
330 if (standalone_cfg.SA_BIND_PWD != NULL) {
331 (void) fprintf(stderr,
332 gettext("The -w option is mutually "
333 "exclusive of -j. -w is ignored.\n"));
334 break;
337 if (optarg != NULL &&
338 optarg[0] == '-' && optarg[1] == '\0') {
339 /* Ask for a password later */
340 break;
343 standalone_cfg.type = NS_LDAP_SERVER;
344 standalone_cfg.SA_BIND_PWD = strdup(optarg);
345 break;
346 case 'j':
347 if (standalone_cfg.SA_BIND_PWD != NULL) {
348 (void) fprintf(stderr,
349 gettext("The -w option is mutually "
350 "exclusive of -j. -w is ignored.\n"));
351 free(standalone_cfg.SA_BIND_PWD);
353 standalone_cfg.type = NS_LDAP_SERVER;
354 standalone_cfg.SA_BIND_PWD = readPwd(optarg);
355 if (standalone_cfg.SA_BIND_PWD == NULL) {
356 exit(1);
358 break;
359 case 'a':
360 authmech = optarg;
361 break;
362 default:
363 usage(gettext("Invalid option"));
367 if (standalone_cfg.type == NS_LDAP_SERVER &&
368 standalone_cfg.SA_SERVER == NULL) {
369 (void) fprintf(stderr,
370 gettext("Please specify an LDAP server you want "
371 "to connect to. \n"));
372 exit(1);
375 if ((c = argc - optind) > 0)
376 database = argv[optind++];
377 if ((--c) > 0)
378 key = &argv[optind];
380 if (authmech != NULL) {
381 if (__ns_ldap_initAuth(authmech,
382 &auth,
383 &errorp) != NS_LDAP_SUCCESS) {
384 if (errorp) {
385 (void) fprintf(stderr, "%s", errorp->message);
386 (void) __ns_ldap_freeError(&errorp);
388 exit(1);
392 if (auth.saslmech != NS_LDAP_SASL_GSSAPI &&
393 standalone_cfg.SA_BIND_DN != NULL &&
394 standalone_cfg.SA_BIND_PWD == NULL) {
395 /* If password is not specified, then prompt user for it. */
396 standalone_cfg.SA_BIND_PWD =
397 strdup(getpassphrase("Enter password:"));
400 standalone_cfg.SA_AUTH = (authmech == NULL) ? NULL : &auth;
402 if (__ns_ldap_initStandalone(&standalone_cfg,
403 &errorp) != NS_LDAP_SUCCESS) {
404 if (errorp) {
405 (void) fprintf(stderr, "%s\n", errorp->message);
406 (void) __ns_ldap_freeError(&errorp);
408 exit(1);
411 if (authmech != NULL) {
412 if (__ns_ldap_setParam(NS_LDAP_AUTH_P,
413 authmech, &errorp) != NS_LDAP_SUCCESS) {
414 __ns_ldap_cancelStandalone();
415 if (errorp != NULL) {
416 (void) fprintf(stderr, "%s", errorp->message);
417 (void) __ns_ldap_freeError(&errorp);
419 exit(1);
422 if (standalone_cfg.SA_CRED != NULL) {
423 if (__ns_ldap_setParam(NS_LDAP_CREDENTIAL_LEVEL_P,
424 standalone_cfg.SA_CRED, &errorp) != NS_LDAP_SUCCESS) {
425 __ns_ldap_cancelStandalone();
426 if (errorp != NULL) {
427 (void) fprintf(stderr, "%s", errorp->message);
428 (void) __ns_ldap_freeError(&errorp);
430 exit(1);
434 if (standalone_cfg.type != NS_CACHEMGR &&
435 standalone_cfg.SA_BIND_DN != NULL) {
436 ns_auth_t **authpp = NULL, **authp = NULL;
438 if (__ns_ldap_getParam(NS_LDAP_AUTH_P,
439 (void ***)&authpp,
440 &errorp) != NS_LDAP_SUCCESS || authpp == NULL) {
441 __ns_ldap_cancelStandalone();
442 (void) __ns_ldap_freeParam((void ***)&authpp);
443 if (errorp) {
444 (void) fprintf(stderr,
445 gettext(errorp->message));
446 (void) __ns_ldap_freeError(&errorp);
448 exit(1);
450 for (authp = authpp; *authp; authp++) {
451 if ((*authp)->saslmech == NS_LDAP_SASL_GSSAPI) {
453 * For now we have no use for bindDN and
454 * bindPassword when using SASL/GSSAPI.
456 (void) fprintf(stderr,
457 gettext("Warning: SASL/GSSAPI will be "
458 "used as an authentication method"
459 "The bind DN and password will "
460 "be ignored.\n"));
461 break;
467 * If dumpping a database,
468 * or all the containers,
469 * use page control just
470 * in case there are too many entries
472 if (!key && !(listflag & NS_LDAP_SCOPE_BASE))
473 listflag |= NS_LDAP_PAGE_CTRL;
475 /* build the attribute array */
476 if (strncasecmp(attribute, "NULL", 4) == 0)
477 ldapattribute = NULL;
478 else {
479 buffer[0] = strdup(attribute);
480 while ((p = strchr(attribute, ',')) != NULL) {
481 buffer[index++] = attribute = p + 1;
482 *p = '\0';
484 buffer[index] = NULL;
485 ldapattribute = buffer;
488 /* build the filter */
489 if (database && (strcasecmp(database, "publickey") == NULL)) {
490 /* user publickey lookup */
491 char *err1 = NULL;
492 int rc1;
494 rc = rc1 = -1;
495 ldapfilter = set_filter_publickey(key, database, 0, &udata);
496 if (ldapfilter) {
497 if (verbose) {
498 (void) fprintf(stdout,
499 gettext("+++ database=%s\n"),
500 (database ? database : "NULL"));
501 (void) fprintf(stdout,
502 gettext("+++ filter=%s\n"),
503 (ldapfilter ? ldapfilter : "NULL"));
504 (void) fprintf(stdout,
505 gettext("+++ template for merging"
506 "SSD filter=%s\n"),
507 (udata ? udata : "NULL"));
509 rc = list("passwd", ldapfilter, ldapattribute,
510 &err, udata);
511 free(ldapfilter);
512 free(udata);
514 /* hosts publickey lookup */
515 ldapfilter = set_filter_publickey(key, database, 1, &udata);
516 if (ldapfilter) {
517 if (verbose) {
518 (void) fprintf(stdout,
519 gettext("+++ database=%s\n"),
520 (database ? database : "NULL"));
521 (void) fprintf(stdout,
522 gettext("+++ filter=%s\n"),
523 (ldapfilter ? ldapfilter : "NULL"));
524 (void) fprintf(stdout,
525 gettext("+++ template for merging"
526 "SSD filter=%s\n"),
527 (udata ? udata : "NULL"));
529 rc1 = list("hosts", ldapfilter, ldapattribute,
530 &err1, udata);
531 free(ldapfilter);
532 free(udata);
534 if (rc == -1 && rc1 == -1) {
535 /* this should never happen */
536 (void) fprintf(stderr,
537 gettext("ldaplist: invalid publickey lookup\n"));
538 rc = 2;
539 } else if (rc != 0 && rc1 != 0) {
540 (void) fprintf(stderr,
541 gettext("ldaplist: %s\n"), (err ? err : err1));
542 if (rc == -1)
543 rc = rc1;
544 } else
545 rc = 0;
546 exit(switch_err(rc));
550 * we set the search filter to (objectclass=*) when we want
551 * to list the directory attribute instead of the entries
552 * (the -d option).
554 if (((ldapfilter = set_filter(key, database, &udata)) == NULL) ||
555 (listflag == NS_LDAP_SCOPE_BASE)) {
556 ldapfilter = strdup("objectclass=*");
557 udata = strdup("%s");
560 if (verbose) {
561 (void) fprintf(stdout, gettext("+++ database=%s\n"),
562 (database ? database : "NULL"));
563 (void) fprintf(stdout, gettext("+++ filter=%s\n"),
564 (ldapfilter ? ldapfilter : "NULL"));
565 (void) fprintf(stdout,
566 gettext("+++ template for merging SSD filter=%s\n"),
567 (udata ? udata : "NULL"));
569 if (rc = list(database, ldapfilter, ldapattribute, &err, udata))
570 (void) fprintf(stderr, gettext("ldaplist: %s\n"), err);
572 __ns_ldap_cancelStandalone();
574 free(ldapfilter);
575 free(udata);
576 exit(switch_err(rc));
577 return (0); /* Never reached */