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 { 80 if (msg) 81 (void) fprintf(stderr, "%s\n", msg); 82 83 (void) fprintf(stderr, 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, char **realfilter, 148 const void *userdata) 149 { 150 int len; 151 char *checker; 152 153 /* sanity check */ 154 if (realfilter == NULL) 155 return (NS_LDAP_INVALID_PARAM); 156 *realfilter = NULL; 157 158 if (desc == NULL || desc->filter == NULL || 159 userdata == NULL) 160 return (NS_LDAP_INVALID_PARAM); 161 162 /* Parameter check. We only want one %s here, otherwise bail. */ 163 len = 0; /* Reuse 'len' as "Number of %s hits"... */ 164 checker = (char *)userdata; 165 do { 166 checker = strchr(checker, '%'); 167 if (checker != NULL) { 168 if (len > 0 || *(checker + 1) != 's') 169 return (NS_LDAP_INVALID_PARAM); 170 len++; /* Got our %s. */ 171 checker += 2; 172 } else if (len != 1) 173 return (NS_LDAP_INVALID_PARAM); 174 } while (checker != NULL); 175 176 len = strlen(userdata) + strlen(desc->filter) + 1; 177 178 *realfilter = (char *)malloc(len); 179 if (*realfilter == NULL) 180 return (NS_LDAP_MEMORY); 181 182 (void) sprintf(*realfilter, (char *)userdata, 183 desc->filter); 184 185 return (NS_LDAP_SUCCESS); 186 } 187 188 /* returns 0=success, 1=error */ 189 int 190 list(char *database, char *ldapfilter, char **ldapattribute, 191 char **err, char *userdata) 192 { 193 ns_ldap_result_t *result; 194 ns_ldap_error_t *errorp; 195 int rc; 196 char buf[500]; 197 const char *sort = NULL; 198 int i; 199 200 if (database) { 201 for (i = 0; databaselist[i].database; i++) { 202 if (strcmp(databaselist[i].database, database) == 0) { 203 sort = databaselist[i].sortattr; 204 break; 205 } 206 if (strcmp(databaselist[i].database, 207 NS_LDAP_TYPE_AUTOMOUNT) == 0 && 208 strncmp(database, NS_LDAP_TYPE_AUTOMOUNT, 209 sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0) { 210 sort = databaselist[i].sortattr; 211 break; 212 } 213 } 214 } 215 216 *err = NULL; 217 buf[0] = '\0'; 218 rc = __ns_ldap_list_sort(database, (const char *)ldapfilter, 219 sort, merge_SSD_filter, (const char **)ldapattribute, NULL, 220 listflag, &result, &errorp, NULL, userdata); 221 if (rc != NS_LDAP_SUCCESS) { 222 char *p; 223 (void) __ns_ldap_err2str(rc, &p); 224 if (errorp && errorp->message) { 225 (void) snprintf(buf, sizeof (buf), "%s (%s)", 226 p, errorp->message); 227 (void) __ns_ldap_freeError(&errorp); 228 } else 229 (void) snprintf(buf, sizeof (buf), "%s\n", p); 230 *err = strdup(buf); 231 return (rc); 232 } 233 234 _printResult(result); 235 (void) __ns_ldap_freeResult(&result); 236 return (0); 237 } 238 239 240 int 241 switch_err(int rc) 242 { 243 switch (rc) { 244 case NS_LDAP_SUCCESS: 245 return (0); 246 case NS_LDAP_NOTFOUND: 247 return (1); 248 } 249 return (2); 250 } 251 252 int 253 main(int argc, char **argv) 254 { 255 256 extern int optind; 257 char *database = NULL; 258 char *ldapfilter = NULL; 259 char *attribute = "dn"; 260 char **key = NULL; 261 char **ldapattribute = NULL; 262 char *buffer[100]; 263 char *err = NULL; 264 char *p; 265 int index = 1; 266 int c; 267 int rc; 268 int verbose = 0; 269 char *udata = NULL; 270 271 ns_standalone_conf_t standalone_cfg = standaloneDefaults; 272 ns_ldap_error_t *errorp = NULL; 273 char *authmech = NULL; 274 ns_auth_t auth = {NS_LDAP_AUTH_NONE, 275 NS_LDAP_TLS_NONE, 276 NS_LDAP_SASL_NONE, 277 NS_LDAP_SASLOPT_NONE}; 278 279 (void) setlocale(LC_ALL, ""); 280 (void) textdomain(TEXT_DOMAIN); 281 282 openlog("ldaplist", LOG_PID, LOG_USER); 283 284 if (argc == 2 && 285 strlen(argv[1]) == 2 && strncmp(argv[1], "-h", 2) == 0) { 286 /* preserve backwards compatability, support old -h option */ 287 (void) printMapping(); 288 exit(0); 289 } 290 291 while ((c = getopt(argc, argv, "h:M:N:P:r:a:D:w:j:dgvl")) != EOF) { 292 switch (c) { 293 case 'd': 294 listflag |= NS_LDAP_SCOPE_BASE; 295 break; 296 case 'g': 297 (void) printMapping(); 298 exit(0); 299 break; /* Never reached */ 300 case 'l': 301 attribute = "NULL"; 302 break; 303 case 'v': 304 verbose = 1; 305 break; 306 case 'M': 307 standalone_cfg.type = NS_LDAP_SERVER; 308 standalone_cfg.SA_DOMAIN = optarg; 309 break; 310 case 'h': 311 standalone_cfg.type = NS_LDAP_SERVER; 312 if (separatePort(optarg, 313 &standalone_cfg.SA_SERVER, 314 &standalone_cfg.SA_PORT) > 0) { 315 exit(1); 316 } 317 break; 318 case 'P': 319 standalone_cfg.type = NS_LDAP_SERVER; 320 standalone_cfg.SA_CERT_PATH = optarg; 321 break; 322 case 'N': 323 standalone_cfg.type = NS_LDAP_SERVER; 324 standalone_cfg.SA_PROFILE_NAME = optarg; 325 break; 326 case 'D': 327 standalone_cfg.type = NS_LDAP_SERVER; 328 standalone_cfg.SA_BIND_DN = strdup(optarg); 329 break; 330 case 'w': 331 if (standalone_cfg.SA_BIND_PWD != NULL) { 332 (void) fprintf(stderr, 333 gettext("The -w option is mutually " 334 "exclusive of -j. -w is ignored.\n")); 335 break; 336 } 337 338 if (optarg != NULL && 339 optarg[0] == '-' && optarg[1] == '\0') { 340 /* Ask for a password later */ 341 break; 342 } 343 344 standalone_cfg.type = NS_LDAP_SERVER; 345 standalone_cfg.SA_BIND_PWD = strdup(optarg); 346 break; 347 case 'j': 348 if (standalone_cfg.SA_BIND_PWD != NULL) { 349 (void) fprintf(stderr, 350 gettext("The -w option is mutually " 351 "exclusive of -j. -w is ignored.\n")); 352 free(standalone_cfg.SA_BIND_PWD); 353 } 354 standalone_cfg.type = NS_LDAP_SERVER; 355 standalone_cfg.SA_BIND_PWD = readPwd(optarg); 356 if (standalone_cfg.SA_BIND_PWD == NULL) { 357 exit(1); 358 } 359 break; 360 case 'a': 361 authmech = optarg; 362 break; 363 default: 364 usage(gettext("Invalid option")); 365 } 366 } 367 368 if (standalone_cfg.type == NS_LDAP_SERVER && 369 standalone_cfg.SA_SERVER == NULL) { 370 (void) fprintf(stderr, 371 gettext("Please specify an LDAP server you want " 372 "to connect to. \n")); 373 exit(1); 374 } 375 376 if ((c = argc - optind) > 0) 377 database = argv[optind++]; 378 if ((--c) > 0) 379 key = &argv[optind]; 380 381 if (authmech != NULL) { 382 if (__ns_ldap_initAuth(authmech, 383 &auth, 384 &errorp) != NS_LDAP_SUCCESS) { 385 if (errorp) { 386 (void) fprintf(stderr, "%s", errorp->message); 387 (void) __ns_ldap_freeError(&errorp); 388 } 389 exit(1); 390 } 391 } 392 393 if (auth.saslmech != NS_LDAP_SASL_GSSAPI && 394 standalone_cfg.SA_BIND_DN != NULL && 395 standalone_cfg.SA_BIND_PWD == NULL) { 396 /* If password is not specified, then prompt user for it. */ 397 standalone_cfg.SA_BIND_PWD = 398 strdup(getpassphrase("Enter password:")); 399 } 400 401 standalone_cfg.SA_AUTH = (authmech == NULL) ? NULL : &auth; 402 403 if (__ns_ldap_initStandalone(&standalone_cfg, 404 &errorp) != NS_LDAP_SUCCESS) { 405 if (errorp) { 406 (void) fprintf(stderr, "%s\n", errorp->message); 407 (void) __ns_ldap_freeError(&errorp); 408 } 409 exit(1); 410 } 411 412 if (authmech != NULL) { 413 if (__ns_ldap_setParam(NS_LDAP_AUTH_P, 414 authmech, &errorp) != NS_LDAP_SUCCESS) { 415 __ns_ldap_cancelStandalone(); 416 if (errorp != NULL) { 417 (void) fprintf(stderr, "%s", errorp->message); 418 (void) __ns_ldap_freeError(&errorp); 419 } 420 exit(1); 421 } 422 } 423 if (standalone_cfg.SA_CRED != NULL) { 424 if (__ns_ldap_setParam(NS_LDAP_CREDENTIAL_LEVEL_P, 425 standalone_cfg.SA_CRED, &errorp) != NS_LDAP_SUCCESS) { 426 __ns_ldap_cancelStandalone(); 427 if (errorp != NULL) { 428 (void) fprintf(stderr, "%s", errorp->message); 429 (void) __ns_ldap_freeError(&errorp); 430 } 431 exit(1); 432 } 433 } 434 435 if (standalone_cfg.type != NS_CACHEMGR && 436 standalone_cfg.SA_BIND_DN != NULL) { 437 ns_auth_t **authpp = NULL, **authp = NULL; 438 439 if (__ns_ldap_getParam(NS_LDAP_AUTH_P, 440 (void ***)&authpp, 441 &errorp) != NS_LDAP_SUCCESS || authpp == NULL) { 442 __ns_ldap_cancelStandalone(); 443 (void) __ns_ldap_freeParam((void ***)&authpp); 444 if (errorp) { 445 (void) fprintf(stderr, 446 gettext(errorp->message)); 447 (void) __ns_ldap_freeError(&errorp); 448 } 449 exit(1); 450 } 451 for (authp = authpp; *authp; authp++) { 452 if ((*authp)->saslmech == NS_LDAP_SASL_GSSAPI) { 453 /* 454 * For now we have no use for bindDN and 455 * bindPassword when using SASL/GSSAPI. 456 */ 457 (void) fprintf(stderr, 458 gettext("Warning: SASL/GSSAPI will be " 459 "used as an authentication method" 460 "The bind DN and password will " 461 "be ignored.\n")); 462 break; 463 } 464 } 465 } 466 467 /* 468 * If dumpping a database, 469 * or all the containers, 470 * use page control just 471 * in case there are too many entries 472 */ 473 if (!key && !(listflag & NS_LDAP_SCOPE_BASE)) 474 listflag |= NS_LDAP_PAGE_CTRL; 475 476 /* build the attribute array */ 477 if (strncasecmp(attribute, "NULL", 4) == 0) 478 ldapattribute = NULL; 479 else { 480 buffer[0] = strdup(attribute); 481 while ((p = strchr(attribute, ',')) != NULL) { 482 buffer[index++] = attribute = p + 1; 483 *p = '\0'; 484 } 485 buffer[index] = NULL; 486 ldapattribute = buffer; 487 } 488 489 /* build the filter */ 490 if (database && (strcasecmp(database, "publickey") == 0)) { 491 /* user publickey lookup */ 492 char *err1 = NULL; 493 int rc1; 494 495 rc = rc1 = -1; 496 ldapfilter = set_filter_publickey(key, database, 0, &udata); 497 if (ldapfilter) { 498 if (verbose) { 499 (void) fprintf(stdout, 500 gettext("+++ database=%s\n"), 501 (database ? database : "NULL")); 502 (void) fprintf(stdout, 503 gettext("+++ filter=%s\n"), 504 (ldapfilter ? ldapfilter : "NULL")); 505 (void) fprintf(stdout, 506 gettext("+++ template for merging" 507 "SSD filter=%s\n"), 508 (udata ? udata : "NULL")); 509 } 510 rc = list("passwd", ldapfilter, ldapattribute, 511 &err, udata); 512 free(ldapfilter); 513 free(udata); 514 } 515 /* hosts publickey lookup */ 516 ldapfilter = set_filter_publickey(key, database, 1, &udata); 517 if (ldapfilter) { 518 if (verbose) { 519 (void) fprintf(stdout, 520 gettext("+++ database=%s\n"), 521 (database ? database : "NULL")); 522 (void) fprintf(stdout, 523 gettext("+++ filter=%s\n"), 524 (ldapfilter ? ldapfilter : "NULL")); 525 (void) fprintf(stdout, 526 gettext("+++ template for merging" 527 "SSD filter=%s\n"), 528 (udata ? udata : "NULL")); 529 } 530 rc1 = list("hosts", ldapfilter, ldapattribute, 531 &err1, udata); 532 free(ldapfilter); 533 free(udata); 534 } 535 if (rc == -1 && rc1 == -1) { 536 /* this should never happen */ 537 (void) fprintf(stderr, 538 gettext("ldaplist: invalid publickey lookup\n")); 539 rc = 2; 540 } else if (rc != 0 && rc1 != 0) { 541 (void) fprintf(stderr, 542 gettext("ldaplist: %s\n"), (err ? err : err1)); 543 if (rc == -1) 544 rc = rc1; 545 } else 546 rc = 0; 547 exit(switch_err(rc)); 548 } 549 550 /* 551 * we set the search filter to (objectclass=*) when we want 552 * to list the directory attribute instead of the entries 553 * (the -d option). 554 */ 555 if (((ldapfilter = set_filter(key, database, &udata)) == NULL) || 556 (listflag == NS_LDAP_SCOPE_BASE)) { 557 ldapfilter = strdup("objectclass=*"); 558 udata = strdup("%s"); 559 } 560 561 if (verbose) { 562 (void) fprintf(stdout, gettext("+++ database=%s\n"), 563 (database ? database : "NULL")); 564 (void) fprintf(stdout, gettext("+++ filter=%s\n"), 565 (ldapfilter ? ldapfilter : "NULL")); 566 (void) fprintf(stdout, 567 gettext("+++ template for merging SSD filter=%s\n"), 568 (udata ? udata : "NULL")); 569 } 570 if (rc = list(database, ldapfilter, ldapattribute, &err, udata)) 571 (void) fprintf(stderr, gettext("ldaplist: %s\n"), err); 572 573 __ns_ldap_cancelStandalone(); 574 575 if (ldapfilter) 576 free(ldapfilter); 577 if (udata) 578 free(udata); 579 exit(switch_err(rc)); 580 return (0); /* Never reached */ 581 } 582