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 = '\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 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 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 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 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