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 * 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 = NULL; 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 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(1M)\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 (void) fprintf(ofp, "%s\n", entry); 172 } 173 174 if (pentry != NULL) 175 (void) fprintf(ofp, "%s\n", pentry); 176 free(t); 177 } 178 179 (void) fclose(ofp); 180 (void) rename(tmpfile, file); 181 } else { 182 (void) close(fd); 183 (void) unlink(tmpfile); 184 exit_status = -1; 185 } 186 187 (void) fclose(ifp); /* releases the lock, after rename on purpose */ 188 (void) free(tmpfile); 189 return (exit_status); 190 } 191 192 193 /* 194 * Support for writing a printer into the FILES /etc/printers.conf 195 * file. 196 */ 197 int 198 files_put_printer(const ns_printer_t *printer) 199 { 200 static char *file = "/etc/printers.conf"; 201 202 return (_file_put_printer(file, printer)); 203 } 204 205 /* 206 * Support for writing a printer into the NIS printers.conf.byname 207 * map. 208 */ 209 210 #include <rpc/rpc.h> 211 #include <rpcsvc/ypclnt.h> 212 #include <rpcsvc/yp_prot.h> 213 214 /* 215 * Run the remote command. We aren't interested in any io, Only the 216 * return code. 217 */ 218 static int 219 remote_command(char *command, char *host) 220 { 221 struct passwd *pw; 222 223 if ((pw = getpwuid(getuid())) != NULL) { 224 int fd; 225 226 if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root", 227 command, NULL, AF_INET6)) < 0) 228 return (-1); 229 (void) close(fd); 230 return (0); 231 } else 232 return (-1); 233 } 234 235 236 /* 237 * This isn't all that pretty, but you can update NIS if the machine this 238 * runs on is in the /.rhosts or /etc/hosts.equiv on the NIS master. 239 * copy it local, update it, copy it remote 240 */ 241 #define TMP_PRINTERS_FILE "/tmp/printers.NIS" 242 #define NIS_MAKEFILE "/var/yp/Makefile" 243 #define MAKE_EXCERPT "/usr/lib/print/Makefile.yp" 244 /*ARGSUSED*/ 245 int 246 nis_put_printer(const ns_printer_t *printer) 247 { 248 static char *domain = NULL; 249 char *map = "printers.conf.byname"; 250 char *tmp = NULL; 251 char *host = NULL; 252 char lfile[BUFSIZ]; 253 char rfile[BUFSIZ]; 254 char cmd[BUFSIZ]; 255 256 if (domain == NULL) 257 (void) yp_get_default_domain(&domain); 258 259 if ((yp_master(domain, (char *)map, &host) != 0) && 260 (yp_master(domain, "passwd.byname", &host) != 0)) 261 return (-1); 262 263 if (snprintf(lfile, sizeof (lfile), "/tmp/%s", map) >= 264 sizeof (lfile)) { 265 syslog(LOG_ERR, "nis_put_printer:lfile buffer overflow"); 266 return (-1); 267 } 268 if (snprintf(rfile, sizeof (rfile), "root@%s:/etc/%s", host, map) >= 269 sizeof (rfile)) { 270 syslog(LOG_ERR, "nis_put_printer:rfile buffer overflow"); 271 return (-1); 272 } 273 274 if (((tmp = strrchr(rfile, '.')) != NULL) && 275 (strcmp(tmp, ".byname") == 0)) 276 *tmp = NULL; /* strip the .byname */ 277 278 /* copy it local */ 279 if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1", 280 rfile, lfile) >= sizeof (cmd)) { 281 syslog(LOG_ERR, 282 "nis_put_printer:buffer overflow building cmd"); 283 return (-1); 284 } 285 (void) system(cmd); /* could fail because it doesn't exist */ 286 287 288 /* update it */ 289 if (_file_put_printer(lfile, printer) != 0) 290 return (-1); 291 292 /* copy it back */ 293 if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1", 294 lfile, rfile) >= sizeof (cmd)) { 295 syslog(LOG_ERR, 296 "nis_put_printer:buffer overflow building cmd"); 297 return (-1); 298 } 299 if (system(cmd) != 0) 300 return (-1); 301 302 /* copy the Makefile excerpt */ 303 if (snprintf(cmd, sizeof (cmd), 304 "rcp %s root@%s:%s.print >/dev/null 2>&1", 305 MAKE_EXCERPT, host, NIS_MAKEFILE) >= sizeof (cmd)) { 306 syslog(LOG_ERR, 307 "nis_put_printer:buffer overflow building cmd"); 308 return (-1); 309 } 310 311 if (system(cmd) != 0) 312 return (-1); 313 314 /* run the make */ 315 if (snprintf(cmd, sizeof (cmd), 316 "/bin/sh -c 'PATH=/usr/ccs/bin:/bin:/usr/bin:$PATH " 317 "make -f %s -f %s.print printers.conf >/dev/null 2>&1'", 318 NIS_MAKEFILE, NIS_MAKEFILE) >= sizeof (cmd)) { 319 syslog(LOG_ERR, 320 "nis_put_printer:buffer overflow on make"); 321 return (-1); 322 } 323 324 return (remote_command(cmd, host)); 325 } 326