summaryrefslogtreecommitdiff
path: root/usr/src/lib/print/libprint/common/nss_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/print/libprint/common/nss_write.c')
-rw-r--r--usr/src/lib/print/libprint/common/nss_write.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/usr/src/lib/print/libprint/common/nss_write.c b/usr/src/lib/print/libprint/common/nss_write.c
new file mode 100644
index 0000000000..77f894be5a
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/nss_write.c
@@ -0,0 +1,402 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libintl.h>
+#include <netdb.h> /* for rcmd() */
+
+#include <ns.h>
+#include <list.h>
+#include <misc.h>
+
+/* escaped chars include delimiters and shell meta characters */
+#define ESCAPE_CHARS "\\\n=: `&;|>^$()<*?["
+
+/*
+ * This modules contains all of the code nedessary to write back to each
+ * printing configuration data repository. The support is intended to
+ * introduce the least number of dependencies in the library, so it doesn't
+ * always perform it's operations in the cleanest fashion.
+ */
+
+
+/*
+ * Generic Files support begins here.
+ */
+static char *
+freadline(FILE *fp, char *buf, int buflen)
+{
+ char *s = buf;
+
+ while (fgets(s, buflen, fp)) {
+ if ((s == buf) && ((*s == '#') || (*s == '\n'))) {
+ continue;
+ } else {
+ if ((*s == '#') || (*s == '\n')) {
+ *s = NULL;
+ break;
+ }
+
+ buflen -= strlen(s);
+ s += strlen(s);
+
+ if (*(s - 2) != '\\')
+ break;
+#ifdef STRIP_CONTINUATION
+ buflen -= 2;
+ s -= 2;
+#endif
+ }
+ }
+
+ if (s == buf)
+ return (NULL);
+ else
+ return (buf);
+}
+
+
+static int
+_file_put_printer(const char *file, const ns_printer_t *printer)
+{
+ FILE *ifp,
+ *ofp;
+ char *tmpfile;
+ int fd;
+ int exit_status = 0;
+ int size;
+
+ size = strlen(file) + 1 + 20;
+ if ((tmpfile = malloc(size)) == NULL)
+ return (-1);
+
+ if (snprintf(tmpfile, size, "%sXXXXXX", file) >= size) {
+ syslog(LOG_ERR, "_file_put_printer:buffer overflow:tmpfile");
+ return (-1);
+ }
+
+ /* LINTED */
+ while (1) { /* syncronize writes */
+ fd = open(file, O_RDWR|O_CREAT|O_EXCL, 0644);
+ if ((fd < 0) && (errno == EEXIST))
+ fd = open(file, O_RDWR);
+ if (fd < 0) {
+ if (errno == EAGAIN)
+ continue;
+ free(tmpfile);
+ return (-1);
+ }
+ if (lockf(fd, F_TLOCK, 0) == 0)
+ break;
+ (void) close(fd);
+ }
+
+ if ((ifp = fdopen(fd, "r")) == NULL) {
+ (void) close(fd);
+ free(tmpfile);
+ return (-1);
+ }
+
+ if ((fd = mkstemp(tmpfile)) < 0) {
+ (void) fclose(ifp);
+ free(tmpfile);
+ return (-1);
+ }
+
+ (void) fchmod(fd, 0644);
+ if ((ofp = fdopen(fd, "wb+")) != NULL) {
+ char buf[4096];
+
+ (void) fprintf(ofp,
+ "#\n#\tIf you hand edit this file, comments and structure may change.\n"
+ "#\tThe preferred method of modifying this file is through the use of\n"
+ "#\tlpset(1M)\n#\n");
+
+ /*
+ * Handle the special case of lpset -x all
+ * This deletes all entries in the file
+ * In this case, just don't write any entries to the tmpfile
+ */
+
+ if (!((strcmp(printer->name, "all") == 0) &&
+ (printer->attributes == NULL))) {
+ char *t, *entry, *pentry;
+
+ (void) _cvt_printer_to_entry((ns_printer_t *)printer,
+ buf, sizeof (buf));
+ t = pentry = strdup(buf);
+
+ while (freadline(ifp, buf, sizeof (buf)) != NULL) {
+ ns_printer_t *tmp = (ns_printer_t *)
+ _cvt_nss_entry_to_printer(buf, "");
+
+ if (ns_printer_match_name(tmp, printer->name)
+ == 0) {
+ entry = pentry;
+ pentry = NULL;
+ } else
+ entry = buf;
+
+ (void) fprintf(ofp, "%s\n", entry);
+ }
+
+ if (pentry != NULL)
+ (void) fprintf(ofp, "%s\n", pentry);
+ free(t);
+ }
+
+ (void) fclose(ofp);
+ (void) rename(tmpfile, file);
+ } else {
+ (void) close(fd);
+ (void) unlink(tmpfile);
+ exit_status = -1;
+ }
+
+ (void) fclose(ifp); /* releases the lock, after rename on purpose */
+ (void) free(tmpfile);
+ return (exit_status);
+}
+
+
+/*
+ * Support for writing a printer into the FILES /etc/printers.conf
+ * file.
+ */
+int
+files_put_printer(const ns_printer_t *printer)
+{
+ static char *file = "/etc/printers.conf";
+
+ return (_file_put_printer(file, printer));
+}
+
+
+/*
+ * Support for writing a printer into the NIS printers.conf.byname
+ * map.
+ */
+
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+
+/*
+ * Run the remote command. We aren't interested in any io, Only the
+ * return code.
+ */
+static int
+remote_command(char *command, char *host)
+{
+ struct passwd *pw;
+
+ if ((pw = getpwuid(getuid())) != NULL) {
+ int fd;
+
+ if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root",
+ command, NULL, AF_INET6)) < 0)
+ return (-1);
+ (void) close(fd);
+ return (0);
+ } else
+ return (-1);
+}
+
+
+/*
+ * This isn't all that pretty, but you can update NIS if the machine this
+ * runs on is in the /.rhosts or /etc/hosts.equiv on the NIS master.
+ * copy it local, update it, copy it remote
+ */
+#define TMP_PRINTERS_FILE "/tmp/printers.NIS"
+#define NIS_MAKEFILE "/var/yp/Makefile"
+#define MAKE_EXCERPT "/usr/lib/print/Makefile.yp"
+/*ARGSUSED*/
+int
+nis_put_printer(const ns_printer_t *printer)
+{
+ static char *domain = NULL;
+ char *map = "printers.conf.byname";
+ char *tmp = NULL;
+ char *host = NULL;
+ char lfile[BUFSIZ];
+ char rfile[BUFSIZ];
+ char cmd[BUFSIZ];
+
+ if (domain == NULL)
+ (void) yp_get_default_domain(&domain);
+
+ if ((yp_master(domain, (char *)map, &host) != 0) &&
+ (yp_master(domain, "passwd.byname", &host) != 0))
+ return (-1);
+
+ if (snprintf(lfile, sizeof (lfile), "/tmp/%s", map) >=
+ sizeof (lfile)) {
+ syslog(LOG_ERR, "nis_put_printer:lfile buffer overflow");
+ return (-1);
+ }
+ if (snprintf(rfile, sizeof (rfile), "root@%s:/etc/%s", host, map) >=
+ sizeof (rfile)) {
+ syslog(LOG_ERR, "nis_put_printer:rfile buffer overflow");
+ return (-1);
+ }
+
+ if (((tmp = strrchr(rfile, '.')) != NULL) &&
+ (strcmp(tmp, ".byname") == 0))
+ *tmp = NULL; /* strip the .byname */
+
+ /* copy it local */
+ if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
+ rfile, lfile) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow building cmd");
+ return (-1);
+ }
+ (void) system(cmd); /* could fail because it doesn't exist */
+
+
+ /* update it */
+ if (_file_put_printer(lfile, printer) != 0)
+ return (-1);
+
+ /* copy it back */
+ if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
+ lfile, rfile) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow building cmd");
+ return (-1);
+ }
+ if (system(cmd) != 0)
+ return (-1);
+
+ /* copy the Makefile excerpt */
+ if (snprintf(cmd, sizeof (cmd),
+ "rcp %s root@%s:%s.print >/dev/null 2>&1",
+ MAKE_EXCERPT, host, NIS_MAKEFILE) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow building cmd");
+ return (-1);
+ }
+
+ if (system(cmd) != 0)
+ return (-1);
+
+ /* run the make */
+ if (snprintf(cmd, sizeof (cmd),
+ "/bin/sh -c 'PATH=/usr/ccs/bin:/bin:/usr/bin:$PATH "
+ "make -f %s -f %s.print printers.conf >/dev/null 2>&1'",
+ NIS_MAKEFILE, NIS_MAKEFILE) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow on make");
+ return (-1);
+ }
+
+ return (remote_command(cmd, host));
+}
+
+/*
+ * Support for writing a printer into the NISPLUS org_dir.printers table
+ * begins here. This support uses the nisplus(5) commands rather than the
+ * nisplus API. This was done to remove the dependency in libprint on the
+ * API, which is used for lookup in a configuration dependent manner.
+ */
+#define NISPLUS_CREATE "/usr/bin/nistest -t T printers.org_dir || "\
+ "( /usr/bin/nistbladm "\
+ "-D access=og=rmcd,nw=r:group=admin."\
+ "`/usr/bin/nisdefaults -d` "\
+ "-c printers_tbl key=S,nogw= datum=,nogw= "\
+ "printers.org_dir.`/usr/bin/nisdefaults -d` )"
+
+#define NISPLUS_REMOVE "/usr/bin/nistbladm -R key=%s printers.org_dir"
+#define NISPLUS_UPDATE "/usr/bin/nistbladm -A key=%s datum="
+
+int
+nisplus_put_printer(const ns_printer_t *printer)
+{
+ int rc = 0;
+ char cmd[BUFSIZ];
+
+ if (printer == NULL)
+ return (rc);
+
+ /* create the table if it doesn't exist */
+ (void) system(NISPLUS_CREATE);
+
+ if (printer->attributes != NULL) {
+ int len;
+ ns_kvp_t **kvp;
+
+ if (snprintf(cmd, sizeof (cmd), NISPLUS_UPDATE,
+ printer->name) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nisplus_put_printer:NISPLUS_UPDATE:buffer overflow");
+ return (-1);
+ }
+
+ len = strlen(cmd);
+
+ /* Append key/value pairs */
+ for (kvp = printer->attributes; *kvp != NULL; kvp++)
+ if (((*kvp)->key != NULL) && ((*kvp)->value != NULL)) {
+ (void) strlcat(cmd, ":", sizeof (cmd));
+ (void) strncat_escaped(cmd, (*kvp)->key, sizeof (cmd),
+ ESCAPE_CHARS);
+ (void) strlcat(cmd, "=", sizeof (cmd));
+ (void) strncat_escaped(cmd, (*kvp)->value,
+ sizeof (cmd), ESCAPE_CHARS);
+ }
+
+ if (len != strlen(cmd))
+ (void) strlcat(cmd, " printers.org_dir", sizeof (cmd));
+ else
+ (void) snprintf(cmd, sizeof (cmd), NISPLUS_REMOVE,
+ printer->name);
+
+ } else
+ (void) snprintf(cmd, sizeof (cmd), NISPLUS_REMOVE,
+ printer->name);
+
+ if (strlcat(cmd, " >/dev/null 2>&1", sizeof (cmd)) >= sizeof (cmd)) {
+ syslog(LOG_ERR, "nisplus_put_printer: buffer overflow");
+ return (-1);
+ }
+
+ /* add/modify/delete the entry */
+ rc = system(cmd);
+
+ return (rc);
+}