xref: /titanic_52/usr/src/lib/print/libprint/common/nss_write.c (revision 36e852a172cba914383d7341c988128b2c667fbd)
1355b4669Sjacobs /*
2355b4669Sjacobs  * CDDL HEADER START
3355b4669Sjacobs  *
4355b4669Sjacobs  * The contents of this file are subject to the terms of the
5355b4669Sjacobs  * Common Development and Distribution License (the "License").
6355b4669Sjacobs  * You may not use this file except in compliance with the License.
7355b4669Sjacobs  *
8355b4669Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9355b4669Sjacobs  * or http://www.opensolaris.org/os/licensing.
10355b4669Sjacobs  * See the License for the specific language governing permissions
11355b4669Sjacobs  * and limitations under the License.
12355b4669Sjacobs  *
13355b4669Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
14355b4669Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15355b4669Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
16355b4669Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
17355b4669Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
18355b4669Sjacobs  *
19355b4669Sjacobs  * CDDL HEADER END
20355b4669Sjacobs  */
21355b4669Sjacobs /*
22*36e852a1SRaja Andra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23355b4669Sjacobs  * Use is subject to license terms.
24355b4669Sjacobs  */
25355b4669Sjacobs 
26355b4669Sjacobs #include <stdio.h>
27355b4669Sjacobs #include <stdlib.h>
28355b4669Sjacobs #include <unistd.h>
29355b4669Sjacobs #include <sys/types.h>
30355b4669Sjacobs #include <sys/stat.h>
31355b4669Sjacobs #include <string.h>
32355b4669Sjacobs #include <stdarg.h>
33355b4669Sjacobs #include <fcntl.h>
34355b4669Sjacobs #include <syslog.h>
35355b4669Sjacobs #include <errno.h>
36355b4669Sjacobs #include <pwd.h>
37355b4669Sjacobs #include <libintl.h>
38355b4669Sjacobs #include <netdb.h>	/* for rcmd() */
39355b4669Sjacobs 
40355b4669Sjacobs #include <ns.h>
41355b4669Sjacobs #include <list.h>
42355b4669Sjacobs 
43355b4669Sjacobs /*  escaped chars include delimiters and shell meta characters */
44355b4669Sjacobs #define	ESCAPE_CHARS	"\\\n=: `&;|>^$()<*?["
45355b4669Sjacobs 
46355b4669Sjacobs /*
47355b4669Sjacobs  * This modules contains all of the code nedessary to write back to each
48355b4669Sjacobs  * printing configuration data repository.  The support is intended to
49355b4669Sjacobs  * introduce the least number of dependencies in the library, so it doesn't
50355b4669Sjacobs  * always perform it's operations in the cleanest fashion.
51355b4669Sjacobs  */
52355b4669Sjacobs 
53355b4669Sjacobs 
54355b4669Sjacobs /*
55355b4669Sjacobs  * Generic Files support begins here.
56355b4669Sjacobs  */
57355b4669Sjacobs static char *
58355b4669Sjacobs freadline(FILE *fp, char *buf, int buflen)
59355b4669Sjacobs {
60355b4669Sjacobs 	char *s = buf;
61355b4669Sjacobs 
62355b4669Sjacobs 	while (fgets(s, buflen, fp)) {
63355b4669Sjacobs 		if ((s == buf) && ((*s == '#') || (*s == '\n'))) {
64355b4669Sjacobs 			continue;
65355b4669Sjacobs 		} else {
66355b4669Sjacobs 			if ((*s == '#') || (*s == '\n')) {
67355b4669Sjacobs 				*s = NULL;
68355b4669Sjacobs 				break;
69355b4669Sjacobs 			}
70355b4669Sjacobs 
71355b4669Sjacobs 			buflen -= strlen(s);
72355b4669Sjacobs 			s += strlen(s);
73355b4669Sjacobs 
74355b4669Sjacobs 			if (*(s - 2) != '\\')
75355b4669Sjacobs 				break;
76355b4669Sjacobs #ifdef STRIP_CONTINUATION
77355b4669Sjacobs 			buflen -= 2;
78355b4669Sjacobs 			s -= 2;
79355b4669Sjacobs #endif
80355b4669Sjacobs 		}
81355b4669Sjacobs 	}
82355b4669Sjacobs 
83355b4669Sjacobs 	if (s == buf)
84355b4669Sjacobs 		return (NULL);
85355b4669Sjacobs 	else
86355b4669Sjacobs 		return (buf);
87355b4669Sjacobs }
88355b4669Sjacobs 
89355b4669Sjacobs 
90355b4669Sjacobs static int
91355b4669Sjacobs _file_put_printer(const char *file, const ns_printer_t *printer)
92355b4669Sjacobs {
93355b4669Sjacobs 	FILE	*ifp,
94355b4669Sjacobs 	    *ofp;
95355b4669Sjacobs 	char *tmpfile;
96355b4669Sjacobs 	int fd;
97355b4669Sjacobs 	int exit_status = 0;
98355b4669Sjacobs 	int size;
99355b4669Sjacobs 
100355b4669Sjacobs 	size = strlen(file) + 1 + 20;
101355b4669Sjacobs 	if ((tmpfile = malloc(size)) == NULL)
102355b4669Sjacobs 		return (-1);
103355b4669Sjacobs 
104355b4669Sjacobs 	if (snprintf(tmpfile, size, "%sXXXXXX", file) >= size) {
105355b4669Sjacobs 		syslog(LOG_ERR, "_file_put_printer:buffer overflow:tmpfile");
106355b4669Sjacobs 		return (-1);
107355b4669Sjacobs 	}
108355b4669Sjacobs 
109355b4669Sjacobs 	/* LINTED */
110355b4669Sjacobs 	while (1) {	/* syncronize writes */
111355b4669Sjacobs 		fd = open(file, O_RDWR|O_CREAT|O_EXCL, 0644);
112355b4669Sjacobs 		if ((fd < 0) && (errno == EEXIST))
113355b4669Sjacobs 			fd = open(file, O_RDWR);
114355b4669Sjacobs 		if (fd < 0) {
115355b4669Sjacobs 			if (errno == EAGAIN)
116355b4669Sjacobs 				continue;
117355b4669Sjacobs 			free(tmpfile);
118355b4669Sjacobs 			return (-1);
119355b4669Sjacobs 		}
120355b4669Sjacobs 		if (lockf(fd, F_TLOCK, 0) == 0)
121355b4669Sjacobs 			break;
122355b4669Sjacobs 		(void) close(fd);
123355b4669Sjacobs 	}
124355b4669Sjacobs 
125355b4669Sjacobs 	if ((ifp = fdopen(fd, "r")) == NULL) {
126355b4669Sjacobs 		(void) close(fd);
127355b4669Sjacobs 		free(tmpfile);
128355b4669Sjacobs 		return (-1);
129355b4669Sjacobs 	}
130355b4669Sjacobs 
131355b4669Sjacobs 	if ((fd = mkstemp(tmpfile)) < 0) {
132355b4669Sjacobs 		(void) fclose(ifp);
133355b4669Sjacobs 		free(tmpfile);
134355b4669Sjacobs 		return (-1);
135355b4669Sjacobs 	}
136355b4669Sjacobs 
137355b4669Sjacobs 	(void) fchmod(fd, 0644);
138355b4669Sjacobs 	if ((ofp = fdopen(fd, "wb+")) != NULL) {
139355b4669Sjacobs 		char buf[4096];
140355b4669Sjacobs 
141355b4669Sjacobs 		(void) fprintf(ofp,
142355b4669Sjacobs 	"#\n#\tIf you hand edit this file, comments and structure may change.\n"
143355b4669Sjacobs 	"#\tThe preferred method of modifying this file is through the use of\n"
144355b4669Sjacobs 	"#\tlpset(1M)\n#\n");
145355b4669Sjacobs 
146355b4669Sjacobs 	/*
147355b4669Sjacobs 	 * Handle the special case of lpset -x all
148355b4669Sjacobs 	 * This deletes all entries in the file
149355b4669Sjacobs 	 * In this case, just don't write any entries to the tmpfile
150355b4669Sjacobs 	 */
151355b4669Sjacobs 
152355b4669Sjacobs 		if (!((strcmp(printer->name, "all") == 0) &&
153355b4669Sjacobs 		    (printer->attributes == NULL))) {
154355b4669Sjacobs 			char *t, *entry, *pentry;
155355b4669Sjacobs 
156355b4669Sjacobs 			(void) _cvt_printer_to_entry((ns_printer_t *)printer,
157355b4669Sjacobs 			    buf, sizeof (buf));
158355b4669Sjacobs 			t = pentry = strdup(buf);
159355b4669Sjacobs 
160355b4669Sjacobs 			while (freadline(ifp, buf, sizeof (buf)) != NULL) {
161355b4669Sjacobs 				ns_printer_t *tmp = (ns_printer_t *)
162355b4669Sjacobs 				    _cvt_nss_entry_to_printer(buf, "");
163355b4669Sjacobs 
164355b4669Sjacobs 				if (ns_printer_match_name(tmp, printer->name)
165355b4669Sjacobs 				    == 0) {
166355b4669Sjacobs 					entry = pentry;
167355b4669Sjacobs 					pentry = NULL;
168355b4669Sjacobs 				} else
169355b4669Sjacobs 					entry = buf;
170355b4669Sjacobs 
171355b4669Sjacobs 				(void) fprintf(ofp, "%s\n", entry);
172355b4669Sjacobs 			}
173355b4669Sjacobs 
174355b4669Sjacobs 			if (pentry != NULL)
175355b4669Sjacobs 				(void) fprintf(ofp, "%s\n", pentry);
176355b4669Sjacobs 			free(t);
177355b4669Sjacobs 		}
178355b4669Sjacobs 
179355b4669Sjacobs 		(void) fclose(ofp);
180355b4669Sjacobs 		(void) rename(tmpfile, file);
181355b4669Sjacobs 	} else {
182355b4669Sjacobs 		(void) close(fd);
183355b4669Sjacobs 		(void) unlink(tmpfile);
184355b4669Sjacobs 		exit_status = -1;
185355b4669Sjacobs 	}
186355b4669Sjacobs 
187355b4669Sjacobs 	(void) fclose(ifp);	/* releases the lock, after rename on purpose */
188355b4669Sjacobs 	(void) free(tmpfile);
189355b4669Sjacobs 	return (exit_status);
190355b4669Sjacobs }
191355b4669Sjacobs 
192355b4669Sjacobs 
193355b4669Sjacobs /*
194355b4669Sjacobs  * Support for writing a printer into the FILES /etc/printers.conf
195355b4669Sjacobs  * file.
196355b4669Sjacobs  */
197355b4669Sjacobs int
198355b4669Sjacobs files_put_printer(const ns_printer_t *printer)
199355b4669Sjacobs {
200355b4669Sjacobs 	static char *file = "/etc/printers.conf";
201355b4669Sjacobs 
202355b4669Sjacobs 	return (_file_put_printer(file, printer));
203355b4669Sjacobs }
204355b4669Sjacobs 
205355b4669Sjacobs /*
206355b4669Sjacobs  * Support for writing a printer into the NIS printers.conf.byname
207355b4669Sjacobs  * map.
208355b4669Sjacobs  */
209355b4669Sjacobs 
210355b4669Sjacobs #include <rpc/rpc.h>
211355b4669Sjacobs #include <rpcsvc/ypclnt.h>
212355b4669Sjacobs #include <rpcsvc/yp_prot.h>
213355b4669Sjacobs 
214355b4669Sjacobs /*
215355b4669Sjacobs  * Run the remote command.  We aren't interested in any io, Only the
216355b4669Sjacobs  * return code.
217355b4669Sjacobs  */
218355b4669Sjacobs static int
219355b4669Sjacobs remote_command(char *command, char *host)
220355b4669Sjacobs {
221355b4669Sjacobs 	struct passwd *pw;
222355b4669Sjacobs 
223355b4669Sjacobs 	if ((pw = getpwuid(getuid())) != NULL) {
224355b4669Sjacobs 		int fd;
225355b4669Sjacobs 
226355b4669Sjacobs 		if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root",
227355b4669Sjacobs 		    command, NULL, AF_INET6)) < 0)
228355b4669Sjacobs 			return (-1);
229355b4669Sjacobs 		(void) close(fd);
230355b4669Sjacobs 		return (0);
231355b4669Sjacobs 	} else
232355b4669Sjacobs 		return (-1);
233355b4669Sjacobs }
234355b4669Sjacobs 
235355b4669Sjacobs 
236355b4669Sjacobs /*
237355b4669Sjacobs  * This isn't all that pretty, but you can update NIS if the machine this
238355b4669Sjacobs  * runs on is in the /.rhosts or /etc/hosts.equiv on the NIS master.
239355b4669Sjacobs  *   copy it local, update it, copy it remote
240355b4669Sjacobs  */
241355b4669Sjacobs #define	TMP_PRINTERS_FILE	"/tmp/printers.NIS"
242355b4669Sjacobs #define	NIS_MAKEFILE		"/var/yp/Makefile"
243355b4669Sjacobs #define	MAKE_EXCERPT		"/usr/lib/print/Makefile.yp"
244355b4669Sjacobs /*ARGSUSED*/
245355b4669Sjacobs int
246355b4669Sjacobs nis_put_printer(const ns_printer_t *printer)
247355b4669Sjacobs {
248355b4669Sjacobs 	static char	*domain = NULL;
249355b4669Sjacobs 	char *map = "printers.conf.byname";
250355b4669Sjacobs 	char *tmp = NULL;
251355b4669Sjacobs 	char *host = NULL;
252355b4669Sjacobs 	char lfile[BUFSIZ];
253355b4669Sjacobs 	char rfile[BUFSIZ];
254355b4669Sjacobs 	char cmd[BUFSIZ];
255355b4669Sjacobs 
256355b4669Sjacobs 	if (domain == NULL)
257355b4669Sjacobs 		(void) yp_get_default_domain(&domain);
258355b4669Sjacobs 
259355b4669Sjacobs 	if ((yp_master(domain, (char *)map, &host) != 0) &&
260355b4669Sjacobs 	    (yp_master(domain, "passwd.byname", &host) != 0))
261355b4669Sjacobs 		return (-1);
262355b4669Sjacobs 
263355b4669Sjacobs 	if (snprintf(lfile, sizeof (lfile), "/tmp/%s", map) >=
264355b4669Sjacobs 	    sizeof (lfile)) {
265355b4669Sjacobs 		syslog(LOG_ERR, "nis_put_printer:lfile buffer overflow");
266355b4669Sjacobs 		return (-1);
267355b4669Sjacobs 	}
268355b4669Sjacobs 	if (snprintf(rfile, sizeof (rfile), "root@%s:/etc/%s", host, map) >=
269355b4669Sjacobs 	    sizeof (rfile)) {
270355b4669Sjacobs 		syslog(LOG_ERR, "nis_put_printer:rfile buffer overflow");
271355b4669Sjacobs 		return (-1);
272355b4669Sjacobs 	}
273355b4669Sjacobs 
274355b4669Sjacobs 	if (((tmp = strrchr(rfile, '.')) != NULL) &&
275355b4669Sjacobs 	    (strcmp(tmp, ".byname") == 0))
276355b4669Sjacobs 		*tmp = NULL;	/* strip the .byname */
277355b4669Sjacobs 
278355b4669Sjacobs 	/* copy it local */
279355b4669Sjacobs 	if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
280355b4669Sjacobs 	    rfile, lfile) >= sizeof (cmd)) {
281355b4669Sjacobs 		syslog(LOG_ERR,
282355b4669Sjacobs 		    "nis_put_printer:buffer overflow building cmd");
283355b4669Sjacobs 		return (-1);
284355b4669Sjacobs 	}
285355b4669Sjacobs 	(void) system(cmd);	/* could fail because it doesn't exist */
286355b4669Sjacobs 
287355b4669Sjacobs 
288355b4669Sjacobs 	/* update it */
289355b4669Sjacobs 	if (_file_put_printer(lfile, printer) != 0)
290355b4669Sjacobs 		return (-1);
291355b4669Sjacobs 
292355b4669Sjacobs 	/* copy it back */
293355b4669Sjacobs 	if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
294355b4669Sjacobs 	    lfile, rfile) >= sizeof (cmd)) {
295355b4669Sjacobs 		syslog(LOG_ERR,
296355b4669Sjacobs 		    "nis_put_printer:buffer overflow building cmd");
297355b4669Sjacobs 		return (-1);
298355b4669Sjacobs 	}
299355b4669Sjacobs 	if (system(cmd) != 0)
300355b4669Sjacobs 		return (-1);
301355b4669Sjacobs 
302355b4669Sjacobs 	/* copy the Makefile excerpt */
303355b4669Sjacobs 	if (snprintf(cmd, sizeof (cmd),
304355b4669Sjacobs 	    "rcp %s root@%s:%s.print >/dev/null 2>&1",
305355b4669Sjacobs 	    MAKE_EXCERPT, host, NIS_MAKEFILE) >= sizeof (cmd)) {
306355b4669Sjacobs 		syslog(LOG_ERR,
307355b4669Sjacobs 		    "nis_put_printer:buffer overflow building cmd");
308355b4669Sjacobs 		return (-1);
309355b4669Sjacobs 	}
310355b4669Sjacobs 
311355b4669Sjacobs 	if (system(cmd) != 0)
312355b4669Sjacobs 		return (-1);
313355b4669Sjacobs 
314355b4669Sjacobs 	/* run the make */
315355b4669Sjacobs 	if (snprintf(cmd, sizeof (cmd),
316355b4669Sjacobs 	    "/bin/sh -c 'PATH=/usr/ccs/bin:/bin:/usr/bin:$PATH "
317355b4669Sjacobs 	    "make -f %s -f %s.print printers.conf >/dev/null 2>&1'",
318355b4669Sjacobs 	    NIS_MAKEFILE, NIS_MAKEFILE) >= sizeof (cmd)) {
319355b4669Sjacobs 		syslog(LOG_ERR,
320355b4669Sjacobs 		    "nis_put_printer:buffer overflow on make");
321355b4669Sjacobs 		return (-1);
322355b4669Sjacobs 	}
323355b4669Sjacobs 
324355b4669Sjacobs 	return (remote_command(cmd, host));
325355b4669Sjacobs }
326