Line | Count | Source |
1 | | /* |
2 | | * Authentication functions for CUPS. |
3 | | * |
4 | | * Copyright © 2020-2025 by OpenPrinting. |
5 | | * Copyright © 2007-2019 by Apple Inc. |
6 | | * Copyright © 1997-2007 by Easy Software Products. |
7 | | * |
8 | | * This file contains Kerberos support code, copyright 2006 by |
9 | | * Jelmer Vernooij. |
10 | | * |
11 | | * Licensed under Apache License v2.0. See the file "LICENSE" for more |
12 | | * information. |
13 | | */ |
14 | | |
15 | | #include "cups-private.h" |
16 | | #include "debug-internal.h" |
17 | | #include <fcntl.h> |
18 | | #include <sys/stat.h> |
19 | | #if defined(_WIN32) || defined(__EMX__) |
20 | | # include <io.h> |
21 | | #else |
22 | | # include <unistd.h> |
23 | | #endif /* _WIN32 || __EMX__ */ |
24 | | |
25 | | #if HAVE_AUTHORIZATION_H |
26 | | # include <Security/Authorization.h> |
27 | | #endif /* HAVE_AUTHORIZATION_H */ |
28 | | |
29 | | #if defined(SO_PEERCRED) && defined(AF_LOCAL) |
30 | | # include <pwd.h> |
31 | | #endif /* SO_PEERCRED && AF_LOCAL */ |
32 | | |
33 | | |
34 | | /* |
35 | | * Local functions... |
36 | | */ |
37 | | |
38 | | static const char *cups_auth_find(const char *www_authenticate, const char *scheme); |
39 | | static const char *cups_auth_param(const char *scheme, const char *name, char *value, size_t valsize); |
40 | | static const char *cups_auth_scheme(const char *www_authenticate, char *scheme, size_t schemesize); |
41 | | |
42 | | #ifdef HAVE_GSSAPI |
43 | | # define CUPS_GSS_OK 0 /* Successfully set credentials */ |
44 | | # define CUPS_GSS_NONE -1 /* No credentials */ |
45 | | # define CUPS_GSS_FAIL -2 /* Failed credentials/authentication */ |
46 | | # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F |
47 | | # ifdef HAVE_GSS_GSSAPI_SPI_H |
48 | | # include <GSS/gssapi_spi.h> |
49 | | # else |
50 | | # define GSS_AUTH_IDENTITY_TYPE_1 1 |
51 | | # define gss_acquire_cred_ex_f __ApplePrivate_gss_acquire_cred_ex_f |
52 | | typedef struct gss_auth_identity /* @private@ */ |
53 | | { |
54 | | uint32_t type; |
55 | | uint32_t flags; |
56 | | char *username; |
57 | | char *realm; |
58 | | char *password; |
59 | | gss_buffer_t *credentialsRef; |
60 | | } gss_auth_identity_desc; |
61 | | extern OM_uint32 gss_acquire_cred_ex_f(gss_status_id_t, const gss_name_t, |
62 | | OM_uint32, OM_uint32, const gss_OID, |
63 | | gss_cred_usage_t, gss_auth_identity_t, |
64 | | void *, void (*)(void *, OM_uint32, |
65 | | gss_status_id_t, |
66 | | gss_cred_id_t, |
67 | | gss_OID_set, |
68 | | OM_uint32)); |
69 | | # endif /* HAVE_GSS_GSSAPI_SPI_H */ |
70 | | # include <dispatch/dispatch.h> |
71 | | typedef struct _cups_gss_acquire_s /* Acquire callback data */ |
72 | | { |
73 | | dispatch_semaphore_t sem; /* Synchronization semaphore */ |
74 | | OM_uint32 major; /* Returned status code */ |
75 | | gss_cred_id_t creds; /* Returned credentials */ |
76 | | } _cups_gss_acquire_t; |
77 | | |
78 | | static void cups_gss_acquire(void *ctx, OM_uint32 major, |
79 | | gss_status_id_t status, |
80 | | gss_cred_id_t creds, gss_OID_set oids, |
81 | | OM_uint32 time_rec); |
82 | | # endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */ |
83 | | static gss_name_t cups_gss_getname(http_t *http, const char *service_name); |
84 | | # ifdef DEBUG |
85 | | static void cups_gss_printf(OM_uint32 major_status, OM_uint32 minor_status, |
86 | | const char *message); |
87 | | # else |
88 | | # define cups_gss_printf(major, minor, message) |
89 | | # endif /* DEBUG */ |
90 | | #endif /* HAVE_GSSAPI */ |
91 | | static int cups_is_local_connection(http_t *http); |
92 | | static int cups_local_auth(http_t *http); |
93 | | |
94 | | |
95 | | /* |
96 | | * 'cupsDoAuthentication()' - Authenticate a request. |
97 | | * |
98 | | * This function should be called in response to a @code HTTP_STATUS_UNAUTHORIZED@ |
99 | | * status, prior to resubmitting your request. |
100 | | * |
101 | | * @since CUPS 1.1.20@ |
102 | | */ |
103 | | |
104 | | int /* O - 0 on success, -1 on error */ |
105 | | cupsDoAuthentication( |
106 | | http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ |
107 | | const char *method, /* I - Request method ("GET", "POST", "PUT") */ |
108 | | const char *resource) /* I - Resource path */ |
109 | 0 | { |
110 | 0 | const char *password, /* Password string */ |
111 | 0 | *www_auth, /* WWW-Authenticate header */ |
112 | 0 | *schemedata; /* Scheme-specific data */ |
113 | 0 | char scheme[256], /* Scheme name */ |
114 | 0 | prompt[1024]; /* Prompt for user */ |
115 | 0 | int localauth; /* Local authentication result */ |
116 | 0 | _cups_globals_t *cg = _cupsGlobals(); /* Global data */ |
117 | | |
118 | |
|
119 | 0 | DEBUG_printf("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")", (void *)http, method, resource); |
120 | |
|
121 | 0 | if (!http) |
122 | 0 | http = _cupsConnect(); |
123 | |
|
124 | 0 | if (!http || !method || !resource) |
125 | 0 | return (-1); |
126 | | |
127 | 0 | DEBUG_printf("2cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"", http->digest_tries, http->userpass); |
128 | 0 | DEBUG_printf("2cupsDoAuthentication: WWW-Authenticate=\"%s\"", httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE)); |
129 | | |
130 | | /* |
131 | | * Clear the current authentication string... |
132 | | */ |
133 | |
|
134 | 0 | httpSetAuthString(http, NULL, NULL); |
135 | | |
136 | | /* |
137 | | * See if we can do local authentication... |
138 | | */ |
139 | |
|
140 | 0 | if (http->digest_tries < 3) |
141 | 0 | { |
142 | 0 | if ((localauth = cups_local_auth(http)) == 0) |
143 | 0 | { |
144 | 0 | DEBUG_printf("2cupsDoAuthentication: authstring=\"%s\"", http->authstring); |
145 | |
|
146 | 0 | if (http->status == HTTP_STATUS_UNAUTHORIZED) |
147 | 0 | http->digest_tries ++; |
148 | |
|
149 | 0 | return (0); |
150 | 0 | } |
151 | 0 | else if (localauth == -1) |
152 | 0 | { |
153 | 0 | http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; |
154 | 0 | return (-1); /* Error or canceled */ |
155 | 0 | } |
156 | 0 | } |
157 | | |
158 | | /* |
159 | | * Nope, loop through the authentication schemes to find the first we support. |
160 | | */ |
161 | | |
162 | 0 | www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); |
163 | |
|
164 | 0 | for (schemedata = cups_auth_scheme(www_auth, scheme, sizeof(scheme)); schemedata; schemedata = cups_auth_scheme(schemedata + strlen(scheme), scheme, sizeof(scheme))) |
165 | 0 | { |
166 | | /* |
167 | | * Check the scheme name... |
168 | | */ |
169 | |
|
170 | 0 | DEBUG_printf("2cupsDoAuthentication: Trying scheme \"%s\"...", scheme); |
171 | |
|
172 | | #ifdef HAVE_GSSAPI |
173 | | if (!_cups_strcasecmp(scheme, "Negotiate") && !cups_is_local_connection(http)) |
174 | | { |
175 | | /* |
176 | | * Kerberos authentication to remote server... |
177 | | */ |
178 | | |
179 | | int gss_status; /* Auth status */ |
180 | | |
181 | | if ((gss_status = _cupsSetNegotiateAuthString(http, method, resource)) == CUPS_GSS_FAIL) |
182 | | { |
183 | | DEBUG_puts("1cupsDoAuthentication: Negotiate failed."); |
184 | | http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; |
185 | | return (-1); |
186 | | } |
187 | | else if (gss_status == CUPS_GSS_NONE) |
188 | | { |
189 | | DEBUG_puts("2cupsDoAuthentication: No credentials for Negotiate."); |
190 | | continue; |
191 | | } |
192 | | else |
193 | | { |
194 | | DEBUG_puts("2cupsDoAuthentication: Using Negotiate."); |
195 | | break; |
196 | | } |
197 | | } |
198 | | else |
199 | | #endif /* HAVE_GSSAPI */ |
200 | 0 | if (!_cups_strcasecmp(scheme, "Bearer")) |
201 | 0 | { |
202 | | // OAuth 2.0 (Bearer) authentication... |
203 | 0 | const char *bearer = NULL; /* Bearer token string, if any */ |
204 | |
|
205 | 0 | if (cg->oauth_cb) |
206 | 0 | { |
207 | | // Try callback... |
208 | 0 | char scope[HTTP_MAX_VALUE]; /* scope="xyz" string */ |
209 | |
|
210 | 0 | cups_auth_param(schemedata, "realm", http->realm, sizeof(http->realm)); |
211 | |
|
212 | 0 | if (cups_auth_param(schemedata, "scope", scope, sizeof(scope))) |
213 | 0 | bearer = (cg->oauth_cb)(http, http->realm, scope, resource, cg->oauth_data); |
214 | 0 | else |
215 | 0 | bearer = (cg->oauth_cb)(http, http->realm, NULL, resource, cg->oauth_data); |
216 | 0 | } |
217 | |
|
218 | 0 | if (bearer) |
219 | 0 | { |
220 | | // Use this access token... |
221 | 0 | httpSetAuthString(http, "Bearer", bearer); |
222 | 0 | break; |
223 | 0 | } |
224 | 0 | else |
225 | 0 | { |
226 | | // No access token, try the next scheme... |
227 | 0 | DEBUG_puts("2cupsDoAuthentication: No OAuth access token to provide."); |
228 | 0 | continue; |
229 | 0 | } |
230 | 0 | } |
231 | 0 | else if (_cups_strcasecmp(scheme, "Basic") && _cups_strcasecmp(scheme, "Digest") && _cups_strcasecmp(scheme, "Negotiate")) |
232 | 0 | { |
233 | | /* |
234 | | * Other schemes not yet supported... |
235 | | */ |
236 | |
|
237 | 0 | DEBUG_printf("2cupsDoAuthentication: Scheme \"%s\" not yet supported.", scheme); |
238 | 0 | continue; |
239 | 0 | } |
240 | | |
241 | | /* |
242 | | * See if we should retry the current username:password... |
243 | | */ |
244 | | |
245 | 0 | if (http->digest_tries > 1 || !http->userpass[0]) |
246 | 0 | { |
247 | | /* |
248 | | * Nope - get a new password from the user... |
249 | | */ |
250 | |
|
251 | 0 | char default_username[HTTP_MAX_VALUE]; |
252 | | /* Default username */ |
253 | |
|
254 | 0 | if (!cg->lang_default) |
255 | 0 | cg->lang_default = cupsLangDefault(); |
256 | |
|
257 | 0 | if (cups_auth_param(schemedata, "username", default_username, sizeof(default_username))) |
258 | 0 | cupsSetUser(default_username); |
259 | |
|
260 | 0 | snprintf(prompt, sizeof(prompt), _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), cupsGetUser(), http->hostname[0] == '/' ? "localhost" : http->hostname); |
261 | |
|
262 | 0 | http->digest_tries = _cups_strncasecmp(scheme, "Digest", 6) != 0; |
263 | 0 | http->userpass[0] = '\0'; |
264 | |
|
265 | 0 | if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL) |
266 | 0 | { |
267 | 0 | DEBUG_puts("1cupsDoAuthentication: User canceled password request."); |
268 | 0 | http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; |
269 | 0 | return (-1); |
270 | 0 | } |
271 | | |
272 | 0 | snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsGetUser(), password); |
273 | 0 | } |
274 | 0 | else if (http->status == HTTP_STATUS_UNAUTHORIZED) |
275 | 0 | http->digest_tries ++; |
276 | | |
277 | 0 | if (http->status == HTTP_STATUS_UNAUTHORIZED && http->digest_tries >= 3) |
278 | 0 | { |
279 | 0 | DEBUG_printf("1cupsDoAuthentication: Too many authentication tries (%d)", http->digest_tries); |
280 | |
|
281 | 0 | http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; |
282 | 0 | return (-1); |
283 | 0 | } |
284 | | |
285 | | /* |
286 | | * Got a password; encode it for the server... |
287 | | */ |
288 | | |
289 | 0 | if (!_cups_strcasecmp(scheme, "Basic")) |
290 | 0 | { |
291 | | /* |
292 | | * Basic authentication... |
293 | | */ |
294 | |
|
295 | 0 | char encode[256]; /* Base64 buffer */ |
296 | |
|
297 | 0 | DEBUG_puts("2cupsDoAuthentication: Using Basic."); |
298 | 0 | httpEncode64_2(encode, sizeof(encode), http->userpass, (int)strlen(http->userpass)); |
299 | 0 | httpSetAuthString(http, "Basic", encode); |
300 | 0 | break; |
301 | 0 | } |
302 | 0 | else if (!_cups_strcasecmp(scheme, "Digest")) |
303 | 0 | { |
304 | | /* |
305 | | * Digest authentication... |
306 | | */ |
307 | |
|
308 | 0 | char nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */ |
309 | |
|
310 | 0 | cups_auth_param(schemedata, "algorithm", http->algorithm, sizeof(http->algorithm)); |
311 | 0 | cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce)); |
312 | 0 | cups_auth_param(schemedata, "opaque", http->opaque, sizeof(http->opaque)); |
313 | 0 | cups_auth_param(schemedata, "qop", http->qop, sizeof(http->qop)); |
314 | 0 | cups_auth_param(schemedata, "realm", http->realm, sizeof(http->realm)); |
315 | |
|
316 | 0 | if (_httpSetDigestAuthString(http, nonce, method, resource)) |
317 | 0 | { |
318 | 0 | DEBUG_puts("2cupsDoAuthentication: Using Digest."); |
319 | 0 | break; |
320 | 0 | } |
321 | 0 | } |
322 | 0 | } |
323 | | |
324 | 0 | if (http->authstring && http->authstring[0]) |
325 | 0 | { |
326 | 0 | DEBUG_printf("1cupsDoAuthentication: authstring=\"%s\".", http->authstring); |
327 | |
|
328 | 0 | return (0); |
329 | 0 | } |
330 | 0 | else |
331 | 0 | { |
332 | 0 | DEBUG_puts("1cupsDoAuthentication: No supported schemes."); |
333 | 0 | http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; |
334 | |
|
335 | 0 | return (-1); |
336 | 0 | } |
337 | 0 | } |
338 | | |
339 | | |
340 | | #ifdef HAVE_GSSAPI |
341 | | /* |
342 | | * '_cupsSetNegotiateAuthString()' - Set the Kerberos authentication string. |
343 | | */ |
344 | | |
345 | | int /* O - 0 on success, negative on error */ |
346 | | _cupsSetNegotiateAuthString( |
347 | | http_t *http, /* I - Connection to server */ |
348 | | const char *method, /* I - Request method ("GET", "POST", "PUT") */ |
349 | | const char *resource) /* I - Resource path */ |
350 | | { |
351 | | OM_uint32 minor_status, /* Minor status code */ |
352 | | major_status; /* Major status code */ |
353 | | gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; |
354 | | /* Output token */ |
355 | | |
356 | | # ifdef __APPLE__ |
357 | | /* |
358 | | * If the weak-linked GSSAPI/Kerberos library is not present, don't try |
359 | | * to use it... |
360 | | */ |
361 | | |
362 | | if (&gss_init_sec_context == NULL) |
363 | | { |
364 | | DEBUG_puts("1_cupsSetNegotiateAuthString: Weak-linked GSSAPI/Kerberos " |
365 | | "framework is not present"); |
366 | | return (CUPS_GSS_NONE); |
367 | | } |
368 | | # endif /* __APPLE__ */ |
369 | | |
370 | | if (!strcmp(http->hostname, "localhost") || http->hostname[0] == '/' || isdigit(http->hostname[0] & 255) || !strchr(http->hostname, '.')) |
371 | | { |
372 | | DEBUG_printf("1_cupsSetNegotiateAuthString: Kerberos not available for host \"%s\".", http->hostname); |
373 | | return (CUPS_GSS_NONE); |
374 | | } |
375 | | |
376 | | if (http->gssname == GSS_C_NO_NAME) |
377 | | { |
378 | | http->gssname = cups_gss_getname(http, _cupsGSSServiceName()); |
379 | | } |
380 | | |
381 | | if (http->gssctx != GSS_C_NO_CONTEXT) |
382 | | { |
383 | | gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER); |
384 | | http->gssctx = GSS_C_NO_CONTEXT; |
385 | | } |
386 | | |
387 | | major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, |
388 | | &http->gssctx, |
389 | | http->gssname, http->gssmech, |
390 | | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG, |
391 | | GSS_C_INDEFINITE, |
392 | | GSS_C_NO_CHANNEL_BINDINGS, |
393 | | GSS_C_NO_BUFFER, &http->gssmech, |
394 | | &output_token, NULL, NULL); |
395 | | |
396 | | # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F |
397 | | if (major_status == GSS_S_NO_CRED) |
398 | | { |
399 | | /* |
400 | | * Ask the user for credentials... |
401 | | */ |
402 | | |
403 | | char prompt[1024], /* Prompt for user */ |
404 | | userbuf[256]; /* Kerberos username */ |
405 | | const char *username, /* Username string */ |
406 | | *password; /* Password string */ |
407 | | _cups_gss_acquire_t data; /* Callback data */ |
408 | | gss_auth_identity_desc identity; /* Kerberos user identity */ |
409 | | _cups_globals_t *cg = _cupsGlobals(); |
410 | | /* Per-thread global data */ |
411 | | |
412 | | if (!cg->lang_default) |
413 | | cg->lang_default = cupsLangDefault(); |
414 | | |
415 | | snprintf(prompt, sizeof(prompt), |
416 | | _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), |
417 | | cupsGetUser(), http->gsshost); |
418 | | |
419 | | if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL) |
420 | | return (CUPS_GSS_FAIL); |
421 | | |
422 | | /* |
423 | | * Try to acquire credentials... |
424 | | */ |
425 | | |
426 | | username = cupsGetUser(); |
427 | | if (!strchr(username, '@')) |
428 | | { |
429 | | snprintf(userbuf, sizeof(userbuf), "%s@%s", username, http->gsshost); |
430 | | username = userbuf; |
431 | | } |
432 | | |
433 | | identity.type = GSS_AUTH_IDENTITY_TYPE_1; |
434 | | identity.flags = 0; |
435 | | identity.username = (char *)username; |
436 | | identity.realm = (char *)""; |
437 | | identity.password = (char *)password; |
438 | | identity.credentialsRef = NULL; |
439 | | |
440 | | data.sem = dispatch_semaphore_create(0); |
441 | | data.major = 0; |
442 | | data.creds = NULL; |
443 | | |
444 | | if (data.sem) |
445 | | { |
446 | | major_status = gss_acquire_cred_ex_f(NULL, GSS_C_NO_NAME, 0, GSS_C_INDEFINITE, GSS_KRB5_MECHANISM, GSS_C_INITIATE, (gss_auth_identity_t)&identity, &data, cups_gss_acquire); |
447 | | |
448 | | if (major_status == GSS_S_COMPLETE) |
449 | | { |
450 | | dispatch_semaphore_wait(data.sem, DISPATCH_TIME_FOREVER); |
451 | | major_status = data.major; |
452 | | } |
453 | | |
454 | | dispatch_release(data.sem); |
455 | | |
456 | | if (major_status == GSS_S_COMPLETE) |
457 | | { |
458 | | OM_uint32 release_minor; /* Minor status from releasing creds */ |
459 | | |
460 | | major_status = gss_init_sec_context(&minor_status, data.creds, |
461 | | &http->gssctx, |
462 | | http->gssname, http->gssmech, |
463 | | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG, |
464 | | GSS_C_INDEFINITE, |
465 | | GSS_C_NO_CHANNEL_BINDINGS, |
466 | | GSS_C_NO_BUFFER, &http->gssmech, |
467 | | &output_token, NULL, NULL); |
468 | | gss_release_cred(&release_minor, &data.creds); |
469 | | } |
470 | | } |
471 | | } |
472 | | # else |
473 | | (void)method; |
474 | | (void)resource; |
475 | | # endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */ |
476 | | |
477 | | if (major_status == GSS_S_NO_CRED) |
478 | | { |
479 | | cups_gss_printf(major_status, minor_status, "_cupsSetNegotiateAuthString: No credentials"); |
480 | | return (CUPS_GSS_NONE); |
481 | | } |
482 | | else if (GSS_ERROR(major_status)) |
483 | | { |
484 | | cups_gss_printf(major_status, minor_status, "_cupsSetNegotiateAuthString: Unable to initialize security context"); |
485 | | return (CUPS_GSS_FAIL); |
486 | | } |
487 | | |
488 | | # ifdef DEBUG |
489 | | else if (major_status == GSS_S_CONTINUE_NEEDED) |
490 | | cups_gss_printf(major_status, minor_status, "_cupsSetNegotiateAuthString: Continuation needed"); |
491 | | # endif /* DEBUG */ |
492 | | |
493 | | if (output_token.length > 0 && output_token.length <= 65536) |
494 | | { |
495 | | /* |
496 | | * Allocate the authorization string since Windows KDCs can have |
497 | | * arbitrarily large credentials... |
498 | | */ |
499 | | |
500 | | int authsize = 10 + /* "Negotiate " */ |
501 | | (((int)output_token.length * 4 / 3 + 3) & ~3) + 1; |
502 | | /* Base64 + nul */ |
503 | | |
504 | | httpSetAuthString(http, NULL, NULL); |
505 | | |
506 | | if ((http->authstring = malloc((size_t)authsize)) == NULL) |
507 | | { |
508 | | http->authstring = http->_authstring; |
509 | | authsize = sizeof(http->_authstring); |
510 | | } |
511 | | |
512 | | cupsCopyString(http->authstring, "Negotiate ", (size_t)authsize); |
513 | | httpEncode64_2(http->authstring + 10, authsize - 10, output_token.value, |
514 | | (int)output_token.length); |
515 | | |
516 | | gss_release_buffer(&minor_status, &output_token); |
517 | | } |
518 | | else |
519 | | { |
520 | | DEBUG_printf("1_cupsSetNegotiateAuthString: Kerberos credentials too large - %d bytes!", (int)output_token.length); |
521 | | gss_release_buffer(&minor_status, &output_token); |
522 | | |
523 | | return (CUPS_GSS_FAIL); |
524 | | } |
525 | | |
526 | | return (CUPS_GSS_OK); |
527 | | } |
528 | | #endif /* HAVE_GSSAPI */ |
529 | | |
530 | | |
531 | | /* |
532 | | * 'cups_auth_find()' - Find the named WWW-Authenticate scheme. |
533 | | * |
534 | | * The "www_authenticate" parameter points to the current position in the header. |
535 | | * |
536 | | * Returns @code NULL@ if the auth scheme is not present. |
537 | | */ |
538 | | |
539 | | static const char * /* O - Start of matching scheme or @code NULL@ if not found */ |
540 | | cups_auth_find(const char *www_authenticate, /* I - Pointer into WWW-Authenticate header */ |
541 | | const char *scheme) /* I - Authentication scheme */ |
542 | 0 | { |
543 | 0 | size_t schemelen = strlen(scheme); /* Length of scheme */ |
544 | | |
545 | |
|
546 | 0 | DEBUG_printf("8cups_auth_find(www_authenticate=\"%s\", scheme=\"%s\"(%d))", www_authenticate, scheme, (int)schemelen); |
547 | |
|
548 | 0 | while (*www_authenticate) |
549 | 0 | { |
550 | | /* |
551 | | * Skip leading whitespace and commas... |
552 | | */ |
553 | |
|
554 | 0 | DEBUG_printf("9cups_auth_find: Before whitespace: \"%s\"", www_authenticate); |
555 | 0 | while (isspace(*www_authenticate & 255) || *www_authenticate == ',') |
556 | 0 | www_authenticate ++; |
557 | 0 | DEBUG_printf("9cups_auth_find: After whitespace: \"%s\"", www_authenticate); |
558 | | |
559 | | /* |
560 | | * See if this is "Scheme" followed by whitespace or the end of the string. |
561 | | */ |
562 | |
|
563 | 0 | if (!strncmp(www_authenticate, scheme, schemelen) && (isspace(www_authenticate[schemelen] & 255) || www_authenticate[schemelen] == ',' || !www_authenticate[schemelen])) |
564 | 0 | { |
565 | | /* |
566 | | * Yes, this is the start of the scheme-specific information... |
567 | | */ |
568 | |
|
569 | 0 | DEBUG_printf("9cups_auth_find: Returning \"%s\".", www_authenticate); |
570 | |
|
571 | 0 | return (www_authenticate); |
572 | 0 | } |
573 | | |
574 | | /* |
575 | | * Skip the scheme name or param="value" string... |
576 | | */ |
577 | | |
578 | 0 | while (!isspace(*www_authenticate & 255) && *www_authenticate) |
579 | 0 | { |
580 | 0 | if (*www_authenticate == '\"') |
581 | 0 | { |
582 | | /* |
583 | | * Skip quoted value... |
584 | | */ |
585 | |
|
586 | 0 | www_authenticate ++; |
587 | 0 | while (*www_authenticate && *www_authenticate != '\"') |
588 | 0 | www_authenticate ++; |
589 | |
|
590 | 0 | DEBUG_printf("9cups_auth_find: After quoted: \"%s\"", www_authenticate); |
591 | 0 | } |
592 | |
|
593 | 0 | www_authenticate ++; |
594 | 0 | } |
595 | |
|
596 | 0 | DEBUG_printf("9cups_auth_find: After skip: \"%s\"", www_authenticate); |
597 | 0 | } |
598 | | |
599 | 0 | DEBUG_puts("9cups_auth_find: Returning NULL."); |
600 | |
|
601 | 0 | return (NULL); |
602 | 0 | } |
603 | | |
604 | | |
605 | | /* |
606 | | * 'cups_auth_param()' - Copy the value for the named authentication parameter, |
607 | | * if present. |
608 | | */ |
609 | | |
610 | | static const char * /* O - Parameter value or @code NULL@ if not present */ |
611 | | cups_auth_param(const char *scheme, /* I - Pointer to auth data */ |
612 | | const char *name, /* I - Name of parameter */ |
613 | | char *value, /* I - Value buffer */ |
614 | | size_t valsize) /* I - Size of value buffer */ |
615 | 0 | { |
616 | 0 | char *valptr = value, /* Pointer into value buffer */ |
617 | 0 | *valend = value + valsize - 1; /* Pointer to end of buffer */ |
618 | 0 | size_t namelen = strlen(name); /* Name length */ |
619 | 0 | int param; /* Is this a parameter? */ |
620 | | |
621 | |
|
622 | 0 | DEBUG_printf("8cups_auth_param(scheme=\"%s\", name=\"%s\", value=%p, valsize=%d)", scheme, name, (void *)value, (int)valsize); |
623 | |
|
624 | 0 | while (!isspace(*scheme & 255) && *scheme) |
625 | 0 | scheme ++; |
626 | |
|
627 | 0 | while (*scheme) |
628 | 0 | { |
629 | 0 | while (isspace(*scheme & 255) || *scheme == ',') |
630 | 0 | scheme ++; |
631 | |
|
632 | 0 | if (!strncmp(scheme, name, namelen) && scheme[namelen] == '=') |
633 | 0 | { |
634 | | /* |
635 | | * Found the parameter, copy the value... |
636 | | */ |
637 | |
|
638 | 0 | scheme += namelen + 1; |
639 | 0 | if (*scheme == '\"') |
640 | 0 | { |
641 | 0 | scheme ++; |
642 | |
|
643 | 0 | while (*scheme && *scheme != '\"') |
644 | 0 | { |
645 | 0 | if (valptr < valend) |
646 | 0 | *valptr++ = *scheme; |
647 | |
|
648 | 0 | scheme ++; |
649 | 0 | } |
650 | 0 | } |
651 | 0 | else |
652 | 0 | { |
653 | 0 | while (*scheme && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~+/=", *scheme)) |
654 | 0 | { |
655 | 0 | if (valptr < valend) |
656 | 0 | *valptr++ = *scheme; |
657 | |
|
658 | 0 | scheme ++; |
659 | 0 | } |
660 | 0 | } |
661 | |
|
662 | 0 | *valptr = '\0'; |
663 | |
|
664 | 0 | DEBUG_printf("9cups_auth_param: Returning \"%s\".", value); |
665 | |
|
666 | 0 | return (value); |
667 | 0 | } |
668 | | |
669 | | /* |
670 | | * Skip the param=value string... |
671 | | */ |
672 | | |
673 | 0 | param = 0; |
674 | |
|
675 | 0 | while (!isspace(*scheme & 255) && *scheme) |
676 | 0 | { |
677 | 0 | if (*scheme == '=') |
678 | 0 | param = 1; |
679 | 0 | else if (*scheme == '\"') |
680 | 0 | { |
681 | | /* |
682 | | * Skip quoted value... |
683 | | */ |
684 | |
|
685 | 0 | scheme ++; |
686 | 0 | while (*scheme && *scheme != '\"') |
687 | 0 | scheme ++; |
688 | 0 | } |
689 | |
|
690 | 0 | scheme ++; |
691 | 0 | } |
692 | | |
693 | | /* |
694 | | * If this wasn't a parameter, we are at the end of this scheme's |
695 | | * parameters... |
696 | | */ |
697 | |
|
698 | 0 | if (!param) |
699 | 0 | break; |
700 | 0 | } |
701 | | |
702 | 0 | *value = '\0'; |
703 | |
|
704 | 0 | DEBUG_puts("9cups_auth_param: Returning NULL."); |
705 | |
|
706 | 0 | return (NULL); |
707 | 0 | } |
708 | | |
709 | | |
710 | | /* |
711 | | * 'cups_auth_scheme()' - Get the (next) WWW-Authenticate scheme. |
712 | | * |
713 | | * The "www_authenticate" parameter points to the current position in the header. |
714 | | * |
715 | | * Returns @code NULL@ if there are no (more) auth schemes present. |
716 | | */ |
717 | | |
718 | | static const char * /* O - Start of scheme or @code NULL@ if not found */ |
719 | | cups_auth_scheme(const char *www_authenticate, /* I - Pointer into WWW-Authenticate header */ |
720 | | char *scheme, /* I - Scheme name buffer */ |
721 | | size_t schemesize) /* I - Size of buffer */ |
722 | 0 | { |
723 | 0 | const char *start; /* Start of scheme data */ |
724 | 0 | char *sptr = scheme, /* Pointer into scheme buffer */ |
725 | 0 | *send = scheme + schemesize - 1;/* End of scheme buffer */ |
726 | 0 | int param; /* Is this a parameter? */ |
727 | | |
728 | |
|
729 | 0 | DEBUG_printf("8cups_auth_scheme(www_authenticate=\"%s\", scheme=%p, schemesize=%u)", www_authenticate, (void *)scheme, (unsigned)schemesize); |
730 | |
|
731 | 0 | while (*www_authenticate) |
732 | 0 | { |
733 | | /* |
734 | | * Skip leading whitespace and commas... |
735 | | */ |
736 | |
|
737 | 0 | while (isspace(*www_authenticate & 255) || *www_authenticate == ',') |
738 | 0 | www_authenticate ++; |
739 | | |
740 | | /* |
741 | | * Parse the scheme name or param="value" string... |
742 | | */ |
743 | |
|
744 | 0 | for (sptr = scheme, start = www_authenticate, param = 0; *www_authenticate && *www_authenticate != ',' && !isspace(*www_authenticate & 255); www_authenticate ++) |
745 | 0 | { |
746 | 0 | if (*www_authenticate == '=') |
747 | 0 | param = 1; |
748 | 0 | else if (!param && sptr < send) |
749 | 0 | *sptr++ = *www_authenticate; |
750 | 0 | else if (*www_authenticate == '\"') |
751 | 0 | { |
752 | | /* |
753 | | * Skip quoted value... |
754 | | */ |
755 | | |
756 | |
|
757 | 0 | do |
758 | 0 | www_authenticate ++; |
759 | 0 | while (*www_authenticate && *www_authenticate != '\"'); |
760 | 0 | } |
761 | 0 | } |
762 | |
|
763 | 0 | if (sptr > scheme && !param) |
764 | 0 | { |
765 | 0 | *sptr = '\0'; |
766 | |
|
767 | 0 | DEBUG_printf("9cups_auth_scheme: Returning \"%s\".", start); |
768 | |
|
769 | 0 | return (start); |
770 | 0 | } |
771 | 0 | } |
772 | | |
773 | 0 | *scheme = '\0'; |
774 | |
|
775 | 0 | DEBUG_puts("9cups_auth_scheme: Returning NULL."); |
776 | |
|
777 | 0 | return (NULL); |
778 | 0 | } |
779 | | |
780 | | |
781 | | #ifdef HAVE_GSSAPI |
782 | | # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F |
783 | | /* |
784 | | * 'cups_gss_acquire()' - Kerberos credentials callback. |
785 | | */ |
786 | | static void |
787 | | cups_gss_acquire( |
788 | | void *ctx, /* I - Caller context */ |
789 | | OM_uint32 major, /* I - Major error code */ |
790 | | gss_status_id_t status, /* I - Status (unused) */ |
791 | | gss_cred_id_t creds, /* I - Credentials (if any) */ |
792 | | gss_OID_set oids, /* I - Mechanism OIDs (unused) */ |
793 | | OM_uint32 time_rec) /* I - Timestamp (unused) */ |
794 | | { |
795 | | uint32_t min; /* Minor error code */ |
796 | | _cups_gss_acquire_t *data; /* Callback data */ |
797 | | |
798 | | |
799 | | (void)status; |
800 | | (void)time_rec; |
801 | | |
802 | | data = (_cups_gss_acquire_t *)ctx; |
803 | | data->major = major; |
804 | | data->creds = creds; |
805 | | |
806 | | gss_release_oid_set(&min, &oids); |
807 | | dispatch_semaphore_signal(data->sem); |
808 | | } |
809 | | # endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */ |
810 | | |
811 | | |
812 | | /* |
813 | | * 'cups_gss_getname()' - Get CUPS service credentials for authentication. |
814 | | */ |
815 | | |
816 | | static gss_name_t /* O - Server name */ |
817 | | cups_gss_getname( |
818 | | http_t *http, /* I - Connection to server */ |
819 | | const char *service_name) /* I - Service name */ |
820 | | { |
821 | | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; |
822 | | /* Service token */ |
823 | | OM_uint32 major_status, /* Major status code */ |
824 | | minor_status; /* Minor status code */ |
825 | | gss_name_t server_name; /* Server name */ |
826 | | char buf[1024]; /* Name buffer */ |
827 | | |
828 | | |
829 | | DEBUG_printf("7cups_gss_getname(http=%p, service_name=\"%s\")", (void *)http, service_name); |
830 | | |
831 | | /* |
832 | | * Get the hostname... |
833 | | */ |
834 | | |
835 | | if (!http->gsshost[0]) |
836 | | { |
837 | | httpGetHostname(http, http->gsshost, sizeof(http->gsshost)); |
838 | | |
839 | | if (!strcmp(http->gsshost, "localhost")) |
840 | | { |
841 | | if (gethostname(http->gsshost, sizeof(http->gsshost)) < 0) |
842 | | { |
843 | | DEBUG_printf("1cups_gss_getname: gethostname() failed: %s", strerror(errno)); |
844 | | http->gsshost[0] = '\0'; |
845 | | return (NULL); |
846 | | } |
847 | | |
848 | | if (!strchr(http->gsshost, '.')) |
849 | | { |
850 | | /* |
851 | | * The hostname is not a FQDN, so look it up... |
852 | | */ |
853 | | |
854 | | struct hostent *host; /* Host entry to get FQDN */ |
855 | | |
856 | | if ((host = gethostbyname(http->gsshost)) != NULL && host->h_name) |
857 | | { |
858 | | /* |
859 | | * Use the resolved hostname... |
860 | | */ |
861 | | |
862 | | cupsCopyString(http->gsshost, host->h_name, sizeof(http->gsshost)); |
863 | | } |
864 | | else |
865 | | { |
866 | | DEBUG_printf("1cups_gss_getname: gethostbyname(\"%s\") failed.", http->gsshost); |
867 | | http->gsshost[0] = '\0'; |
868 | | return (NULL); |
869 | | } |
870 | | } |
871 | | } |
872 | | } |
873 | | |
874 | | /* |
875 | | * Get a service name we can use for authentication purposes... |
876 | | */ |
877 | | |
878 | | snprintf(buf, sizeof(buf), "%s@%s", service_name, http->gsshost); |
879 | | |
880 | | DEBUG_printf("8cups_gss_getname: Looking up \"%s\".", buf); |
881 | | |
882 | | token.value = buf; |
883 | | token.length = strlen(buf); |
884 | | server_name = GSS_C_NO_NAME; |
885 | | major_status = gss_import_name(&minor_status, &token, |
886 | | GSS_C_NT_HOSTBASED_SERVICE, |
887 | | &server_name); |
888 | | |
889 | | if (GSS_ERROR(major_status)) |
890 | | { |
891 | | cups_gss_printf(major_status, minor_status, |
892 | | "cups_gss_getname: gss_import_name() failed"); |
893 | | return (NULL); |
894 | | } |
895 | | |
896 | | return (server_name); |
897 | | } |
898 | | |
899 | | |
900 | | # ifdef DEBUG |
901 | | /* |
902 | | * 'cups_gss_printf()' - Show debug error messages from GSSAPI. |
903 | | */ |
904 | | |
905 | | static void |
906 | | cups_gss_printf(OM_uint32 major_status,/* I - Major status code */ |
907 | | OM_uint32 minor_status,/* I - Minor status code */ |
908 | | const char *message) /* I - Prefix for error message */ |
909 | | { |
910 | | OM_uint32 err_major_status, /* Major status code for display */ |
911 | | err_minor_status; /* Minor status code for display */ |
912 | | OM_uint32 msg_ctx; /* Message context */ |
913 | | gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER, |
914 | | /* Major status message */ |
915 | | minor_status_string = GSS_C_EMPTY_BUFFER; |
916 | | /* Minor status message */ |
917 | | |
918 | | |
919 | | msg_ctx = 0; |
920 | | err_major_status = gss_display_status(&err_minor_status, |
921 | | major_status, |
922 | | GSS_C_GSS_CODE, |
923 | | GSS_C_NO_OID, |
924 | | &msg_ctx, |
925 | | &major_status_string); |
926 | | |
927 | | if (!GSS_ERROR(err_major_status)) |
928 | | gss_display_status(&err_minor_status, minor_status, GSS_C_MECH_CODE, |
929 | | GSS_C_NULL_OID, &msg_ctx, &minor_status_string); |
930 | | |
931 | | DEBUG_printf("1%s: %s, %s", message, (char *)major_status_string.value, (char *)minor_status_string.value); |
932 | | |
933 | | gss_release_buffer(&err_minor_status, &major_status_string); |
934 | | gss_release_buffer(&err_minor_status, &minor_status_string); |
935 | | } |
936 | | # endif /* DEBUG */ |
937 | | #endif /* HAVE_GSSAPI */ |
938 | | |
939 | | static int /* O - 0 if not a local connection */ |
940 | | /* 1 if local connection */ |
941 | | cups_is_local_connection(http_t *http) /* I - HTTP connection to server */ |
942 | 0 | { |
943 | 0 | if (!httpAddrLocalhost(http->hostaddr) && _cups_strcasecmp(http->hostname, "localhost") != 0) |
944 | 0 | return 0; |
945 | 0 | return 1; |
946 | 0 | } |
947 | | |
948 | | /* |
949 | | * 'cups_local_auth()' - Get the local authorization certificate if |
950 | | * available/applicable. |
951 | | */ |
952 | | |
953 | | static int /* O - 0 if available */ |
954 | | /* 1 if not available */ |
955 | | /* -1 error */ |
956 | | cups_local_auth(http_t *http) /* I - HTTP connection to server */ |
957 | 0 | { |
958 | | #if defined(_WIN32) || defined(__EMX__) |
959 | | /* |
960 | | * Currently _WIN32 and OS-2 do not support the CUPS server... |
961 | | */ |
962 | | |
963 | | return (1); |
964 | | #else |
965 | 0 | int pid; /* Current process ID */ |
966 | 0 | FILE *fp; /* Certificate file */ |
967 | 0 | char trc[16], /* Try Root Certificate parameter */ |
968 | 0 | filename[1024]; /* Certificate filename */ |
969 | 0 | const char *www_auth, /* WWW-Authenticate header */ |
970 | 0 | *schemedata; /* Data for the named auth scheme */ |
971 | 0 | _cups_globals_t *cg = _cupsGlobals(); /* Global data */ |
972 | | # if defined(HAVE_AUTHORIZATION_H) |
973 | | OSStatus status; /* Status */ |
974 | | AuthorizationItem auth_right; /* Authorization right */ |
975 | | AuthorizationRights auth_rights; /* Authorization rights */ |
976 | | AuthorizationFlags auth_flags; /* Authorization flags */ |
977 | | AuthorizationExternalForm auth_extrn; /* Authorization ref external */ |
978 | | char auth_key[1024]; /* Buffer */ |
979 | | char buffer[1024]; /* Buffer */ |
980 | | # endif /* HAVE_AUTHORIZATION_H */ |
981 | | |
982 | |
|
983 | 0 | DEBUG_printf("7cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"", (void *)http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname); |
984 | | |
985 | | /* |
986 | | * See if we are accessing localhost... |
987 | | */ |
988 | |
|
989 | 0 | if (!cups_is_local_connection(http)) |
990 | 0 | { |
991 | 0 | DEBUG_puts("8cups_local_auth: Not a local connection!"); |
992 | 0 | return (1); |
993 | 0 | } |
994 | | |
995 | 0 | www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); |
996 | |
|
997 | | # if defined(HAVE_AUTHORIZATION_H) |
998 | | /* |
999 | | * Delete any previous authorization reference... |
1000 | | */ |
1001 | | |
1002 | | if (http->auth_ref) |
1003 | | { |
1004 | | AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults); |
1005 | | http->auth_ref = NULL; |
1006 | | } |
1007 | | |
1008 | | if (!getenv("GATEWAY_INTERFACE") && (schemedata = cups_auth_find(www_auth, "AuthRef")) != NULL && cups_auth_param(schemedata, "key", auth_key, sizeof(auth_key))) |
1009 | | { |
1010 | | status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &http->auth_ref); |
1011 | | if (status != errAuthorizationSuccess) |
1012 | | { |
1013 | | DEBUG_printf("8cups_local_auth: AuthorizationCreate() returned %d", (int)status); |
1014 | | return (-1); |
1015 | | } |
1016 | | |
1017 | | auth_right.name = auth_key; |
1018 | | auth_right.valueLength = 0; |
1019 | | auth_right.value = NULL; |
1020 | | auth_right.flags = 0; |
1021 | | |
1022 | | auth_rights.count = 1; |
1023 | | auth_rights.items = &auth_right; |
1024 | | |
1025 | | auth_flags = kAuthorizationFlagDefaults | |
1026 | | kAuthorizationFlagPreAuthorize | |
1027 | | kAuthorizationFlagInteractionAllowed | |
1028 | | kAuthorizationFlagExtendRights; |
1029 | | |
1030 | | status = AuthorizationCopyRights(http->auth_ref, &auth_rights, |
1031 | | kAuthorizationEmptyEnvironment, |
1032 | | auth_flags, NULL); |
1033 | | if (status == errAuthorizationSuccess) |
1034 | | status = AuthorizationMakeExternalForm(http->auth_ref, &auth_extrn); |
1035 | | |
1036 | | if (status == errAuthorizationSuccess) |
1037 | | { |
1038 | | /* |
1039 | | * Set the authorization string and return... |
1040 | | */ |
1041 | | |
1042 | | httpEncode64_2(buffer, sizeof(buffer), (void *)&auth_extrn, |
1043 | | sizeof(auth_extrn)); |
1044 | | |
1045 | | httpSetAuthString(http, "AuthRef", buffer); |
1046 | | |
1047 | | DEBUG_printf("8cups_local_auth: Returning authstring=\"%s\"", http->authstring); |
1048 | | return (0); |
1049 | | } |
1050 | | else if (status == errAuthorizationCanceled) |
1051 | | return (-1); |
1052 | | |
1053 | | DEBUG_printf("9cups_local_auth: AuthorizationCopyRights() returned %d", (int)status); |
1054 | | |
1055 | | /* |
1056 | | * Fall through to try certificates... |
1057 | | */ |
1058 | | } |
1059 | | # endif /* HAVE_AUTHORIZATION_H */ |
1060 | |
|
1061 | 0 | # if defined(SO_PEERCRED) && defined(AF_LOCAL) |
1062 | | /* |
1063 | | * See if we can authenticate using the peer credentials provided over a |
1064 | | * domain socket; if so, specify "PeerCred username" as the authentication |
1065 | | * information... |
1066 | | */ |
1067 | |
|
1068 | 0 | if (http->hostaddr->addr.sa_family == AF_LOCAL && |
1069 | 0 | !getenv("GATEWAY_INTERFACE") && /* Not via CGI programs... */ |
1070 | 0 | cups_auth_find(www_auth, "PeerCred")) |
1071 | 0 | { |
1072 | | /* |
1073 | | * Verify that the current cupsGetUser() matches the current UID... |
1074 | | */ |
1075 | |
|
1076 | 0 | struct passwd pwd; /* Password information */ |
1077 | 0 | struct passwd *result; /* Auxiliary pointer */ |
1078 | 0 | const char *username; /* Current username */ |
1079 | |
|
1080 | 0 | username = cupsGetUser(); |
1081 | |
|
1082 | 0 | getpwnam_r(username, &pwd, cg->pw_buf, PW_BUF_SIZE, &result); |
1083 | 0 | if (result && pwd.pw_uid == getuid()) |
1084 | 0 | { |
1085 | 0 | httpSetAuthString(http, "PeerCred", username); |
1086 | |
|
1087 | 0 | DEBUG_printf("8cups_local_auth: Returning authstring=\"%s\"", http->authstring); |
1088 | |
|
1089 | 0 | return (0); |
1090 | 0 | } |
1091 | 0 | } |
1092 | 0 | # endif /* SO_PEERCRED && AF_LOCAL */ |
1093 | | |
1094 | 0 | if ((schemedata = cups_auth_find(www_auth, "Local")) == NULL) |
1095 | 0 | return (1); |
1096 | | |
1097 | | /* |
1098 | | * Try opening a certificate file for this PID. If that fails, |
1099 | | * try the root certificate... |
1100 | | */ |
1101 | | |
1102 | 0 | pid = getpid(); |
1103 | 0 | snprintf(filename, sizeof(filename), "%s/certs/%d", cg->cups_statedir, pid); |
1104 | 0 | if ((fp = fopen(filename, "r")) == NULL && pid > 0) |
1105 | 0 | { |
1106 | | /* |
1107 | | * No certificate for this PID; see if we can get the root certificate... |
1108 | | */ |
1109 | |
|
1110 | 0 | DEBUG_printf("9cups_local_auth: Unable to open file \"%s\": %s", filename, strerror(errno)); |
1111 | |
|
1112 | 0 | if (!cups_auth_param(schemedata, "trc", trc, sizeof(trc))) |
1113 | 0 | { |
1114 | | /* |
1115 | | * Scheduler doesn't want us to use the root certificate... |
1116 | | */ |
1117 | |
|
1118 | 0 | return (1); |
1119 | 0 | } |
1120 | | |
1121 | 0 | snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir); |
1122 | 0 | if ((fp = fopen(filename, "r")) == NULL) |
1123 | 0 | DEBUG_printf("9cups_local_auth: Unable to open file \"%s\": %s", filename, strerror(errno)); |
1124 | 0 | } |
1125 | | |
1126 | 0 | if (fp) |
1127 | 0 | { |
1128 | | /* |
1129 | | * Read the certificate from the file... |
1130 | | */ |
1131 | |
|
1132 | 0 | char certificate[33], /* Certificate string */ |
1133 | 0 | *certptr; /* Pointer to certificate string */ |
1134 | |
|
1135 | 0 | certptr = fgets(certificate, sizeof(certificate), fp); |
1136 | 0 | fclose(fp); |
1137 | |
|
1138 | 0 | if (certptr) |
1139 | 0 | { |
1140 | | /* |
1141 | | * Set the authorization string and return... |
1142 | | */ |
1143 | |
|
1144 | 0 | httpSetAuthString(http, "Local", certificate); |
1145 | |
|
1146 | 0 | DEBUG_printf("8cups_local_auth: Returning authstring=\"%s\"", http->authstring); |
1147 | |
|
1148 | 0 | return (0); |
1149 | 0 | } |
1150 | 0 | } |
1151 | | |
1152 | 0 | return (1); |
1153 | 0 | #endif /* _WIN32 || __EMX__ */ |
1154 | 0 | } |