]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
bc44d920 | 2 | * "$Id: auth.c 6673 2007-07-14 00:16:39Z mike $" |
ef416fc2 | 3 | * |
4 | * Authentication functions for the Common UNIX Printing System (CUPS). | |
5 | * | |
bc44d920 | 6 | * Copyright 2007 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 | * | |
22 | * cupsDoAuthentication() - Authenticate a request. | |
f7deaa1a | 23 | * DEBUG_gss_printf() - Show debug error messages from GSSAPI... |
24 | * cups_get_gss_creds() - Get CUPS service credentials for authentication. | |
ef416fc2 | 25 | * cups_local_auth() - Get the local authorization certificate if |
26 | * available/applicable... | |
27 | */ | |
28 | ||
29 | /* | |
30 | * Include necessary headers... | |
31 | */ | |
32 | ||
33 | #include "globals.h" | |
34 | #include "debug.h" | |
35 | #include <stdlib.h> | |
36 | #include <ctype.h> | |
37 | #include <errno.h> | |
38 | #include <fcntl.h> | |
39 | #include <sys/stat.h> | |
40 | #if defined(WIN32) || defined(__EMX__) | |
41 | # include <io.h> | |
42 | #else | |
43 | # include <unistd.h> | |
44 | #endif /* WIN32 || __EMX__ */ | |
45 | ||
f7deaa1a | 46 | #if HAVE_AUTHORIZATION_H |
47 | # include <Security/Authorization.h> | |
48 | # ifdef HAVE_SECBASEPRIV_H | |
49 | # include <Security/SecBasePriv.h> | |
50 | # else | |
51 | extern const char *cssmErrorString(int error); | |
52 | # endif /* HAVE_SECBASEPRIV_H */ | |
53 | #endif /* HAVE_AUTHORIZATION_H */ | |
54 | ||
bc44d920 | 55 | #if defined(SO_PEERCRED) && defined(AF_LOCAL) |
56 | # include <pwd.h> | |
57 | #endif /* SO_PEERCRED && AF_LOCAL */ | |
58 | ||
ef416fc2 | 59 | |
60 | /* | |
61 | * Local functions... | |
62 | */ | |
63 | ||
f7deaa1a | 64 | #ifdef HAVE_GSSAPI |
65 | # ifdef DEBUG | |
66 | static void DEBUG_gss_printf(OM_uint32 major_status, OM_uint32 minor_status, | |
67 | const char *message); | |
68 | # endif /* DEBUG */ | |
69 | static gss_name_t cups_get_gss_creds(http_t *http, const char *service_name); | |
70 | #endif /* HAVE_GSSAPI */ | |
ef416fc2 | 71 | static int cups_local_auth(http_t *http); |
72 | ||
73 | ||
74 | /* | |
75 | * 'cupsDoAuthentication()' - Authenticate a request. | |
76 | * | |
77 | * This function should be called in response to a HTTP_UNAUTHORIZED | |
78 | * status, prior to resubmitting your request. | |
79 | * | |
80 | * @since CUPS 1.1.20@ | |
81 | */ | |
82 | ||
83 | int /* O - 0 on success, -1 on error */ | |
84 | cupsDoAuthentication(http_t *http, /* I - HTTP connection to server */ | |
85 | const char *method,/* I - Request method (GET, POST, PUT) */ | |
86 | const char *resource) | |
87 | /* I - Resource path */ | |
88 | { | |
89 | const char *password; /* Password string */ | |
90 | char prompt[1024], /* Prompt for user */ | |
91 | realm[HTTP_MAX_VALUE], /* realm="xyz" string */ | |
92 | nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ | |
f7deaa1a | 93 | encode[2048]; /* Encoded username:password */ |
94 | int localauth; /* Local authentication result */ | |
b86bc4cf | 95 | _cups_globals_t *cg; /* Global data */ |
ef416fc2 | 96 | |
97 | ||
98 | DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")\n", | |
99 | http, method, resource)); | |
100 | DEBUG_printf(("cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"\n", | |
101 | http->digest_tries, http->userpass)); | |
07725fee | 102 | DEBUG_printf(("cupsDoAuthentication: WWW-Authenticate=\"%s\"\n", |
103 | httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE))); | |
ef416fc2 | 104 | |
105 | /* | |
106 | * Clear the current authentication string... | |
107 | */ | |
108 | ||
f7deaa1a | 109 | http->_authstring[0] = '\0'; |
110 | ||
111 | if (http->authstring && http->authstring != http->_authstring) | |
112 | free(http->authstring); | |
113 | ||
114 | http->authstring = http->_authstring; | |
ef416fc2 | 115 | |
116 | /* | |
117 | * See if we can do local authentication... | |
118 | */ | |
119 | ||
f7deaa1a | 120 | if (http->digest_tries < 3) |
ef416fc2 | 121 | { |
f7deaa1a | 122 | if ((localauth = cups_local_auth(http)) == 0) |
123 | { | |
124 | DEBUG_printf(("cupsDoAuthentication: authstring=\"%s\"\n", | |
125 | http->authstring)); | |
126 | ||
127 | if (http->status == HTTP_UNAUTHORIZED) | |
128 | http->digest_tries ++; | |
129 | ||
130 | return (0); | |
131 | } | |
132 | else if (localauth == -1) | |
133 | return (-1); /* Error or canceled */ | |
ef416fc2 | 134 | } |
135 | ||
136 | /* | |
137 | * Nope, see if we should retry the current username:password... | |
138 | */ | |
139 | ||
f7deaa1a | 140 | if ((http->digest_tries > 1 || !http->userpass[0]) && |
141 | strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9)) | |
ef416fc2 | 142 | { |
143 | /* | |
144 | * Nope - get a new password from the user... | |
145 | */ | |
146 | ||
b86bc4cf | 147 | cg = _cupsGlobals(); |
148 | ||
149 | if (!cg->lang_default) | |
150 | cg->lang_default = cupsLangDefault(); | |
151 | ||
152 | snprintf(prompt, sizeof(prompt), | |
153 | _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), | |
154 | cupsUser(), | |
155 | http->hostname[0] == '/' ? "localhost" : http->hostname); | |
ef416fc2 | 156 | |
157 | http->digest_tries = strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], | |
158 | "Digest", 5) != 0; | |
159 | http->userpass[0] = '\0'; | |
160 | ||
161 | if ((password = cupsGetPassword(prompt)) == NULL) | |
162 | return (-1); | |
163 | ||
164 | if (!password[0]) | |
165 | return (-1); | |
166 | ||
167 | snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(), | |
168 | password); | |
169 | } | |
170 | else if (http->status == HTTP_UNAUTHORIZED) | |
171 | http->digest_tries ++; | |
172 | ||
173 | /* | |
174 | * Got a password; encode it for the server... | |
175 | */ | |
176 | ||
f7deaa1a | 177 | if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9)) |
178 | { | |
bc44d920 | 179 | if (http->status == HTTP_UNAUTHORIZED && http->digest_tries >= 3) |
180 | { | |
181 | DEBUG_printf(("cupsDoAuthentication: too many Negotiate tries (%d)\n", | |
182 | http->digest_tries)); | |
183 | ||
184 | return (-1); | |
185 | } | |
f7deaa1a | 186 | #ifdef HAVE_GSSAPI |
187 | /* | |
188 | * Kerberos authentication... | |
189 | */ | |
190 | ||
191 | OM_uint32 minor_status, /* Minor status code */ | |
192 | major_status; /* Major status code */ | |
193 | gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER, | |
194 | /* Output token */ | |
195 | input_token = GSS_C_EMPTY_BUFFER; | |
196 | /* Input token */ | |
197 | char *gss_service_name; | |
198 | /* GSS service name */ | |
199 | const char *authorization; | |
200 | /* Pointer into Authorization string */ | |
201 | ||
202 | ||
f42414bf | 203 | # ifdef __APPLE__ |
204 | /* | |
205 | * If the weak-linked GSSAPI/Kerberos library is not present, don't try | |
206 | * to use it... | |
207 | */ | |
208 | ||
209 | if (gss_init_sec_context == NULL) | |
210 | { | |
211 | DEBUG_puts("cupsDoAuthentication: Weak-linked GSSAPI/Kerberos framework " | |
212 | "is not present"); | |
213 | return (-1); | |
214 | } | |
215 | # endif /* __APPLE__ */ | |
216 | ||
f7deaa1a | 217 | if (http->gssname == GSS_C_NO_NAME) |
218 | { | |
219 | if ((gss_service_name = getenv("CUPS_GSSSERVICENAME")) == NULL) | |
220 | gss_service_name = CUPS_DEFAULT_GSSSERVICENAME; | |
221 | else | |
222 | DEBUG_puts("cupsDoAuthentication: GSS service name set via environment"); | |
223 | ||
224 | http->gssname = cups_get_gss_creds(http, gss_service_name); | |
225 | } | |
226 | ||
227 | /* | |
228 | * Find the start of the Kerberos input token... | |
229 | */ | |
230 | ||
231 | authorization = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); | |
232 | ||
233 | authorization += 9; | |
234 | while (*authorization && isspace(*authorization & 255)) | |
235 | authorization ++; | |
236 | ||
237 | if (*authorization) | |
238 | { | |
239 | /* | |
240 | * For SPNEGO, this is where we'll feed the server's authorization data | |
241 | * back into gss via input_token... | |
242 | */ | |
243 | } | |
bc44d920 | 244 | |
245 | if (http->gssctx != GSS_C_NO_CONTEXT) | |
f7deaa1a | 246 | { |
bc44d920 | 247 | major_status = gss_delete_sec_context(&minor_status, &http->gssctx, |
248 | GSS_C_NO_BUFFER); | |
249 | http->gssctx = GSS_C_NO_CONTEXT; | |
f7deaa1a | 250 | } |
251 | ||
252 | major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, | |
253 | &http->gssctx, | |
254 | http->gssname, http->gssmech, | |
bc44d920 | 255 | GSS_C_DELEG_FLAG | GSS_C_MUTUAL_FLAG, |
256 | GSS_C_INDEFINITE, | |
f7deaa1a | 257 | GSS_C_NO_CHANNEL_BINDINGS, |
258 | &input_token, &http->gssmech, | |
259 | &output_token, NULL, NULL); | |
260 | ||
261 | if (input_token.value) | |
262 | free(input_token.value); | |
263 | ||
264 | if (GSS_ERROR(major_status)) | |
265 | { | |
266 | # ifdef DEBUG | |
267 | DEBUG_gss_printf(major_status, minor_status, | |
268 | "Unable to initialise security context"); | |
269 | # endif /* DEBUG */ | |
270 | return (-1); | |
271 | } | |
272 | ||
273 | # ifdef DEBUG | |
274 | if (major_status == GSS_S_CONTINUE_NEEDED) | |
275 | DEBUG_gss_printf(major_status, minor_status, "Continuation needed!"); | |
276 | # endif /* DEBUG */ | |
277 | ||
278 | if (output_token.length) | |
279 | { | |
280 | httpEncode64_2(encode, sizeof(encode), output_token.value, | |
281 | output_token.length); | |
282 | ||
283 | http->authstring = malloc(strlen(encode) + 11); | |
284 | sprintf(http->authstring, "Negotiate %s", encode); /* Safe because allocated */ | |
285 | ||
286 | major_status = gss_release_buffer(&minor_status, &output_token); | |
287 | } | |
288 | ||
289 | /* | |
290 | * Copy back what we can to _authstring for backwards compatibility... | |
291 | */ | |
292 | ||
293 | strlcpy(http->_authstring, http->authstring, sizeof(http->_authstring)); | |
294 | #endif /* HAVE_GSSAPI */ | |
295 | } | |
296 | else if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6)) | |
ef416fc2 | 297 | { |
298 | /* | |
299 | * Basic authentication... | |
300 | */ | |
301 | ||
302 | httpEncode64_2(encode, sizeof(encode), http->userpass, | |
b86bc4cf | 303 | (int)strlen(http->userpass)); |
f7deaa1a | 304 | snprintf(http->_authstring, sizeof(http->_authstring), "Basic %s", encode); |
ef416fc2 | 305 | } |
306 | else | |
307 | { | |
308 | /* | |
309 | * Digest authentication... | |
310 | */ | |
311 | ||
312 | httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); | |
313 | httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); | |
314 | ||
315 | httpMD5(cupsUser(), realm, strchr(http->userpass, ':') + 1, encode); | |
316 | httpMD5Final(nonce, method, resource, encode); | |
f7deaa1a | 317 | snprintf(http->_authstring, sizeof(http->_authstring), |
ef416fc2 | 318 | "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " |
319 | "uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, | |
320 | resource, encode); | |
321 | } | |
322 | ||
323 | DEBUG_printf(("cupsDoAuthentication: authstring=\"%s\"\n", http->authstring)); | |
324 | ||
325 | return (0); | |
326 | } | |
327 | ||
328 | ||
f7deaa1a | 329 | #ifdef HAVE_GSSAPI |
330 | # ifdef DEBUG | |
331 | /* | |
332 | * 'DEBUG_gss_printf()' - Show debug error messages from GSSAPI... | |
333 | */ | |
334 | ||
335 | static void | |
336 | DEBUG_gss_printf(OM_uint32 major_status,/* I - Major status code */ | |
337 | OM_uint32 minor_status,/* I - Minor status code */ | |
338 | const char *message) /* I - Prefix for error message */ | |
339 | { | |
340 | OM_uint32 err_major_status, /* Major status code for display */ | |
341 | err_minor_status; /* Minor status code for display */ | |
342 | OM_uint32 msg_ctx; /* Message context */ | |
343 | gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER, | |
344 | /* Major status message */ | |
345 | minor_status_string = GSS_C_EMPTY_BUFFER; | |
346 | /* Minor status message */ | |
347 | ||
348 | ||
349 | msg_ctx = 0; | |
350 | err_major_status = gss_display_status(&err_minor_status, | |
351 | major_status, | |
352 | GSS_C_GSS_CODE, | |
353 | GSS_C_NO_OID, | |
354 | &msg_ctx, | |
355 | &major_status_string); | |
356 | ||
357 | if (!GSS_ERROR(err_major_status)) | |
358 | err_major_status = gss_display_status(&err_minor_status, | |
359 | minor_status, | |
360 | GSS_C_MECH_CODE, | |
361 | GSS_C_NULL_OID, | |
362 | &msg_ctx, | |
363 | &minor_status_string); | |
364 | ||
365 | printf("%s: %s, %s\n", message, (char *)major_status_string.value, | |
366 | (char *)minor_status_string.value); | |
367 | ||
368 | gss_release_buffer(&err_minor_status, &major_status_string); | |
369 | gss_release_buffer(&err_minor_status, &minor_status_string); | |
370 | } | |
371 | # endif /* DEBUG */ | |
372 | ||
373 | ||
374 | /* | |
375 | * 'cups_get_gss_creds()' - Get CUPS service credentials for authentication. | |
376 | */ | |
377 | ||
378 | static gss_name_t /* O - Server name */ | |
379 | cups_get_gss_creds( | |
380 | http_t *http, /* I - Connection to server */ | |
381 | const char *service_name) /* I - Service name */ | |
382 | { | |
383 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; | |
384 | /* Service token */ | |
bc44d920 | 385 | OM_uint32 major_status, /* Major status code */ |
386 | minor_status; /* Minor status code */ | |
387 | gss_name_t server_name; /* Server name */ | |
388 | char buf[1024], /* Name buffer */ | |
389 | fqdn[HTTP_MAX_URI]; /* Server name buffer */ | |
390 | ||
391 | ||
392 | /* | |
393 | * Get the hostname... | |
394 | */ | |
f7deaa1a | 395 | |
bc44d920 | 396 | httpGetHostname(http, fqdn, sizeof(fqdn)); |
397 | ||
398 | if (!strcmp(fqdn, "localhost")) | |
399 | httpGetHostname(NULL, fqdn, sizeof(fqdn)); | |
f7deaa1a | 400 | |
401 | /* | |
402 | * Get a server name we can use for authentication purposes... | |
403 | */ | |
404 | ||
bc44d920 | 405 | snprintf(buf, sizeof(buf), "%s@%s", service_name, fqdn); |
f7deaa1a | 406 | |
407 | token.value = buf; | |
408 | token.length = strlen(buf); | |
409 | server_name = GSS_C_NO_NAME; | |
410 | major_status = gss_import_name(&minor_status, &token, | |
411 | GSS_C_NT_HOSTBASED_SERVICE, | |
412 | &server_name); | |
413 | ||
414 | if (GSS_ERROR(major_status)) | |
415 | { | |
416 | # ifdef DEBUG | |
417 | DEBUG_gss_printf(major_status, minor_status, "gss_import_name() failed"); | |
418 | # endif /* DEBUG */ | |
419 | ||
420 | return (NULL); | |
421 | } | |
422 | ||
423 | return (server_name); | |
424 | } | |
425 | #endif /* HAVE_GSSAPI */ | |
426 | ||
427 | ||
ef416fc2 | 428 | /* |
429 | * 'cups_local_auth()' - Get the local authorization certificate if | |
430 | * available/applicable... | |
431 | */ | |
432 | ||
f7deaa1a | 433 | static int /* O - 0 if available */ |
bc44d920 | 434 | /* 1 if not available */ |
f7deaa1a | 435 | /* -1 error */ |
ef416fc2 | 436 | cups_local_auth(http_t *http) /* I - HTTP connection to server */ |
437 | { | |
438 | #if defined(WIN32) || defined(__EMX__) | |
439 | /* | |
440 | * Currently WIN32 and OS-2 do not support the CUPS server... | |
441 | */ | |
442 | ||
bc44d920 | 443 | return (1); |
ef416fc2 | 444 | #else |
f7deaa1a | 445 | int pid; /* Current process ID */ |
446 | FILE *fp; /* Certificate file */ | |
447 | char filename[1024], /* Certificate filename */ | |
448 | certificate[33];/* Certificate string */ | |
ef416fc2 | 449 | _cups_globals_t *cg = _cupsGlobals(); /* Global data */ |
bc44d920 | 450 | # if defined(HAVE_AUTHORIZATION_H) |
f7deaa1a | 451 | OSStatus status; /* Status */ |
452 | AuthorizationItem auth_right; /* Authorization right */ | |
453 | AuthorizationRights auth_rights; /* Authorization rights */ | |
454 | AuthorizationFlags auth_flags; /* Authorization flags */ | |
455 | AuthorizationExternalForm auth_extrn; /* Authorization ref external */ | |
456 | char auth_key[1024]; /* Buffer */ | |
457 | char buffer[1024]; /* Buffer */ | |
bc44d920 | 458 | # endif /* HAVE_AUTHORIZATION_H */ |
ef416fc2 | 459 | |
460 | ||
461 | DEBUG_printf(("cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"\n", | |
462 | http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname)); | |
463 | ||
464 | /* | |
465 | * See if we are accessing localhost... | |
466 | */ | |
467 | ||
468 | if (!httpAddrLocalhost(http->hostaddr) && | |
469 | strcasecmp(http->hostname, "localhost") != 0) | |
470 | { | |
471 | DEBUG_puts("cups_local_auth: Not a local connection!"); | |
bc44d920 | 472 | return (1); |
ef416fc2 | 473 | } |
474 | ||
bc44d920 | 475 | # if defined(HAVE_AUTHORIZATION_H) |
f7deaa1a | 476 | /* |
477 | * Delete any previous authorization reference... | |
478 | */ | |
479 | ||
b94498cf | 480 | if (http->auth_ref) |
f7deaa1a | 481 | { |
b94498cf | 482 | AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults); |
483 | http->auth_ref = NULL; | |
f7deaa1a | 484 | } |
485 | ||
486 | if (httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey", | |
487 | auth_key, sizeof(auth_key))) | |
488 | { | |
489 | status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, | |
b94498cf | 490 | kAuthorizationFlagDefaults, &http->auth_ref); |
f7deaa1a | 491 | if (status != errAuthorizationSuccess) |
492 | { | |
493 | DEBUG_printf(("cups_local_auth: AuthorizationCreate() returned %d (%s)\n", | |
494 | (int)status, cssmErrorString(status))); | |
495 | return (-1); | |
496 | } | |
497 | ||
498 | auth_right.name = auth_key; | |
499 | auth_right.valueLength = 0; | |
500 | auth_right.value = NULL; | |
501 | auth_right.flags = 0; | |
502 | ||
503 | auth_rights.count = 1; | |
504 | auth_rights.items = &auth_right; | |
505 | ||
506 | auth_flags = kAuthorizationFlagDefaults | | |
507 | kAuthorizationFlagPreAuthorize | | |
508 | kAuthorizationFlagInteractionAllowed | | |
509 | kAuthorizationFlagExtendRights; | |
510 | ||
b94498cf | 511 | status = AuthorizationCopyRights(http->auth_ref, &auth_rights, |
f7deaa1a | 512 | kAuthorizationEmptyEnvironment, |
513 | auth_flags, NULL); | |
514 | if (status == errAuthorizationSuccess) | |
b94498cf | 515 | status = AuthorizationMakeExternalForm(http->auth_ref, &auth_extrn); |
f7deaa1a | 516 | |
517 | if (status == errAuthorizationSuccess) | |
518 | { | |
519 | /* | |
520 | * Set the authorization string and return... | |
521 | */ | |
522 | ||
523 | httpEncode64_2(buffer, sizeof(buffer), (void *)&auth_extrn, | |
524 | sizeof(auth_extrn)); | |
525 | ||
526 | http->authstring = malloc(strlen(buffer) + 9); | |
527 | sprintf(http->authstring, "AuthRef %s", buffer); | |
528 | ||
529 | /* Copy back to _authstring for backwards compatibility */ | |
530 | strlcpy(http->_authstring, http->authstring, sizeof(http->_authstring)); | |
531 | ||
532 | DEBUG_printf(("cups_local_auth: Returning authstring = \"%s\"\n", | |
533 | http->authstring)); | |
534 | return (0); | |
535 | } | |
536 | else if (status == errAuthorizationCanceled) | |
537 | return (-1); | |
538 | ||
539 | DEBUG_printf(("cups_local_auth: AuthorizationCopyRights() returned %d (%s)\n", | |
540 | (int)status, cssmErrorString(status))); | |
541 | ||
542 | /* | |
543 | * Fall through to try certificates... | |
544 | */ | |
545 | } | |
bc44d920 | 546 | # endif /* HAVE_AUTHORIZATION_H */ |
f7deaa1a | 547 | |
ef416fc2 | 548 | /* |
549 | * Try opening a certificate file for this PID. If that fails, | |
550 | * try the root certificate... | |
551 | */ | |
552 | ||
553 | pid = getpid(); | |
554 | snprintf(filename, sizeof(filename), "%s/certs/%d", cg->cups_statedir, pid); | |
555 | if ((fp = fopen(filename, "r")) == NULL && pid > 0) | |
556 | { | |
557 | DEBUG_printf(("cups_local_auth: Unable to open file %s: %s\n", | |
558 | filename, strerror(errno))); | |
559 | ||
bc44d920 | 560 | #ifdef HAVE_GSSAPI |
561 | /* | |
562 | * If local certificate authentication isn't available for this PID, | |
563 | * check if we need Kerberos authentication... | |
564 | */ | |
565 | ||
566 | if (!strcmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate")) | |
567 | { | |
568 | /* | |
569 | * Yes, don't try the root certificate... | |
570 | */ | |
571 | ||
572 | return (1); | |
573 | } | |
574 | #endif /* HAVE_GSSAPI */ | |
575 | ||
ef416fc2 | 576 | snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir); |
577 | fp = fopen(filename, "r"); | |
578 | } | |
579 | ||
f7deaa1a | 580 | if (fp) |
ef416fc2 | 581 | { |
f7deaa1a | 582 | /* |
583 | * Read the certificate from the file... | |
584 | */ | |
ef416fc2 | 585 | |
f7deaa1a | 586 | fgets(certificate, sizeof(certificate), fp); |
587 | fclose(fp); | |
ef416fc2 | 588 | |
f7deaa1a | 589 | /* |
590 | * Set the authorization string and return... | |
591 | */ | |
ef416fc2 | 592 | |
bc44d920 | 593 | http->authstring = malloc(strlen(certificate) + 7); |
f7deaa1a | 594 | sprintf(http->authstring, "Local %s", certificate); |
ef416fc2 | 595 | |
f7deaa1a | 596 | /* Copy back to _authstring for backwards compatibility */ |
597 | strlcpy(http->_authstring, http->authstring, sizeof(http->_authstring)); | |
ef416fc2 | 598 | |
f7deaa1a | 599 | DEBUG_printf(("cups_local_auth: Returning authstring = \"%s\"\n", |
600 | http->authstring)); | |
ef416fc2 | 601 | |
f7deaa1a | 602 | return (0); |
603 | } | |
604 | ||
bc44d920 | 605 | # if defined(SO_PEERCRED) && defined(AF_LOCAL) |
606 | /* | |
607 | * See if we can authenticate using the peer credentials provided over a | |
608 | * domain socket; if so, specify "PeerCred username" as the authentication | |
609 | * information... | |
610 | */ | |
611 | ||
612 | if (http->hostaddr->addr.sa_family == AF_LOCAL && | |
613 | !getenv("GATEWAY_INTERFACE")) /* Not via CGI programs... */ | |
614 | { | |
615 | /* | |
616 | * Verify that the current cupsUser() matches the current UID... | |
617 | */ | |
618 | ||
619 | struct passwd *pwd; /* Password information */ | |
620 | const char *username; /* Current username */ | |
621 | ||
622 | username = cupsUser(); | |
623 | ||
624 | if ((pwd = getpwnam(username)) != NULL && pwd->pw_uid == getuid()) | |
625 | { | |
626 | http->authstring = malloc(strlen(username) + 10); | |
627 | sprintf(http->authstring, "PeerCred %s", username); | |
628 | ||
629 | /* Copy back to _authstring for backwards compatibility */ | |
630 | strlcpy(http->_authstring, http->authstring, sizeof(http->_authstring)); | |
631 | ||
632 | DEBUG_printf(("cups_local_auth: Returning authstring = \"%s\"\n", | |
633 | http->authstring)); | |
634 | ||
635 | return (0); | |
636 | } | |
637 | } | |
638 | # endif /* SO_PEERCRED && AF_LOCAL */ | |
639 | ||
f7deaa1a | 640 | return (1); |
ef416fc2 | 641 | #endif /* WIN32 || __EMX__ */ |
642 | } | |
643 | ||
644 | ||
645 | /* | |
bc44d920 | 646 | * End of "$Id: auth.c 6673 2007-07-14 00:16:39Z mike $". |
ef416fc2 | 647 | */ |