xref: /onnv-gate/usr/src/lib/print/libprint/common/nss_write.c (revision 11262:b7ebfbf2359e)
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