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