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