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