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