12264Sjacobs /* 22264Sjacobs * CDDL HEADER START 32264Sjacobs * 42264Sjacobs * The contents of this file are subject to the terms of the 52264Sjacobs * Common Development and Distribution License (the "License"). 62264Sjacobs * You may not use this file except in compliance with the License. 72264Sjacobs * 82264Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92264Sjacobs * or http://www.opensolaris.org/os/licensing. 102264Sjacobs * See the License for the specific language governing permissions 112264Sjacobs * and limitations under the License. 122264Sjacobs * 132264Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 142264Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152264Sjacobs * If applicable, add the following below this CDDL HEADER, with the 162264Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 172264Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 182264Sjacobs * 192264Sjacobs * CDDL HEADER END 202264Sjacobs */ 212264Sjacobs /* 22*11262SRajagopal.Andra@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 232264Sjacobs * Use is subject to license terms. 242264Sjacobs */ 252264Sjacobs 262264Sjacobs #include <stdio.h> 272264Sjacobs #include <stdlib.h> 282264Sjacobs #include <unistd.h> 292264Sjacobs #include <sys/types.h> 302264Sjacobs #include <sys/stat.h> 312264Sjacobs #include <string.h> 322264Sjacobs #include <stdarg.h> 332264Sjacobs #include <fcntl.h> 342264Sjacobs #include <syslog.h> 352264Sjacobs #include <errno.h> 362264Sjacobs #include <pwd.h> 372264Sjacobs #include <libintl.h> 382264Sjacobs #include <netdb.h> /* for rcmd() */ 392264Sjacobs 402264Sjacobs #include <ns.h> 412264Sjacobs #include <list.h> 422264Sjacobs 432264Sjacobs /* escaped chars include delimiters and shell meta characters */ 442264Sjacobs #define ESCAPE_CHARS "\\\n=: `&;|>^$()<*?[" 452264Sjacobs 462264Sjacobs /* 472264Sjacobs * This modules contains all of the code nedessary to write back to each 482264Sjacobs * printing configuration data repository. The support is intended to 492264Sjacobs * introduce the least number of dependencies in the library, so it doesn't 502264Sjacobs * always perform it's operations in the cleanest fashion. 512264Sjacobs */ 522264Sjacobs 532264Sjacobs 542264Sjacobs /* 552264Sjacobs * Generic Files support begins here. 562264Sjacobs */ 572264Sjacobs static char * 582264Sjacobs freadline(FILE *fp, char *buf, int buflen) 592264Sjacobs { 602264Sjacobs char *s = buf; 612264Sjacobs 622264Sjacobs while (fgets(s, buflen, fp)) { 632264Sjacobs if ((s == buf) && ((*s == '#') || (*s == '\n'))) { 642264Sjacobs continue; 652264Sjacobs } else { 662264Sjacobs if ((*s == '#') || (*s == '\n')) { 672264Sjacobs *s = NULL; 682264Sjacobs break; 692264Sjacobs } 702264Sjacobs 712264Sjacobs buflen -= strlen(s); 722264Sjacobs s += strlen(s); 732264Sjacobs 742264Sjacobs if (*(s - 2) != '\\') 752264Sjacobs break; 762264Sjacobs #ifdef STRIP_CONTINUATION 772264Sjacobs buflen -= 2; 782264Sjacobs s -= 2; 792264Sjacobs #endif 802264Sjacobs } 812264Sjacobs } 822264Sjacobs 832264Sjacobs if (s == buf) 842264Sjacobs return (NULL); 852264Sjacobs else 862264Sjacobs return (buf); 872264Sjacobs } 882264Sjacobs 892264Sjacobs 902264Sjacobs static int 912264Sjacobs _file_put_printer(const char *file, const ns_printer_t *printer) 922264Sjacobs { 932264Sjacobs FILE *ifp, 94*11262SRajagopal.Andra@Sun.COM *ofp; 952264Sjacobs char *tmpfile; 962264Sjacobs int fd; 972264Sjacobs int exit_status = 0; 982264Sjacobs int size; 992264Sjacobs 1002264Sjacobs size = strlen(file) + 1 + 20; 1012264Sjacobs if ((tmpfile = malloc(size)) == NULL) 1022264Sjacobs return (-1); 1032264Sjacobs 1042264Sjacobs if (snprintf(tmpfile, size, "%sXXXXXX", file) >= size) { 1052264Sjacobs syslog(LOG_ERR, "_file_put_printer:buffer overflow:tmpfile"); 1062264Sjacobs return (-1); 1072264Sjacobs } 1082264Sjacobs 1092264Sjacobs /* LINTED */ 1102264Sjacobs while (1) { /* syncronize writes */ 1112264Sjacobs fd = open(file, O_RDWR|O_CREAT|O_EXCL, 0644); 1122264Sjacobs if ((fd < 0) && (errno == EEXIST)) 1132264Sjacobs fd = open(file, O_RDWR); 1142264Sjacobs if (fd < 0) { 1152264Sjacobs if (errno == EAGAIN) 1162264Sjacobs continue; 1172264Sjacobs free(tmpfile); 1182264Sjacobs return (-1); 1192264Sjacobs } 1202264Sjacobs if (lockf(fd, F_TLOCK, 0) == 0) 1212264Sjacobs break; 1222264Sjacobs (void) close(fd); 1232264Sjacobs } 1242264Sjacobs 1252264Sjacobs if ((ifp = fdopen(fd, "r")) == NULL) { 1262264Sjacobs (void) close(fd); 1272264Sjacobs free(tmpfile); 1282264Sjacobs return (-1); 1292264Sjacobs } 1302264Sjacobs 1312264Sjacobs if ((fd = mkstemp(tmpfile)) < 0) { 1322264Sjacobs (void) fclose(ifp); 1332264Sjacobs free(tmpfile); 1342264Sjacobs return (-1); 1352264Sjacobs } 1362264Sjacobs 1372264Sjacobs (void) fchmod(fd, 0644); 1382264Sjacobs if ((ofp = fdopen(fd, "wb+")) != NULL) { 1392264Sjacobs char buf[4096]; 1402264Sjacobs 1412264Sjacobs (void) fprintf(ofp, 1422264Sjacobs "#\n#\tIf you hand edit this file, comments and structure may change.\n" 1432264Sjacobs "#\tThe preferred method of modifying this file is through the use of\n" 1442264Sjacobs "#\tlpset(1M)\n#\n"); 1452264Sjacobs 1462264Sjacobs /* 1472264Sjacobs * Handle the special case of lpset -x all 1482264Sjacobs * This deletes all entries in the file 1492264Sjacobs * In this case, just don't write any entries to the tmpfile 1502264Sjacobs */ 1512264Sjacobs 1522264Sjacobs if (!((strcmp(printer->name, "all") == 0) && 153*11262SRajagopal.Andra@Sun.COM (printer->attributes == NULL))) { 1542264Sjacobs char *t, *entry, *pentry; 1552264Sjacobs 1562264Sjacobs (void) _cvt_printer_to_entry((ns_printer_t *)printer, 157*11262SRajagopal.Andra@Sun.COM buf, sizeof (buf)); 1582264Sjacobs t = pentry = strdup(buf); 1592264Sjacobs 1602264Sjacobs while (freadline(ifp, buf, sizeof (buf)) != NULL) { 1612264Sjacobs ns_printer_t *tmp = (ns_printer_t *) 162*11262SRajagopal.Andra@Sun.COM _cvt_nss_entry_to_printer(buf, ""); 1632264Sjacobs 1642264Sjacobs if (ns_printer_match_name(tmp, printer->name) 165*11262SRajagopal.Andra@Sun.COM == 0) { 1662264Sjacobs entry = pentry; 1672264Sjacobs pentry = NULL; 1682264Sjacobs } else 1692264Sjacobs entry = buf; 1702264Sjacobs 1712264Sjacobs (void) fprintf(ofp, "%s\n", entry); 1722264Sjacobs } 1732264Sjacobs 1742264Sjacobs if (pentry != NULL) 1752264Sjacobs (void) fprintf(ofp, "%s\n", pentry); 1762264Sjacobs free(t); 1772264Sjacobs } 1782264Sjacobs 1792264Sjacobs (void) fclose(ofp); 1802264Sjacobs (void) rename(tmpfile, file); 1812264Sjacobs } else { 1822264Sjacobs (void) close(fd); 1832264Sjacobs (void) unlink(tmpfile); 1842264Sjacobs exit_status = -1; 1852264Sjacobs } 1862264Sjacobs 1872264Sjacobs (void) fclose(ifp); /* releases the lock, after rename on purpose */ 1882264Sjacobs (void) free(tmpfile); 1892264Sjacobs return (exit_status); 1902264Sjacobs } 1912264Sjacobs 1922264Sjacobs 1932264Sjacobs /* 1942264Sjacobs * Support for writing a printer into the FILES /etc/printers.conf 1952264Sjacobs * file. 1962264Sjacobs */ 1972264Sjacobs int 1982264Sjacobs files_put_printer(const ns_printer_t *printer) 1992264Sjacobs { 2002264Sjacobs static char *file = "/etc/printers.conf"; 2012264Sjacobs 2022264Sjacobs return (_file_put_printer(file, printer)); 2032264Sjacobs } 2042264Sjacobs 2052264Sjacobs /* 2062264Sjacobs * Support for writing a printer into the NIS printers.conf.byname 2072264Sjacobs * map. 2082264Sjacobs */ 2092264Sjacobs 2102264Sjacobs #include <rpc/rpc.h> 2112264Sjacobs #include <rpcsvc/ypclnt.h> 2122264Sjacobs #include <rpcsvc/yp_prot.h> 2132264Sjacobs 2142264Sjacobs /* 2152264Sjacobs * Run the remote command. We aren't interested in any io, Only the 2162264Sjacobs * return code. 2172264Sjacobs */ 2182264Sjacobs static int 2192264Sjacobs remote_command(char *command, char *host) 2202264Sjacobs { 2212264Sjacobs struct passwd *pw; 2222264Sjacobs 2232264Sjacobs if ((pw = getpwuid(getuid())) != NULL) { 2242264Sjacobs int fd; 2252264Sjacobs 2262264Sjacobs if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root", 227*11262SRajagopal.Andra@Sun.COM command, NULL, AF_INET6)) < 0) 2282264Sjacobs return (-1); 2292264Sjacobs (void) close(fd); 2302264Sjacobs return (0); 2312264Sjacobs } else 2322264Sjacobs return (-1); 2332264Sjacobs } 2342264Sjacobs 2352264Sjacobs 2362264Sjacobs /* 2372264Sjacobs * This isn't all that pretty, but you can update NIS if the machine this 2382264Sjacobs * runs on is in the /.rhosts or /etc/hosts.equiv on the NIS master. 2392264Sjacobs * copy it local, update it, copy it remote 2402264Sjacobs */ 2412264Sjacobs #define TMP_PRINTERS_FILE "/tmp/printers.NIS" 2422264Sjacobs #define NIS_MAKEFILE "/var/yp/Makefile" 2432264Sjacobs #define MAKE_EXCERPT "/usr/lib/print/Makefile.yp" 2442264Sjacobs /*ARGSUSED*/ 2452264Sjacobs int 2462264Sjacobs nis_put_printer(const ns_printer_t *printer) 2472264Sjacobs { 2482264Sjacobs static char *domain = NULL; 2492264Sjacobs char *map = "printers.conf.byname"; 2502264Sjacobs char *tmp = NULL; 2512264Sjacobs char *host = NULL; 2522264Sjacobs char lfile[BUFSIZ]; 2532264Sjacobs char rfile[BUFSIZ]; 2542264Sjacobs char cmd[BUFSIZ]; 2552264Sjacobs 2562264Sjacobs if (domain == NULL) 2572264Sjacobs (void) yp_get_default_domain(&domain); 2582264Sjacobs 2592264Sjacobs if ((yp_master(domain, (char *)map, &host) != 0) && 2602264Sjacobs (yp_master(domain, "passwd.byname", &host) != 0)) 2612264Sjacobs return (-1); 2622264Sjacobs 2632264Sjacobs if (snprintf(lfile, sizeof (lfile), "/tmp/%s", map) >= 264*11262SRajagopal.Andra@Sun.COM sizeof (lfile)) { 2652264Sjacobs syslog(LOG_ERR, "nis_put_printer:lfile buffer overflow"); 2662264Sjacobs return (-1); 2672264Sjacobs } 2682264Sjacobs if (snprintf(rfile, sizeof (rfile), "root@%s:/etc/%s", host, map) >= 269*11262SRajagopal.Andra@Sun.COM sizeof (rfile)) { 2702264Sjacobs syslog(LOG_ERR, "nis_put_printer:rfile buffer overflow"); 2712264Sjacobs return (-1); 2722264Sjacobs } 2732264Sjacobs 2742264Sjacobs if (((tmp = strrchr(rfile, '.')) != NULL) && 2752264Sjacobs (strcmp(tmp, ".byname") == 0)) 2762264Sjacobs *tmp = NULL; /* strip the .byname */ 2772264Sjacobs 2782264Sjacobs /* copy it local */ 2792264Sjacobs if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1", 280*11262SRajagopal.Andra@Sun.COM rfile, lfile) >= sizeof (cmd)) { 281*11262SRajagopal.Andra@Sun.COM syslog(LOG_ERR, 282*11262SRajagopal.Andra@Sun.COM "nis_put_printer:buffer overflow building cmd"); 283*11262SRajagopal.Andra@Sun.COM return (-1); 2842264Sjacobs } 2852264Sjacobs (void) system(cmd); /* could fail because it doesn't exist */ 2862264Sjacobs 2872264Sjacobs 2882264Sjacobs /* update it */ 2892264Sjacobs if (_file_put_printer(lfile, printer) != 0) 2902264Sjacobs return (-1); 2912264Sjacobs 2922264Sjacobs /* copy it back */ 2932264Sjacobs if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1", 294*11262SRajagopal.Andra@Sun.COM lfile, rfile) >= sizeof (cmd)) { 295*11262SRajagopal.Andra@Sun.COM syslog(LOG_ERR, 296*11262SRajagopal.Andra@Sun.COM "nis_put_printer:buffer overflow building cmd"); 297*11262SRajagopal.Andra@Sun.COM return (-1); 2982264Sjacobs } 2992264Sjacobs if (system(cmd) != 0) 3002264Sjacobs return (-1); 3012264Sjacobs 3022264Sjacobs /* copy the Makefile excerpt */ 3032264Sjacobs if (snprintf(cmd, sizeof (cmd), 304*11262SRajagopal.Andra@Sun.COM "rcp %s root@%s:%s.print >/dev/null 2>&1", 305*11262SRajagopal.Andra@Sun.COM MAKE_EXCERPT, host, NIS_MAKEFILE) >= sizeof (cmd)) { 3062264Sjacobs syslog(LOG_ERR, 307*11262SRajagopal.Andra@Sun.COM "nis_put_printer:buffer overflow building cmd"); 3082264Sjacobs return (-1); 3092264Sjacobs } 3102264Sjacobs 3112264Sjacobs if (system(cmd) != 0) 3122264Sjacobs return (-1); 3132264Sjacobs 3142264Sjacobs /* run the make */ 3152264Sjacobs if (snprintf(cmd, sizeof (cmd), 316*11262SRajagopal.Andra@Sun.COM "/bin/sh -c 'PATH=/usr/ccs/bin:/bin:/usr/bin:$PATH " 317*11262SRajagopal.Andra@Sun.COM "make -f %s -f %s.print printers.conf >/dev/null 2>&1'", 318*11262SRajagopal.Andra@Sun.COM NIS_MAKEFILE, NIS_MAKEFILE) >= sizeof (cmd)) { 3192264Sjacobs syslog(LOG_ERR, 320*11262SRajagopal.Andra@Sun.COM "nis_put_printer:buffer overflow on make"); 3212264Sjacobs return (-1); 3222264Sjacobs } 3232264Sjacobs 3242264Sjacobs return (remote_command(cmd, host)); 3252264Sjacobs } 326