/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include #include #include static char ** strsplit(char *string, char *seperators) { char **list = NULL; char *where = NULL; char *element; for (element = strtok_r(string, seperators, &where); element != NULL; element = strtok_r(NULL, seperators, &where)) list = (char **)list_append((void **)list, element); return (list); } /* * Manipulate bsd_addr structures */ ns_bsd_addr_t * bsd_addr_create(const char *server, const char *printer, const char *extension) { ns_bsd_addr_t *addr = NULL; if ((server != NULL) && ((addr = calloc(1, sizeof (*addr))) != NULL)) { addr->printer = (char *)printer; addr->server = (char *)server; addr->extension = (char *)extension; } return (addr); } static char * bsd_addr_to_string(const ns_bsd_addr_t *addr) { char buf[BUFSIZ]; if ((addr == NULL) || (addr->server == NULL)) return (NULL); if (snprintf(buf, sizeof (buf), "%s", addr->server) >= sizeof (buf)) { syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow"); return (NULL); } if ((addr->printer != NULL) || (addr->extension != NULL)) (void) strlcat(buf, ",", sizeof (buf)); if (addr->printer != NULL) if (strlcat(buf, addr->printer, sizeof (buf)) >= sizeof (buf)) { syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow"); return (NULL); } if (addr->extension != NULL) { (void) strlcat(buf, ",", sizeof (buf)); if (strlcat(buf, addr->extension, sizeof (buf)) >= sizeof (buf)) { syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow"); return (NULL); } } return (strdup(buf)); } ns_bsd_addr_t * string_to_bsd_addr(const char *string) { char **list, *tmp, *printer = NULL, *extension = NULL; if (string == NULL) return (NULL); tmp = strdup(string); list = strsplit(tmp, ","); if (list[1] != NULL) { printer = list[1]; if (list[2] != NULL) extension = list[2]; } return (bsd_addr_create(list[0], printer, extension)); } static char * list_to_string(const char **list) { char buf[BUFSIZ]; if ((list == NULL) || (*list == NULL)) return (NULL); if (snprintf(buf, sizeof (buf), "%s", *list) >= sizeof (buf)) { syslog(LOG_ERR, "list_to_string: buffer overflow"); return (NULL); } while (*++list != NULL) { (void) strlcat(buf, ",", sizeof (buf)); if (strlcat(buf, *list, sizeof (buf)) >= sizeof (buf)) { syslog(LOG_ERR, "list_to_string: buffer overflow"); return (NULL); } } return (strdup(buf)); } static char * internal_list_to_string(const ns_printer_t **list) { char buf[BUFSIZ]; if ((list == NULL) || (*list == NULL)) return (NULL); if (snprintf(buf, sizeof (buf), "%s", (*list)->name) >= sizeof (buf)) { syslog(LOG_ERR, "internal_list_to_string:buffer overflow"); return (NULL); } while (*++list != NULL) { (void) strlcat(buf, ",", sizeof (buf)); if (strlcat(buf, (*list)->name, sizeof (buf)) >= sizeof (buf)) { syslog(LOG_ERR, "internal_list_to_string:buffer overflow"); return (NULL); } } return (strdup(buf)); } char * value_to_string(const char *key, void *value) { char *string = NULL; if ((key != NULL) && (value != NULL)) { if (strcmp(key, NS_KEY_BSDADDR) == 0) { string = bsd_addr_to_string(value); } else if ((strcmp(key, NS_KEY_ALL) == 0) || (strcmp(key, NS_KEY_GROUP) == 0)) { string = list_to_string(value); } else if (strcmp(key, NS_KEY_LIST) == 0) { string = internal_list_to_string(value); } else { string = strdup((char *)value); } } return (string); } void * string_to_value(const char *key, char *string) { void *value = NULL; if ((key != NULL) && (string != NULL) && (string[0] != '\0')) { if (strcmp(key, NS_KEY_BSDADDR) == 0) { value = (void *)string_to_bsd_addr(string); } else if ((strcmp(key, NS_KEY_ALL) == 0) || (strcmp(key, NS_KEY_GROUP) == 0)) { value = (void *)strsplit(string, ","); } else { value = (void *)string; } } return (value); } static void split_name(char *name, const char *delimiter, char **p1, char **p2, char **p3) { char *tmp, *junk = NULL; if (p1 != NULL) *p1 = NULL; if (p2 != NULL) *p2 = NULL; if (p3 != NULL) *p3 = NULL; if ((name == NULL) || (delimiter == NULL)) { syslog(LOG_DEBUG, "split_name(): name/delimter invalid\n"); return; } for (tmp = (char *)strtok_r(name, delimiter, &junk); tmp != NULL; tmp = (char *)strtok_r(NULL, delimiter, &junk)) if ((p1 != NULL) && (*p1 == NULL)) { *p1 = tmp; } else if ((p2 != NULL) && (*p2 == NULL)) { *p2 = tmp; if (p3 == NULL) break; } else if ((p3 != NULL) && (*p3 == NULL)) { *p3 = tmp; break; } } /* * This implements support for printer names that are fully resolvable * on their own. These "complete" names are converted into a ns_printer_t * structure containing an appropriate "bsdaddr" attribute. The supported * formats are as follows: * POSIX style (server:printer[:conformance]). * This format is an adaptation of the format originally * described in POSIX 1387.4. The POSIX draft has since been * squashed, but this particular component lives on. The * conformace field has been added to allow further identification * of the the server. */ ns_printer_t * posix_name(const char *name) { ns_printer_t *printer = NULL; char *tmp = NULL; if ((name != NULL) && ((tmp = strpbrk(name, ":")) != NULL)) { char *server = NULL; char *queue = NULL; char *extension = NULL; char *addr = strdup(name); char buf[BUFSIZ]; if (*tmp == ':') split_name(addr, ": \t", &server, &queue, &extension); memset(buf, 0, sizeof (buf)); if ((server != NULL) && (queue != NULL)) snprintf(buf, sizeof (buf), "%s,%s%s%s", server, queue, (extension != NULL ? "," : ""), (extension != NULL ? extension : "")); /* build the structure here */ if (buf[0] != '\0') { ns_kvp_t **list, *kvp; kvp = ns_kvp_create(NS_KEY_BSDADDR, buf); list = (ns_kvp_t **)list_append(NULL, kvp); if (list != NULL) printer = ns_printer_create(strdup(name), NULL, "posix", list); } } return (printer); } /* * FUNCTION: * int ns_bsd_addr_cmp(ns_bsd_addr_t *at, ns_bsd_addr_t *a2) * INPUTS: * ns_bsd_addr_t *a1 - a bsd addr * ns_bsd_addr_t *21 - another bsd addr * DESCRIPTION: * This functions compare 2 bsd_addr structures to determine if the * information in them is the same. */ static int ns_bsd_addr_cmp(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2) { int rc; if ((a1 == NULL) || (a2 == NULL)) return (1); if ((rc = strcmp(a1->server, a2->server)) != 0) return (rc); if ((a1->printer == NULL) || (a2->printer == NULL)) return (a1->printer != a2->printer); return (strcmp(a1->printer, a2->printer)); } /* * FUNCTION: ns_bsd_addr_cmp_local() * * DESCRIPTION: This function compares 2 bsd_addr structures to determine if * the information in them is the same. It destinquishes between * real printer names and alias names while doing the compare. * * INPUTS: ns_bsd_addr_t *a1 - a bsd addr * ns_bsd_addr_t *a2 - another bsd addr */ static int ns_bsd_addr_cmp_local(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2) { int rc; if ((a1 == NULL) || (a2 == NULL)) { return (1); } if ((rc = strcmp(a1->server, a2->server)) != 0) { return (rc); } if ((a1->printer == NULL) || (a2->printer == NULL)) { return (a1->printer != a2->printer); } rc = strcmp(a1->printer, a2->printer); if (rc == 0) { /* * The printer's real names are the same, but now check if * their local names (alias) are the same. */ rc = strcmp(a1->pname, a2->pname); } return (rc); } /* ns_bsd_addr_cmp_local */ /* * FUNCTION: * ns_bsd_addr_t *ns_bsd_addr_get_name(char *name) * INPUTS: * char *name - name of printer to get address for * OUTPUTS: * ns_bsd_addr_t *(return) - the address of the printer * DESCRIPTION: * This function will get the BSD address of the printer specified. * it fills in the printer name if none is specified in the "name service" * as a convenience to calling functions. */ ns_bsd_addr_t * ns_bsd_addr_get_name(char *name) { ns_printer_t *printer; ns_bsd_addr_t *addr = NULL; endprinterentry(); if ((printer = ns_printer_get_name(name, NULL)) != NULL) { addr = ns_get_value(NS_KEY_BSDADDR, printer); if (addr != NULL && addr->printer == NULL) addr->printer = strdup(printer->name); if (addr != NULL) { /* * if the name given is not the same as that in the * this is an alias/remote name so put that into the * pname field otherwise duplicate the real printer * name */ if (strcmp(name, printer->name) != 0) { addr->pname = strdup(name); } else { addr->pname = strdup(printer->name); } } } return (addr); } /* * FUNCTION: * ns_bsd_addr_t **ns_bsd_addr_get_list() * OUTPUT: * ns_bsd_addr_t **(return) - a list of bsd addresses for all printers * in all "name services" * DESCRIPTION: * This function will gather a list of all printer addresses in all * of the "name services". All redundancy is removed. */ ns_bsd_addr_t ** ns_bsd_addr_get_list(int unique) { ns_printer_t **printers; ns_bsd_addr_t **list = NULL; char **aliases = NULL; for (printers = ns_printer_get_list(NULL); printers != NULL && *printers != NULL; printers++) { ns_bsd_addr_t *addr; if (strcmp(NS_NAME_ALL, (*printers)->name) == 0) continue; if ((addr = ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) { if (addr->printer == NULL) addr->printer = strdup((*printers)->name); addr->pname = strdup((*printers)->name); } if (unique == UNIQUE) list = (ns_bsd_addr_t **)list_append_unique((void **)list, (void *)addr, (COMP_T)ns_bsd_addr_cmp); else if (unique == LOCAL_UNIQUE) list = (ns_bsd_addr_t **)list_append_unique((void **)list, (void *)addr, (COMP_T)ns_bsd_addr_cmp_local); else list = (ns_bsd_addr_t **)list_append((void **)list, (void *)addr); for (aliases = (*printers)->aliases; (aliases != NULL) && (*aliases != NULL); aliases++) { /* * Include any alias names that belong to the printer */ if ((addr = ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) { if (addr->printer == NULL) { addr->printer = strdup(*aliases); } addr->pname = strdup(*aliases); } if (unique == UNIQUE) { list = (ns_bsd_addr_t **) list_append_unique((void **)list, (void *)addr, (COMP_T)ns_bsd_addr_cmp); } else if (unique == LOCAL_UNIQUE) { list = (ns_bsd_addr_t **) list_append_unique((void **)list, (void *)addr, (COMP_T)ns_bsd_addr_cmp_local); } else { list = (ns_bsd_addr_t **) list_append((void **)list, (void *)addr); } } } return (list); } /* * FUNCTION: * ns_bsd_addr_t **ns_bsd_addr_get_list() * OUTPUT: * ns_bsd_addr_t **(return) - a list of bsd addresses for "_all" printers * in the "name service" * DESCRIPTION: * This function will use the "_all" entry to find a list of printers and * addresses. The "default" printer is also added to the list. * All redundancy is removed. */ ns_bsd_addr_t ** ns_bsd_addr_get_all(int unique) { ns_printer_t *printer; ns_bsd_addr_t **list = NULL; char **printers; char *def = NULL; if (((def = (char *)getenv("PRINTER")) == NULL) && ((def = (char *)getenv("LPDEST")) == NULL)) def = NS_NAME_DEFAULT; list = (ns_bsd_addr_t **)list_append((void **)list, (void *)ns_bsd_addr_get_name(def)); endprinterentry(); if ((printer = ns_printer_get_name(NS_NAME_ALL, NULL)) == NULL) return (ns_bsd_addr_get_list(unique)); for (printers = (char **)ns_get_value(NS_KEY_ALL, printer); printers != NULL && *printers != NULL; printers++) { ns_bsd_addr_t *addr; addr = ns_bsd_addr_get_name(*printers); if (addr != NULL) addr->pname = *printers; if (unique == UNIQUE) list = (ns_bsd_addr_t **)list_append_unique((void **)list, (void *)addr, (COMP_T)ns_bsd_addr_cmp); else list = (ns_bsd_addr_t **)list_append((void **)list, (void *)addr); } return (list); } ns_bsd_addr_t * ns_bsd_addr_get_default() { char *def = NULL; ns_bsd_addr_t *addr; if (((def = (char *)getenv("PRINTER")) == NULL) && ((def = (char *)getenv("LPDEST")) == NULL)) { def = NS_NAME_DEFAULT; addr = ns_bsd_addr_get_name(def); if (addr != NULL) { addr->pname = def; return (addr); } } return (NULL); }