Home | History | Annotate | Download | only in common
      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 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  *
     26  */
     27 
     28 /* Id: nss.c 180 2006-07-20 17:33:02Z njacobs $ */
     29 
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <unistd.h>
     33 #include <string.h>
     34 #include <ctype.h>
     35 #include <sys/types.h>
     36 #include <syslog.h>
     37 #include <papi.h>
     38 #include <uri.h>
     39 #include <papi_impl.h>
     40 #ifdef NSS_EMULATION
     41 #include <nss-emulation.h>
     42 #elif NSS_SOLARIS
     43 #include <nss_dbdefs.h>
     44 #endif
     45 #include <config-site.h>
     46 #if defined(__sun) && defined(__SVR4)
     47 #include <sys/systeminfo.h>
     48 #endif
     49 
     50 
     51 static char *
     52 bsdaddr_to_uri(papi_attribute_t **list, char *bsdaddr)
     53 {
     54 	char *result = NULL;
     55 
     56 	if (bsdaddr != NULL) {
     57 		char *bsd[3], *tmp, *iter = NULL;
     58 		char buf[512];
     59 
     60 		tmp = strdup(bsdaddr);
     61 
     62 		bsd[0] = strtok_r(tmp, ":,", &iter);
     63 		if ((bsd[1] = strtok_r(NULL, ":,", &iter)) == NULL)
     64 			papiAttributeListGetString(list, NULL,
     65 					"printer-name", &bsd[1]);
     66 		bsd[2] = strtok_r(NULL, ":,", &iter);
     67 
     68 		snprintf(buf, sizeof (buf), "lpd://%s/printers/%s%s%s", bsd[0],
     69 			(bsd[1] != NULL) ? bsd[1] : "",
     70 			(bsd[2] != NULL) ? "#" : "",
     71 			(bsd[2] != NULL) ? bsd[2] : "");
     72 
     73 		free(tmp);
     74 
     75 		result = strdup(buf);
     76 	}
     77 
     78 	return (result);
     79 }
     80 
     81 #if defined(__sun) && defined(__SVR4)
     82 /*
     83  * This is an awful HACK to force the dynamic PAPI library to use the
     84  * lpsched support when the destination apears to be a local lpsched
     85  * queue on Solaris.
     86  */
     87 static void
     88 solaris_lpsched_shortcircuit_hack(papi_attribute_t ***list)
     89 {
     90 	papi_attribute_t *attribute;
     91 	uri_t *uri = NULL;
     92 	char *printer = NULL;
     93 	char buf[128], buf2[128];
     94 
     95 	/* setting this in the calling env can be useful for debugging */
     96 	if (getenv("DISABLE_LPSCHED_SHORTCIRCUIT") != NULL)
     97 		return;
     98 
     99 	papiAttributeListGetString(*list, NULL,
    100 				"printer-uri-supported", &printer);
    101 	/* if there is no printer-uri-supported, there is nothing to do */
    102 	if (printer == NULL) {
    103 		return;
    104 	}
    105 
    106 	if (uri_from_string(printer, &uri) < 0) {
    107 		papiAttributeListFree(*list);
    108 		*list = NULL;
    109 		uri_free(uri);
    110 		return;
    111 	}
    112 
    113 	/* already an lpsched URI ? */
    114 	if (strcasecmp(uri->scheme, "lpsched") == 0) {
    115 		uri_free(uri);
    116 		return;
    117 	}
    118 
    119 	if (uri->path == NULL) {
    120 		printer = "";
    121 	} else {
    122 		if ((printer = strrchr(uri->path, '/')) == NULL)
    123 			printer = uri->path;
    124 		else
    125 			printer++;
    126 	}
    127 
    128 	/* is there an lpsched queue (printer/class) */
    129 	snprintf(buf, sizeof (buf), "/etc/lp/interfaces/%s", printer);
    130 	snprintf(buf2, sizeof (buf2), "/etc/lp/classes/%s", printer);
    131 	if ((access(buf, F_OK) < 0) && (access(buf2, F_OK) < 0)) {
    132 		uri_free(uri);
    133 		return;
    134 	}
    135 
    136 	/* is this the "local" host */
    137 	if ((uri->host != NULL) && (is_localhost(uri->host) == 0)) {
    138 		uri_free(uri);
    139 		return;
    140 	}
    141 
    142 	snprintf(buf, sizeof (buf), "lpsched://%s/printers/%s",
    143 			(uri->host ? uri->host : "localhost"), printer);
    144 	papiAttributeListAddString(list, PAPI_ATTR_REPLACE,
    145 			"printer-uri-supported", buf);
    146 	uri_free(uri);
    147 }
    148 #endif
    149 
    150 static void
    151 fill_printer_uri_supported(papi_attribute_t ***list)
    152 {
    153 	papi_attribute_t *attribute;
    154 	char *string = NULL;
    155 
    156 	/* do we have a printer-uri-supported */
    157 	attribute = papiAttributeListFind(*list, "printer-uri-supported");
    158 	if (attribute != NULL) /* we have what we need, return */
    159 		return;
    160 
    161 	/* do we have a printer-uri (in URI form) to rename */
    162 	attribute = papiAttributeListFind(*list, "printer-uri");
    163 	if ((attribute != NULL) &&
    164 	    (attribute->type == PAPI_STRING) &&
    165 	    (attribute->values != NULL) &&
    166 	    (attribute->values[0]->string != NULL) &&
    167 	    (strstr(attribute->values[0]->string, "://") != NULL)) {
    168 			/* rename it in place and return */
    169 		free(attribute->name);
    170 		attribute->name = strdup("printer-uri-supported");
    171 		return;
    172 	}
    173 
    174 	/* do we have a printers.conf(4) "bsdaddr" to convert */
    175 	papiAttributeListGetString(*list, NULL, "bsdaddr", &string);
    176 	if (string != NULL) { /* parse it, convert it, add it */
    177 		char *uri = bsdaddr_to_uri(*list, string);
    178 
    179 		if (uri != NULL) {
    180 			papiAttributeListAddString(list, PAPI_ATTR_APPEND,
    181 					"printer-uri-supported", uri);
    182 			papiAttributeListDelete(list, "bsdaddr");
    183 			free(uri);
    184 			return;
    185 		}
    186 	}
    187 
    188 	/* do we have a printers.conf(4) "rm" (and "rp") to convert */
    189 	papiAttributeListGetString(*list, NULL, "rm", &string);
    190 	if (string != NULL) {
    191 		char *rp = NULL;
    192 
    193 		/* default to "printer-name", but use "rp" if we have it */
    194 		papiAttributeListGetString(*list, NULL, "printer-name", &rp);
    195 		papiAttributeListGetString(*list, NULL, "rp", &rp);
    196 
    197 		if (rp != NULL) { /* fill in the uri if we have the data */
    198 			char buf[BUFSIZ];
    199 
    200 			snprintf(buf, sizeof (buf), "lpd://%s/printers/%s",
    201 				string, rp);
    202 			papiAttributeListAddString(list, PAPI_ATTR_APPEND,
    203 					"printer-uri-supported", strdup(buf));
    204 			return;
    205 		}
    206 	}
    207 
    208 	/* if were are here, we don't have a printer-uri-supported */
    209 }
    210 
    211 #ifdef NEED_BROKEN_PRINTER_URI_SEMANTIC
    212 static void
    213 fill_printer_uri(papi_attribute_t ***list)
    214 {
    215 	papi_attribute_t *attribute;
    216 	char *uri = NULL;
    217 
    218 	if ((list == NULL) || (*list == NULL))
    219 		return;
    220 
    221 	/* do we have a printer-uri */
    222 	attribute = papiAttributeListFind(*list, "printer-uri");
    223 	if (attribute != NULL) /* we have what we need, return */
    224 		return;
    225 
    226 	/*
    227 	 * this is sufficient to fool libgnomeprintpapi, but not promote it's
    228 	 * use in the future.
    229 	 */
    230 	papiAttributeListAddString(list, PAPI_ATTR_EXCL, "printer-uri",
    231 			"broken printer-uri semantic");
    232 }
    233 #endif /* NEED_BROKEN_PRINTER_URI_SEMANTIC */
    234 
    235 static void
    236 cvt_all_to_member_names(papi_attribute_t ***list)
    237 {
    238 	papi_status_t status;
    239 	void *iter = NULL;
    240 	char *string = NULL;
    241 
    242 	papiAttributeListGetString(*list, NULL, "member-names", &string);
    243 	if (string != NULL) /* already have a member-names */
    244 		return;
    245 
    246 	for (status = papiAttributeListGetString(*list, &iter, "all", &string);
    247 	    status == PAPI_OK;
    248 	    status = papiAttributeListGetString(*list, &iter, NULL, &string)) {
    249 		char *s_iter = NULL, *value, *tmp = strdup(string);
    250 
    251 		for (value = strtok_r(tmp, ", \t", &s_iter);
    252 		    value != NULL;
    253 		    value = strtok_r(NULL, ", \t", &s_iter))
    254 			papiAttributeListAddString(list, PAPI_ATTR_APPEND,
    255 					"member-names", value);
    256 		free(tmp);
    257 	}
    258 }
    259 
    260 static papi_attribute_t **
    261 _cvt_nss_entry_to_printer(char *entry)
    262 {
    263 	char    *key = NULL,
    264 		*cp,
    265 		buf[BUFSIZ];
    266 	int in_namelist = 1, buf_pos = 0;
    267 	papi_attribute_t **list = NULL;
    268 
    269 	if (entry == NULL)
    270 		return (NULL);
    271 
    272 	memset(buf, 0, sizeof (buf));
    273 	for (cp = entry; *cp != '\0'; cp++) {
    274 		switch (*cp) {
    275 		case ':':	/* end of kvp */
    276 			if (in_namelist != 0) {
    277 				papiAttributeListAddString(&list,
    278 					PAPI_ATTR_APPEND, "printer-name", buf);
    279 				in_namelist = 0;
    280 			} else if (key != NULL) {
    281 				papiAttributeListAddString(&list,
    282 					PAPI_ATTR_APPEND, key, buf);
    283 				free(key);
    284 			}
    285 			memset(buf, 0, sizeof (buf));
    286 			buf_pos = 0;
    287 			key = NULL;
    288 			break;
    289 		case '=':	/* kvp seperator */
    290 			if (key == NULL) {
    291 				key = strdup(buf);
    292 				memset(buf, 0, sizeof (buf));
    293 				buf_pos = 0;
    294 			} else
    295 				buf[buf_pos++] = *cp;
    296 			break;
    297 		case '|':	/* namelist seperator */
    298 			if (in_namelist != 0) {
    299 				papiAttributeListAddString(&list,
    300 					PAPI_ATTR_APPEND, "printer-name", buf);
    301 				memset(buf, 0, sizeof (buf));
    302 				buf_pos = 0;
    303 			} else	/* add it to the buffer */
    304 				buf[buf_pos++] = *cp;
    305 			break;
    306 		case '\\':	/* escape char */
    307 			buf[buf_pos++] = *(++cp);
    308 			break;
    309 		default:
    310 			buf[buf_pos++] = *cp;
    311 		}
    312 
    313 	}
    314 
    315 	if (key != NULL) {
    316 		papiAttributeListAddString(&list, PAPI_ATTR_APPEND, key, buf);
    317 		free(key);
    318 	}
    319 
    320 	/* resolve any "use" references in the configuration DB */
    321 	key = NULL;
    322 	papiAttributeListGetString(list, NULL, "use", &key);
    323 	if (key != NULL) {
    324 		papi_attribute_t **use_attrs = getprinterbyname(key, NULL);
    325 
    326 		list_concatenate(&list, use_attrs);
    327 	}
    328 
    329 	fill_printer_uri_supported(&list);
    330 	cvt_all_to_member_names(&list); /* convert "all" to "member-names" */
    331 
    332 	return (list);
    333 }
    334 
    335 #if defined(NSS_SOLARIS) && !defined(NSS_EMULATION)
    336 
    337 #ifndef	NSS_DBNAM__PRINTERS	/* not in nss_dbdefs.h because it's private */
    338 #define	NSS_DBNAM__PRINTERS	"_printers"
    339 #endif
    340 
    341 static DEFINE_NSS_DB_ROOT(db_root);
    342 static DEFINE_NSS_GETENT(context);
    343 
    344 static char *private_ns = NULL;
    345 
    346 static void
    347 _nss_initf_printers(p)
    348     nss_db_params_t *p;
    349 {
    350 	if (private_ns != NULL) {
    351 		/*
    352 		 * because we need to support a legacy interface that allows
    353 		 * us to select a specific name service, we need to dummy up
    354 		 * the parameters to use a private nsswitch database and set
    355 		 * the * default_config entry to the name service we are
    356 		 * looking into.
    357 		 */
    358 		p->name = NSS_DBNAM__PRINTERS;		/* "_printers" */
    359 		p->default_config = private_ns;
    360 	} else {
    361 		/* regular behaviour */
    362 		p->name = NSS_DBNAM_PRINTERS;	 /* "printers" */
    363 		p->default_config = NSS_DEFCONF_PRINTERS;
    364 	}
    365 	syslog(LOG_DEBUG, "database: %s, default: %s",
    366 		(p->name ? p->name : "NULL"),
    367 		(p->default_config ? p->default_config : "NULL"));
    368 }
    369 
    370 /*
    371  * Return values: 0 = success, 1 = parse error, 2 = erange ...
    372  * The structure pointer passed in is a structure in the caller's space
    373  * wherein the field pointers would be set to areas in the buffer if
    374  * need be. instring and buffer should be separate areas.
    375  */
    376 /* ARGSUSED */
    377 static int
    378 str2printer(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
    379 {
    380 	if (lenstr + 1 > buflen)
    381 		return (NSS_STR_PARSE_ERANGE);
    382 
    383 	/* skip entries that begin with '#' */
    384 	if (instr[0] == '#')
    385 		return (NSS_STR_PARSE_PARSE);
    386 
    387 	/*
    388 	 * We copy the input string into the output buffer
    389 	 */
    390 	(void) memcpy(buffer, instr, lenstr);
    391 	buffer[lenstr] = '\0';
    392 
    393 	return (NSS_STR_PARSE_SUCCESS);
    394 }
    395 #endif /* NSS_SOLARIS */
    396 
    397 int
    398 setprinterentry(int stayopen, char *ns)
    399 {
    400 #ifdef NSS_EMULATION
    401 	emul_setprinterentry(stayopen);
    402 #elif NSS_SOLARIS
    403 	private_ns = ns;
    404 	nss_setent(&db_root, _nss_initf_printers, &context);
    405 	private_ns = NULL;
    406 #endif
    407 	return (0);
    408 }
    409 
    410 
    411 int
    412 endprinterentry(int i)
    413 {
    414 #ifdef NSS_EMULATION
    415 	emul_endprinterentry();
    416 #elif NSS_SOLARIS
    417 	nss_endent(&db_root, _nss_initf_printers, &context);
    418 	nss_delete(&db_root);
    419 	private_ns = NULL;
    420 #endif
    421 	return (0);
    422 }
    423 
    424 /* ARGSUSED2 */
    425 papi_attribute_t **
    426 getprinterentry(char *ns)
    427 {
    428 	papi_attribute_t **result = NULL;
    429 
    430 #if defined(NSS_EMULATION) || defined(NSS_SOLARIS)
    431 	char buf[10240];
    432 	nss_status_t	res = NSS_NOTFOUND;
    433 
    434 #ifdef NSS_EMULATION
    435 	res = emul_getprinterentry_r(buf, sizeof (buf));
    436 #elif NSS_SOLARIS
    437 	nss_XbyY_args_t arg;
    438 
    439 	private_ns = ns;
    440 	NSS_XbyY_INIT(&arg, buf, buf, sizeof (buf), str2printer);
    441 	res = nss_getent(&db_root, _nss_initf_printers, &context, &arg);
    442 	(void) NSS_XbyY_FINI(&arg);
    443 	private_ns = NULL;
    444 #endif
    445 
    446 	if (res != NSS_SUCCESS)
    447 		buf[0] = '\0';
    448 
    449 	result = _cvt_nss_entry_to_printer(buf);
    450 #if defined(__sun) && defined(__SVR4)
    451 	solaris_lpsched_shortcircuit_hack(&result);
    452 #endif
    453 #ifdef NEED_BROKEN_PRINTER_URI_SEMANTIC
    454 	fill_printer_uri(&result);
    455 #endif /* NEED_BROKEN_PRINTER_URI_SEMANTIC */
    456 #endif
    457 
    458 #ifdef DEBUG
    459 	printf("getprinterentry(%s): 0x%8.8x\n", (ns ? ns : "NULL"), result);
    460 	if (result != NULL) {
    461 		char buf[4096];
    462 
    463 		papiAttributeListToString(result, "\n\t", buf, sizeof (buf));
    464 		printf("\t%s\n", buf);
    465 	}
    466 #endif /* DEBUG */
    467 
    468 	return (result);
    469 }
    470 
    471 
    472 papi_attribute_t **
    473 getprinterbyname(char *name, char *ns)
    474 {
    475 	papi_attribute_t **result = NULL;
    476 
    477 	if (strstr(name, "://") != NULL) {	/* shortcut for URI form */
    478 		papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
    479 				"printer-name", name);
    480 		papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
    481 				"printer-uri-supported", name);
    482 	} else if (strchr(name, ':') != NULL) {	/* shortcut for POSIX form */
    483 		char *uri = bsdaddr_to_uri(result, name);
    484 
    485 		papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
    486 				"printer-name", name);
    487 		if (uri != NULL) {
    488 			papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
    489 					"printer-uri-supported", uri);
    490 			free(uri);
    491 		}
    492 	} else {				/* anything else */
    493 #if defined(NSS_EMULATION) || defined(NSS_SOLARIS)
    494 		char buf[10240];
    495 		nss_status_t	res = NSS_NOTFOUND;
    496 
    497 #ifdef NSS_EMULATION
    498 		res = emul_getprinterbyname_r(name, buf, sizeof (buf));
    499 #elif NSS_SOLARIS
    500 		nss_XbyY_args_t arg;
    501 
    502 		private_ns = ns;
    503 		NSS_XbyY_INIT(&arg, buf, buf, sizeof (buf), str2printer);
    504 		arg.key.name = name;
    505 		res = nss_search(&db_root, _nss_initf_printers,
    506 				NSS_DBOP_PRINTERS_BYNAME, &arg);
    507 		(void) NSS_XbyY_FINI(&arg);
    508 		private_ns = NULL;
    509 
    510 		if (res != NSS_SUCCESS)
    511 			buf[0] = '\0';
    512 #endif
    513 
    514 		result = _cvt_nss_entry_to_printer(buf);
    515 #endif
    516 	}
    517 #if defined(__sun) && defined(__SVR4)
    518 	solaris_lpsched_shortcircuit_hack(&result);
    519 #endif
    520 #ifdef DEBUG
    521 	printf("getprinterbyname(%s): %s = 0x%8.8x\n", (ns ? ns : "NULL"),
    522 		name, result);
    523 	if (result != NULL) {
    524 		char buf[4096];
    525 
    526 		papiAttributeListToString(result, "\n\t", buf, sizeof (buf));
    527 		printf("\t%s\n", buf);
    528 	}
    529 #endif /* DEBUG */
    530 
    531 	return (result);
    532 }
    533