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