xref: /illumos-gate/usr/src/cmd/print/lpset/lpset.c (revision 08f1bbed5edd2a2e9c8be7b7424c32e67c2f3f2c)
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 <sys/types.h>
29 #include <stdarg.h>
30 #include <unistd.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <syslog.h>
34 #include <errno.h>
35 #include <locale.h>
36 #ifndef SUNOS_4
37 #include <libintl.h>
38 #endif
39 #include <pwd.h>
40 #include <alloca.h>
41 
42 #include <ns.h>
43 #include <list.h>
44 
45 extern char *optarg;
46 extern int optind, opterr, optopt;
47 extern char *getenv(const char *);
48 
49 static void _decode_ldapResult(int result, char *printerName);
50 
51 static int
52 authorized()
53 {
54 	struct passwd *pw;
55 	uid_t uid;
56 	gid_t *list;
57 	int len;
58 	int maxgrp;
59 
60 	if ((uid = getuid()) == 0)
61 		return (1);	/* "root" is authorized */
62 
63 	if (((pw = getpwnam("lp")) != NULL) && (uid == pw->pw_uid))
64 		return (1);	/* "lp" is authorized */
65 
66 	if ((pw = getpwuid(uid)) == NULL)
67 		return (0);	/* intruders are not authorized */
68 
69 	if (chkauthattr("solaris.print.admin", pw->pw_name) == 1)
70 		return (1);	/* "solaris.print.admin" is authorized */
71 
72 	/* How many supplemental groups do we have? */
73 	maxgrp = getgroups(0, NULL);
74 	list = alloca(maxgrp * sizeof (gid_t));
75 
76 	if ((len = getgroups(maxgrp, list)) != -1)
77 		while (len-- > 0)
78 			if (list[len] == 14)
79 				return (1);	/* group 14 is authorized */
80 
81 	return (0);	/* nobody else is authorized */
82 }
83 
84 static void
85 Usage(char *name)
86 {
87 	(void) fprintf(stderr,
88 	    gettext("Usage: %s [-n files | ldap] [-x] "
89 	    "[-h ldaphost] [-D binddn] [-w passwd] "
90 	    "[-a key=value] [-d key] (printer)\n"),
91 	    name);
92 	exit(1);
93 }
94 
95 
96 /*
97  *  main() calls the appropriate routine to parse the command line arguments
98  *	and then calls the local remove routine, followed by the remote remove
99  *	routine to remove jobs.
100  */
101 int
102 main(int ac, char *av[])
103 {
104 	int result = 0;
105 	int delete_printer = 0;
106 	int c;
107 	char	*program = NULL,
108 	    *printer = NULL,
109 	    *host = NULL,
110 	    *binddn = NULL,
111 	    *passwd = NULL,
112 	    *ins = NULL,
113 	    *ons = "files";
114 	char	**changes = NULL;
115 	ns_cred_t	*cred = NULL;
116 	ns_printer_t 	*printer_obj = NULL;
117 
118 	(void) setlocale(LC_ALL, "");
119 
120 #if	!defined(TEXT_DOMAIN)
121 #define	TEXT_DOMAIN "SYS_TEST"
122 #endif
123 	(void) textdomain(TEXT_DOMAIN);
124 
125 	if ((program = strrchr(av[0], '/')) == NULL)
126 		program = av[0];
127 	else
128 		program++;
129 
130 	openlog(program, LOG_PID, LOG_LPR);
131 
132 	if (ac < 2)
133 		Usage(program);
134 
135 	while ((c = getopt(ac, av, "a:d:D:h:n:r:w:x")) != EOF)
136 		switch (c) {
137 		case 'd':
138 			if (strchr(optarg, '=') != NULL)
139 				Usage(program);
140 			/* FALLTHRU */
141 		case 'a':
142 			changes = (char **)list_append((void**)changes,
143 			    (void *)strdup(optarg));
144 			break;
145 		case 'D':
146 			binddn = optarg;
147 			break;
148 		case 'h':
149 			host = optarg;
150 			break;
151 		case 'n':
152 			ons = optarg;
153 			break;
154 		case 'r':
155 			ins = optarg;
156 			break;
157 		case 'w':
158 			passwd = optarg;
159 			break;
160 		case 'x':
161 			delete_printer++;
162 			break;
163 		default:
164 			Usage(program);
165 		}
166 
167 	if (optind != ac-1)
168 		Usage(program);
169 
170 	/*
171 	 * Check required options have been given: [ -x | [ -a | -d ]]
172 	 */
173 	if ((changes == NULL) && (delete_printer == 0)) {
174 		Usage(program);
175 	}
176 
177 	printer = av[optind];
178 
179 	if (strchr(printer, ':') != NULL) {
180 		(void) fprintf(stderr, gettext(
181 		    "POSIX-Style names are not valid destinations (%s)\n"),
182 		    printer);
183 		return (1);
184 	}
185 
186 	ins = normalize_ns_name(ins);
187 	ons = normalize_ns_name(ons);
188 	if (ins == NULL)
189 		ins = ons;
190 
191 	/* check / set the name service for writing */
192 	if (strcasecmp("user", ons) == 0) {
193 		(void) setuid(getuid());
194 		ons = "user";
195 	} else if (strcasecmp("files", ons) == 0) {
196 		if (authorized() == 0) {
197 			(void) fprintf(stderr, gettext(
198 			    "Permission denied: not authorized\n"));
199 			return (1);
200 		}
201 		ons = "files";
202 	} else if (strcasecmp("ldap", ons) == 0) {
203 		if ((cred = calloc(1, sizeof (*cred))) == NULL) {
204 			(void) fprintf(stderr,
205 			    gettext("could not initialize credential\n"));
206 			return (1);
207 		}
208 
209 		if (binddn == NULL) {
210 			(void) fprintf(stderr,
211 			    gettext("Distinguished Name is required.\n"));
212 			return (1);
213 		}
214 
215 		if (passwd == NULL) {
216 			passwd = getpassphrase(gettext("Bind Password:"));
217 		}
218 
219 		/*
220 		 * Setup LDAP bind credentials, so that it uses
221 		 * the default ldap port, and the NS domain for this
222 		 * ldapclient box. Note: passwdType is currently not
223 		 * used but once the ldap native function can select
224 		 * secure or insure password it will pass the user selected
225 		 * security type.
226 		 */
227 		cred->passwd = passwd;
228 		cred->passwdType = NS_PW_INSECURE; /* use default */
229 		cred->binddn = binddn;
230 		cred->host = host;
231 		cred->port = 0;		/* use default */
232 		cred->domainDN = NULL;	/* use default */
233 
234 		ons = "ldap";
235 		(void) setuid(getuid());
236 	} else {
237 		(void) fprintf(stderr,
238 		    gettext("%s is not a supported name service.\n"),
239 		    ons);
240 		return (1);
241 	}
242 
243 	if (strcasecmp(NS_SVC_LDAP, ons) != 0) {
244 
245 	    /* Naming Service is not LDAP */
246 
247 	    /* get the printer object */
248 		if ((printer_obj = ns_printer_get_name(printer, ins)) == NULL) {
249 			if (delete_printer != 0) {
250 				(void) fprintf(stderr, gettext
251 				    ("%s: unknown printer\n"), printer);
252 			return (1);
253 			}
254 			if ((printer_obj = calloc(1, sizeof (*printer_obj)))
255 			    == NULL) {
256 				(void) fprintf(stderr, gettext(
257 				    "could not initialize printer object\n"));
258 				return (1);
259 			}
260 			printer_obj->name = strdup(printer);
261 		}
262 
263 		printer_obj->source = ons;
264 
265 		if (cred != NULL) {
266 			printer_obj->cred = cred;
267 		}
268 
269 	    /* make the changes to it */
270 		while (changes != NULL && *changes != NULL) {
271 			int has_equals = (strchr(*changes, '=') != NULL);
272 			char *p, *key = NULL, *value = NULL;
273 
274 			key = *(changes++);
275 
276 			for (p = key; ((p != NULL) && (*p != '\0')); p++)
277 				if (*p == '=') {
278 					*p = '\0';
279 					value = ++p;
280 					break;
281 				} else if (*p == '\\')
282 					p++;
283 
284 			if ((value != NULL) && (*value == '\0'))
285 				value = NULL;
286 
287 			if ((key != NULL) && (key[0] != '\0')) {
288 				if ((value == NULL) &&
289 				    (ns_get_value(key, printer_obj) == NULL) &&
290 				    (has_equals == 0)) {
291 					fprintf(stderr,
292 					    gettext("%s: unknown attribute\n"),
293 					    key);
294 					result = 1;
295 				} else
296 				(void) ns_set_value_from_string(key, value,
297 				    printer_obj);
298 			}
299 		}
300 		if (delete_printer != 0)
301 			printer_obj->attributes = NULL;
302 
303 		/* write it back */
304 		if (ns_printer_put(printer_obj) != 0) {
305 			(void) fprintf(stderr,
306 			    gettext("Failed to write into %s database\n"),
307 			    ons);
308 			result = 1;
309 		}
310 	}
311 
312 	else {
313 		/*
314 		 * Naming Service is LDAP
315 		 *
316 		 * Action the request by calling ns ldap functions to
317 		 * add, modify or delete the printer object.
318 		 */
319 
320 		if ((printer_obj = calloc(1, sizeof (*printer_obj))) == NULL) {
321 			(void) fprintf(stderr, gettext(
322 			    "could not initialize printer object\n"));
323 			return (1);
324 		}
325 
326 		if ((cred != NULL) && (printer_obj != NULL)) {
327 			printer_obj->name = strdup(printer);
328 			printer_obj->cred = cred;
329 			printer_obj->cred->domainDN = NULL; /* use default */
330 			printer_obj->source = ons;
331 			printer_obj->nsdata = malloc(sizeof (NS_LDAPDATA));
332 
333 			if (printer_obj->nsdata != NULL) {
334 				/*
335 				 * Update the LDAP directory for this printer
336 				 */
337 
338 				if (delete_printer != 0) {
339 					/* Delete the printer object */
340 					((NS_LDAPDATA *)
341 					    (printer_obj->nsdata))->attrList
342 					    = NULL;
343 				} else {
344 					/* Add or modify the printer object */
345 					((NS_LDAPDATA *)
346 					    (printer_obj->nsdata))->attrList =
347 					    changes;
348 				}
349 
350 				result = ns_printer_put(printer_obj);
351 				if (result != 0) {
352 					/* display LDAP specific message */
353 					_decode_ldapResult(result, printer);
354 
355 					(void) fprintf(stderr, gettext(
356 					"Failed to update %s database\n"), ons);
357 					result = 1;
358 				}
359 
360 				free(printer_obj->nsdata);
361 			}
362 
363 			else {
364 				_decode_ldapResult(NSL_ERR_MEMORY, NULL);
365 				result = 1;
366 			}
367 		}
368 
369 		else {
370 			result = 1;
371 			(void) fprintf(stderr,
372 			    gettext("Error - no LDAP credentials\n"));
373 		}
374 
375 		if (printer_obj != NULL) {
376 			if (printer_obj->name != NULL) {
377 				free(printer_obj->name);
378 			}
379 			free(printer_obj);
380 		}
381 
382 	}
383 
384 	return (result);
385 } /* main */
386 
387 
388 
389 
390 /*
391  * *****************************************************************************
392  *
393  * Function:    _decode_ldapResult()
394  *
395  * Description: Decode the ldap_put_printer specific error codes and display
396  *              the appropriate error message.
397  *
398  * Parameters:
399  * Input:       int result - contains the NSL_RESULT codes
400  *              char *printerName - name of printer
401  * Output:      None
402  *
403  * Returns:     void
404  *
405  * *****************************************************************************
406  */
407 
408 static void
409 _decode_ldapResult(int result, char *printerName)
410 
411 {
412 	NSL_RESULT lresult = (NSL_RESULT)result;
413 
414 	/* ------------- */
415 
416 	switch (lresult)
417 	{
418 		case NSL_OK:
419 		{
420 			break;
421 		}
422 
423 		case NSL_ERR_INTERNAL:
424 		{
425 			(void) fprintf(stderr,
426 				gettext("Unexpected software error\n"));
427 			break;
428 		}
429 
430 		case NSL_ERR_ADD_FAILED:
431 		{
432 			(void) fprintf(stderr, "%s %s\n",
433 				gettext("Failed to add printer:"), printerName);
434 			break;
435 		}
436 
437 		case NSL_ERR_MOD_FAILED:
438 		{
439 			(void) fprintf(stderr, "%s %s\n",
440 				gettext("Failed to modify printer:"),
441 					printerName);
442 			break;
443 		}
444 
445 		case NSL_ERR_DEL_FAILED:
446 		{
447 			(void) fprintf(stderr, "%s %s\n",
448 				gettext("Failed to delete printer:"),
449 					printerName);
450 			break;
451 		}
452 
453 
454 		case NSL_ERR_UNKNOWN_PRINTER:
455 		{
456 			(void) fprintf(stderr, "%s %s\n",
457 				gettext("Unknown printer:"), printerName);
458 			break;
459 		}
460 
461 		case NSL_ERR_CREDENTIALS:
462 		{
463 			(void) fprintf(stderr, "%s\n",
464 		gettext("Missing LDAP credential information for printer:"));
465 			break;
466 		}
467 
468 		case NSL_ERR_CONNECT:
469 		{
470 			(void) fprintf(stderr, "%s\n",
471 				gettext("Failed to connect to LDAP server"));
472 			break;
473 		}
474 
475 		case NSL_ERR_BIND:
476 		{
477 			(void) fprintf(stderr, gettext("LDAP bind failed\n"));
478 			break;
479 		}
480 
481 		case NSL_ERR_RENAME:
482 		{
483 			(void) fprintf(stderr, "%s %s\n",
484 			    gettext("Object rename not allowed for printer:"),
485 			    printerName);
486 			break;
487 		}
488 
489 		case NSL_ERR_KVP:
490 		{
491 			(void) fprintf(stderr, "%s",
492 			    gettext("Setting sun-printer-kvp attribute is "
493 				"not supported through this command.\n"));
494 			break;
495 		}
496 
497 		case NSL_ERR_BSDADDR:
498 		{
499 			(void) fprintf(stderr, "%s",
500 			    gettext("Setting sun-printer-bsdaddr attribute is "
501 				"not supported through this command.\n"
502 				"Use the bsaddr attribute instead.\n"));
503 			break;
504 		}
505 
506 		case NSL_ERR_PNAME:
507 		{
508 			(void) fprintf(stderr, "%s",
509 			    gettext("Setting printer-name attribute is "
510 				"not supported through this command.\n"));
511 			break;
512 		}
513 
514 		case NSL_ERR_MEMORY:
515 		{
516 			(void) fprintf(stderr,
517 					gettext("Memory allocation error\n"));
518 			break;
519 		}
520 
521 		case NSL_ERR_MULTIOP:
522 		{
523 			(void) fprintf(stderr,
524 				gettext("Delete and add operation on the "
525 					"same key attribute is not allowed\n"));
526 			break;
527 		}
528 
529 		case NSL_ERR_NOTALLOWED:
530 		{
531 			(void) fprintf(stderr,
532 				gettext("KVP attribute is not allowed\n"));
533 			break;
534 		}
535 
536 		default:
537 		{
538 			(void) fprintf(stderr,
539 					gettext("Error code = %d\n"), result);
540 			break;
541 		}
542 	}
543 
544 } /* _decode_ldapResult */
545