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