1*2264Sjacobs /* 2*2264Sjacobs * CDDL HEADER START 3*2264Sjacobs * 4*2264Sjacobs * The contents of this file are subject to the terms of the 5*2264Sjacobs * Common Development and Distribution License (the "License"). 6*2264Sjacobs * You may not use this file except in compliance with the License. 7*2264Sjacobs * 8*2264Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2264Sjacobs * or http://www.opensolaris.org/os/licensing. 10*2264Sjacobs * See the License for the specific language governing permissions 11*2264Sjacobs * and limitations under the License. 12*2264Sjacobs * 13*2264Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 14*2264Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2264Sjacobs * If applicable, add the following below this CDDL HEADER, with the 16*2264Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 17*2264Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 18*2264Sjacobs * 19*2264Sjacobs * CDDL HEADER END 20*2264Sjacobs */ 21*2264Sjacobs /* 22*2264Sjacobs * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*2264Sjacobs * Use is subject to license terms. 24*2264Sjacobs */ 25*2264Sjacobs 26*2264Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 27*2264Sjacobs 28*2264Sjacobs #include <stdio.h> 29*2264Sjacobs #include <stdlib.h> 30*2264Sjacobs #include <unistd.h> 31*2264Sjacobs #include <sys/types.h> 32*2264Sjacobs #include <sys/stat.h> 33*2264Sjacobs #include <string.h> 34*2264Sjacobs #include <stdarg.h> 35*2264Sjacobs #include <fcntl.h> 36*2264Sjacobs #include <syslog.h> 37*2264Sjacobs #include <errno.h> 38*2264Sjacobs #include <pwd.h> 39*2264Sjacobs #include <libintl.h> 40*2264Sjacobs #include <netdb.h> /* for rcmd() */ 41*2264Sjacobs 42*2264Sjacobs #include <ns.h> 43*2264Sjacobs #include <list.h> 44*2264Sjacobs #include <misc.h> 45*2264Sjacobs 46*2264Sjacobs /* escaped chars include delimiters and shell meta characters */ 47*2264Sjacobs #define ESCAPE_CHARS "\\\n=: `&;|>^$()<*?[" 48*2264Sjacobs 49*2264Sjacobs /* 50*2264Sjacobs * This modules contains all of the code nedessary to write back to each 51*2264Sjacobs * printing configuration data repository. The support is intended to 52*2264Sjacobs * introduce the least number of dependencies in the library, so it doesn't 53*2264Sjacobs * always perform it's operations in the cleanest fashion. 54*2264Sjacobs */ 55*2264Sjacobs 56*2264Sjacobs 57*2264Sjacobs /* 58*2264Sjacobs * Generic Files support begins here. 59*2264Sjacobs */ 60*2264Sjacobs static char * 61*2264Sjacobs freadline(FILE *fp, char *buf, int buflen) 62*2264Sjacobs { 63*2264Sjacobs char *s = buf; 64*2264Sjacobs 65*2264Sjacobs while (fgets(s, buflen, fp)) { 66*2264Sjacobs if ((s == buf) && ((*s == '#') || (*s == '\n'))) { 67*2264Sjacobs continue; 68*2264Sjacobs } else { 69*2264Sjacobs if ((*s == '#') || (*s == '\n')) { 70*2264Sjacobs *s = NULL; 71*2264Sjacobs break; 72*2264Sjacobs } 73*2264Sjacobs 74*2264Sjacobs buflen -= strlen(s); 75*2264Sjacobs s += strlen(s); 76*2264Sjacobs 77*2264Sjacobs if (*(s - 2) != '\\') 78*2264Sjacobs break; 79*2264Sjacobs #ifdef STRIP_CONTINUATION 80*2264Sjacobs buflen -= 2; 81*2264Sjacobs s -= 2; 82*2264Sjacobs #endif 83*2264Sjacobs } 84*2264Sjacobs } 85*2264Sjacobs 86*2264Sjacobs if (s == buf) 87*2264Sjacobs return (NULL); 88*2264Sjacobs else 89*2264Sjacobs return (buf); 90*2264Sjacobs } 91*2264Sjacobs 92*2264Sjacobs 93*2264Sjacobs static int 94*2264Sjacobs _file_put_printer(const char *file, const ns_printer_t *printer) 95*2264Sjacobs { 96*2264Sjacobs FILE *ifp, 97*2264Sjacobs *ofp; 98*2264Sjacobs char *tmpfile; 99*2264Sjacobs int fd; 100*2264Sjacobs int exit_status = 0; 101*2264Sjacobs int size; 102*2264Sjacobs 103*2264Sjacobs size = strlen(file) + 1 + 20; 104*2264Sjacobs if ((tmpfile = malloc(size)) == NULL) 105*2264Sjacobs return (-1); 106*2264Sjacobs 107*2264Sjacobs if (snprintf(tmpfile, size, "%sXXXXXX", file) >= size) { 108*2264Sjacobs syslog(LOG_ERR, "_file_put_printer:buffer overflow:tmpfile"); 109*2264Sjacobs return (-1); 110*2264Sjacobs } 111*2264Sjacobs 112*2264Sjacobs /* LINTED */ 113*2264Sjacobs while (1) { /* syncronize writes */ 114*2264Sjacobs fd = open(file, O_RDWR|O_CREAT|O_EXCL, 0644); 115*2264Sjacobs if ((fd < 0) && (errno == EEXIST)) 116*2264Sjacobs fd = open(file, O_RDWR); 117*2264Sjacobs if (fd < 0) { 118*2264Sjacobs if (errno == EAGAIN) 119*2264Sjacobs continue; 120*2264Sjacobs free(tmpfile); 121*2264Sjacobs return (-1); 122*2264Sjacobs } 123*2264Sjacobs if (lockf(fd, F_TLOCK, 0) == 0) 124*2264Sjacobs break; 125*2264Sjacobs (void) close(fd); 126*2264Sjacobs } 127*2264Sjacobs 128*2264Sjacobs if ((ifp = fdopen(fd, "r")) == NULL) { 129*2264Sjacobs (void) close(fd); 130*2264Sjacobs free(tmpfile); 131*2264Sjacobs return (-1); 132*2264Sjacobs } 133*2264Sjacobs 134*2264Sjacobs if ((fd = mkstemp(tmpfile)) < 0) { 135*2264Sjacobs (void) fclose(ifp); 136*2264Sjacobs free(tmpfile); 137*2264Sjacobs return (-1); 138*2264Sjacobs } 139*2264Sjacobs 140*2264Sjacobs (void) fchmod(fd, 0644); 141*2264Sjacobs if ((ofp = fdopen(fd, "wb+")) != NULL) { 142*2264Sjacobs char buf[4096]; 143*2264Sjacobs 144*2264Sjacobs (void) fprintf(ofp, 145*2264Sjacobs "#\n#\tIf you hand edit this file, comments and structure may change.\n" 146*2264Sjacobs "#\tThe preferred method of modifying this file is through the use of\n" 147*2264Sjacobs "#\tlpset(1M)\n#\n"); 148*2264Sjacobs 149*2264Sjacobs /* 150*2264Sjacobs * Handle the special case of lpset -x all 151*2264Sjacobs * This deletes all entries in the file 152*2264Sjacobs * In this case, just don't write any entries to the tmpfile 153*2264Sjacobs */ 154*2264Sjacobs 155*2264Sjacobs if (!((strcmp(printer->name, "all") == 0) && 156*2264Sjacobs (printer->attributes == NULL))) { 157*2264Sjacobs char *t, *entry, *pentry; 158*2264Sjacobs 159*2264Sjacobs (void) _cvt_printer_to_entry((ns_printer_t *)printer, 160*2264Sjacobs buf, sizeof (buf)); 161*2264Sjacobs t = pentry = strdup(buf); 162*2264Sjacobs 163*2264Sjacobs while (freadline(ifp, buf, sizeof (buf)) != NULL) { 164*2264Sjacobs ns_printer_t *tmp = (ns_printer_t *) 165*2264Sjacobs _cvt_nss_entry_to_printer(buf, ""); 166*2264Sjacobs 167*2264Sjacobs if (ns_printer_match_name(tmp, printer->name) 168*2264Sjacobs == 0) { 169*2264Sjacobs entry = pentry; 170*2264Sjacobs pentry = NULL; 171*2264Sjacobs } else 172*2264Sjacobs entry = buf; 173*2264Sjacobs 174*2264Sjacobs (void) fprintf(ofp, "%s\n", entry); 175*2264Sjacobs } 176*2264Sjacobs 177*2264Sjacobs if (pentry != NULL) 178*2264Sjacobs (void) fprintf(ofp, "%s\n", pentry); 179*2264Sjacobs free(t); 180*2264Sjacobs } 181*2264Sjacobs 182*2264Sjacobs (void) fclose(ofp); 183*2264Sjacobs (void) rename(tmpfile, file); 184*2264Sjacobs } else { 185*2264Sjacobs (void) close(fd); 186*2264Sjacobs (void) unlink(tmpfile); 187*2264Sjacobs exit_status = -1; 188*2264Sjacobs } 189*2264Sjacobs 190*2264Sjacobs (void) fclose(ifp); /* releases the lock, after rename on purpose */ 191*2264Sjacobs (void) free(tmpfile); 192*2264Sjacobs return (exit_status); 193*2264Sjacobs } 194*2264Sjacobs 195*2264Sjacobs 196*2264Sjacobs /* 197*2264Sjacobs * Support for writing a printer into the FILES /etc/printers.conf 198*2264Sjacobs * file. 199*2264Sjacobs */ 200*2264Sjacobs int 201*2264Sjacobs files_put_printer(const ns_printer_t *printer) 202*2264Sjacobs { 203*2264Sjacobs static char *file = "/etc/printers.conf"; 204*2264Sjacobs 205*2264Sjacobs return (_file_put_printer(file, printer)); 206*2264Sjacobs } 207*2264Sjacobs 208*2264Sjacobs 209*2264Sjacobs /* 210*2264Sjacobs * Support for writing a printer into the NIS printers.conf.byname 211*2264Sjacobs * map. 212*2264Sjacobs */ 213*2264Sjacobs 214*2264Sjacobs #include <rpc/rpc.h> 215*2264Sjacobs #include <rpcsvc/ypclnt.h> 216*2264Sjacobs #include <rpcsvc/yp_prot.h> 217*2264Sjacobs 218*2264Sjacobs /* 219*2264Sjacobs * Run the remote command. We aren't interested in any io, Only the 220*2264Sjacobs * return code. 221*2264Sjacobs */ 222*2264Sjacobs static int 223*2264Sjacobs remote_command(char *command, char *host) 224*2264Sjacobs { 225*2264Sjacobs struct passwd *pw; 226*2264Sjacobs 227*2264Sjacobs if ((pw = getpwuid(getuid())) != NULL) { 228*2264Sjacobs int fd; 229*2264Sjacobs 230*2264Sjacobs if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root", 231*2264Sjacobs command, NULL, AF_INET6)) < 0) 232*2264Sjacobs return (-1); 233*2264Sjacobs (void) close(fd); 234*2264Sjacobs return (0); 235*2264Sjacobs } else 236*2264Sjacobs return (-1); 237*2264Sjacobs } 238*2264Sjacobs 239*2264Sjacobs 240*2264Sjacobs /* 241*2264Sjacobs * This isn't all that pretty, but you can update NIS if the machine this 242*2264Sjacobs * runs on is in the /.rhosts or /etc/hosts.equiv on the NIS master. 243*2264Sjacobs * copy it local, update it, copy it remote 244*2264Sjacobs */ 245*2264Sjacobs #define TMP_PRINTERS_FILE "/tmp/printers.NIS" 246*2264Sjacobs #define NIS_MAKEFILE "/var/yp/Makefile" 247*2264Sjacobs #define MAKE_EXCERPT "/usr/lib/print/Makefile.yp" 248*2264Sjacobs /*ARGSUSED*/ 249*2264Sjacobs int 250*2264Sjacobs nis_put_printer(const ns_printer_t *printer) 251*2264Sjacobs { 252*2264Sjacobs static char *domain = NULL; 253*2264Sjacobs char *map = "printers.conf.byname"; 254*2264Sjacobs char *tmp = NULL; 255*2264Sjacobs char *host = NULL; 256*2264Sjacobs char lfile[BUFSIZ]; 257*2264Sjacobs char rfile[BUFSIZ]; 258*2264Sjacobs char cmd[BUFSIZ]; 259*2264Sjacobs 260*2264Sjacobs if (domain == NULL) 261*2264Sjacobs (void) yp_get_default_domain(&domain); 262*2264Sjacobs 263*2264Sjacobs if ((yp_master(domain, (char *)map, &host) != 0) && 264*2264Sjacobs (yp_master(domain, "passwd.byname", &host) != 0)) 265*2264Sjacobs return (-1); 266*2264Sjacobs 267*2264Sjacobs if (snprintf(lfile, sizeof (lfile), "/tmp/%s", map) >= 268*2264Sjacobs sizeof (lfile)) { 269*2264Sjacobs syslog(LOG_ERR, "nis_put_printer:lfile buffer overflow"); 270*2264Sjacobs return (-1); 271*2264Sjacobs } 272*2264Sjacobs if (snprintf(rfile, sizeof (rfile), "root@%s:/etc/%s", host, map) >= 273*2264Sjacobs sizeof (rfile)) { 274*2264Sjacobs syslog(LOG_ERR, "nis_put_printer:rfile buffer overflow"); 275*2264Sjacobs return (-1); 276*2264Sjacobs } 277*2264Sjacobs 278*2264Sjacobs if (((tmp = strrchr(rfile, '.')) != NULL) && 279*2264Sjacobs (strcmp(tmp, ".byname") == 0)) 280*2264Sjacobs *tmp = NULL; /* strip the .byname */ 281*2264Sjacobs 282*2264Sjacobs /* copy it local */ 283*2264Sjacobs if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1", 284*2264Sjacobs rfile, lfile) >= sizeof (cmd)) { 285*2264Sjacobs syslog(LOG_ERR, 286*2264Sjacobs "nis_put_printer:buffer overflow building cmd"); 287*2264Sjacobs return (-1); 288*2264Sjacobs } 289*2264Sjacobs (void) system(cmd); /* could fail because it doesn't exist */ 290*2264Sjacobs 291*2264Sjacobs 292*2264Sjacobs /* update it */ 293*2264Sjacobs if (_file_put_printer(lfile, printer) != 0) 294*2264Sjacobs return (-1); 295*2264Sjacobs 296*2264Sjacobs /* copy it back */ 297*2264Sjacobs if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1", 298*2264Sjacobs lfile, rfile) >= sizeof (cmd)) { 299*2264Sjacobs syslog(LOG_ERR, 300*2264Sjacobs "nis_put_printer:buffer overflow building cmd"); 301*2264Sjacobs return (-1); 302*2264Sjacobs } 303*2264Sjacobs if (system(cmd) != 0) 304*2264Sjacobs return (-1); 305*2264Sjacobs 306*2264Sjacobs /* copy the Makefile excerpt */ 307*2264Sjacobs if (snprintf(cmd, sizeof (cmd), 308*2264Sjacobs "rcp %s root@%s:%s.print >/dev/null 2>&1", 309*2264Sjacobs MAKE_EXCERPT, host, NIS_MAKEFILE) >= sizeof (cmd)) { 310*2264Sjacobs syslog(LOG_ERR, 311*2264Sjacobs "nis_put_printer:buffer overflow building cmd"); 312*2264Sjacobs return (-1); 313*2264Sjacobs } 314*2264Sjacobs 315*2264Sjacobs if (system(cmd) != 0) 316*2264Sjacobs return (-1); 317*2264Sjacobs 318*2264Sjacobs /* run the make */ 319*2264Sjacobs if (snprintf(cmd, sizeof (cmd), 320*2264Sjacobs "/bin/sh -c 'PATH=/usr/ccs/bin:/bin:/usr/bin:$PATH " 321*2264Sjacobs "make -f %s -f %s.print printers.conf >/dev/null 2>&1'", 322*2264Sjacobs NIS_MAKEFILE, NIS_MAKEFILE) >= sizeof (cmd)) { 323*2264Sjacobs syslog(LOG_ERR, 324*2264Sjacobs "nis_put_printer:buffer overflow on make"); 325*2264Sjacobs return (-1); 326*2264Sjacobs } 327*2264Sjacobs 328*2264Sjacobs return (remote_command(cmd, host)); 329*2264Sjacobs } 330*2264Sjacobs 331*2264Sjacobs /* 332*2264Sjacobs * Support for writing a printer into the NISPLUS org_dir.printers table 333*2264Sjacobs * begins here. This support uses the nisplus(5) commands rather than the 334*2264Sjacobs * nisplus API. This was done to remove the dependency in libprint on the 335*2264Sjacobs * API, which is used for lookup in a configuration dependent manner. 336*2264Sjacobs */ 337*2264Sjacobs #define NISPLUS_CREATE "/usr/bin/nistest -t T printers.org_dir || "\ 338*2264Sjacobs "( /usr/bin/nistbladm "\ 339*2264Sjacobs "-D access=og=rmcd,nw=r:group=admin."\ 340*2264Sjacobs "`/usr/bin/nisdefaults -d` "\ 341*2264Sjacobs "-c printers_tbl key=S,nogw= datum=,nogw= "\ 342*2264Sjacobs "printers.org_dir.`/usr/bin/nisdefaults -d` )" 343*2264Sjacobs 344*2264Sjacobs #define NISPLUS_REMOVE "/usr/bin/nistbladm -R key=%s printers.org_dir" 345*2264Sjacobs #define NISPLUS_UPDATE "/usr/bin/nistbladm -A key=%s datum=" 346*2264Sjacobs 347*2264Sjacobs int 348*2264Sjacobs nisplus_put_printer(const ns_printer_t *printer) 349*2264Sjacobs { 350*2264Sjacobs int rc = 0; 351*2264Sjacobs char cmd[BUFSIZ]; 352*2264Sjacobs 353*2264Sjacobs if (printer == NULL) 354*2264Sjacobs return (rc); 355*2264Sjacobs 356*2264Sjacobs /* create the table if it doesn't exist */ 357*2264Sjacobs (void) system(NISPLUS_CREATE); 358*2264Sjacobs 359*2264Sjacobs if (printer->attributes != NULL) { 360*2264Sjacobs int len; 361*2264Sjacobs ns_kvp_t **kvp; 362*2264Sjacobs 363*2264Sjacobs if (snprintf(cmd, sizeof (cmd), NISPLUS_UPDATE, 364*2264Sjacobs printer->name) >= sizeof (cmd)) { 365*2264Sjacobs syslog(LOG_ERR, 366*2264Sjacobs "nisplus_put_printer:NISPLUS_UPDATE:buffer overflow"); 367*2264Sjacobs return (-1); 368*2264Sjacobs } 369*2264Sjacobs 370*2264Sjacobs len = strlen(cmd); 371*2264Sjacobs 372*2264Sjacobs /* Append key/value pairs */ 373*2264Sjacobs for (kvp = printer->attributes; *kvp != NULL; kvp++) 374*2264Sjacobs if (((*kvp)->key != NULL) && ((*kvp)->value != NULL)) { 375*2264Sjacobs (void) strlcat(cmd, ":", sizeof (cmd)); 376*2264Sjacobs (void) strncat_escaped(cmd, (*kvp)->key, sizeof (cmd), 377*2264Sjacobs ESCAPE_CHARS); 378*2264Sjacobs (void) strlcat(cmd, "=", sizeof (cmd)); 379*2264Sjacobs (void) strncat_escaped(cmd, (*kvp)->value, 380*2264Sjacobs sizeof (cmd), ESCAPE_CHARS); 381*2264Sjacobs } 382*2264Sjacobs 383*2264Sjacobs if (len != strlen(cmd)) 384*2264Sjacobs (void) strlcat(cmd, " printers.org_dir", sizeof (cmd)); 385*2264Sjacobs else 386*2264Sjacobs (void) snprintf(cmd, sizeof (cmd), NISPLUS_REMOVE, 387*2264Sjacobs printer->name); 388*2264Sjacobs 389*2264Sjacobs } else 390*2264Sjacobs (void) snprintf(cmd, sizeof (cmd), NISPLUS_REMOVE, 391*2264Sjacobs printer->name); 392*2264Sjacobs 393*2264Sjacobs if (strlcat(cmd, " >/dev/null 2>&1", sizeof (cmd)) >= sizeof (cmd)) { 394*2264Sjacobs syslog(LOG_ERR, "nisplus_put_printer: buffer overflow"); 395*2264Sjacobs return (-1); 396*2264Sjacobs } 397*2264Sjacobs 398*2264Sjacobs /* add/modify/delete the entry */ 399*2264Sjacobs rc = system(cmd); 400*2264Sjacobs 401*2264Sjacobs return (rc); 402*2264Sjacobs } 403