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 *
freadline(FILE * fp,char * buf,int buflen)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
_file_put_printer(const char * file,const ns_printer_t * printer)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
files_put_printer(const ns_printer_t * printer)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
remote_command(char * command,char * host)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
nis_put_printer(const ns_printer_t * printer)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