]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/auth.c
Merge changes from CUPS 1.6svn-r10112.
[thirdparty/cups.git] / cups / auth.c
1 /*
2 * "$Id: auth.c 7720 2008-07-11 22:46:21Z mike $"
3 *
4 * Authentication functions for CUPS.
5 *
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
9 * This file contains Kerberos support code, copyright 2006 by
10 * Jelmer Vernooij.
11 *
12 * These coded instructions, statements, and computer programs are the
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/".
17 *
18 * This file is subject to the Apple OS-Developed Software exception.
19 *
20 * Contents:
21 *
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.
30 */
31
32 /*
33 * Include necessary headers...
34 */
35
36 #include "cups-private.h"
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
45 #if HAVE_AUTHORIZATION_H
46 # include <Security/Authorization.h>
47 # ifdef HAVE_SECBASEPRIV_H
48 # include <Security/SecBasePriv.h>
49 # else
50 extern const char *cssmErrorString(int error);
51 # endif /* HAVE_SECBASEPRIV_H */
52 #endif /* HAVE_AUTHORIZATION_H */
53
54 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
55 # include <pwd.h>
56 #endif /* SO_PEERCRED && AF_LOCAL */
57
58
59 /*
60 * Local functions...
61 */
62
63 #ifdef HAVE_GSSAPI
64 # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
65 # ifdef HAVE_GSS_GSSAPI_SPI_H
66 # include <GSS/gssapi_spi.h>
67 # else
68 # define GSS_AUTH_IDENTITY_TYPE_1 1
69 # define gss_acquire_cred_ex_f __ApplePrivate_gss_acquire_cred_ex_f
70 typedef 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;
79 extern 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>
89 typedef 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
96 static 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 */
101 static gss_name_t cups_gss_getname(http_t *http, const char *service_name);
102 # ifdef DEBUG
103 static void cups_gss_printf(OM_uint32 major_status, OM_uint32 minor_status,
104 const char *message);
105 # else
106 # define cups_gss_printf(major, minor, message)
107 # endif /* DEBUG */
108 #endif /* HAVE_GSSAPI */
109 static int cups_local_auth(http_t *http);
110
111
112 /*
113 * 'cupsDoAuthentication()' - Authenticate a request.
114 *
115 * This function should be called in response to a @code HTTP_UNAUTHORIZED@
116 * status, prior to resubmitting your request.
117 *
118 * @since CUPS 1.1.20/Mac OS X 10.4@
119 */
120
121 int /* O - 0 on success, -1 on error */
122 cupsDoAuthentication(
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 */
126 {
127 const char *password; /* Password string */
128 char prompt[1024], /* Prompt for user */
129 realm[HTTP_MAX_VALUE], /* realm="xyz" string */
130 nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */
131 int localauth; /* Local authentication result */
132 _cups_globals_t *cg; /* Global data */
133
134
135 DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")",
136 http, method, resource));
137
138 if (!http)
139 http = _cupsConnect();
140
141 if (!http || !method || !resource)
142 return (-1);
143
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
149 /*
150 * Clear the current authentication string...
151 */
152
153 httpSetAuthString(http, NULL, NULL);
154
155 /*
156 * See if we can do local authentication...
157 */
158
159 if (http->digest_tries < 3)
160 {
161 if ((localauth = cups_local_auth(http)) == 0)
162 {
163 DEBUG_printf(("2cupsDoAuthentication: authstring=\"%s\"",
164 http->authstring));
165
166 if (http->status == HTTP_UNAUTHORIZED)
167 http->digest_tries ++;
168
169 return (0);
170 }
171 else if (localauth == -1)
172 {
173 http->status = HTTP_AUTHORIZATION_CANCELED;
174 return (-1); /* Error or canceled */
175 }
176 }
177
178 /*
179 * Nope, see if we should retry the current username:password...
180 */
181
182 if ((http->digest_tries > 1 || !http->userpass[0]) &&
183 (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) ||
184 !strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6)))
185 {
186 /*
187 * Nope - get a new password from the user...
188 */
189
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);
199
200 http->digest_tries = _cups_strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE],
201 "Digest", 5) != 0;
202 http->userpass[0] = '\0';
203
204 if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
205 {
206 http->status = HTTP_AUTHORIZATION_CANCELED;
207 return (-1);
208 }
209
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
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
225 /*
226 * Got a password; encode it for the server...
227 */
228
229 #ifdef HAVE_GSSAPI
230 if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9))
231 {
232 /*
233 * Kerberos authentication...
234 */
235
236 if (_cupsSetNegotiateAuthString(http, method, resource))
237 {
238 http->status = HTTP_AUTHORIZATION_CANCELED;
239 return (-1);
240 }
241 }
242 else
243 #endif /* HAVE_GSSAPI */
244 if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5))
245 {
246 /*
247 * Basic authentication...
248 */
249
250 char encode[256]; /* Base64 buffer */
251
252
253 httpEncode64_2(encode, sizeof(encode), http->userpass,
254 (int)strlen(http->userpass));
255 httpSetAuthString(http, "Basic", encode);
256 }
257 else if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6))
258 {
259 /*
260 * Digest authentication...
261 */
262
263 char encode[33], /* MD5 buffer */
264 digest[1024]; /* Digest auth data */
265
266
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);
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);
276 }
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 }
284
285 DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring));
286
287 return (0);
288 }
289
290
291 #ifdef HAVE_GSSAPI
292 /*
293 * '_cupsSetNegotiateAuthString()' - Set the Kerberos authentication string.
294 */
295
296 int /* O - 0 on success, -1 on error */
297 _cupsSetNegotiateAuthString(
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 */
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;
305 /* Output token */
306
307
308 (void)method;
309 (void)resource;
310
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 {
327 http->gssname = cups_gss_getname(http, _cupsGSSServiceName());
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
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? ")),
366 cupsUser(), http->gsshost);
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 {
378 snprintf(userbuf, sizeof(userbuf), "%s@%s", username, http->gsshost);
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 }
424 #endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */
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
434 #ifdef DEBUG
435 else if (major_status == GSS_S_CONTINUE_NEEDED)
436 cups_gss_printf(major_status, minor_status,
437 "_cupsSetNegotiateAuthString: Continuation needed!");
438 #endif /* DEBUG */
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
478 # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
479 /*
480 * 'cups_gss_acquire()' - Kerberos credentials callback.
481 */
482 static void
483 cups_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.
510 */
511
512 static gss_name_t /* O - Server name */
513 cups_gss_getname(
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 */
519 OM_uint32 major_status, /* Major status code */
520 minor_status; /* Minor status code */
521 gss_name_t server_name; /* Server name */
522 char buf[1024]; /* Name buffer */
523
524
525 DEBUG_printf(("7cups_gss_getname(http=%p, service_name=\"%s\")", http,
526 service_name));
527
528
529 /*
530 * Get the hostname...
531 */
532
533 if (!http->gsshost[0])
534 {
535 httpGetHostname(http, http->gsshost, sizeof(http->gsshost));
536
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 }
573
574 /*
575 * Get a service name we can use for authentication purposes...
576 */
577
578 snprintf(buf, sizeof(buf), "%s@%s", service_name, http->gsshost);
579
580 DEBUG_printf(("8cups_gss_getname: Looking up \"%s\".", buf));
581
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 {
591 cups_gss_printf(major_status, minor_status,
592 "cups_gss_getname: gss_import_name() failed");
593 return (NULL);
594 }
595
596 return (server_name);
597 }
598
599
600 # ifdef DEBUG
601 /*
602 * 'cups_gss_printf()' - Show debug error messages from GSSAPI.
603 */
604
605 static void
606 cups_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
631 DEBUG_printf(("1%s: %s, %s", message, (char *)major_status_string.value,
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 */
638 #endif /* HAVE_GSSAPI */
639
640
641 /*
642 * 'cups_local_auth()' - Get the local authorization certificate if
643 * available/applicable.
644 */
645
646 static int /* O - 0 if available */
647 /* 1 if not available */
648 /* -1 error */
649 cups_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
656 return (1);
657 #else
658 int pid; /* Current process ID */
659 FILE *fp; /* Certificate file */
660 char trc[16], /* Try Root Certificate parameter */
661 filename[1024], /* Certificate filename */
662 certificate[33];/* Certificate string */
663 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
664 # if defined(HAVE_AUTHORIZATION_H)
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 */
672 # endif /* HAVE_AUTHORIZATION_H */
673
674
675 DEBUG_printf(("7cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"",
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) &&
683 _cups_strcasecmp(http->hostname, "localhost") != 0)
684 {
685 DEBUG_puts("8cups_local_auth: Not a local connection!");
686 return (1);
687 }
688
689 # if defined(HAVE_AUTHORIZATION_H)
690 /*
691 * Delete any previous authorization reference...
692 */
693
694 if (http->auth_ref)
695 {
696 AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
697 http->auth_ref = NULL;
698 }
699
700 if (!getenv("GATEWAY_INTERFACE") &&
701 httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
702 auth_key, sizeof(auth_key)))
703 {
704 status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
705 kAuthorizationFlagDefaults, &http->auth_ref);
706 if (status != errAuthorizationSuccess)
707 {
708 DEBUG_printf(("8cups_local_auth: AuthorizationCreate() returned %d (%s)",
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
721 auth_flags = kAuthorizationFlagDefaults |
722 kAuthorizationFlagPreAuthorize |
723 kAuthorizationFlagInteractionAllowed |
724 kAuthorizationFlagExtendRights;
725
726 status = AuthorizationCopyRights(http->auth_ref, &auth_rights,
727 kAuthorizationEmptyEnvironment,
728 auth_flags, NULL);
729 if (status == errAuthorizationSuccess)
730 status = AuthorizationMakeExternalForm(http->auth_ref, &auth_extrn);
731
732 if (status == errAuthorizationSuccess)
733 {
734 /*
735 * Set the authorization string and return...
736 */
737
738 httpEncode64_2(buffer, sizeof(buffer), (void *)&auth_extrn,
739 sizeof(auth_extrn));
740
741 httpSetAuthString(http, "AuthRef", buffer);
742
743 DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
744 http->authstring));
745 return (0);
746 }
747 else if (status == errAuthorizationCanceled)
748 return (-1);
749
750 DEBUG_printf(("9cups_local_auth: AuthorizationCopyRights() returned %d (%s)",
751 (int)status, cssmErrorString(status)));
752
753 /*
754 * Fall through to try certificates...
755 */
756 }
757 # endif /* HAVE_AUTHORIZATION_H */
758
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
766 if (
767 # ifdef HAVE_GSSAPI
768 strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9) &&
769 # endif /* HAVE_GSSAPI */
770 # ifdef HAVE_AUTHORIZATION_H
771 !httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
772 auth_key, sizeof(auth_key)) &&
773 # endif /* HAVE_AUTHORIZATION_H */
774 http->hostaddr->addr.sa_family == AF_LOCAL &&
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
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 {
807 /*
808 * No certificate for this PID; see if we can get the root certificate...
809 */
810
811 DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s",
812 filename, strerror(errno)));
813
814 # ifdef HAVE_GSSAPI
815 if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9))
816 {
817 /*
818 * Kerberos required, don't try the root certificate...
819 */
820
821 return (1);
822 }
823 # endif /* HAVE_GSSAPI */
824
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 */
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
846 snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir);
847 fp = fopen(filename, "r");
848 }
849
850 if (fp)
851 {
852 /*
853 * Read the certificate from the file...
854 */
855
856 fgets(certificate, sizeof(certificate), fp);
857 fclose(fp);
858
859 /*
860 * Set the authorization string and return...
861 */
862
863 httpSetAuthString(http, "Local", certificate);
864
865 DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
866 http->authstring));
867
868 return (0);
869 }
870
871 return (1);
872 #endif /* WIN32 || __EMX__ */
873 }
874
875
876 /*
877 * End of "$Id: auth.c 7720 2008-07-11 22:46:21Z mike $".
878 */