Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / cmd / ldap / ns_ldap / ldaplist.c
blob1e111eff5356ba3073e77ac4fe99511ab107e4f1
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_PROJECT, "SolarisProjectName" },
70 { 0, 0 }
74 void
75 usage(char *msg) {
76 if (msg)
77 (void) fprintf(stderr, "%s\n", msg);
79 (void) fprintf(stderr,
80 gettext(
81 "\n"
82 "usage: ldaplist [-dlv] [-h LDAP_server[:serverPort] [-M domainName]\n"
83 "[-N profileName] [-a authenticationMethod] [-P certifPath]\n"
84 "[-D bindDN] [-w bindPassword] [-j passwdFile]]\n"
85 "[<database> [<key>] ...]\n\n"
86 "usage: ldaplist -h\n"
87 "\n"
88 "usage: ldaplist -g\n\n"
89 "\tOptions:\n"
90 "\t -l list all the attributes found in entry.\n"
91 "\t By default, it lists only the DNs.\n"
92 "\t -d list attributes for the database instead of its entries\n"
93 "\t -v print out the LDAP search filter.\n"
94 "\t -g list the database mappings.\n"
95 "\t -h An address (or a name) and a port of the LDAP server in\n"
96 "\t which the entries will be stored. The default value for\n"
97 "\t the port is 389 (or 636 for TLS connections).\n"
98 "\t -M The name of a domain served by the specified server.\n"
99 "\t If not specified, the default domain name will be used.\n"
100 "\t -N Specifies a DUAProfile name.\n"
101 "\t The default value is \"default\".\n"
102 "\t -a Specifies an authentication method.\n"
103 "\t -P The certificate path for the location of the certificate\n"
104 "\t database.\n"
105 "\t -D Specifies an entry which has read permission to\n"
106 "\t the requested database.\n"
107 "\t -w Password to be used for authenticating the bindDN.\n"
108 "\t -j File containing the password for bindDN or SSL key db.\n"
109 "\t<database> is the database to be searched in. Standard system\n"
110 "\tdatabases are:\n"
111 "\t\tpassword, printers, group, hosts, ethers, networks, netmasks,\n"
112 "\t\trpc, bootparams, protocols, services, netgroup, auto_*.\n"
113 "\tNon-standard system databases can be specified as follows:\n"
114 "\t\tby specific container: ou=<dbname> or\n"
115 "\t\tby default container: <dbname>. In this case, 'nismapname'\n"
116 "\t\twill be used, thus mapping this to nismapname=<dbname>.\n"
117 "\t<key> is the key to search in the database. For the standard\n"
118 "\tdatabases, the search type for the key is predefined. You can\n"
119 "\toverride this by specifying <type>=<key>.\n"
120 "\nNOTE: The old -h option printing the mapping information is "
121 "deprecated.\nFor backward compatibility the following mode is "
122 "available:\nldaplist -h\n"));
123 exit(1);
127 * This is a generic filter call back function for
128 * merging the filter from service search descriptor with
129 * an existing search filter. This routine expects userdata
130 * contain a format string with a single %s in it, and will
131 * use the format string with sprintf() to insert the SSD filter.
133 * This routine is passed to the __ns_ldap_list() or
134 * __ns_ldap_firstEntry() APIs as the filter call back
135 * together with the userdata. For example,
136 * the "ldaplist hosts sys1" processing may call __ns_ldap_list()
137 * with "(&(objectClass=ipHost)(cn=sys1))" as filter, this function
138 * as the filter call back, and "(&(%s)(cn=sys1))" as the
139 * userdata, this routine will in turn gets call to produce
140 * "(&(department=sds)(cn=sys1))" as the real search
141 * filter, if the input SSD contains a filter "department=sds".
143 static int
144 merge_SSD_filter(const ns_ldap_search_desc_t *desc,
145 char **realfilter,
146 const void *userdata)
148 int len;
149 char *checker;
151 /* sanity check */
152 if (realfilter == NULL)
153 return (NS_LDAP_INVALID_PARAM);
154 *realfilter = NULL;
156 if (desc == NULL || desc->filter == NULL ||
157 userdata == NULL)
158 return (NS_LDAP_INVALID_PARAM);
160 /* Parameter check. We only want one %s here, otherwise bail. */
161 len = 0; /* Reuse 'len' as "Number of %s hits"... */
162 checker = (char *)userdata;
163 do {
164 checker = strchr(checker, '%');
165 if (checker != NULL) {
166 if (len > 0 || *(checker + 1) != 's')
167 return (NS_LDAP_INVALID_PARAM);
168 len++; /* Got our %s. */
169 checker += 2;
170 } else if (len != 1)
171 return (NS_LDAP_INVALID_PARAM);
172 } while (checker != NULL);
174 len = strlen(userdata) + strlen(desc->filter) + 1;
176 *realfilter = (char *)malloc(len);
177 if (*realfilter == NULL)
178 return (NS_LDAP_MEMORY);
180 (void) sprintf(*realfilter, (char *)userdata,
181 desc->filter);
183 return (NS_LDAP_SUCCESS);
186 /* returns 0=success, 1=error */
188 list(char *database, char *ldapfilter, char **ldapattribute,
189 char **err, char *userdata)
191 ns_ldap_result_t *result;
192 ns_ldap_error_t *errorp;
193 int rc;
194 char buf[500];
195 const char *sort = NULL;
196 int i;
198 if (database) {
199 for (i = 0; databaselist[i].database; i++) {
200 if (strcmp(databaselist[i].database, database) == 0) {
201 sort = databaselist[i].sortattr;
202 break;
204 if (strcmp(databaselist[i].database,
205 NS_LDAP_TYPE_AUTOMOUNT) == 0 &&
206 strncmp(database, NS_LDAP_TYPE_AUTOMOUNT,
207 sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0) {
208 sort = databaselist[i].sortattr;
209 break;
214 *err = NULL;
215 buf[0] = '\0';
216 rc = __ns_ldap_list_sort(database, (const char *)ldapfilter,
217 sort, merge_SSD_filter, (const char **)ldapattribute, NULL,
218 listflag, &result, &errorp, NULL, userdata);
219 if (rc != NS_LDAP_SUCCESS) {
220 char *p;
221 (void) __ns_ldap_err2str(rc, &p);
222 if (errorp && errorp->message) {
223 (void) snprintf(buf, sizeof (buf), "%s (%s)",
224 p, errorp->message);
225 (void) __ns_ldap_freeError(&errorp);
226 } else
227 (void) snprintf(buf, sizeof (buf), "%s\n", p);
228 *err = strdup(buf);
229 return (rc);
232 _printResult(result);
233 (void) __ns_ldap_freeResult(&result);
234 return (0);
239 switch_err(int rc)
241 switch (rc) {
242 case NS_LDAP_SUCCESS:
243 return (0);
244 case NS_LDAP_NOTFOUND:
245 return (1);
247 return (2);
251 main(int argc, char **argv)
254 extern int optind;
255 char *database = NULL;
256 char *ldapfilter = NULL;
257 char *attribute = "dn";
258 char **key = NULL;
259 char **ldapattribute = NULL;
260 char *buffer[100];
261 char *err = NULL;
262 char *p;
263 int index = 1;
264 int c;
265 int rc;
266 int verbose = 0;
267 char *udata = NULL;
269 ns_standalone_conf_t standalone_cfg = standaloneDefaults;
270 ns_ldap_error_t *errorp = NULL;
271 char *authmech = NULL;
272 ns_auth_t auth = {NS_LDAP_AUTH_NONE,
273 NS_LDAP_TLS_NONE,
274 NS_LDAP_SASL_NONE,
275 NS_LDAP_SASLOPT_NONE};
277 (void) setlocale(LC_ALL, "");
278 (void) textdomain(TEXT_DOMAIN);
280 openlog("ldaplist", LOG_PID, LOG_USER);
282 if (argc == 2 &&
283 strlen(argv[1]) == 2 && strncmp(argv[1], "-h", 2) == 0) {
284 /* preserve backwards compatability, support old -h option */
285 (void) printMapping();
286 exit(0);
289 while ((c = getopt(argc, argv, "h:M:N:P:r:a:D:w:j:dgvl")) != EOF) {
290 switch (c) {
291 case 'd':
292 listflag |= NS_LDAP_SCOPE_BASE;
293 break;
294 case 'g':
295 (void) printMapping();
296 exit(0);
297 break; /* Never reached */
298 case 'l':
299 attribute = "NULL";
300 break;
301 case 'v':
302 verbose = 1;
303 break;
304 case 'M':
305 standalone_cfg.type = NS_LDAP_SERVER;
306 standalone_cfg.SA_DOMAIN = optarg;
307 break;
308 case 'h':
309 standalone_cfg.type = NS_LDAP_SERVER;
310 if (separatePort(optarg,
311 &standalone_cfg.SA_SERVER,
312 &standalone_cfg.SA_PORT) > 0) {
313 exit(1);
315 break;
316 case 'P':
317 standalone_cfg.type = NS_LDAP_SERVER;
318 standalone_cfg.SA_CERT_PATH = optarg;
319 break;
320 case 'N':
321 standalone_cfg.type = NS_LDAP_SERVER;
322 standalone_cfg.SA_PROFILE_NAME = optarg;
323 break;
324 case 'D':
325 standalone_cfg.type = NS_LDAP_SERVER;
326 standalone_cfg.SA_BIND_DN = strdup(optarg);
327 break;
328 case 'w':
329 if (standalone_cfg.SA_BIND_PWD != NULL) {
330 (void) fprintf(stderr,
331 gettext("The -w option is mutually "
332 "exclusive of -j. -w is ignored.\n"));
333 break;
336 if (optarg != NULL &&
337 optarg[0] == '-' && optarg[1] == '\0') {
338 /* Ask for a password later */
339 break;
342 standalone_cfg.type = NS_LDAP_SERVER;
343 standalone_cfg.SA_BIND_PWD = strdup(optarg);
344 break;
345 case 'j':
346 if (standalone_cfg.SA_BIND_PWD != NULL) {
347 (void) fprintf(stderr,
348 gettext("The -w option is mutually "
349 "exclusive of -j. -w is ignored.\n"));
350 free(standalone_cfg.SA_BIND_PWD);
352 standalone_cfg.type = NS_LDAP_SERVER;
353 standalone_cfg.SA_BIND_PWD = readPwd(optarg);
354 if (standalone_cfg.SA_BIND_PWD == NULL) {
355 exit(1);
357 break;
358 case 'a':
359 authmech = optarg;
360 break;
361 default:
362 usage(gettext("Invalid option"));
366 if (standalone_cfg.type == NS_LDAP_SERVER &&
367 standalone_cfg.SA_SERVER == NULL) {
368 (void) fprintf(stderr,
369 gettext("Please specify an LDAP server you want "
370 "to connect to. \n"));
371 exit(1);
374 if ((c = argc - optind) > 0)
375 database = argv[optind++];
376 if ((--c) > 0)
377 key = &argv[optind];
379 if (authmech != NULL) {
380 if (__ns_ldap_initAuth(authmech,
381 &auth,
382 &errorp) != NS_LDAP_SUCCESS) {
383 if (errorp) {
384 (void) fprintf(stderr, "%s", errorp->message);
385 (void) __ns_ldap_freeError(&errorp);
387 exit(1);
391 if (auth.saslmech != NS_LDAP_SASL_GSSAPI &&
392 standalone_cfg.SA_BIND_DN != NULL &&
393 standalone_cfg.SA_BIND_PWD == NULL) {
394 /* If password is not specified, then prompt user for it. */
395 standalone_cfg.SA_BIND_PWD =
396 strdup(getpassphrase("Enter password:"));
399 standalone_cfg.SA_AUTH = (authmech == NULL) ? NULL : &auth;
401 if (__ns_ldap_initStandalone(&standalone_cfg,
402 &errorp) != NS_LDAP_SUCCESS) {
403 if (errorp) {
404 (void) fprintf(stderr, "%s\n", errorp->message);
405 (void) __ns_ldap_freeError(&errorp);
407 exit(1);
410 if (authmech != NULL) {
411 if (__ns_ldap_setParam(NS_LDAP_AUTH_P,
412 authmech, &errorp) != NS_LDAP_SUCCESS) {
413 __ns_ldap_cancelStandalone();
414 if (errorp != NULL) {
415 (void) fprintf(stderr, "%s", errorp->message);
416 (void) __ns_ldap_freeError(&errorp);
418 exit(1);
421 if (standalone_cfg.SA_CRED != NULL) {
422 if (__ns_ldap_setParam(NS_LDAP_CREDENTIAL_LEVEL_P,
423 standalone_cfg.SA_CRED, &errorp) != NS_LDAP_SUCCESS) {
424 __ns_ldap_cancelStandalone();
425 if (errorp != NULL) {
426 (void) fprintf(stderr, "%s", errorp->message);
427 (void) __ns_ldap_freeError(&errorp);
429 exit(1);
433 if (standalone_cfg.type != NS_CACHEMGR &&
434 standalone_cfg.SA_BIND_DN != NULL) {
435 ns_auth_t **authpp = NULL, **authp = NULL;
437 if (__ns_ldap_getParam(NS_LDAP_AUTH_P,
438 (void ***)&authpp,
439 &errorp) != NS_LDAP_SUCCESS || authpp == NULL) {
440 __ns_ldap_cancelStandalone();
441 (void) __ns_ldap_freeParam((void ***)&authpp);
442 if (errorp) {
443 (void) fprintf(stderr,
444 gettext(errorp->message));
445 (void) __ns_ldap_freeError(&errorp);
447 exit(1);
449 for (authp = authpp; *authp; authp++) {
450 if ((*authp)->saslmech == NS_LDAP_SASL_GSSAPI) {
452 * For now we have no use for bindDN and
453 * bindPassword when using SASL/GSSAPI.
455 (void) fprintf(stderr,
456 gettext("Warning: SASL/GSSAPI will be "
457 "used as an authentication method"
458 "The bind DN and password will "
459 "be ignored.\n"));
460 break;
466 * If dumpping a database,
467 * or all the containers,
468 * use page control just
469 * in case there are too many entries
471 if (!key && !(listflag & NS_LDAP_SCOPE_BASE))
472 listflag |= NS_LDAP_PAGE_CTRL;
474 /* build the attribute array */
475 if (strncasecmp(attribute, "NULL", 4) == 0)
476 ldapattribute = NULL;
477 else {
478 buffer[0] = strdup(attribute);
479 while ((p = strchr(attribute, ',')) != NULL) {
480 buffer[index++] = attribute = p + 1;
481 *p = '\0';
483 buffer[index] = NULL;
484 ldapattribute = buffer;
487 /* build the filter */
488 if (database && (strcasecmp(database, "publickey") == 0)) {
489 /* user publickey lookup */
490 char *err1 = NULL;
491 int rc1;
493 rc = rc1 = -1;
494 ldapfilter = set_filter_publickey(key, database, 0, &udata);
495 if (ldapfilter) {
496 if (verbose) {
497 (void) fprintf(stdout,
498 gettext("+++ database=%s\n"),
499 (database ? database : "NULL"));
500 (void) fprintf(stdout,
501 gettext("+++ filter=%s\n"),
502 (ldapfilter ? ldapfilter : "NULL"));
503 (void) fprintf(stdout,
504 gettext("+++ template for merging"
505 "SSD filter=%s\n"),
506 (udata ? udata : "NULL"));
508 rc = list("passwd", ldapfilter, ldapattribute,
509 &err, udata);
510 free(ldapfilter);
511 free(udata);
513 /* hosts publickey lookup */
514 ldapfilter = set_filter_publickey(key, database, 1, &udata);
515 if (ldapfilter) {
516 if (verbose) {
517 (void) fprintf(stdout,
518 gettext("+++ database=%s\n"),
519 (database ? database : "NULL"));
520 (void) fprintf(stdout,
521 gettext("+++ filter=%s\n"),
522 (ldapfilter ? ldapfilter : "NULL"));
523 (void) fprintf(stdout,
524 gettext("+++ template for merging"
525 "SSD filter=%s\n"),
526 (udata ? udata : "NULL"));
528 rc1 = list("hosts", ldapfilter, ldapattribute,
529 &err1, udata);
530 free(ldapfilter);
531 free(udata);
533 if (rc == -1 && rc1 == -1) {
534 /* this should never happen */
535 (void) fprintf(stderr,
536 gettext("ldaplist: invalid publickey lookup\n"));
537 rc = 2;
538 } else if (rc != 0 && rc1 != 0) {
539 (void) fprintf(stderr,
540 gettext("ldaplist: %s\n"), (err ? err : err1));
541 if (rc == -1)
542 rc = rc1;
543 } else
544 rc = 0;
545 exit(switch_err(rc));
549 * we set the search filter to (objectclass=*) when we want
550 * to list the directory attribute instead of the entries
551 * (the -d option).
553 if (((ldapfilter = set_filter(key, database, &udata)) == NULL) ||
554 (listflag == NS_LDAP_SCOPE_BASE)) {
555 ldapfilter = strdup("objectclass=*");
556 udata = strdup("%s");
559 if (verbose) {
560 (void) fprintf(stdout, gettext("+++ database=%s\n"),
561 (database ? database : "NULL"));
562 (void) fprintf(stdout, gettext("+++ filter=%s\n"),
563 (ldapfilter ? ldapfilter : "NULL"));
564 (void) fprintf(stdout,
565 gettext("+++ template for merging SSD filter=%s\n"),
566 (udata ? udata : "NULL"));
568 if (rc = list(database, ldapfilter, ldapattribute, &err, udata))
569 (void) fprintf(stderr, gettext("ldaplist: %s\n"), err);
571 __ns_ldap_cancelStandalone();
573 free(ldapfilter);
574 free(udata);
575 exit(switch_err(rc));
576 return (0); /* Never reached */