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