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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <libintl.h> 31 #include <strings.h> 32 #include <locale.h> 33 #include <syslog.h> 34 35 #include "standalone.h" 36 37 extern char *set_filter(char **, char *, char **); 38 extern char *set_filter_publickey(char **, char *, int, char **); 39 extern void _printResult(ns_ldap_result_t *); 40 extern void printMapping(); 41 42 int listflag = 0; 43 44 void 45 usage(char *msg) { 46 if (msg) 47 (void) fprintf(stderr, "%s\n", msg); 48 49 (void) fprintf(stderr, 50 gettext( 51 "\n" 52 "usage: ldaplist [-dlv] [-h LDAP_server[:serverPort] [-M domainName]\n" 53 "[-N profileName] [-a authenticationMethod] [-P certifPath]\n" 54 "[-D bindDN] [-w bindPassword] [-j passwdFile]]\n" 55 "[<database> [<key>] ...]\n\n" 56 "usage: ldaplist -h\n" 57 "\n" 58 "usage: ldaplist -g\n\n" 59 "\tOptions:\n" 60 "\t -l list all the attributes found in entry.\n" 61 "\t By default, it lists only the DNs.\n" 62 "\t -d list attributes for the database instead of its entries\n" 63 "\t -v print out the LDAP search filter.\n" 64 "\t -g list the database mappings.\n" 65 "\t -h An address (or a name) and a port of the LDAP server in\n" 66 "\t which the entries will be stored. The default value for\n" 67 "\t the port is 389 (or 636 for TLS connections).\n" 68 "\t -M The name of a domain served by the specified server.\n" 69 "\t If not specified, the default domain name will be used.\n" 70 "\t -N Specifies a DUAProfile name.\n" 71 "\t The default value is \"default\".\n" 72 "\t -a Specifies an authentication method.\n" 73 "\t -P The certificate path for the location of the certificate\n" 74 "\t database.\n" 75 "\t -D Specifies an entry which has read permission to\n" 76 "\t the requested database.\n" 77 "\t -w Password to be used for authenticating the bindDN.\n" 78 "\t -j File containing the password for bindDN or SSL key db.\n" 79 "\t<database> is the database to be searched in. Standard system\n" 80 "\tdatabases are:\n" 81 "\t\tpassword, printers, group, hosts, ethers, networks, netmasks,\n" 82 "\t\trpc, bootparams, protocols, services, netgroup, auto_*.\n" 83 "\tNon-standard system databases can be specified as follows:\n" 84 "\t\tby specific container: ou=<dbname> or\n" 85 "\t\tby default container: <dbname>. In this case, 'nismapname'\n" 86 "\t\twill be used, thus mapping this to nismapname=<dbname>.\n" 87 "\t<key> is the key to search in the database. For the standard\n" 88 "\tdatabases, the search type for the key is predefined. You can\n" 89 "\toverride this by specifying <type>=<key>.\n" 90 "\nNOTE: The old -h option printing the mapping information is " 91 "deprecated.\nFor backward compatibility the following mode is " 92 "available:\nldaplist -h\n")); 93 exit(1); 94 } 95 96 /* 97 * This is a generic filter call back function for 98 * merging the filter from service search descriptor with 99 * an existing search filter. This routine expects userdata 100 * contain a format string with a single %s in it, and will 101 * use the format string with sprintf() to insert the SSD filter. 102 * 103 * This routine is passed to the __ns_ldap_list() or 104 * __ns_ldap_firstEntry() APIs as the filter call back 105 * together with the userdata. For example, 106 * the "ldaplist hosts sys1" processing may call __ns_ldap_list() 107 * with "(&(objectClass=ipHost)(cn=sys1))" as filter, this function 108 * as the filter call back, and "(&(%s)(cn=sys1))" as the 109 * userdata, this routine will in turn gets call to produce 110 * "(&(department=sds)(cn=sys1))" as the real search 111 * filter, if the input SSD contains a filter "department=sds". 112 */ 113 static int 114 merge_SSD_filter(const ns_ldap_search_desc_t *desc, 115 char **realfilter, 116 const void *userdata) 117 { 118 int len; 119 120 /* sanity check */ 121 if (realfilter == NULL) 122 return (NS_LDAP_INVALID_PARAM); 123 *realfilter = NULL; 124 125 if (desc == NULL || desc->filter == NULL || 126 userdata == NULL) 127 return (NS_LDAP_INVALID_PARAM); 128 129 len = strlen(userdata) + strlen(desc->filter) + 1; 130 131 *realfilter = (char *)malloc(len); 132 if (*realfilter == NULL) 133 return (NS_LDAP_MEMORY); 134 135 (void) sprintf(*realfilter, (char *)userdata, 136 desc->filter); 137 138 return (NS_LDAP_SUCCESS); 139 } 140 141 /* returns 0=success, 1=error */ 142 int 143 list(char *database, char *ldapfilter, char **ldapattribute, 144 char **err, char *userdata) 145 { 146 ns_ldap_result_t *result; 147 ns_ldap_error_t *errorp; 148 int rc; 149 char buf[500]; 150 151 *err = NULL; 152 buf[0] = '\0'; 153 rc = __ns_ldap_list(database, (const char *)ldapfilter, 154 merge_SSD_filter, (const char **)ldapattribute, NULL, 155 listflag, &result, &errorp, NULL, userdata); 156 if (rc != NS_LDAP_SUCCESS) { 157 char *p; 158 (void) __ns_ldap_err2str(rc, &p); 159 if (errorp && errorp->message) { 160 (void) snprintf(buf, sizeof (buf), "%s (%s)", 161 p, errorp->message); 162 (void) __ns_ldap_freeError(&errorp); 163 } else 164 (void) snprintf(buf, sizeof (buf), "%s\n", p); 165 *err = strdup(buf); 166 return (rc); 167 } 168 169 _printResult(result); 170 (void) __ns_ldap_freeResult(&result); 171 return (0); 172 } 173 174 175 int 176 switch_err(int rc) 177 { 178 switch (rc) { 179 case NS_LDAP_SUCCESS: 180 return (0); 181 case NS_LDAP_NOTFOUND: 182 return (1); 183 } 184 return (2); 185 } 186 187 int 188 main(int argc, char **argv) 189 { 190 191 extern int optind; 192 char *database = NULL; 193 char *ldapfilter = NULL; 194 char *attribute = "dn"; 195 char **key = NULL; 196 char **ldapattribute = NULL; 197 char *buffer[100]; 198 char *err = NULL; 199 char *p; 200 int index = 1; 201 int c; 202 int rc; 203 int verbose = 0; 204 char *udata = NULL; 205 206 ns_standalone_conf_t standalone_cfg = standaloneDefaults; 207 ns_ldap_error_t *errorp = NULL; 208 char *authmech = NULL; 209 ns_auth_t auth = {NS_LDAP_AUTH_NONE, 210 NS_LDAP_TLS_NONE, 211 NS_LDAP_SASL_NONE, 212 NS_LDAP_SASLOPT_NONE}; 213 214 (void) setlocale(LC_ALL, ""); 215 (void) textdomain(TEXT_DOMAIN); 216 217 openlog("ldaplist", LOG_PID, LOG_USER); 218 219 if (argc == 2 && 220 strlen(argv[1]) == 2 && strncmp(argv[1], "-h", 2) == 0) { 221 /* preserve backwards compatability, support old -h option */ 222 (void) printMapping(); 223 exit(0); 224 } 225 226 while ((c = getopt(argc, argv, "h:M:N:P:r:a:D:w:j:dgvl")) != EOF) { 227 switch (c) { 228 case 'd': 229 listflag |= NS_LDAP_SCOPE_BASE; 230 break; 231 case 'g': 232 (void) printMapping(); 233 exit(0); 234 break; /* Never reached */ 235 case 'l': 236 attribute = "NULL"; 237 break; 238 case 'v': 239 verbose = 1; 240 break; 241 case 'M': 242 standalone_cfg.type = NS_LDAP_SERVER; 243 standalone_cfg.SA_DOMAIN = optarg; 244 break; 245 case 'h': 246 standalone_cfg.type = NS_LDAP_SERVER; 247 if (separatePort(optarg, 248 &standalone_cfg.SA_SERVER, 249 &standalone_cfg.SA_PORT) > 0) { 250 exit(1); 251 } 252 break; 253 case 'P': 254 standalone_cfg.type = NS_LDAP_SERVER; 255 standalone_cfg.SA_CERT_PATH = optarg; 256 break; 257 case 'N': 258 standalone_cfg.type = NS_LDAP_SERVER; 259 standalone_cfg.SA_PROFILE_NAME = optarg; 260 break; 261 case 'D': 262 standalone_cfg.type = NS_LDAP_SERVER; 263 standalone_cfg.SA_BIND_DN = strdup(optarg); 264 break; 265 case 'w': 266 if (standalone_cfg.SA_BIND_PWD != NULL) { 267 (void) fprintf(stderr, 268 gettext("The -w option is mutually " 269 "exclusive of -j. -w is ignored.\n")); 270 break; 271 } 272 273 if (optarg != NULL && 274 optarg[0] == '-' && optarg[1] == '\0') { 275 /* Ask for a password later */ 276 break; 277 } 278 279 standalone_cfg.type = NS_LDAP_SERVER; 280 standalone_cfg.SA_BIND_PWD = strdup(optarg); 281 break; 282 case 'j': 283 if (standalone_cfg.SA_BIND_PWD != NULL) { 284 (void) fprintf(stderr, 285 gettext("The -w option is mutually " 286 "exclusive of -j. -w is ignored.\n")); 287 free(standalone_cfg.SA_BIND_PWD); 288 } 289 standalone_cfg.type = NS_LDAP_SERVER; 290 standalone_cfg.SA_BIND_PWD = readPwd(optarg); 291 if (standalone_cfg.SA_BIND_PWD == NULL) { 292 exit(1); 293 } 294 break; 295 case 'a': 296 authmech = optarg; 297 break; 298 default: 299 usage(gettext("Invalid option")); 300 } 301 } 302 303 if (standalone_cfg.type == NS_LDAP_SERVER && 304 standalone_cfg.SA_SERVER == NULL) { 305 (void) fprintf(stderr, 306 gettext("Please specify an LDAP server you want " 307 "to connect to. \n")); 308 exit(1); 309 } 310 311 if ((c = argc - optind) > 0) 312 database = argv[optind++]; 313 if ((--c) > 0) 314 key = &argv[optind]; 315 316 if (authmech != NULL) { 317 if (__ns_ldap_initAuth(authmech, 318 &auth, 319 &errorp) != NS_LDAP_SUCCESS) { 320 if (errorp) { 321 (void) fprintf(stderr, "%s", errorp->message); 322 (void) __ns_ldap_freeError(&errorp); 323 } 324 exit(1); 325 } 326 } 327 328 if (auth.saslmech != NS_LDAP_SASL_GSSAPI && 329 standalone_cfg.SA_BIND_DN != NULL && 330 standalone_cfg.SA_BIND_PWD == NULL) { 331 /* If password is not specified, then prompt user for it. */ 332 standalone_cfg.SA_BIND_PWD = 333 strdup(getpassphrase("Enter password:")); 334 } 335 336 standalone_cfg.SA_AUTH = (authmech == NULL) ? NULL : &auth; 337 338 if (__ns_ldap_initStandalone(&standalone_cfg, 339 &errorp) != NS_LDAP_SUCCESS) { 340 if (errorp) { 341 (void) fprintf(stderr, "%s\n", errorp->message); 342 (void) __ns_ldap_freeError(&errorp); 343 } 344 exit(1); 345 } 346 347 if (authmech != NULL) { 348 if (__ns_ldap_setParam(NS_LDAP_AUTH_P, 349 authmech, &errorp) != NS_LDAP_SUCCESS) { 350 __ns_ldap_cancelStandalone(); 351 if (errorp != NULL) { 352 (void) fprintf(stderr, "%s", errorp->message); 353 (void) __ns_ldap_freeError(&errorp); 354 } 355 exit(1); 356 } 357 } 358 if (standalone_cfg.SA_CRED != NULL) { 359 if (__ns_ldap_setParam(NS_LDAP_CREDENTIAL_LEVEL_P, 360 standalone_cfg.SA_CRED, &errorp) != NS_LDAP_SUCCESS) { 361 __ns_ldap_cancelStandalone(); 362 if (errorp != NULL) { 363 (void) fprintf(stderr, "%s", errorp->message); 364 (void) __ns_ldap_freeError(&errorp); 365 } 366 exit(1); 367 } 368 } 369 370 if (standalone_cfg.type != NS_CACHEMGR && 371 standalone_cfg.SA_BIND_DN != NULL) { 372 ns_auth_t **authpp = NULL, **authp = NULL; 373 374 if (__ns_ldap_getParam(NS_LDAP_AUTH_P, 375 (void ***)&authpp, 376 &errorp) != NS_LDAP_SUCCESS || authpp == NULL) { 377 __ns_ldap_cancelStandalone(); 378 (void) __ns_ldap_freeParam((void ***)&authpp); 379 if (errorp) { 380 (void) fprintf(stderr, 381 gettext(errorp->message)); 382 (void) __ns_ldap_freeError(&errorp); 383 } 384 exit(1); 385 } 386 for (authp = authpp; *authp; authp++) { 387 if ((*authp)->saslmech == NS_LDAP_SASL_GSSAPI) { 388 /* 389 * For now we have no use for bindDN and 390 * bindPassword when using SASL/GSSAPI. 391 */ 392 (void) fprintf(stderr, 393 gettext("Warning: SASL/GSSAPI will be " 394 "used as an authentication method" 395 "The bind DN and password will " 396 "be ignored.\n")); 397 break; 398 } 399 } 400 } 401 402 /* 403 * If dumpping a database, 404 * or all the containers, 405 * use page control just 406 * in case there are too many entries 407 */ 408 if (!key && !(listflag & NS_LDAP_SCOPE_BASE)) 409 listflag |= NS_LDAP_PAGE_CTRL; 410 411 /* build the attribute array */ 412 if (strncasecmp(attribute, "NULL", 4) == 0) 413 ldapattribute = NULL; 414 else { 415 buffer[0] = strdup(attribute); 416 while ((p = strchr(attribute, ',')) != NULL) { 417 buffer[index++] = attribute = p + 1; 418 *p = '\0'; 419 } 420 buffer[index] = NULL; 421 ldapattribute = buffer; 422 } 423 424 /* build the filter */ 425 if (database && (strcasecmp(database, "publickey") == NULL)) { 426 /* user publickey lookup */ 427 char *err1 = NULL; 428 int rc1; 429 430 rc = rc1 = -1; 431 ldapfilter = set_filter_publickey(key, database, 0, &udata); 432 if (ldapfilter) { 433 if (verbose) { 434 (void) fprintf(stdout, 435 gettext("+++ database=%s\n"), 436 (database ? database : "NULL")); 437 (void) fprintf(stdout, 438 gettext("+++ filter=%s\n"), 439 (ldapfilter ? ldapfilter : "NULL")); 440 (void) fprintf(stdout, 441 gettext("+++ template for merging" 442 "SSD filter=%s\n"), 443 (udata ? udata : "NULL")); 444 } 445 rc = list("passwd", ldapfilter, ldapattribute, 446 &err, udata); 447 free(ldapfilter); 448 free(udata); 449 } 450 /* hosts publickey lookup */ 451 ldapfilter = set_filter_publickey(key, database, 1, &udata); 452 if (ldapfilter) { 453 if (verbose) { 454 (void) fprintf(stdout, 455 gettext("+++ database=%s\n"), 456 (database ? database : "NULL")); 457 (void) fprintf(stdout, 458 gettext("+++ filter=%s\n"), 459 (ldapfilter ? ldapfilter : "NULL")); 460 (void) fprintf(stdout, 461 gettext("+++ template for merging" 462 "SSD filter=%s\n"), 463 (udata ? udata : "NULL")); 464 } 465 rc1 = list("hosts", ldapfilter, ldapattribute, 466 &err1, udata); 467 free(ldapfilter); 468 free(udata); 469 } 470 if (rc == -1 && rc1 == -1) { 471 /* this should never happen */ 472 (void) fprintf(stderr, 473 gettext("ldaplist: invalid publickey lookup\n")); 474 rc = 2; 475 } if (rc != 0 && rc1 != 0) { 476 (void) fprintf(stderr, 477 gettext("ldaplist: %s\n"), (err ? err : err1)); 478 if (rc == -1) 479 rc = rc1; 480 } else 481 rc = 0; 482 exit(switch_err(rc)); 483 } 484 485 /* 486 * we set the search filter to (objectclass=*) when we want 487 * to list the directory attribute instead of the entries 488 * (the -d option). 489 */ 490 if (((ldapfilter = set_filter(key, database, &udata)) == NULL) || 491 (listflag == NS_LDAP_SCOPE_BASE)) { 492 ldapfilter = strdup("objectclass=*"); 493 udata = strdup("%s"); 494 } 495 496 if (verbose) { 497 (void) fprintf(stdout, gettext("+++ database=%s\n"), 498 (database ? database : "NULL")); 499 (void) fprintf(stdout, gettext("+++ filter=%s\n"), 500 (ldapfilter ? ldapfilter : "NULL")); 501 (void) fprintf(stdout, 502 gettext("+++ template for merging SSD filter=%s\n"), 503 (udata ? udata : "NULL")); 504 } 505 if (rc = list(database, ldapfilter, ldapattribute, &err, udata)) 506 (void) fprintf(stderr, gettext("ldaplist: %s\n"), err); 507 508 __ns_ldap_cancelStandalone(); 509 510 if (ldapfilter) 511 free(ldapfilter); 512 if (udata) 513 free(udata); 514 exit(switch_err(rc)); 515 return (0); /* Never reached */ 516 } 517