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