]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/auth.c
Merge changes from CUPS 1.6svn-r10112.
[thirdparty/cups.git] / cups / auth.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: auth.c 7720 2008-07-11 22:46:21Z mike $"
ef416fc2 3 *
71e16022 4 * Authentication functions for CUPS.
ef416fc2 5 *
f14324a7 6 * Copyright 2007-2011 by Apple Inc.
b86bc4cf 7 * Copyright 1997-2007 by Easy Software Products.
ef416fc2 8 *
f7deaa1a 9 * This file contains Kerberos support code, copyright 2006 by
10 * Jelmer Vernooij.
11 *
ef416fc2 12 * These coded instructions, statements, and computer programs are the
bc44d920 13 * property of Apple Inc. and are protected by Federal copyright
14 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
15 * which should have been included with this file. If this file is
16 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 17 *
18 * This file is subject to the Apple OS-Developed Software exception.
19 *
20 * Contents:
21 *
eac3a0a0
MS
22 * cupsDoAuthentication() - Authenticate a request.
23 * _cupsSetNegotiateAuthString() - Set the Kerberos authentication string.
24 * cups_gss_acquire() - Kerberos credentials callback.
25 * cups_gss_getname() - Get CUPS service credentials for
26 * authentication.
27 * cups_gss_printf() - Show debug error messages from GSSAPI.
28 * cups_local_auth() - Get the local authorization certificate if
29 * available/applicable.
ef416fc2 30 */
31
32/*
33 * Include necessary headers...
34 */
35
71e16022 36#include "cups-private.h"
ef416fc2 37#include <fcntl.h>
38#include <sys/stat.h>
39#if defined(WIN32) || defined(__EMX__)
40# include <io.h>
41#else
42# include <unistd.h>
43#endif /* WIN32 || __EMX__ */
44
f7deaa1a 45#if HAVE_AUTHORIZATION_H
46# include <Security/Authorization.h>
47# ifdef HAVE_SECBASEPRIV_H
48# include <Security/SecBasePriv.h>
49# else
50extern const char *cssmErrorString(int error);
51# endif /* HAVE_SECBASEPRIV_H */
52#endif /* HAVE_AUTHORIZATION_H */
53
bc44d920 54#if defined(SO_PEERCRED) && defined(AF_LOCAL)
55# include <pwd.h>
56#endif /* SO_PEERCRED && AF_LOCAL */
57
ef416fc2 58
59/*
60 * Local functions...
61 */
62
f7deaa1a 63#ifdef HAVE_GSSAPI
eac3a0a0
MS
64# ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
65# ifdef HAVE_GSS_GSSAPI_SPI_H
66# include <GSS/gssapi_spi.h>
67# else
a2326b5b
MS
68# define GSS_AUTH_IDENTITY_TYPE_1 1
69# define gss_acquire_cred_ex_f __ApplePrivate_gss_acquire_cred_ex_f
eac3a0a0
MS
70typedef struct gss_auth_identity
71{
72 uint32_t type;
73 uint32_t flags;
74 char *username;
75 char *realm;
76 char *password;
77 gss_buffer_t *credentialsRef;
78} gss_auth_identity_desc;
79extern OM_uint32 gss_acquire_cred_ex_f(gss_status_id_t, const gss_name_t,
80 OM_uint32, OM_uint32, const gss_OID,
81 gss_cred_usage_t, gss_auth_identity_t,
82 void *, void (*)(void *, OM_uint32,
83 gss_status_id_t,
84 gss_cred_id_t,
85 gss_OID_set,
86 OM_uint32));
87# endif /* HAVE_GSS_GSSAPI_SPI_H */
88# include <dispatch/dispatch.h>
89typedef struct _cups_gss_acquire_s /* Acquire callback data */
90{
91 dispatch_semaphore_t sem; /* Synchronization semaphore */
92 OM_uint32 major; /* Returned status code */
93 gss_cred_id_t creds; /* Returned credentials */
94} _cups_gss_acquire_t;
95
96static void cups_gss_acquire(void *ctx, OM_uint32 major,
97 gss_status_id_t status,
98 gss_cred_id_t creds, gss_OID_set oids,
99 OM_uint32 time_rec);
100# endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */
101static gss_name_t cups_gss_getname(http_t *http, const char *service_name);
f7deaa1a 102# ifdef DEBUG
e07d4801
MS
103static void cups_gss_printf(OM_uint32 major_status, OM_uint32 minor_status,
104 const char *message);
355e94dc 105# else
e07d4801
MS
106# define cups_gss_printf(major, minor, message)
107# endif /* DEBUG */
f7deaa1a 108#endif /* HAVE_GSSAPI */
ef416fc2 109static int cups_local_auth(http_t *http);
110
111
112/*
113 * 'cupsDoAuthentication()' - Authenticate a request.
114 *
5a738aea 115 * This function should be called in response to a @code HTTP_UNAUTHORIZED@
ef416fc2 116 * status, prior to resubmitting your request.
117 *
426c6a59 118 * @since CUPS 1.1.20/Mac OS X 10.4@
ef416fc2 119 */
120
121int /* O - 0 on success, -1 on error */
f11a948a
MS
122cupsDoAuthentication(
123 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
124 const char *method, /* I - Request method ("GET", "POST", "PUT") */
125 const char *resource) /* I - Resource path */
ef416fc2 126{
127 const char *password; /* Password string */
128 char prompt[1024], /* Prompt for user */
129 realm[HTTP_MAX_VALUE], /* realm="xyz" string */
5a738aea 130 nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */
f7deaa1a 131 int localauth; /* Local authentication result */
b86bc4cf 132 _cups_globals_t *cg; /* Global data */
ef416fc2 133
134
e07d4801 135 DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")",
ef416fc2 136 http, method, resource));
ef416fc2 137
f11a948a
MS
138 if (!http)
139 http = _cupsConnect();
140
141 if (!http || !method || !resource)
142 return (-1);
143
5a6b583a
MS
144 DEBUG_printf(("2cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"",
145 http->digest_tries, http->userpass));
146 DEBUG_printf(("2cupsDoAuthentication: WWW-Authenticate=\"%s\"",
147 httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE)));
148
ef416fc2 149 /*
150 * Clear the current authentication string...
151 */
152
355e94dc 153 httpSetAuthString(http, NULL, NULL);
ef416fc2 154
155 /*
156 * See if we can do local authentication...
157 */
158
f7deaa1a 159 if (http->digest_tries < 3)
ef416fc2 160 {
f7deaa1a 161 if ((localauth = cups_local_auth(http)) == 0)
162 {
e07d4801 163 DEBUG_printf(("2cupsDoAuthentication: authstring=\"%s\"",
f7deaa1a 164 http->authstring));
f14324a7 165
f7deaa1a 166 if (http->status == HTTP_UNAUTHORIZED)
167 http->digest_tries ++;
f14324a7 168
f7deaa1a 169 return (0);
170 }
171 else if (localauth == -1)
f11a948a
MS
172 {
173 http->status = HTTP_AUTHORIZATION_CANCELED;
f7deaa1a 174 return (-1); /* Error or canceled */
f11a948a 175 }
ef416fc2 176 }
177
178 /*
179 * Nope, see if we should retry the current username:password...
180 */
181
f7deaa1a 182 if ((http->digest_tries > 1 || !http->userpass[0]) &&
f14324a7
MS
183 (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) ||
184 !strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6)))
ef416fc2 185 {
186 /*
187 * Nope - get a new password from the user...
188 */
189
b86bc4cf 190 cg = _cupsGlobals();
191
192 if (!cg->lang_default)
193 cg->lang_default = cupsLangDefault();
194
195 snprintf(prompt, sizeof(prompt),
196 _cupsLangString(cg->lang_default, _("Password for %s on %s? ")),
197 cupsUser(),
198 http->hostname[0] == '/' ? "localhost" : http->hostname);
ef416fc2 199
88f9aafc 200 http->digest_tries = _cups_strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE],
ef416fc2 201 "Digest", 5) != 0;
202 http->userpass[0] = '\0';
203
f11a948a
MS
204 if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
205 {
206 http->status = HTTP_AUTHORIZATION_CANCELED;
ef416fc2 207 return (-1);
f11a948a 208 }
ef416fc2 209
ef416fc2 210 snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(),
211 password);
212 }
213 else if (http->status == HTTP_UNAUTHORIZED)
214 http->digest_tries ++;
215
5a6b583a
MS
216 if (http->status == HTTP_UNAUTHORIZED && http->digest_tries >= 3)
217 {
218 DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)",
219 http->digest_tries));
220
221 http->status = HTTP_AUTHORIZATION_CANCELED;
222 return (-1);
223 }
224
ef416fc2 225 /*
226 * Got a password; encode it for the server...
227 */
228
f14324a7 229#ifdef HAVE_GSSAPI
f7deaa1a 230 if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9))
231 {
f7deaa1a 232 /*
233 * Kerberos authentication...
234 */
235
eac3a0a0 236 if (_cupsSetNegotiateAuthString(http, method, resource))
f7deaa1a 237 {
f11a948a 238 http->status = HTTP_AUTHORIZATION_CANCELED;
f7deaa1a 239 return (-1);
240 }
f7deaa1a 241 }
f14324a7
MS
242 else
243#endif /* HAVE_GSSAPI */
244 if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5))
ef416fc2 245 {
246 /*
247 * Basic authentication...
248 */
249
5a738aea
MS
250 char encode[256]; /* Base64 buffer */
251
252
ef416fc2 253 httpEncode64_2(encode, sizeof(encode), http->userpass,
b86bc4cf 254 (int)strlen(http->userpass));
355e94dc 255 httpSetAuthString(http, "Basic", encode);
ef416fc2 256 }
f14324a7 257 else if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6))
ef416fc2 258 {
259 /*
260 * Digest authentication...
261 */
262
5a738aea
MS
263 char encode[33], /* MD5 buffer */
264 digest[1024]; /* Digest auth data */
355e94dc
MS
265
266
ef416fc2 267 httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm);
268 httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce);
269
270 httpMD5(cupsUser(), realm, strchr(http->userpass, ':') + 1, encode);
271 httpMD5Final(nonce, method, resource, encode);
355e94dc
MS
272 snprintf(digest, sizeof(digest),
273 "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
274 "response=\"%s\"", cupsUser(), realm, nonce, resource, encode);
275 httpSetAuthString(http, "Digest", digest);
ef416fc2 276 }
f14324a7
MS
277 else
278 {
279 DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"",
280 http->fields[HTTP_FIELD_WWW_AUTHENTICATE]));
281 http->status = HTTP_AUTHORIZATION_CANCELED;
282 return (-1);
283 }
ef416fc2 284
e07d4801 285 DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring));
ef416fc2 286
287 return (0);
288}
289
290
f7deaa1a 291#ifdef HAVE_GSSAPI
f14324a7
MS
292/*
293 * '_cupsSetNegotiateAuthString()' - Set the Kerberos authentication string.
294 */
295
296int /* O - 0 on success, -1 on error */
297_cupsSetNegotiateAuthString(
eac3a0a0
MS
298 http_t *http, /* I - Connection to server */
299 const char *method, /* I - Request method ("GET", "POST", "PUT") */
300 const char *resource) /* I - Resource path */
f14324a7
MS
301{
302 OM_uint32 minor_status, /* Minor status code */
303 major_status; /* Major status code */
304 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
07ed0e9a 305 /* Output token */
f14324a7
MS
306
307
321d8d57
MS
308 (void)method;
309 (void)resource;
310
f14324a7
MS
311# ifdef __APPLE__
312 /*
313 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
314 * to use it...
315 */
316
317 if (gss_init_sec_context == NULL)
318 {
319 DEBUG_puts("1_cupsSetNegotiateAuthString: Weak-linked GSSAPI/Kerberos "
320 "framework is not present");
321 return (-1);
322 }
323# endif /* __APPLE__ */
324
325 if (http->gssname == GSS_C_NO_NAME)
326 {
eac3a0a0 327 http->gssname = cups_gss_getname(http, _cupsGSSServiceName());
f14324a7
MS
328 }
329
330 if (http->gssctx != GSS_C_NO_CONTEXT)
331 {
332 gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER);
333 http->gssctx = GSS_C_NO_CONTEXT;
334 }
335
eac3a0a0
MS
336 major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL,
337 &http->gssctx,
338 http->gssname, http->gssmech,
339 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG,
340 GSS_C_INDEFINITE,
341 GSS_C_NO_CHANNEL_BINDINGS,
342 GSS_C_NO_BUFFER, &http->gssmech,
343 &output_token, NULL, NULL);
344
345#ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
346 if (major_status == GSS_S_NO_CRED)
347 {
348 /*
349 * Ask the user for credentials...
350 */
351
352 char prompt[1024], /* Prompt for user */
353 userbuf[256]; /* Kerberos username */
354 const char *username, /* Username string */
355 *password; /* Password string */
356 _cups_gss_acquire_t data; /* Callback data */
357 gss_auth_identity_desc identity; /* Kerberos user identity */
358 _cups_globals_t *cg = _cupsGlobals();
359 /* Per-thread global data */
360
361 if (!cg->lang_default)
362 cg->lang_default = cupsLangDefault();
363
364 snprintf(prompt, sizeof(prompt),
365 _cupsLangString(cg->lang_default, _("Password for %s on %s? ")),
f228370c 366 cupsUser(), http->gsshost);
eac3a0a0
MS
367
368 if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
369 return (-1);
370
371 /*
372 * Try to acquire credentials...
373 */
374
375 username = cupsUser();
376 if (!strchr(username, '@'))
377 {
f228370c 378 snprintf(userbuf, sizeof(userbuf), "%s@%s", username, http->gsshost);
eac3a0a0
MS
379 username = userbuf;
380 }
381
382 identity.type = GSS_AUTH_IDENTITY_TYPE_1;
383 identity.flags = 0;
384 identity.username = (char *)username;
385 identity.realm = (char *)"";
386 identity.password = (char *)password;
387 identity.credentialsRef = NULL;
388
389 data.sem = dispatch_semaphore_create(0);
390 data.major = 0;
391 data.creds = NULL;
392
393 if (data.sem)
394 {
395 major_status = gss_acquire_cred_ex_f(NULL, GSS_C_NO_NAME, 0,
396 GSS_C_INDEFINITE, GSS_KRB5_MECHANISM,
397 GSS_C_INITIATE, &identity, &data,
398 cups_gss_acquire);
399
400 if (major_status == GSS_S_COMPLETE)
401 {
402 dispatch_semaphore_wait(data.sem, DISPATCH_TIME_FOREVER);
403 major_status = data.major;
404 }
405
406 dispatch_release(data.sem);
407
408 if (major_status == GSS_S_COMPLETE)
409 {
410 OM_uint32 release_minor; /* Minor status from releasing creds */
411
412 major_status = gss_init_sec_context(&minor_status, data.creds,
413 &http->gssctx,
414 http->gssname, http->gssmech,
415 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG,
416 GSS_C_INDEFINITE,
417 GSS_C_NO_CHANNEL_BINDINGS,
418 GSS_C_NO_BUFFER, &http->gssmech,
419 &output_token, NULL, NULL);
420 gss_release_cred(&release_minor, &data.creds);
421 }
422 }
423 }
eac3a0a0 424#endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */
f14324a7
MS
425
426 if (GSS_ERROR(major_status))
427 {
428 cups_gss_printf(major_status, minor_status,
429 "_cupsSetNegotiateAuthString: Unable to initialize "
430 "security context");
431 return (-1);
432 }
433
22c9029b 434#ifdef DEBUG
eac3a0a0 435 else if (major_status == GSS_S_CONTINUE_NEEDED)
f14324a7
MS
436 cups_gss_printf(major_status, minor_status,
437 "_cupsSetNegotiateAuthString: Continuation needed!");
22c9029b 438#endif /* DEBUG */
f14324a7
MS
439
440 if (output_token.length > 0 && output_token.length <= 65536)
441 {
442 /*
443 * Allocate the authorization string since Windows KDCs can have
444 * arbitrarily large credentials...
445 */
446
447 int authsize = 10 + /* "Negotiate " */
448 output_token.length * 4 / 3 + 1 + /* Base64 */
449 1; /* nul */
450
451 httpSetAuthString(http, NULL, NULL);
452
453 if ((http->authstring = malloc(authsize)) == NULL)
454 {
455 http->authstring = http->_authstring;
456 authsize = sizeof(http->_authstring);
457 }
458
459 strcpy(http->authstring, "Negotiate ");
460 httpEncode64_2(http->authstring + 10, authsize - 10, output_token.value,
461 output_token.length);
462
463 gss_release_buffer(&minor_status, &output_token);
464 }
465 else
466 {
467 DEBUG_printf(("1_cupsSetNegotiateAuthString: Kerberos credentials too "
468 "large - %d bytes!", (int)output_token.length));
469 gss_release_buffer(&minor_status, &output_token);
470
471 return (-1);
472 }
473
474 return (0);
475}
476
477
eac3a0a0 478# ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
f7deaa1a 479/*
eac3a0a0
MS
480 * 'cups_gss_acquire()' - Kerberos credentials callback.
481 */
482static void
483cups_gss_acquire(
484 void *ctx, /* I - Caller context */
485 OM_uint32 major, /* I - Major error code */
486 gss_status_id_t status, /* I - Status (unused) */
487 gss_cred_id_t creds, /* I - Credentials (if any) */
488 gss_OID_set oids, /* I - Mechanism OIDs (unused) */
489 OM_uint32 time_rec) /* I - Timestamp (unused) */
490{
491 uint32_t min; /* Minor error code */
492 _cups_gss_acquire_t *data; /* Callback data */
493
494
495 (void)status;
496 (void)time_rec;
497
498 data = (_cups_gss_acquire_t *)ctx;
499 data->major = major;
500 data->creds = creds;
501
502 gss_release_oid_set(&min, &oids);
503 dispatch_semaphore_signal(data->sem);
504}
505# endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */
506
507
508/*
509 * 'cups_gss_getname()' - Get CUPS service credentials for authentication.
f7deaa1a 510 */
511
512static gss_name_t /* O - Server name */
eac3a0a0 513cups_gss_getname(
f7deaa1a 514 http_t *http, /* I - Connection to server */
515 const char *service_name) /* I - Service name */
516{
517 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
518 /* Service token */
bc44d920 519 OM_uint32 major_status, /* Major status code */
520 minor_status; /* Minor status code */
521 gss_name_t server_name; /* Server name */
eac3a0a0 522 char buf[1024]; /* Name buffer */
bc44d920 523
524
eac3a0a0 525 DEBUG_printf(("7cups_gss_getname(http=%p, service_name=\"%s\")", http,
e07d4801
MS
526 service_name));
527
528
bc44d920 529 /*
530 * Get the hostname...
531 */
f7deaa1a 532
eac3a0a0
MS
533 if (!http->gsshost[0])
534 {
535 httpGetHostname(http, http->gsshost, sizeof(http->gsshost));
bc44d920 536
eac3a0a0
MS
537 if (!strcmp(http->gsshost, "localhost"))
538 {
539 if (gethostname(http->gsshost, sizeof(http->gsshost)) < 0)
540 {
541 DEBUG_printf(("1cups_gss_getname: gethostname() failed: %s",
542 strerror(errno)));
543 http->gsshost[0] = '\0';
544 return (NULL);
545 }
546
547 if (!strchr(http->gsshost, '.'))
548 {
549 /*
550 * The hostname is not a FQDN, so look it up...
551 */
552
553 struct hostent *host; /* Host entry to get FQDN */
554
555 if ((host = gethostbyname(http->gsshost)) != NULL && host->h_name)
556 {
557 /*
558 * Use the resolved hostname...
559 */
560
561 strlcpy(http->gsshost, host->h_name, sizeof(http->gsshost));
562 }
563 else
564 {
565 DEBUG_printf(("1cups_gss_getname: gethostbyname(\"%s\") failed.",
566 http->gsshost));
567 http->gsshost[0] = '\0';
568 return (NULL);
569 }
570 }
571 }
572 }
f7deaa1a 573
574 /*
eac3a0a0 575 * Get a service name we can use for authentication purposes...
f7deaa1a 576 */
577
eac3a0a0 578 snprintf(buf, sizeof(buf), "%s@%s", service_name, http->gsshost);
f7deaa1a 579
eac3a0a0 580 DEBUG_printf(("8cups_gss_getname: Looking up \"%s\".", buf));
7ff4fea9 581
f7deaa1a 582 token.value = buf;
583 token.length = strlen(buf);
584 server_name = GSS_C_NO_NAME;
585 major_status = gss_import_name(&minor_status, &token,
586 GSS_C_NT_HOSTBASED_SERVICE,
587 &server_name);
588
589 if (GSS_ERROR(major_status))
590 {
e07d4801 591 cups_gss_printf(major_status, minor_status,
eac3a0a0 592 "cups_gss_getname: gss_import_name() failed");
f7deaa1a 593 return (NULL);
594 }
595
596 return (server_name);
597}
e07d4801
MS
598
599
600# ifdef DEBUG
601/*
eac3a0a0 602 * 'cups_gss_printf()' - Show debug error messages from GSSAPI.
e07d4801
MS
603 */
604
605static void
606cups_gss_printf(OM_uint32 major_status,/* I - Major status code */
607 OM_uint32 minor_status,/* I - Minor status code */
608 const char *message) /* I - Prefix for error message */
609{
610 OM_uint32 err_major_status, /* Major status code for display */
611 err_minor_status; /* Minor status code for display */
612 OM_uint32 msg_ctx; /* Message context */
613 gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER,
614 /* Major status message */
615 minor_status_string = GSS_C_EMPTY_BUFFER;
616 /* Minor status message */
617
618
619 msg_ctx = 0;
620 err_major_status = gss_display_status(&err_minor_status,
621 major_status,
622 GSS_C_GSS_CODE,
623 GSS_C_NO_OID,
624 &msg_ctx,
625 &major_status_string);
626
627 if (!GSS_ERROR(err_major_status))
628 gss_display_status(&err_minor_status, minor_status, GSS_C_MECH_CODE,
629 GSS_C_NULL_OID, &msg_ctx, &minor_status_string);
630
68b10830 631 DEBUG_printf(("1%s: %s, %s", message, (char *)major_status_string.value,
e07d4801
MS
632 (char *)minor_status_string.value));
633
634 gss_release_buffer(&err_minor_status, &major_status_string);
635 gss_release_buffer(&err_minor_status, &minor_status_string);
636}
637# endif /* DEBUG */
f7deaa1a 638#endif /* HAVE_GSSAPI */
639
640
ef416fc2 641/*
642 * 'cups_local_auth()' - Get the local authorization certificate if
eac3a0a0 643 * available/applicable.
ef416fc2 644 */
645
f7deaa1a 646static int /* O - 0 if available */
bc44d920 647 /* 1 if not available */
f7deaa1a 648 /* -1 error */
ef416fc2 649cups_local_auth(http_t *http) /* I - HTTP connection to server */
650{
651#if defined(WIN32) || defined(__EMX__)
652 /*
653 * Currently WIN32 and OS-2 do not support the CUPS server...
654 */
655
bc44d920 656 return (1);
ef416fc2 657#else
f7deaa1a 658 int pid; /* Current process ID */
659 FILE *fp; /* Certificate file */
e07d4801
MS
660 char trc[16], /* Try Root Certificate parameter */
661 filename[1024], /* Certificate filename */
f7deaa1a 662 certificate[33];/* Certificate string */
ef416fc2 663 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
bc44d920 664# if defined(HAVE_AUTHORIZATION_H)
f7deaa1a 665 OSStatus status; /* Status */
666 AuthorizationItem auth_right; /* Authorization right */
667 AuthorizationRights auth_rights; /* Authorization rights */
668 AuthorizationFlags auth_flags; /* Authorization flags */
669 AuthorizationExternalForm auth_extrn; /* Authorization ref external */
670 char auth_key[1024]; /* Buffer */
671 char buffer[1024]; /* Buffer */
bc44d920 672# endif /* HAVE_AUTHORIZATION_H */
ef416fc2 673
674
e07d4801 675 DEBUG_printf(("7cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"",
ef416fc2 676 http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname));
677
678 /*
679 * See if we are accessing localhost...
680 */
681
682 if (!httpAddrLocalhost(http->hostaddr) &&
88f9aafc 683 _cups_strcasecmp(http->hostname, "localhost") != 0)
ef416fc2 684 {
e07d4801 685 DEBUG_puts("8cups_local_auth: Not a local connection!");
bc44d920 686 return (1);
ef416fc2 687 }
688
bc44d920 689# if defined(HAVE_AUTHORIZATION_H)
f7deaa1a 690 /*
691 * Delete any previous authorization reference...
692 */
f14324a7 693
b94498cf 694 if (http->auth_ref)
f7deaa1a 695 {
b94498cf 696 AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
697 http->auth_ref = NULL;
f7deaa1a 698 }
699
e4572d57 700 if (!getenv("GATEWAY_INTERFACE") &&
f14324a7 701 httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
f7deaa1a 702 auth_key, sizeof(auth_key)))
703 {
f14324a7 704 status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
b94498cf 705 kAuthorizationFlagDefaults, &http->auth_ref);
f7deaa1a 706 if (status != errAuthorizationSuccess)
707 {
e07d4801 708 DEBUG_printf(("8cups_local_auth: AuthorizationCreate() returned %d (%s)",
f7deaa1a 709 (int)status, cssmErrorString(status)));
710 return (-1);
711 }
712
713 auth_right.name = auth_key;
714 auth_right.valueLength = 0;
715 auth_right.value = NULL;
716 auth_right.flags = 0;
717
718 auth_rights.count = 1;
719 auth_rights.items = &auth_right;
720
f14324a7 721 auth_flags = kAuthorizationFlagDefaults |
f7deaa1a 722 kAuthorizationFlagPreAuthorize |
f14324a7 723 kAuthorizationFlagInteractionAllowed |
f7deaa1a 724 kAuthorizationFlagExtendRights;
725
f14324a7
MS
726 status = AuthorizationCopyRights(http->auth_ref, &auth_rights,
727 kAuthorizationEmptyEnvironment,
f7deaa1a 728 auth_flags, NULL);
729 if (status == errAuthorizationSuccess)
b94498cf 730 status = AuthorizationMakeExternalForm(http->auth_ref, &auth_extrn);
f7deaa1a 731
732 if (status == errAuthorizationSuccess)
733 {
734 /*
735 * Set the authorization string and return...
736 */
737
f14324a7 738 httpEncode64_2(buffer, sizeof(buffer), (void *)&auth_extrn,
f7deaa1a 739 sizeof(auth_extrn));
740
355e94dc 741 httpSetAuthString(http, "AuthRef", buffer);
f7deaa1a 742
e07d4801 743 DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
f7deaa1a 744 http->authstring));
745 return (0);
746 }
747 else if (status == errAuthorizationCanceled)
748 return (-1);
749
e07d4801 750 DEBUG_printf(("9cups_local_auth: AuthorizationCopyRights() returned %d (%s)",
f7deaa1a 751 (int)status, cssmErrorString(status)));
752
753 /*
754 * Fall through to try certificates...
755 */
756 }
bc44d920 757# endif /* HAVE_AUTHORIZATION_H */
f7deaa1a 758
f11a948a
MS
759# if defined(SO_PEERCRED) && defined(AF_LOCAL)
760 /*
761 * See if we can authenticate using the peer credentials provided over a
762 * domain socket; if so, specify "PeerCred username" as the authentication
763 * information...
764 */
765
68b10830 766 if (
f14324a7
MS
767# ifdef HAVE_GSSAPI
768 strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9) &&
68b10830 769# endif /* HAVE_GSSAPI */
f14324a7
MS
770# ifdef HAVE_AUTHORIZATION_H
771 !httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
772 auth_key, sizeof(auth_key)) &&
773# endif /* HAVE_AUTHORIZATION_H */
68b10830 774 http->hostaddr->addr.sa_family == AF_LOCAL &&
f11a948a
MS
775 !getenv("GATEWAY_INTERFACE")) /* Not via CGI programs... */
776 {
777 /*
778 * Verify that the current cupsUser() matches the current UID...
779 */
780
781 struct passwd *pwd; /* Password information */
782 const char *username; /* Current username */
783
784 username = cupsUser();
785
786 if ((pwd = getpwnam(username)) != NULL && pwd->pw_uid == getuid())
787 {
788 httpSetAuthString(http, "PeerCred", username);
789
790 DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
791 http->authstring));
792
793 return (0);
794 }
795 }
796# endif /* SO_PEERCRED && AF_LOCAL */
797
ef416fc2 798 /*
799 * Try opening a certificate file for this PID. If that fails,
800 * try the root certificate...
801 */
802
803 pid = getpid();
804 snprintf(filename, sizeof(filename), "%s/certs/%d", cg->cups_statedir, pid);
805 if ((fp = fopen(filename, "r")) == NULL && pid > 0)
806 {
bc44d920 807 /*
e07d4801 808 * No certificate for this PID; see if we can get the root certificate...
bc44d920 809 */
810
e07d4801
MS
811 DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s",
812 filename, strerror(errno)));
813
07ed0e9a 814# ifdef HAVE_GSSAPI
355e94dc 815 if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9))
bc44d920 816 {
817 /*
e07d4801 818 * Kerberos required, don't try the root certificate...
bc44d920 819 */
820
821 return (1);
822 }
07ed0e9a 823# endif /* HAVE_GSSAPI */
bc44d920 824
07ed0e9a
MS
825# ifdef HAVE_AUTHORIZATION_H
826 if (httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
827 auth_key, sizeof(auth_key)))
828 {
829 /*
830 * Don't use the root certificate as a replacement for an authkey...
831 */
832
833 return (1);
834 }
835# endif /* HAVE_AUTHORIZATION_H */
e07d4801
MS
836 if (!httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "trc", trc,
837 sizeof(trc)))
838 {
839 /*
840 * Scheduler doesn't want us to use the root certificate...
841 */
842
843 return (1);
844 }
845
ef416fc2 846 snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir);
847 fp = fopen(filename, "r");
848 }
849
f7deaa1a 850 if (fp)
ef416fc2 851 {
f7deaa1a 852 /*
853 * Read the certificate from the file...
854 */
ef416fc2 855
f7deaa1a 856 fgets(certificate, sizeof(certificate), fp);
857 fclose(fp);
ef416fc2 858
f7deaa1a 859 /*
860 * Set the authorization string and return...
861 */
ef416fc2 862
355e94dc 863 httpSetAuthString(http, "Local", certificate);
ef416fc2 864
e07d4801 865 DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
f7deaa1a 866 http->authstring));
ef416fc2 867
f7deaa1a 868 return (0);
869 }
870
871 return (1);
ef416fc2 872#endif /* WIN32 || __EMX__ */
873}
874
875
876/*
b19ccc9e 877 * End of "$Id: auth.c 7720 2008-07-11 22:46:21Z mike $".
ef416fc2 878 */