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