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 /*LINTLIBRARY*/ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <sys/types.h> 32 #include <stdarg.h> 33 #include <string.h> 34 #include <syslog.h> 35 36 #include <ns.h> 37 #include <list.h> 38 39 static char ** 40 strsplit(char *string, char *seperators) 41 { 42 char **list = NULL; 43 char *where = NULL; 44 char *element; 45 46 for (element = strtok_r(string, seperators, &where); element != NULL; 47 element = strtok_r(NULL, seperators, &where)) 48 list = (char **)list_append((void **)list, element); 49 50 return (list); 51 } 52 53 /* 54 * Manipulate bsd_addr structures 55 */ 56 ns_bsd_addr_t * 57 bsd_addr_create(const char *server, const char *printer, const char *extension) 58 { 59 ns_bsd_addr_t *addr = NULL; 60 61 if ((server != NULL) && 62 ((addr = calloc(1, sizeof (*addr))) != NULL)) { 63 addr->printer = (char *)printer; 64 addr->server = (char *)server; 65 addr->extension = (char *)extension; 66 } 67 68 return (addr); 69 } 70 71 static char * 72 bsd_addr_to_string(const ns_bsd_addr_t *addr) 73 { 74 char buf[BUFSIZ]; 75 76 if ((addr == NULL) || (addr->server == NULL)) 77 return (NULL); 78 79 if (snprintf(buf, sizeof (buf), "%s", addr->server) >= sizeof (buf)) { 80 syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow"); 81 return (NULL); 82 } 83 84 if ((addr->printer != NULL) || (addr->extension != NULL)) 85 (void) strlcat(buf, ",", sizeof (buf)); 86 if (addr->printer != NULL) 87 if (strlcat(buf, addr->printer, sizeof (buf)) >= sizeof (buf)) { 88 syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow"); 89 return (NULL); 90 } 91 if (addr->extension != NULL) { 92 (void) strlcat(buf, ",", sizeof (buf)); 93 if (strlcat(buf, addr->extension, sizeof (buf)) 94 >= sizeof (buf)) { 95 syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow"); 96 return (NULL); 97 } 98 } 99 100 return (strdup(buf)); 101 } 102 103 ns_bsd_addr_t * 104 string_to_bsd_addr(const char *string) 105 { 106 char **list, *tmp, *printer = NULL, *extension = NULL; 107 108 if (string == NULL) 109 return (NULL); 110 111 tmp = strdup(string); 112 list = strsplit(tmp, ","); 113 114 if (list[1] != NULL) { 115 printer = list[1]; 116 if (list[2] != NULL) 117 extension = list[2]; 118 } 119 120 return (bsd_addr_create(list[0], printer, extension)); 121 } 122 123 static char * 124 list_to_string(const char **list) 125 { 126 char buf[BUFSIZ]; 127 128 if ((list == NULL) || (*list == NULL)) 129 return (NULL); 130 131 if (snprintf(buf, sizeof (buf), "%s", *list) >= sizeof (buf)) { 132 syslog(LOG_ERR, "list_to_string: buffer overflow"); 133 return (NULL); 134 } 135 136 while (*++list != NULL) { 137 (void) strlcat(buf, ",", sizeof (buf)); 138 if (strlcat(buf, *list, sizeof (buf)) >= sizeof (buf)) { 139 syslog(LOG_ERR, "list_to_string: buffer overflow"); 140 return (NULL); 141 } 142 } 143 144 return (strdup(buf)); 145 } 146 147 static char * 148 internal_list_to_string(const ns_printer_t **list) 149 { 150 char buf[BUFSIZ]; 151 152 if ((list == NULL) || (*list == NULL)) 153 return (NULL); 154 155 if (snprintf(buf, sizeof (buf), "%s", (*list)->name) >= sizeof (buf)) { 156 syslog(LOG_ERR, "internal_list_to_string:buffer overflow"); 157 return (NULL); 158 } 159 160 while (*++list != NULL) { 161 (void) strlcat(buf, ",", sizeof (buf)); 162 if (strlcat(buf, (*list)->name, sizeof (buf)) >= sizeof (buf)) { 163 syslog(LOG_ERR, 164 "internal_list_to_string:buffer overflow"); 165 return (NULL); 166 } 167 } 168 169 return (strdup(buf)); 170 } 171 172 173 char * 174 value_to_string(const char *key, void *value) 175 { 176 char *string = NULL; 177 178 if ((key != NULL) && (value != NULL)) { 179 if (strcmp(key, NS_KEY_BSDADDR) == 0) { 180 string = bsd_addr_to_string(value); 181 } else if ((strcmp(key, NS_KEY_ALL) == 0) || 182 (strcmp(key, NS_KEY_GROUP) == 0)) { 183 string = list_to_string(value); 184 } else if (strcmp(key, NS_KEY_LIST) == 0) { 185 string = internal_list_to_string(value); 186 } else { 187 string = strdup((char *)value); 188 } 189 } 190 191 return (string); 192 } 193 194 195 void * 196 string_to_value(const char *key, char *string) 197 { 198 void *value = NULL; 199 200 if ((key != NULL) && (string != NULL) && (string[0] != '\0')) { 201 if (strcmp(key, NS_KEY_BSDADDR) == 0) { 202 value = (void *)string_to_bsd_addr(string); 203 } else if ((strcmp(key, NS_KEY_ALL) == 0) || 204 (strcmp(key, NS_KEY_GROUP) == 0)) { 205 value = (void *)strsplit(string, ","); 206 } else { 207 value = (void *)string; 208 } 209 } 210 211 return (value); 212 } 213 214 static void 215 split_name(char *name, const char *delimiter, char **p1, char **p2, char **p3) 216 { 217 char *tmp, *junk = NULL; 218 219 if (p1 != NULL) 220 *p1 = NULL; 221 if (p2 != NULL) 222 *p2 = NULL; 223 if (p3 != NULL) 224 *p3 = NULL; 225 226 if ((name == NULL) || (delimiter == NULL)) { 227 syslog(LOG_DEBUG, "split_name(): name/delimter invalid\n"); 228 return; 229 } 230 231 for (tmp = (char *)strtok_r(name, delimiter, &junk); tmp != NULL; 232 tmp = (char *)strtok_r(NULL, delimiter, &junk)) 233 if ((p1 != NULL) && (*p1 == NULL)) { 234 *p1 = tmp; 235 } else if ((p2 != NULL) && (*p2 == NULL)) { 236 *p2 = tmp; 237 if (p3 == NULL) 238 break; 239 } else if ((p3 != NULL) && (*p3 == NULL)) { 240 *p3 = tmp; 241 break; 242 } 243 } 244 245 /* 246 * This implements support for printer names that are fully resolvable 247 * on their own. These "complete" names are converted into a ns_printer_t 248 * structure containing an appropriate "bsdaddr" attribute. The supported 249 * formats are as follows: 250 * POSIX style (server:printer[:conformance]). 251 * This format is an adaptation of the format originally 252 * described in POSIX 1387.4. The POSIX draft has since been 253 * squashed, but this particular component lives on. The 254 * conformace field has been added to allow further identification 255 * of the the server. 256 */ 257 ns_printer_t * 258 posix_name(const char *name) 259 { 260 ns_printer_t *printer = NULL; 261 char *tmp = NULL; 262 263 if ((name != NULL) && ((tmp = strpbrk(name, ":")) != NULL)) { 264 char *server = NULL; 265 char *queue = NULL; 266 char *extension = NULL; 267 char *addr = strdup(name); 268 char buf[BUFSIZ]; 269 270 if (*tmp == ':') 271 split_name(addr, ": \t", &server, &queue, &extension); 272 273 memset(buf, 0, sizeof (buf)); 274 if ((server != NULL) && (queue != NULL)) 275 snprintf(buf, sizeof (buf), "%s,%s%s%s", server, 276 queue, (extension != NULL ? "," : ""), 277 (extension != NULL ? extension : "")); 278 279 /* build the structure here */ 280 if (buf[0] != '\0') { 281 ns_kvp_t **list, *kvp; 282 283 kvp = ns_kvp_create(NS_KEY_BSDADDR, buf); 284 list = (ns_kvp_t **)list_append(NULL, kvp); 285 if (list != NULL) 286 printer = ns_printer_create(strdup(name), NULL, 287 "posix", list); 288 } 289 } 290 291 return (printer); 292 } 293 294 /* 295 * FUNCTION: 296 * int ns_bsd_addr_cmp(ns_bsd_addr_t *at, ns_bsd_addr_t *a2) 297 * INPUTS: 298 * ns_bsd_addr_t *a1 - a bsd addr 299 * ns_bsd_addr_t *21 - another bsd addr 300 * DESCRIPTION: 301 * This functions compare 2 bsd_addr structures to determine if the 302 * information in them is the same. 303 */ 304 static int 305 ns_bsd_addr_cmp(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2) 306 { 307 int rc; 308 309 if ((a1 == NULL) || (a2 == NULL)) 310 return (1); 311 312 if ((rc = strcmp(a1->server, a2->server)) != 0) 313 return (rc); 314 315 if ((a1->printer == NULL) || (a2->printer == NULL)) 316 return (a1->printer != a2->printer); 317 318 return (strcmp(a1->printer, a2->printer)); 319 } 320 321 322 323 324 /* 325 * FUNCTION: ns_bsd_addr_cmp_local() 326 * 327 * DESCRIPTION: This function compares 2 bsd_addr structures to determine if 328 * the information in them is the same. It destinquishes between 329 * real printer names and alias names while doing the compare. 330 * 331 * INPUTS: ns_bsd_addr_t *a1 - a bsd addr 332 * ns_bsd_addr_t *a2 - another bsd addr 333 */ 334 335 static int 336 ns_bsd_addr_cmp_local(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2) 337 { 338 int rc; 339 340 if ((a1 == NULL) || (a2 == NULL)) { 341 return (1); 342 } 343 344 if ((rc = strcmp(a1->server, a2->server)) != 0) { 345 return (rc); 346 } 347 348 if ((a1->printer == NULL) || (a2->printer == NULL)) { 349 return (a1->printer != a2->printer); 350 } 351 352 rc = strcmp(a1->printer, a2->printer); 353 if (rc == 0) { 354 /* 355 * The printer's real names are the same, but now check if 356 * their local names (alias) are the same. 357 */ 358 rc = strcmp(a1->pname, a2->pname); 359 } 360 361 return (rc); 362 } /* ns_bsd_addr_cmp_local */ 363 364 365 366 /* 367 * FUNCTION: 368 * ns_bsd_addr_t *ns_bsd_addr_get_name(char *name) 369 * INPUTS: 370 * char *name - name of printer to get address for 371 * OUTPUTS: 372 * ns_bsd_addr_t *(return) - the address of the printer 373 * DESCRIPTION: 374 * This function will get the BSD address of the printer specified. 375 * it fills in the printer name if none is specified in the "name service" 376 * as a convenience to calling functions. 377 */ 378 ns_bsd_addr_t * 379 ns_bsd_addr_get_name(char *name) 380 { 381 ns_printer_t *printer; 382 ns_bsd_addr_t *addr = NULL; 383 384 endprinterentry(); 385 if ((printer = ns_printer_get_name(name, NULL)) != NULL) { 386 addr = ns_get_value(NS_KEY_BSDADDR, printer); 387 388 if (addr != NULL && addr->printer == NULL) 389 addr->printer = strdup(printer->name); 390 if (addr != NULL) { 391 /* 392 * if the name given is not the same as that in the 393 * this is an alias/remote name so put that into the 394 * pname field otherwise duplicate the real printer 395 * name 396 */ 397 if (strcmp(name, printer->name) != 0) { 398 addr->pname = strdup(name); 399 } else { 400 addr->pname = strdup(printer->name); 401 } 402 } 403 } 404 405 return (addr); 406 } 407 408 409 /* 410 * FUNCTION: 411 * ns_bsd_addr_t **ns_bsd_addr_get_list() 412 * OUTPUT: 413 * ns_bsd_addr_t **(return) - a list of bsd addresses for all printers 414 * in all "name services" 415 * DESCRIPTION: 416 * This function will gather a list of all printer addresses in all 417 * of the "name services". All redundancy is removed. 418 */ 419 ns_bsd_addr_t ** 420 ns_bsd_addr_get_list(int unique) 421 { 422 ns_printer_t **printers; 423 ns_bsd_addr_t **list = NULL; 424 char **aliases = NULL; 425 426 for (printers = ns_printer_get_list(NULL); 427 printers != NULL && *printers != NULL; printers++) { 428 ns_bsd_addr_t *addr; 429 430 if (strcmp(NS_NAME_ALL, (*printers)->name) == 0) 431 continue; 432 433 if ((addr = ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) { 434 if (addr->printer == NULL) 435 addr->printer = strdup((*printers)->name); 436 addr->pname = strdup((*printers)->name); 437 } 438 439 if (unique == UNIQUE) 440 list = 441 (ns_bsd_addr_t **)list_append_unique((void **)list, 442 (void *)addr, (COMP_T)ns_bsd_addr_cmp); 443 else if (unique == LOCAL_UNIQUE) 444 list = 445 (ns_bsd_addr_t **)list_append_unique((void **)list, 446 (void *)addr, (COMP_T)ns_bsd_addr_cmp_local); 447 else 448 list = (ns_bsd_addr_t **)list_append((void **)list, 449 (void *)addr); 450 451 for (aliases = (*printers)->aliases; 452 (aliases != NULL) && (*aliases != NULL); aliases++) { 453 /* 454 * Include any alias names that belong to the printer 455 */ 456 457 if ((addr = 458 ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) { 459 if (addr->printer == NULL) { 460 addr->printer = strdup(*aliases); 461 } 462 addr->pname = strdup(*aliases); 463 } 464 465 if (unique == UNIQUE) { 466 list = (ns_bsd_addr_t **) 467 list_append_unique((void **)list, 468 (void *)addr, (COMP_T)ns_bsd_addr_cmp); 469 } else if (unique == LOCAL_UNIQUE) { 470 list = (ns_bsd_addr_t **) 471 list_append_unique((void **)list, 472 (void *)addr, 473 (COMP_T)ns_bsd_addr_cmp_local); 474 } else { 475 list = (ns_bsd_addr_t **) 476 list_append((void **)list, (void *)addr); 477 } 478 } 479 } 480 481 return (list); 482 } 483 484 485 486 487 /* 488 * FUNCTION: 489 * ns_bsd_addr_t **ns_bsd_addr_get_list() 490 * OUTPUT: 491 * ns_bsd_addr_t **(return) - a list of bsd addresses for "_all" printers 492 * in the "name service" 493 * DESCRIPTION: 494 * This function will use the "_all" entry to find a list of printers and 495 * addresses. The "default" printer is also added to the list. 496 * All redundancy is removed. 497 */ 498 ns_bsd_addr_t ** 499 ns_bsd_addr_get_all(int unique) 500 { 501 ns_printer_t *printer; 502 ns_bsd_addr_t **list = NULL; 503 char **printers; 504 char *def = NULL; 505 506 if (((def = (char *)getenv("PRINTER")) == NULL) && 507 ((def = (char *)getenv("LPDEST")) == NULL)) 508 def = NS_NAME_DEFAULT; 509 510 list = (ns_bsd_addr_t **)list_append((void **)list, 511 (void *)ns_bsd_addr_get_name(def)); 512 513 endprinterentry(); 514 if ((printer = ns_printer_get_name(NS_NAME_ALL, NULL)) == NULL) 515 return (ns_bsd_addr_get_list(unique)); 516 517 for (printers = (char **)ns_get_value(NS_KEY_ALL, printer); 518 printers != NULL && *printers != NULL; printers++) { 519 ns_bsd_addr_t *addr; 520 521 addr = ns_bsd_addr_get_name(*printers); 522 if (addr != NULL) 523 addr->pname = *printers; 524 if (unique == UNIQUE) 525 list = 526 (ns_bsd_addr_t **)list_append_unique((void **)list, 527 (void *)addr, (COMP_T)ns_bsd_addr_cmp); 528 else 529 list = (ns_bsd_addr_t **)list_append((void **)list, 530 (void *)addr); 531 } 532 533 return (list); 534 } 535 536 ns_bsd_addr_t * 537 ns_bsd_addr_get_default() 538 { 539 char *def = NULL; 540 ns_bsd_addr_t *addr; 541 542 if (((def = (char *)getenv("PRINTER")) == NULL) && 543 ((def = (char *)getenv("LPDEST")) == NULL)) { 544 def = NS_NAME_DEFAULT; 545 addr = ns_bsd_addr_get_name(def); 546 if (addr != NULL) { 547 addr->pname = def; 548 return (addr); 549 } 550 } 551 552 return (NULL); 553 } 554