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]
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
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();
45 static struct database_t
{
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" },
78 (void) fprintf(stderr
, "%s\n", msg
);
80 (void) fprintf(stderr
,
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"
89 "usage: ldaplist -g\n\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"
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"
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"));
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".
145 merge_SSD_filter(const ns_ldap_search_desc_t
*desc
,
147 const void *userdata
)
153 if (realfilter
== NULL
)
154 return (NS_LDAP_INVALID_PARAM
);
157 if (desc
== NULL
|| desc
->filter
== 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
;
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. */
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
,
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
;
196 const char *sort
= NULL
;
200 for (i
= 0; databaselist
[i
].database
; i
++) {
201 if (strcmp(databaselist
[i
].database
, database
) == 0) {
202 sort
= databaselist
[i
].sortattr
;
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
;
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
) {
222 (void) __ns_ldap_err2str(rc
, &p
);
223 if (errorp
&& errorp
->message
) {
224 (void) snprintf(buf
, sizeof (buf
), "%s (%s)",
226 (void) __ns_ldap_freeError(&errorp
);
228 (void) snprintf(buf
, sizeof (buf
), "%s\n", p
);
233 _printResult(result
);
234 (void) __ns_ldap_freeResult(&result
);
243 case NS_LDAP_SUCCESS
:
245 case NS_LDAP_NOTFOUND
:
252 main(int argc
, char **argv
)
256 char *database
= NULL
;
257 char *ldapfilter
= NULL
;
258 char *attribute
= "dn";
260 char **ldapattribute
= 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
,
276 NS_LDAP_SASLOPT_NONE
};
278 (void) setlocale(LC_ALL
, "");
279 (void) textdomain(TEXT_DOMAIN
);
281 openlog("ldaplist", LOG_PID
, LOG_USER
);
284 strlen(argv
[1]) == 2 && strncmp(argv
[1], "-h", 2) == 0) {
285 /* preserve backwards compatability, support old -h option */
286 (void) printMapping();
290 while ((c
= getopt(argc
, argv
, "h:M:N:P:r:a:D:w:j:dgvl")) != EOF
) {
293 listflag
|= NS_LDAP_SCOPE_BASE
;
296 (void) printMapping();
298 break; /* Never reached */
306 standalone_cfg
.type
= NS_LDAP_SERVER
;
307 standalone_cfg
.SA_DOMAIN
= optarg
;
310 standalone_cfg
.type
= NS_LDAP_SERVER
;
311 if (separatePort(optarg
,
312 &standalone_cfg
.SA_SERVER
,
313 &standalone_cfg
.SA_PORT
) > 0) {
318 standalone_cfg
.type
= NS_LDAP_SERVER
;
319 standalone_cfg
.SA_CERT_PATH
= optarg
;
322 standalone_cfg
.type
= NS_LDAP_SERVER
;
323 standalone_cfg
.SA_PROFILE_NAME
= optarg
;
326 standalone_cfg
.type
= NS_LDAP_SERVER
;
327 standalone_cfg
.SA_BIND_DN
= strdup(optarg
);
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"));
337 if (optarg
!= NULL
&&
338 optarg
[0] == '-' && optarg
[1] == '\0') {
339 /* Ask for a password later */
343 standalone_cfg
.type
= NS_LDAP_SERVER
;
344 standalone_cfg
.SA_BIND_PWD
= strdup(optarg
);
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
) {
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"));
375 if ((c
= argc
- optind
) > 0)
376 database
= argv
[optind
++];
380 if (authmech
!= NULL
) {
381 if (__ns_ldap_initAuth(authmech
,
383 &errorp
) != NS_LDAP_SUCCESS
) {
385 (void) fprintf(stderr
, "%s", errorp
->message
);
386 (void) __ns_ldap_freeError(&errorp
);
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
) {
405 (void) fprintf(stderr
, "%s\n", errorp
->message
);
406 (void) __ns_ldap_freeError(&errorp
);
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
);
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
);
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
,
440 &errorp
) != NS_LDAP_SUCCESS
|| authpp
== NULL
) {
441 __ns_ldap_cancelStandalone();
442 (void) __ns_ldap_freeParam((void ***)&authpp
);
444 (void) fprintf(stderr
,
445 gettext(errorp
->message
));
446 (void) __ns_ldap_freeError(&errorp
);
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 "
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
;
479 buffer
[0] = strdup(attribute
);
480 while ((p
= strchr(attribute
, ',')) != NULL
) {
481 buffer
[index
++] = attribute
= p
+ 1;
484 buffer
[index
] = NULL
;
485 ldapattribute
= buffer
;
488 /* build the filter */
489 if (database
&& (strcasecmp(database
, "publickey") == NULL
)) {
490 /* user publickey lookup */
495 ldapfilter
= set_filter_publickey(key
, database
, 0, &udata
);
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"
507 (udata
? udata
: "NULL"));
509 rc
= list("passwd", ldapfilter
, ldapattribute
,
514 /* hosts publickey lookup */
515 ldapfilter
= set_filter_publickey(key
, database
, 1, &udata
);
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"
527 (udata
? udata
: "NULL"));
529 rc1
= list("hosts", ldapfilter
, ldapattribute
,
534 if (rc
== -1 && rc1
== -1) {
535 /* this should never happen */
536 (void) fprintf(stderr
,
537 gettext("ldaplist: invalid publickey lookup\n"));
539 } else if (rc
!= 0 && rc1
!= 0) {
540 (void) fprintf(stderr
,
541 gettext("ldaplist: %s\n"), (err
? err
: err1
));
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
554 if (((ldapfilter
= set_filter(key
, database
, &udata
)) == NULL
) ||
555 (listflag
== NS_LDAP_SCOPE_BASE
)) {
556 ldapfilter
= strdup("objectclass=*");
557 udata
= strdup("%s");
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();
576 exit(switch_err(rc
));
577 return (0); /* Never reached */