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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <fcntl.h>
34 #include <syslog.h>
35 #include <errno.h>
36 #include <pwd.h>
37 #include <libintl.h>
38 #include <netdb.h> /* for rcmd() */
39
40 #include <ns.h>
41 #include <list.h>
42
43 /* escaped chars include delimiters and shell meta characters */
44 #define ESCAPE_CHARS "\\\n=: `&;|>^$()<*?["
45
46 /*
47 * This modules contains all of the code nedessary to write back to each
48 * printing configuration data repository. The support is intended to
49 * introduce the least number of dependencies in the library, so it doesn't
50 * always perform it's operations in the cleanest fashion.
51 */
52
53
54 /*
55 * Generic Files support begins here.
56 */
57 static char *
freadline(FILE * fp,char * buf,int buflen)58 freadline(FILE *fp, char *buf, int buflen)
59 {
60 char *s = buf;
61
62 while (fgets(s, buflen, fp)) {
63 if ((s == buf) && ((*s == '#') || (*s == '\n'))) {
64 continue;
65 } else {
66 if ((*s == '#') || (*s == '\n')) {
67 *s = '\0';
68 break;
69 }
70
71 buflen -= strlen(s);
72 s += strlen(s);
73
74 if (*(s - 2) != '\\')
75 break;
76 #ifdef STRIP_CONTINUATION
77 buflen -= 2;
78 s -= 2;
79 #endif
80 }
81 }
82
83 if (s == buf)
84 return (NULL);
85 else
86 return (buf);
87 }
88
89
90 static int
_file_put_printer(const char * file,const ns_printer_t * printer)91 _file_put_printer(const char *file, const ns_printer_t *printer)
92 {
93 FILE *ifp,
94 *ofp;
95 char *tmpfile;
96 int fd;
97 int exit_status = 0;
98 int size;
99
100 size = strlen(file) + 1 + 20;
101 if ((tmpfile = malloc(size)) == NULL)
102 return (-1);
103
104 if (snprintf(tmpfile, size, "%sXXXXXX", file) >= size) {
105 syslog(LOG_ERR, "_file_put_printer:buffer overflow:tmpfile");
106 return (-1);
107 }
108
109 /* LINTED */
110 while (1) { /* syncronize writes */
111 fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644);
112 if ((fd < 0) && (errno == EEXIST))
113 fd = open(file, O_RDWR);
114 if (fd < 0) {
115 if (errno == EAGAIN)
116 continue;
117 free(tmpfile);
118 return (-1);
119 }
120 if (lockf(fd, F_TLOCK, 0) == 0)
121 break;
122 (void) close(fd);
123 }
124
125 if ((ifp = fdopen(fd, "r")) == NULL) {
126 (void) close(fd);
127 free(tmpfile);
128 return (-1);
129 }
130
131 if ((fd = mkstemp(tmpfile)) < 0) {
132 (void) fclose(ifp);
133 free(tmpfile);
134 return (-1);
135 }
136
137 (void) fchmod(fd, 0644);
138 if ((ofp = fdopen(fd, "wb+")) != NULL) {
139 char buf[4096];
140
141 (void) fprintf(ofp,
142 "#\n#\tIf you hand edit this file, comments and structure may change.\n"
143 "#\tThe preferred method of modifying this file is through the use of\n"
144 "#\tlpset(8)\n#\n");
145
146 /*
147 * Handle the special case of lpset -x all
148 * This deletes all entries in the file
149 * In this case, just don't write any entries to the tmpfile
150 */
151
152 if (!((strcmp(printer->name, "all") == 0) &&
153 (printer->attributes == NULL))) {
154 char *t, *entry, *pentry;
155
156 (void) _cvt_printer_to_entry((ns_printer_t *)printer,
157 buf, sizeof (buf));
158 t = pentry = strdup(buf);
159
160 while (freadline(ifp, buf, sizeof (buf)) != NULL) {
161 ns_printer_t *tmp = (ns_printer_t *)
162 _cvt_nss_entry_to_printer(buf, "");
163
164 if (ns_printer_match_name(tmp, printer->name)
165 == 0) {
166 entry = pentry;
167 pentry = NULL;
168 } else {
169 entry = buf;
170 }
171
172 (void) fprintf(ofp, "%s\n", entry);
173 }
174
175 if (pentry != NULL)
176 (void) fprintf(ofp, "%s\n", pentry);
177 free(t);
178 }
179
180 (void) fclose(ofp);
181 (void) rename(tmpfile, file);
182 } else {
183 (void) close(fd);
184 (void) unlink(tmpfile);
185 exit_status = -1;
186 }
187
188 (void) fclose(ifp); /* releases the lock, after rename on purpose */
189 (void) free(tmpfile);
190 return (exit_status);
191 }
192
193
194 /*
195 * Support for writing a printer into the FILES /etc/printers.conf
196 * file.
197 */
198 int
files_put_printer(const ns_printer_t * printer)199 files_put_printer(const ns_printer_t *printer)
200 {
201 static char *file = "/etc/printers.conf";
202
203 return (_file_put_printer(file, printer));
204 }
205
206 /*
207 * Support for writing a printer into the NIS printers.conf.byname
208 * map.
209 */
210
211 #include <rpc/rpc.h>
212 #include <rpcsvc/ypclnt.h>
213 #include <rpcsvc/yp_prot.h>
214
215 /*
216 * Run the remote command. We aren't interested in any io, Only the
217 * return code.
218 */
219 static int
remote_command(char * command,char * host)220 remote_command(char *command, char *host)
221 {
222 struct passwd *pw;
223
224 if ((pw = getpwuid(getuid())) != NULL) {
225 int fd;
226
227 if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root",
228 command, NULL, AF_INET6)) < 0)
229 return (-1);
230 (void) close(fd);
231 return (0);
232 } else {
233 return (-1);
234 }
235 }
236
237
238 /*
239 * This isn't all that pretty, but you can update NIS if the machine this
240 * runs on is in the /.rhosts or /etc/hosts.equiv on the NIS master.
241 * copy it local, update it, copy it remote
242 */
243 #define TMP_PRINTERS_FILE "/tmp/printers.NIS"
244 #define NIS_MAKEFILE "/var/yp/Makefile"
245 #define MAKE_EXCERPT "/usr/lib/print/Makefile.yp"
246 /*ARGSUSED*/
247 int
nis_put_printer(const ns_printer_t * printer)248 nis_put_printer(const ns_printer_t *printer)
249 {
250 static char *domain = NULL;
251 char *map = "printers.conf.byname";
252 char *tmp = NULL;
253 char *host = NULL;
254 char lfile[BUFSIZ];
255 char rfile[BUFSIZ];
256 char cmd[BUFSIZ];
257
258 if (domain == NULL)
259 (void) yp_get_default_domain(&domain);
260
261 if ((yp_master(domain, (char *)map, &host) != 0) &&
262 (yp_master(domain, "passwd.byname", &host) != 0))
263 return (-1);
264
265 if (snprintf(lfile, sizeof (lfile), "/tmp/%s", map) >=
266 sizeof (lfile)) {
267 syslog(LOG_ERR, "nis_put_printer:lfile buffer overflow");
268 return (-1);
269 }
270 if (snprintf(rfile, sizeof (rfile), "root@%s:/etc/%s", host, map) >=
271 sizeof (rfile)) {
272 syslog(LOG_ERR, "nis_put_printer:rfile buffer overflow");
273 return (-1);
274 }
275
276 if (((tmp = strrchr(rfile, '.')) != NULL) &&
277 (strcmp(tmp, ".byname") == 0))
278 *tmp = '\0'; /* strip the .byname */
279
280 /* copy it local */
281 if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
282 rfile, lfile) >= sizeof (cmd)) {
283 syslog(LOG_ERR,
284 "nis_put_printer:buffer overflow building cmd");
285 return (-1);
286 }
287 (void) system(cmd); /* could fail because it doesn't exist */
288
289
290 /* update it */
291 if (_file_put_printer(lfile, printer) != 0)
292 return (-1);
293
294 /* copy it back */
295 if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
296 lfile, rfile) >= sizeof (cmd)) {
297 syslog(LOG_ERR,
298 "nis_put_printer:buffer overflow building cmd");
299 return (-1);
300 }
301 if (system(cmd) != 0)
302 return (-1);
303
304 /* copy the Makefile excerpt */
305 if (snprintf(cmd, sizeof (cmd),
306 "rcp %s root@%s:%s.print >/dev/null 2>&1",
307 MAKE_EXCERPT, host, NIS_MAKEFILE) >= sizeof (cmd)) {
308 syslog(LOG_ERR,
309 "nis_put_printer:buffer overflow building cmd");
310 return (-1);
311 }
312
313 if (system(cmd) != 0)
314 return (-1);
315
316 /* run the make */
317 if (snprintf(cmd, sizeof (cmd),
318 "/bin/sh -c 'PATH=/usr/ccs/bin:/bin:/usr/bin:$PATH "
319 "make -f %s -f %s.print printers.conf >/dev/null 2>&1'",
320 NIS_MAKEFILE, NIS_MAKEFILE) >= sizeof (cmd)) {
321 syslog(LOG_ERR,
322 "nis_put_printer:buffer overflow on make");
323 return (-1);
324 }
325
326 return (remote_command(cmd, host));
327 }
328