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