1/*
2 * "$Id: usersys.c 11693 2014-03-11 01:24:45Z msweet $"
3 *
4 * User, system, and password routines for CUPS.
5 *
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file.  If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18/*
19 * Include necessary headers...
20 */
21
22#include "cups-private.h"
23#include <stdlib.h>
24#include <sys/stat.h>
25#ifdef WIN32
26#  include <windows.h>
27#else
28#  include <pwd.h>
29#  include <termios.h>
30#  include <sys/utsname.h>
31#endif /* WIN32 */
32
33
34/*
35 * Local constants...
36 */
37
38#define _CUPS_PASSCHAR	'*'		/* Character that is echoed for password */
39
40
41/*
42 * Local functions...
43 */
44
45static void	cups_read_client_conf(cups_file_t *fp,
46		                      _cups_globals_t *cg,
47		                      const char *cups_encryption,
48				      const char *cups_server,
49				      const char *cups_user,
50#ifdef HAVE_GSSAPI
51                                      const char *cups_gssservicename,
52#endif /* HAVE_GSSAPI */
53				      const char *cups_anyroot,
54				      const char *cups_expiredroot,
55				      const char *cups_expiredcerts);
56
57
58/*
59 * 'cupsEncryption()' - Get the current encryption settings.
60 *
61 * The default encryption setting comes from the CUPS_ENCRYPTION
62 * environment variable, then the ~/.cups/client.conf file, and finally the
63 * /etc/cups/client.conf file. If not set, the default is
64 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
65 *
66 * Note: The current encryption setting is tracked separately for each thread
67 * in a program. Multi-threaded programs that override the setting via the
68 * @link cupsSetEncryption@ function need to do so in each thread for the same
69 * setting to be used.
70 */
71
72http_encryption_t			/* O - Encryption settings */
73cupsEncryption(void)
74{
75  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
76
77
78  if (cg->encryption == (http_encryption_t)-1)
79    _cupsSetDefaults();
80
81  return (cg->encryption);
82}
83
84
85/*
86 * 'cupsGetPassword()' - Get a password from the user.
87 *
88 * Uses the current password callback function. Returns @code NULL@ if the
89 * user does not provide a password.
90 *
91 * Note: The current password callback function is tracked separately for each
92 * thread in a program. Multi-threaded programs that override the setting via
93 * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
94 * do so in each thread for the same function to be used.
95 */
96
97const char *				/* O - Password */
98cupsGetPassword(const char *prompt)	/* I - Prompt string */
99{
100  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
101
102
103  return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
104}
105
106
107/*
108 * 'cupsGetPassword2()' - Get a password from the user using the advanced
109 *                        password callback.
110 *
111 * Uses the current password callback function. Returns @code NULL@ if the
112 * user does not provide a password.
113 *
114 * Note: The current password callback function is tracked separately for each
115 * thread in a program. Multi-threaded programs that override the setting via
116 * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
117 * do so in each thread for the same function to be used.
118 *
119 * @since CUPS 1.4/OS X 10.6@
120 */
121
122const char *				/* O - Password */
123cupsGetPassword2(const char *prompt,	/* I - Prompt string */
124		 http_t     *http,	/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
125		 const char *method,	/* I - Request method ("GET", "POST", "PUT") */
126		 const char *resource)	/* I - Resource path */
127{
128  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
129
130
131  if (!http)
132    http = _cupsConnect();
133
134  return ((cg->password_cb)(prompt, http, method, resource, cg->password_data));
135}
136
137
138/*
139 * 'cupsServer()' - Return the hostname/address of the current server.
140 *
141 * The default server comes from the CUPS_SERVER environment variable, then the
142 * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
143 * set, the default is the local system - either "localhost" or a domain socket
144 * path.
145 *
146 * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
147 * address, or a domain socket pathname.
148 *
149 * Note: The current server is tracked separately for each thread in a program.
150 * Multi-threaded programs that override the server via the
151 * @link cupsSetServer@ function need to do so in each thread for the same
152 * server to be used.
153 */
154
155const char *				/* O - Server name */
156cupsServer(void)
157{
158  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
159
160
161  if (!cg->server[0])
162    _cupsSetDefaults();
163
164  return (cg->server);
165}
166
167
168/*
169 * 'cupsSetClientCertCB()' - Set the client certificate callback.
170 *
171 * Pass @code NULL@ to restore the default callback.
172 *
173 * Note: The current certificate callback is tracked separately for each thread
174 * in a program. Multi-threaded programs that override the callback need to do
175 * so in each thread for the same callback to be used.
176 *
177 * @since CUPS 1.5/OS X 10.7@
178 */
179
180void
181cupsSetClientCertCB(
182    cups_client_cert_cb_t cb,		/* I - Callback function */
183    void                  *user_data)	/* I - User data pointer */
184{
185  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
186
187
188  cg->client_cert_cb	= cb;
189  cg->client_cert_data	= user_data;
190}
191
192
193/*
194 * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
195 *			    connections.
196 *
197 * Note: The default credentials are tracked separately for each thread in a
198 * program. Multi-threaded programs that override the setting need to do so in
199 * each thread for the same setting to be used.
200 *
201 * @since CUPS 1.5/OS X 10.7@
202 */
203
204int					/* O - Status of call (0 = success) */
205cupsSetCredentials(
206    cups_array_t *credentials)		/* I - Array of credentials */
207{
208  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
209
210
211  if (cupsArrayCount(credentials) < 1)
212    return (-1);
213
214  _httpFreeCredentials(cg->tls_credentials);
215  cg->tls_credentials = _httpCreateCredentials(credentials);
216
217  return (cg->tls_credentials ? 0 : -1);
218}
219
220
221/*
222 * 'cupsSetEncryption()' - Set the encryption preference.
223 *
224 * The default encryption setting comes from the CUPS_ENCRYPTION
225 * environment variable, then the ~/.cups/client.conf file, and finally the
226 * /etc/cups/client.conf file. If not set, the default is
227 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
228 *
229 * Note: The current encryption setting is tracked separately for each thread
230 * in a program. Multi-threaded programs that override the setting need to do
231 * so in each thread for the same setting to be used.
232 */
233
234void
235cupsSetEncryption(http_encryption_t e)	/* I - New encryption preference */
236{
237  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
238
239
240  cg->encryption = e;
241
242  if (cg->http)
243    httpEncryption(cg->http, e);
244}
245
246
247/*
248 * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
249 *
250 * Pass @code NULL@ to restore the default (console) password callback, which
251 * reads the password from the console. Programs should call either this
252 * function or @link cupsSetPasswordCB2@, as only one callback can be registered
253 * by a program per thread.
254 *
255 * Note: The current password callback is tracked separately for each thread
256 * in a program. Multi-threaded programs that override the callback need to do
257 * so in each thread for the same callback to be used.
258 */
259
260void
261cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
262{
263  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
264
265
266  if (cb == (cups_password_cb_t)0)
267    cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
268  else
269    cg->password_cb = (cups_password_cb2_t)cb;
270
271  cg->password_data = NULL;
272}
273
274
275/*
276 * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
277 *
278 * Pass @code NULL@ to restore the default (console) password callback, which
279 * reads the password from the console. Programs should call either this
280 * function or @link cupsSetPasswordCB2@, as only one callback can be registered
281 * by a program per thread.
282 *
283 * Note: The current password callback is tracked separately for each thread
284 * in a program. Multi-threaded programs that override the callback need to do
285 * so in each thread for the same callback to be used.
286 *
287 * @since CUPS 1.4/OS X 10.6@
288 */
289
290void
291cupsSetPasswordCB2(
292    cups_password_cb2_t cb,		/* I - Callback function */
293    void                *user_data)	/* I - User data pointer */
294{
295  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
296
297
298  if (cb == (cups_password_cb2_t)0)
299    cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
300  else
301    cg->password_cb = cb;
302
303  cg->password_data = user_data;
304}
305
306
307/*
308 * 'cupsSetServer()' - Set the default server name and port.
309 *
310 * The "server" string can be a fully-qualified hostname, a numeric
311 * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
312 * addresses can be optionally followed by a colon and port number to override
313 * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
314 * default server name and port.
315 *
316 * Note: The current server is tracked separately for each thread in a program.
317 * Multi-threaded programs that override the server need to do so in each
318 * thread for the same server to be used.
319 */
320
321void
322cupsSetServer(const char *server)	/* I - Server name */
323{
324  char		*options,		/* Options */
325		*port;			/* Pointer to port */
326  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
327
328
329  if (server)
330  {
331    strlcpy(cg->server, server, sizeof(cg->server));
332
333    if (cg->server[0] != '/' && (options = strrchr(cg->server, '/')) != NULL)
334    {
335      *options++ = '\0';
336
337      if (!strcmp(options, "version=1.0"))
338        cg->server_version = 10;
339      else if (!strcmp(options, "version=1.1"))
340        cg->server_version = 11;
341      else if (!strcmp(options, "version=2.0"))
342        cg->server_version = 20;
343      else if (!strcmp(options, "version=2.1"))
344        cg->server_version = 21;
345      else if (!strcmp(options, "version=2.2"))
346        cg->server_version = 22;
347    }
348    else
349      cg->server_version = 20;
350
351    if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
352        !strchr(port, ']') && isdigit(port[1] & 255))
353    {
354      *port++ = '\0';
355
356      cg->ipp_port = atoi(port);
357    }
358
359    if (cg->server[0] == '/')
360      strlcpy(cg->servername, "localhost", sizeof(cg->servername));
361    else
362      strlcpy(cg->servername, cg->server, sizeof(cg->servername));
363  }
364  else
365  {
366    cg->server[0]      = '\0';
367    cg->servername[0]  = '\0';
368    cg->server_version = 20;
369  }
370
371  if (cg->http)
372  {
373    httpClose(cg->http);
374    cg->http = NULL;
375  }
376}
377
378
379/*
380 * 'cupsSetServerCertCB()' - Set the server certificate callback.
381 *
382 * Pass @code NULL@ to restore the default callback.
383 *
384 * Note: The current credentials callback is tracked separately for each thread
385 * in a program. Multi-threaded programs that override the callback need to do
386 * so in each thread for the same callback to be used.
387 *
388 * @since CUPS 1.5/OS X 10.7@
389 */
390
391void
392cupsSetServerCertCB(
393    cups_server_cert_cb_t cb,		/* I - Callback function */
394    void		  *user_data)	/* I - User data pointer */
395{
396  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
397
398
399  cg->server_cert_cb	= cb;
400  cg->server_cert_data	= user_data;
401}
402
403
404/*
405 * 'cupsSetUser()' - Set the default user name.
406 *
407 * Pass @code NULL@ to restore the default user name.
408 *
409 * Note: The current user name is tracked separately for each thread in a
410 * program. Multi-threaded programs that override the user name need to do so
411 * in each thread for the same user name to be used.
412 */
413
414void
415cupsSetUser(const char *user)		/* I - User name */
416{
417  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
418
419
420  if (user)
421    strlcpy(cg->user, user, sizeof(cg->user));
422  else
423    cg->user[0] = '\0';
424}
425
426
427/*
428 * 'cupsSetUserAgent()' - Set the default HTTP User-Agent string.
429 *
430 * Setting the string to NULL forces the default value containing the CUPS
431 * version, IPP version, and operating system version and architecture.
432 *
433 * @since CUPS 1.7/OS X 10.9@
434 */
435
436void
437cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ */
438{
439  _cups_globals_t	*cg = _cupsGlobals();
440					/* Thread globals */
441#ifdef WIN32
442  SYSTEM_INFO		sysinfo;	/* System information */
443  OSVERSIONINFO		version;	/* OS version info */
444#else
445  struct utsname	name;		/* uname info */
446#endif /* WIN32 */
447
448
449  if (user_agent)
450  {
451    strlcpy(cg->user_agent, user_agent, sizeof(cg->user_agent));
452    return;
453  }
454
455#ifdef WIN32
456  version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
457  GetVersionEx(&version);
458  GetNativeSystemInfo(&sysinfo);
459
460  snprintf(cg->user_agent, sizeof(cg->user_agent),
461           CUPS_MINIMAL " (Windows %d.%d; %s) IPP/2.0",
462	   version.dwMajorVersion, version.dwMinorVersion,
463	   sysinfo.wProcessorArchitecture
464	       == PROCESSOR_ARCHITECTURE_AMD64 ? "amd64" :
465	       sysinfo.wProcessorArchitecture
466		   == PROCESSOR_ARCHITECTURE_ARM ? "arm" :
467	       sysinfo.wProcessorArchitecture
468		   == PROCESSOR_ARCHITECTURE_IA64 ? "ia64" :
469	       sysinfo.wProcessorArchitecture
470		   == PROCESSOR_ARCHITECTURE_INTEL ? "intel" :
471	       "unknown");
472
473#else
474  uname(&name);
475
476  snprintf(cg->user_agent, sizeof(cg->user_agent),
477           CUPS_MINIMAL " (%s %s; %s) IPP/2.0",
478	   name.sysname, name.release, name.machine);
479#endif /* WIN32 */
480}
481
482
483/*
484 * 'cupsUser()' - Return the current user's name.
485 *
486 * Note: The current user name is tracked separately for each thread in a
487 * program. Multi-threaded programs that override the user name with the
488 * @link cupsSetUser@ function need to do so in each thread for the same user
489 * name to be used.
490 */
491
492const char *				/* O - User name */
493cupsUser(void)
494{
495  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
496
497
498  if (!cg->user[0])
499    _cupsSetDefaults();
500
501  return (cg->user);
502}
503
504
505/*
506 * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
507 *
508 * @since CUPS 1.7/OS X 10.9@
509 */
510
511const char *				/* O - User-Agent string */
512cupsUserAgent(void)
513{
514  _cups_globals_t *cg = _cupsGlobals();	/* Thread globals */
515
516
517  if (!cg->user_agent[0])
518    cupsSetUserAgent(NULL);
519
520  return (cg->user_agent);
521}
522
523
524/*
525 * '_cupsGetPassword()' - Get a password from the user.
526 */
527
528const char *				/* O - Password or @code NULL@ if none */
529_cupsGetPassword(const char *prompt)	/* I - Prompt string */
530{
531#ifdef WIN32
532  HANDLE		tty;		/* Console handle */
533  DWORD			mode;		/* Console mode */
534  char			passch,		/* Current key press */
535			*passptr,	/* Pointer into password string */
536			*passend;	/* End of password string */
537  DWORD			passbytes;	/* Bytes read */
538  _cups_globals_t	*cg = _cupsGlobals();
539					/* Thread globals */
540
541
542 /*
543  * Disable input echo and set raw input...
544  */
545
546  if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
547    return (NULL);
548
549  if (!GetConsoleMode(tty, &mode))
550    return (NULL);
551
552  if (!SetConsoleMode(tty, 0))
553    return (NULL);
554
555 /*
556  * Display the prompt...
557  */
558
559  printf("%s ", prompt);
560  fflush(stdout);
561
562 /*
563  * Read the password string from /dev/tty until we get interrupted or get a
564  * carriage return or newline...
565  */
566
567  passptr = cg->password;
568  passend = cg->password + sizeof(cg->password) - 1;
569
570  while (ReadFile(tty, &passch, 1, &passbytes, NULL))
571  {
572    if (passch == 0x0A || passch == 0x0D)
573    {
574     /*
575      * Enter/return...
576      */
577
578      break;
579    }
580    else if (passch == 0x08 || passch == 0x7F)
581    {
582     /*
583      * Backspace/delete (erase character)...
584      */
585
586      if (passptr > cg->password)
587      {
588        passptr --;
589        fputs("\010 \010", stdout);
590      }
591      else
592        putchar(0x07);
593    }
594    else if (passch == 0x15)
595    {
596     /*
597      * CTRL+U (erase line)
598      */
599
600      if (passptr > cg->password)
601      {
602	while (passptr > cg->password)
603	{
604          passptr --;
605          fputs("\010 \010", stdout);
606        }
607      }
608      else
609        putchar(0x07);
610    }
611    else if (passch == 0x03)
612    {
613     /*
614      * CTRL+C...
615      */
616
617      passptr = cg->password;
618      break;
619    }
620    else if ((passch & 255) < 0x20 || passptr >= passend)
621      putchar(0x07);
622    else
623    {
624      *passptr++ = passch;
625      putchar(_CUPS_PASSCHAR);
626    }
627
628    fflush(stdout);
629  }
630
631  putchar('\n');
632  fflush(stdout);
633
634 /*
635  * Cleanup...
636  */
637
638  SetConsoleMode(tty, mode);
639
640 /*
641  * Return the proper value...
642  */
643
644  if (passbytes == 1 && passptr > cg->password)
645  {
646    *passptr = '\0';
647    return (cg->password);
648  }
649  else
650  {
651    memset(cg->password, 0, sizeof(cg->password));
652    return (NULL);
653  }
654
655#else
656  int			tty;		/* /dev/tty - never read from stdin */
657  struct termios	original,	/* Original input mode */
658			noecho;		/* No echo input mode */
659  char			passch,		/* Current key press */
660			*passptr,	/* Pointer into password string */
661			*passend;	/* End of password string */
662  ssize_t		passbytes;	/* Bytes read */
663  _cups_globals_t	*cg = _cupsGlobals();
664					/* Thread globals */
665
666
667 /*
668  * Disable input echo and set raw input...
669  */
670
671  if ((tty = open("/dev/tty", O_RDONLY)) < 0)
672    return (NULL);
673
674  if (tcgetattr(tty, &original))
675  {
676    close(tty);
677    return (NULL);
678  }
679
680  noecho = original;
681  noecho.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
682
683  if (tcsetattr(tty, TCSAFLUSH, &noecho))
684  {
685    close(tty);
686    return (NULL);
687  }
688
689 /*
690  * Display the prompt...
691  */
692
693  printf("%s ", prompt);
694  fflush(stdout);
695
696 /*
697  * Read the password string from /dev/tty until we get interrupted or get a
698  * carriage return or newline...
699  */
700
701  passptr = cg->password;
702  passend = cg->password + sizeof(cg->password) - 1;
703
704  while ((passbytes = read(tty, &passch, 1)) == 1)
705  {
706    if (passch == noecho.c_cc[VEOL] ||
707#  ifdef VEOL2
708        passch == noecho.c_cc[VEOL2] ||
709#  endif /* VEOL2 */
710        passch == 0x0A || passch == 0x0D)
711    {
712     /*
713      * Enter/return...
714      */
715
716      break;
717    }
718    else if (passch == noecho.c_cc[VERASE] ||
719             passch == 0x08 || passch == 0x7F)
720    {
721     /*
722      * Backspace/delete (erase character)...
723      */
724
725      if (passptr > cg->password)
726      {
727        passptr --;
728        fputs("\010 \010", stdout);
729      }
730      else
731        putchar(0x07);
732    }
733    else if (passch == noecho.c_cc[VKILL])
734    {
735     /*
736      * CTRL+U (erase line)
737      */
738
739      if (passptr > cg->password)
740      {
741	while (passptr > cg->password)
742	{
743          passptr --;
744          fputs("\010 \010", stdout);
745        }
746      }
747      else
748        putchar(0x07);
749    }
750    else if (passch == noecho.c_cc[VINTR] || passch == noecho.c_cc[VQUIT] ||
751             passch == noecho.c_cc[VEOF])
752    {
753     /*
754      * CTRL+C, CTRL+D, or CTRL+Z...
755      */
756
757      passptr = cg->password;
758      break;
759    }
760    else if ((passch & 255) < 0x20 || passptr >= passend)
761      putchar(0x07);
762    else
763    {
764      *passptr++ = passch;
765      putchar(_CUPS_PASSCHAR);
766    }
767
768    fflush(stdout);
769  }
770
771  putchar('\n');
772  fflush(stdout);
773
774 /*
775  * Cleanup...
776  */
777
778  tcsetattr(tty, TCSAFLUSH, &original);
779  close(tty);
780
781 /*
782  * Return the proper value...
783  */
784
785  if (passbytes == 1 && passptr > cg->password)
786  {
787    *passptr = '\0';
788    return (cg->password);
789  }
790  else
791  {
792    memset(cg->password, 0, sizeof(cg->password));
793    return (NULL);
794  }
795#endif /* WIN32 */
796}
797
798
799#ifdef HAVE_GSSAPI
800/*
801 * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
802 */
803
804const char *
805_cupsGSSServiceName(void)
806{
807  _cups_globals_t *cg = _cupsGlobals();	/* Thread globals */
808
809
810  if (!cg->gss_service_name[0])
811    _cupsSetDefaults();
812
813  return (cg->gss_service_name);
814}
815#endif /* HAVE_GSSAPI */
816
817
818/*
819 * '_cupsSetDefaults()' - Set the default server, port, and encryption.
820 */
821
822void
823_cupsSetDefaults(void)
824{
825  cups_file_t	*fp;			/* File */
826  const char	*home,			/* Home directory of user */
827		*cups_encryption,	/* CUPS_ENCRYPTION env var */
828		*cups_server,		/* CUPS_SERVER env var */
829		*cups_user,		/* CUPS_USER/USER env var */
830#ifdef HAVE_GSSAPI
831		*cups_gssservicename,	/* CUPS_GSSSERVICENAME env var */
832#endif /* HAVE_GSSAPI */
833		*cups_anyroot,		/* CUPS_ANYROOT env var */
834		*cups_expiredroot,	/* CUPS_EXPIREDROOT env var */
835		*cups_expiredcerts;	/* CUPS_EXPIREDCERTS env var */
836  char		filename[1024];		/* Filename */
837  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
838
839
840  DEBUG_puts("_cupsSetDefaults()");
841
842 /*
843  * First collect environment variables...
844  */
845
846  cups_encryption     = getenv("CUPS_ENCRYPTION");
847  cups_server	      = getenv("CUPS_SERVER");
848#ifdef HAVE_GSSAPI
849  cups_gssservicename = getenv("CUPS_GSSSERVICENAME");
850#endif /* HAVE_GSSAPI */
851  cups_anyroot	      = getenv("CUPS_ANYROOT");
852  cups_expiredroot    = getenv("CUPS_EXPIREDROOT");
853  cups_expiredcerts   = getenv("CUPS_EXPIREDCERTS");
854
855  if ((cups_user = getenv("CUPS_USER")) == NULL)
856  {
857#ifndef WIN32
858   /*
859    * Try the USER environment variable...
860    */
861
862    if ((cups_user = getenv("USER")) != NULL)
863    {
864     /*
865      * Validate USER matches the current UID, otherwise don't allow it to
866      * override things...  This makes sure that printing after doing su or
867      * sudo records the correct username.
868      */
869
870      struct passwd	*pw;		/* Account information */
871
872      if ((pw = getpwnam(cups_user)) == NULL || pw->pw_uid != getuid())
873        cups_user = NULL;
874    }
875#endif /* !WIN32 */
876  }
877
878 /*
879  * Then, if needed, read the ~/.cups/client.conf or /etc/cups/client.conf
880  * files to get the default values...
881  */
882
883  if (cg->encryption == (http_encryption_t)-1 || !cg->server[0] ||
884      !cg->user[0] || !cg->ipp_port)
885  {
886#  ifdef HAVE_GETEUID
887    if ((geteuid() == getuid() || !getuid()) && getegid() == getgid() && (home = getenv("HOME")) != NULL)
888#  elif !defined(WIN32)
889    if (getuid() && (home = getenv("HOME")) != NULL)
890#  else
891    if ((home = getenv("HOME")) != NULL)
892#  endif /* HAVE_GETEUID */
893    {
894     /*
895      * Look for ~/.cups/client.conf...
896      */
897
898      snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
899      fp = cupsFileOpen(filename, "r");
900    }
901    else
902      fp = NULL;
903
904    if (!fp)
905    {
906     /*
907      * Look for CUPS_SERVERROOT/client.conf...
908      */
909
910      snprintf(filename, sizeof(filename), "%s/client.conf",
911               cg->cups_serverroot);
912      fp = cupsFileOpen(filename, "r");
913    }
914
915   /*
916    * Read the configuration file and apply any environment variables; both
917    * functions handle NULL cups_file_t pointers...
918    */
919
920    cups_read_client_conf(fp, cg, cups_encryption, cups_server, cups_user,
921#ifdef HAVE_GSSAPI
922			  cups_gssservicename,
923#endif /* HAVE_GSSAPI */
924			  cups_anyroot, cups_expiredroot,
925			  cups_expiredcerts);
926    cupsFileClose(fp);
927  }
928}
929
930
931/*
932 * 'cups_read_client_conf()' - Read a client.conf file.
933 */
934
935static void
936cups_read_client_conf(
937    cups_file_t     *fp,		/* I - File to read */
938    _cups_globals_t *cg,		/* I - Global data */
939    const char      *cups_encryption,	/* I - CUPS_ENCRYPTION env var */
940    const char      *cups_server,	/* I - CUPS_SERVER env var */
941    const char      *cups_user,		/* I - CUPS_USER env var */
942#ifdef HAVE_GSSAPI
943    const char      *cups_gssservicename,
944					/* I - CUPS_GSSSERVICENAME env var */
945#endif /* HAVE_GSSAPI */
946    const char	    *cups_anyroot,	/* I - CUPS_ANYROOT env var */
947    const char	    *cups_expiredroot,	/* I - CUPS_EXPIREDROOT env var */
948    const char	    *cups_expiredcerts)	/* I - CUPS_EXPIREDCERTS env var */
949{
950  int	linenum;			/* Current line number */
951  char	line[1024],			/* Line from file */
952        *value,				/* Pointer into line */
953	encryption[1024],		/* Encryption value */
954#ifndef __APPLE__
955	server_name[1024],		/* ServerName value */
956#endif /* !__APPLE__ */
957	user[256],			/* User value */
958	any_root[1024],			/* AllowAnyRoot value */
959	expired_root[1024],		/* AllowExpiredRoot value */
960	expired_certs[1024];		/* AllowExpiredCerts value */
961#ifdef HAVE_GSSAPI
962  char	gss_service_name[32];		/* GSSServiceName value */
963#endif /* HAVE_GSSAPI */
964
965
966 /*
967  * Read from the file...
968  */
969
970  linenum = 0;
971  while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
972  {
973    if (!cups_encryption && cg->encryption == (http_encryption_t)-1 &&
974        !_cups_strcasecmp(line, "Encryption") && value)
975    {
976      strlcpy(encryption, value, sizeof(encryption));
977      cups_encryption = encryption;
978    }
979#ifndef __APPLE__
980   /*
981    * The Server directive is not supported on OS X due to app sandboxing
982    * restrictions, i.e. not all apps request network access.
983    */
984    else if (!cups_server && (!cg->server[0] || !cg->ipp_port) &&
985             !_cups_strcasecmp(line, "ServerName") && value)
986    {
987      strlcpy(server_name, value, sizeof(server_name));
988      cups_server = server_name;
989    }
990#endif /* !__APPLE__ */
991    else if (!cups_user && !_cups_strcasecmp(line, "User") && value)
992    {
993      strlcpy(user, value, sizeof(user));
994      cups_user = user;
995    }
996    else if (!cups_anyroot && !_cups_strcasecmp(line, "AllowAnyRoot") && value)
997    {
998      strlcpy(any_root, value, sizeof(any_root));
999      cups_anyroot = any_root;
1000    }
1001    else if (!cups_expiredroot && !_cups_strcasecmp(line, "AllowExpiredRoot") &&
1002             value)
1003    {
1004      strlcpy(expired_root, value, sizeof(expired_root));
1005      cups_expiredroot = expired_root;
1006    }
1007    else if (!cups_expiredcerts && !_cups_strcasecmp(line, "AllowExpiredCerts") &&
1008             value)
1009    {
1010      strlcpy(expired_certs, value, sizeof(expired_certs));
1011      cups_expiredcerts = expired_certs;
1012    }
1013#ifdef HAVE_GSSAPI
1014    else if (!cups_gssservicename && !_cups_strcasecmp(line, "GSSServiceName") &&
1015             value)
1016    {
1017      strlcpy(gss_service_name, value, sizeof(gss_service_name));
1018      cups_gssservicename = gss_service_name;
1019    }
1020#endif /* HAVE_GSSAPI */
1021  }
1022
1023 /*
1024  * Set values...
1025  */
1026
1027  if (cg->encryption == (http_encryption_t)-1 && cups_encryption)
1028  {
1029    if (!_cups_strcasecmp(cups_encryption, "never"))
1030      cg->encryption = HTTP_ENCRYPTION_NEVER;
1031    else if (!_cups_strcasecmp(cups_encryption, "always"))
1032      cg->encryption = HTTP_ENCRYPTION_ALWAYS;
1033    else if (!_cups_strcasecmp(cups_encryption, "required"))
1034      cg->encryption = HTTP_ENCRYPTION_REQUIRED;
1035    else
1036      cg->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1037  }
1038
1039  if ((!cg->server[0] || !cg->ipp_port) && cups_server)
1040    cupsSetServer(cups_server);
1041
1042  if (!cg->server[0])
1043  {
1044#ifdef CUPS_DEFAULT_DOMAINSOCKET
1045   /*
1046    * If we are compiled with domain socket support, only use the
1047    * domain socket if it exists and has the right permissions...
1048    */
1049
1050    struct stat	sockinfo;		/* Domain socket information */
1051
1052    if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
1053	(sockinfo.st_mode & S_IRWXO) == S_IRWXO)
1054      cups_server = CUPS_DEFAULT_DOMAINSOCKET;
1055    else
1056#endif /* CUPS_DEFAULT_DOMAINSOCKET */
1057      cups_server = "localhost";
1058
1059    cupsSetServer(cups_server);
1060  }
1061
1062  if (!cg->ipp_port)
1063  {
1064    const char	*ipp_port;		/* IPP_PORT environment variable */
1065
1066    if ((ipp_port = getenv("IPP_PORT")) != NULL)
1067    {
1068      if ((cg->ipp_port = atoi(ipp_port)) <= 0)
1069        cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1070    }
1071    else
1072      cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1073  }
1074
1075  if (!cg->user[0])
1076  {
1077    if (cups_user)
1078      strlcpy(cg->user, cups_user, sizeof(cg->user));
1079    else
1080    {
1081#ifdef WIN32
1082     /*
1083      * Get the current user name from the OS...
1084      */
1085
1086      DWORD	size;			/* Size of string */
1087
1088      size = sizeof(cg->user);
1089      if (!GetUserName(cg->user, &size))
1090#else
1091     /*
1092      * Get the user name corresponding to the current UID...
1093      */
1094
1095      struct passwd	*pwd;		/* User/password entry */
1096
1097      setpwent();
1098      if ((pwd = getpwuid(getuid())) != NULL)
1099      {
1100       /*
1101	* Found a match!
1102	*/
1103
1104	strlcpy(cg->user, pwd->pw_name, sizeof(cg->user));
1105      }
1106      else
1107#endif /* WIN32 */
1108      {
1109       /*
1110	* Use the default "unknown" user name...
1111	*/
1112
1113	strlcpy(cg->user, "unknown", sizeof(cg->user));
1114      }
1115    }
1116  }
1117
1118#ifdef HAVE_GSSAPI
1119  if (!cups_gssservicename)
1120    cups_gssservicename = CUPS_DEFAULT_GSSSERVICENAME;
1121
1122  strlcpy(cg->gss_service_name, cups_gssservicename,
1123	  sizeof(cg->gss_service_name));
1124#endif /* HAVE_GSSAPI */
1125
1126  if (cups_anyroot)
1127    cg->any_root = !_cups_strcasecmp(cups_anyroot, "yes") ||
1128		   !_cups_strcasecmp(cups_anyroot, "on")  ||
1129		   !_cups_strcasecmp(cups_anyroot, "true");
1130
1131  if (cups_expiredroot)
1132    cg->expired_root  = !_cups_strcasecmp(cups_expiredroot, "yes") ||
1133			!_cups_strcasecmp(cups_expiredroot, "on")  ||
1134			!_cups_strcasecmp(cups_expiredroot, "true");
1135
1136  if (cups_expiredcerts)
1137    cg->expired_certs = !_cups_strcasecmp(cups_expiredcerts, "yes") ||
1138			!_cups_strcasecmp(cups_expiredcerts, "on")  ||
1139			!_cups_strcasecmp(cups_expiredcerts, "true");
1140}
1141
1142
1143/*
1144 * End of "$Id: usersys.c 11693 2014-03-11 01:24:45Z msweet $".
1145 */
1146