xref: /illumos-gate/usr/src/cmd/print/lpset/lpset.c (revision 89b2a9fbeabf42fa54594df0e5927bcc50a07cc9)
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 | nisplus | 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("nisplus", ons) == 0) {
203 		ons = "nisplus";
204 	} else if (strcasecmp("ldap", ons) == 0) {
205 		if ((cred = calloc(1, sizeof (*cred))) == NULL) {
206 			(void) fprintf(stderr,
207 				gettext("could not initialize credential\n"));
208 			return (1);
209 		}
210 
211 		if (binddn == NULL) {
212 			(void) fprintf(stderr,
213 			    gettext("Distinguished Name is required.\n"));
214 			return (1);
215 		}
216 
217 		if (passwd == NULL) {
218 			passwd = getpassphrase(gettext("Bind Password:"));
219 		}
220 
221 		/*
222 		 * Setup LDAP bind credentials, so that it uses
223 		 * the default ldap port, and the NS domain for this
224 		 * ldapclient box. Note: passwdType is currently not
225 		 * used but once the ldap native function can select
226 		 * secure or insure password it will pass the user selected
227 		 * security type.
228 		 */
229 		cred->passwd = passwd;
230 		cred->passwdType = NS_PW_INSECURE; /* use default */
231 		cred->binddn = binddn;
232 		cred->host = host;
233 		cred->port = 0;		/* use default */
234 		cred->domainDN = NULL;	/* use default */
235 
236 		ons = "ldap";
237 		(void) setuid(getuid());
238 	} else {
239 		(void) fprintf(stderr,
240 			gettext("%s is not a supported name service.\n"),
241 			ons);
242 		return (1);
243 	}
244 
245 	if (strcasecmp(NS_SVC_LDAP, ons) != 0) {
246 
247 	    /* Naming Service is not LDAP */
248 
249 	    /* get the printer object */
250 	    if ((printer_obj = ns_printer_get_name(printer, ins)) == NULL) {
251 		if (delete_printer != 0) {
252 			(void) fprintf(stderr, gettext("%s: unknown printer\n"),
253 				printer);
254 			return (1);
255 		}
256 		if ((printer_obj = calloc(1, sizeof (*printer_obj))) == NULL) {
257 			(void) fprintf(stderr, gettext(
258 				"could not initialize printer object\n"));
259 			return (1);
260 		}
261 		printer_obj->name = strdup(printer);
262 	    }
263 
264 	    printer_obj->source = ons;
265 
266 	    if (cred != NULL) {
267 		printer_obj->cred = cred;
268 	    }
269 
270 	    /* make the changes to it */
271 	    while (changes != NULL && *changes != NULL) {
272 		int has_equals = (strchr(*changes, '=') != NULL);
273 		char *p, *key = NULL, *value = NULL;
274 
275 		key = *(changes++);
276 
277 		for (p = key; ((p != NULL) && (*p != NULL)); p++)
278 			if (*p == '=') {
279 				*p = NULL;
280 				value = ++p;
281 				break;
282 			} else if (*p == '\\')
283 				p++;
284 
285 		if ((value != NULL) && (*value == NULL))
286 			value = NULL;
287 
288 		if ((key != NULL) && (key[0] != NULL)) {
289 			if ((value == NULL) &&
290 			    (ns_get_value(key, printer_obj) == NULL) &&
291 			    (has_equals == 0)) {
292 				fprintf(stderr,
293 					gettext("%s: unknown attribute\n"),
294 					key);
295 				result = 1;
296 			} else
297 			(void) ns_set_value_from_string(key, value,
298 				printer_obj);
299 		}
300 	    }
301 	    if (delete_printer != 0)
302 		printer_obj->attributes = NULL;
303 
304 	    /* write it back */
305 	    if (ns_printer_put(printer_obj) != 0) {
306 		(void) fprintf(stderr,
307 				gettext("Failed to write into %s database\n"),
308 				ons);
309 		result = 1;
310 	    }
311 	}
312 
313 	else {
314 		/*
315 		 * Naming Service is LDAP
316 		 *
317 		 * Action the request by calling ns ldap functions to
318 		 * add, modify or delete the printer object.
319 		 */
320 
321 		if ((printer_obj = calloc(1, sizeof (*printer_obj))) == NULL) {
322 			(void) fprintf(stderr, gettext(
323 				"could not initialize printer object\n"));
324 			return (1);
325 		}
326 
327 		if ((cred != NULL) && (printer_obj != NULL)) {
328 			printer_obj->name = strdup(printer);
329 			printer_obj->cred = cred;
330 			printer_obj->cred->domainDN = NULL; /* use default */
331 			printer_obj->source = ons;
332 			printer_obj->nsdata = malloc(sizeof (NS_LDAPDATA));
333 
334 			if (printer_obj->nsdata != NULL) {
335 				/*
336 				 * Update the LDAP directory for this printer
337 				 */
338 
339 				if (delete_printer != 0) {
340 					/* Delete the printer object */
341 					((NS_LDAPDATA *)
342 					(printer_obj->nsdata))->attrList = 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