]>
Commit | Line | Data |
---|---|---|
82cc1f9a MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
4 | * TLS support code for the CUPS scheduler on OS X. | |
5 | * | |
e1578ed9 | 6 | * Copyright 2007-2013 by Apple Inc. |
82cc1f9a MS |
7 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. |
8 | * | |
9 | * These coded instructions, statements, and computer programs are the | |
10 | * property of Apple Inc. and are protected by Federal copyright | |
11 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
12 | * which should have been included with this file. If this file is | |
13 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
14 | * | |
15 | * Contents: | |
16 | * | |
17 | * cupsdEndTLS() - Shutdown a secure session with the client. | |
18 | * cupsdStartTLS() - Start a secure session with the client. | |
19 | * copy_cdsa_certificate() - Copy a SSL/TLS certificate from the System | |
20 | * keychain. | |
21 | * make_certificate() - Make a self-signed SSL/TLS certificate. | |
22 | */ | |
23 | ||
24 | ||
25 | /* | |
26 | * Local functions... | |
27 | */ | |
28 | ||
29 | static CFArrayRef copy_cdsa_certificate(cupsd_client_t *con); | |
30 | static int make_certificate(cupsd_client_t *con); | |
31 | ||
32 | ||
33 | /* | |
34 | * 'cupsdEndTLS()' - Shutdown a secure session with the client. | |
35 | */ | |
36 | ||
37 | int /* O - 1 on success, 0 on error */ | |
38 | cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ | |
39 | { | |
40 | while (SSLClose(con->http.tls) == errSSLWouldBlock) | |
41 | usleep(1000); | |
42 | ||
cb7f98ee | 43 | CFRelease(con->http.tls); |
82cc1f9a MS |
44 | con->http.tls = NULL; |
45 | ||
46 | if (con->http.tls_credentials) | |
47 | CFRelease(con->http.tls_credentials); | |
48 | ||
49 | return (1); | |
50 | } | |
51 | ||
52 | ||
53 | /* | |
54 | * 'cupsdStartTLS()' - Start a secure session with the client. | |
55 | */ | |
56 | ||
57 | int /* O - 1 on success, 0 on error */ | |
58 | cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ | |
59 | { | |
60 | OSStatus error = 0; /* Error code */ | |
cb7f98ee | 61 | SecTrustRef peerTrust; /* Peer certificates */ |
82cc1f9a MS |
62 | |
63 | ||
64 | cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", | |
65 | con->http.fd); | |
66 | ||
67 | con->http.tls_credentials = copy_cdsa_certificate(con); | |
68 | ||
69 | if (!con->http.tls_credentials) | |
70 | { | |
71 | /* | |
72 | * No keychain (yet), make a self-signed certificate... | |
73 | */ | |
74 | ||
75 | if (make_certificate(con)) | |
76 | con->http.tls_credentials = copy_cdsa_certificate(con); | |
77 | } | |
78 | ||
79 | if (!con->http.tls_credentials) | |
80 | { | |
81 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
82 | "Could not find signing key in keychain \"%s\"", | |
83 | ServerCertificate); | |
84 | error = errSSLBadConfiguration; | |
85 | } | |
86 | ||
87 | if (!error) | |
cb7f98ee MS |
88 | con->http.tls = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, |
89 | kSSLStreamType); | |
82cc1f9a MS |
90 | |
91 | if (!error) | |
92 | error = SSLSetIOFuncs(con->http.tls, _httpReadCDSA, _httpWriteCDSA); | |
93 | ||
94 | if (!error) | |
95 | error = SSLSetConnection(con->http.tls, HTTP(con)); | |
96 | ||
82cc1f9a MS |
97 | if (!error) |
98 | error = SSLSetCertificate(con->http.tls, con->http.tls_credentials); | |
99 | ||
100 | if (!error) | |
101 | { | |
102 | /* | |
103 | * Perform SSL/TLS handshake | |
104 | */ | |
105 | ||
106 | while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock) | |
107 | usleep(1000); | |
108 | } | |
109 | ||
110 | if (error) | |
111 | { | |
112 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
113 | "Unable to encrypt connection from %s - %s (%d)", | |
114 | con->http.hostname, cssmErrorString(error), (int)error); | |
115 | ||
116 | con->http.error = error; | |
117 | con->http.status = HTTP_ERROR; | |
118 | ||
119 | if (con->http.tls) | |
120 | { | |
cb7f98ee | 121 | CFRelease(con->http.tls); |
82cc1f9a MS |
122 | con->http.tls = NULL; |
123 | } | |
124 | ||
125 | if (con->http.tls_credentials) | |
126 | { | |
127 | CFRelease(con->http.tls_credentials); | |
128 | con->http.tls_credentials = NULL; | |
129 | } | |
130 | ||
131 | return (0); | |
132 | } | |
133 | ||
134 | cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", | |
135 | con->http.hostname); | |
136 | ||
cb7f98ee | 137 | if (!SSLCopyPeerTrust(con->http.tls, &peerTrust) && peerTrust) |
82cc1f9a | 138 | { |
e1578ed9 | 139 | cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates.", |
cb7f98ee MS |
140 | (int)SecTrustGetCertificateCount(peerTrust)); |
141 | CFRelease(peerTrust); | |
82cc1f9a MS |
142 | } |
143 | else | |
e1578ed9 | 144 | cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates."); |
82cc1f9a MS |
145 | |
146 | return (1); | |
147 | } | |
148 | ||
149 | ||
150 | /* | |
151 | * 'copy_cdsa_certificate()' - Copy a SSL/TLS certificate from the System | |
152 | * keychain. | |
153 | */ | |
154 | ||
155 | static CFArrayRef /* O - Array of certificates */ | |
156 | copy_cdsa_certificate( | |
157 | cupsd_client_t *con) /* I - Client connection */ | |
158 | { | |
159 | OSStatus err; /* Error info */ | |
160 | SecKeychainRef keychain = NULL;/* Keychain reference */ | |
161 | SecIdentitySearchRef search = NULL; /* Search reference */ | |
162 | SecIdentityRef identity = NULL;/* Identity */ | |
163 | CFArrayRef certificates = NULL; | |
164 | /* Certificate array */ | |
82cc1f9a MS |
165 | SecPolicyRef policy = NULL; /* Policy ref */ |
166 | CFStringRef servername = NULL; | |
167 | /* Server name */ | |
168 | CFMutableDictionaryRef query = NULL; /* Query qualifiers */ | |
169 | CFArrayRef list = NULL; /* Keychain list */ | |
a29fd7dd | 170 | # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) |
82cc1f9a | 171 | char localname[1024];/* Local hostname */ |
a29fd7dd | 172 | # endif /* HAVE_DNSSD || HAVE_AVAHI */ |
82cc1f9a MS |
173 | |
174 | ||
175 | cupsdLogMessage(CUPSD_LOG_DEBUG, | |
e1578ed9 | 176 | "copy_cdsa_certificate: Looking for certs for \"%s\".", |
82cc1f9a MS |
177 | con->servername); |
178 | ||
179 | if ((err = SecKeychainOpen(ServerCertificate, &keychain))) | |
180 | { | |
181 | cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)", | |
182 | ServerCertificate, cssmErrorString(err), (int)err); | |
183 | goto cleanup; | |
184 | } | |
185 | ||
82cc1f9a MS |
186 | servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername, |
187 | kCFStringEncodingUTF8); | |
188 | ||
189 | policy = SecPolicyCreateSSL(1, servername); | |
190 | ||
191 | if (servername) | |
192 | CFRelease(servername); | |
193 | ||
194 | if (!policy) | |
195 | { | |
196 | cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); | |
197 | goto cleanup; | |
198 | } | |
199 | ||
200 | if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, | |
201 | &kCFTypeDictionaryKeyCallBacks, | |
202 | &kCFTypeDictionaryValueCallBacks))) | |
203 | { | |
204 | cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary"); | |
205 | goto cleanup; | |
206 | } | |
207 | ||
208 | list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, | |
209 | &kCFTypeArrayCallBacks); | |
210 | ||
211 | CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); | |
212 | CFDictionaryAddValue(query, kSecMatchPolicy, policy); | |
213 | CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); | |
214 | CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); | |
215 | CFDictionaryAddValue(query, kSecMatchSearchList, list); | |
216 | ||
217 | CFRelease(list); | |
218 | ||
219 | err = SecItemCopyMatching(query, (CFTypeRef *)&identity); | |
220 | ||
a29fd7dd | 221 | # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) |
82cc1f9a MS |
222 | if (err && DNSSDHostName) |
223 | { | |
224 | /* | |
225 | * Search for the connection server name failed; try the DNS-SD .local | |
226 | * hostname instead... | |
227 | */ | |
228 | ||
229 | snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); | |
230 | ||
231 | cupsdLogMessage(CUPSD_LOG_DEBUG, | |
e1578ed9 | 232 | "copy_cdsa_certificate: Looking for certs for \"%s\".", |
82cc1f9a MS |
233 | localname); |
234 | ||
235 | servername = CFStringCreateWithCString(kCFAllocatorDefault, localname, | |
236 | kCFStringEncodingUTF8); | |
237 | ||
238 | CFRelease(policy); | |
239 | ||
240 | policy = SecPolicyCreateSSL(1, servername); | |
241 | ||
242 | if (servername) | |
243 | CFRelease(servername); | |
244 | ||
245 | if (!policy) | |
246 | { | |
247 | cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); | |
248 | goto cleanup; | |
249 | } | |
250 | ||
251 | CFDictionarySetValue(query, kSecMatchPolicy, policy); | |
252 | ||
253 | err = SecItemCopyMatching(query, (CFTypeRef *)&identity); | |
254 | } | |
a29fd7dd | 255 | # endif /* HAVE_DNSSD || HAVE_AVAHI */ |
82cc1f9a MS |
256 | |
257 | if (err) | |
258 | { | |
259 | cupsdLogMessage(CUPSD_LOG_DEBUG, | |
260 | "Cannot find signing key in keychain \"%s\": %s (%d)", | |
261 | ServerCertificate, cssmErrorString(err), (int)err); | |
262 | goto cleanup; | |
263 | } | |
264 | ||
82cc1f9a MS |
265 | if (CFGetTypeID(identity) != SecIdentityGetTypeID()) |
266 | { | |
e1578ed9 | 267 | cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure."); |
82cc1f9a MS |
268 | goto cleanup; |
269 | } | |
270 | ||
271 | if ((certificates = CFArrayCreate(NULL, (const void **)&identity, | |
272 | 1, &kCFTypeArrayCallBacks)) == NULL) | |
273 | { | |
274 | cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array"); | |
275 | goto cleanup; | |
276 | } | |
277 | ||
278 | cleanup : | |
279 | ||
280 | if (keychain) | |
281 | CFRelease(keychain); | |
282 | if (search) | |
283 | CFRelease(search); | |
284 | if (identity) | |
285 | CFRelease(identity); | |
286 | ||
82cc1f9a MS |
287 | if (policy) |
288 | CFRelease(policy); | |
289 | if (query) | |
290 | CFRelease(query); | |
82cc1f9a MS |
291 | |
292 | return (certificates); | |
293 | } | |
294 | ||
295 | ||
296 | /* | |
297 | * 'make_certificate()' - Make a self-signed SSL/TLS certificate. | |
298 | */ | |
299 | ||
300 | static int /* O - 1 on success, 0 on failure */ | |
301 | make_certificate(cupsd_client_t *con) /* I - Client connection */ | |
302 | { | |
e1578ed9 MS |
303 | # ifdef HAVE_SECGENERATESELFSIGNEDCERTIFICATE |
304 | int status = 0; /* Return status */ | |
305 | OSStatus err; /* Error code (if any) */ | |
306 | # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) | |
307 | char localname[1024];/* Local hostname */ | |
308 | # endif /* HAVE_DNSSD || HAVE_AVAHI */ | |
309 | const char *servername; /* Name of server in cert */ | |
310 | CFStringRef cfservername = NULL; | |
311 | /* CF string for server name */ | |
312 | SecIdentityRef ident = NULL; /* Identity */ | |
313 | SecKeyRef publicKey = NULL, | |
314 | /* Public key */ | |
315 | privateKey = NULL; | |
316 | /* Private key */ | |
317 | CFMutableDictionaryRef keyParams = NULL; | |
318 | /* Key generation parameters */ | |
319 | ||
320 | ||
321 | cupsdLogMessage(CUPSD_LOG_INFO, | |
322 | "Generating SSL server key and certificate."); | |
323 | ||
324 | # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) | |
325 | if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) | |
326 | { | |
327 | snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); | |
328 | servername = localname; | |
329 | } | |
330 | else | |
331 | # endif /* HAVE_DNSSD || HAVE_AVAHI */ | |
332 | servername = con->servername; | |
333 | ||
334 | cfservername = CFStringCreateWithCString(kCFAllocatorDefault, servername, | |
335 | kCFStringEncodingUTF8); | |
336 | if (!cfservername) | |
337 | goto cleanup; | |
338 | ||
339 | /* | |
340 | * Create a public/private key pair... | |
341 | */ | |
342 | ||
343 | keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, | |
344 | &kCFTypeDictionaryKeyCallBacks, | |
345 | &kCFTypeDictionaryValueCallBacks); | |
346 | if (!keyParams) | |
347 | goto cleanup; | |
348 | ||
349 | CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA); | |
350 | CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048")); | |
351 | CFDictionaryAddValue(keyParams, kSecAttrLabel, | |
352 | CFSTR("CUPS Self-Signed Certificate")); | |
353 | ||
354 | err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey); | |
355 | if (err != noErr) | |
356 | { | |
357 | cupsdLogMessage(CUPSD_LOG_DEBUG, "SecKeyGeneratePair returned %ld.", | |
358 | (long)err); | |
359 | goto cleanup; | |
360 | } | |
361 | ||
362 | /* | |
363 | * Create a self-signed certificate using the public/private key pair... | |
364 | */ | |
365 | ||
366 | CFIndex usageInt = kSecKeyUsageAll; | |
367 | CFNumberRef usage = CFNumberCreate(alloc, kCFNumberCFIndexType, &usageInt); | |
368 | CFDictionaryRef certParams = CFDictionaryCreateMutable(kCFAllocatorDefault, | |
369 | kSecCSRBasicContraintsPathLen, CFINT(0), | |
370 | kSecSubjectAltName, cfservername, | |
371 | kSecCertificateKeyUsage, usage, | |
372 | NULL, NULL); | |
373 | CFRelease(usage); | |
374 | ||
375 | const void *ca_o[] = { kSecOidOrganization, CFSTR("") }; | |
376 | const void *ca_cn[] = { kSecOidCommonName, cfservername }; | |
377 | CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL); | |
378 | CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL); | |
379 | const void *ca_dn_array[2]; | |
380 | ||
381 | ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, | |
382 | 1, NULL); | |
383 | ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, | |
384 | 1, NULL); | |
385 | ||
386 | CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, | |
387 | NULL); | |
388 | SecCertificateRef cert = SecGenerateSelfSignedCertificate(subject, certParams, | |
389 | publicKey, | |
390 | privateKey); | |
391 | CFRelease(subject); | |
392 | CFRelease(certParams); | |
393 | ||
394 | if (!cert) | |
395 | { | |
396 | cupsdLogMessage(CUPSD_LOG_DEBUG, "SecGenerateSelfSignedCertificate failed."); | |
397 | goto cleanup; | |
398 | } | |
399 | ||
400 | ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey); | |
401 | ||
402 | if (ident) | |
403 | cupsdLogMessage(CUPSD_LOG_INFO, | |
404 | "Created SSL server certificate file \"%s\".", | |
405 | ServerCertificate); | |
406 | ||
407 | /* | |
408 | * Cleanup and return... | |
409 | */ | |
410 | ||
411 | cleanup: | |
412 | ||
413 | if (cfservername) | |
414 | CFRelease(cfservername); | |
415 | ||
416 | if (keyParams) | |
417 | CFRelease(keyParams); | |
418 | ||
419 | if (ident) | |
420 | CFRelease(ident); | |
421 | ||
422 | if (cert) | |
423 | CFRelease(cert); | |
424 | ||
425 | if (publicKey) | |
426 | CFRelease(publicKey); | |
427 | ||
428 | if (privateKey) | |
429 | CFRelease(publicKey); | |
430 | ||
431 | if (!status) | |
432 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
433 | "Unable to create SSL server key and certificate."); | |
434 | ||
435 | return (status); | |
436 | ||
437 | # else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ | |
82cc1f9a MS |
438 | int pid, /* Process ID of command */ |
439 | status; /* Status of command */ | |
440 | char command[1024], /* Command */ | |
441 | *argv[4], /* Command-line arguments */ | |
442 | *envp[MAX_ENV + 1], /* Environment variables */ | |
443 | keychain[1024], /* Keychain argument */ | |
444 | infofile[1024], /* Type-in information for cert */ | |
e1578ed9 | 445 | # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) |
82cc1f9a | 446 | localname[1024], /* Local hostname */ |
e1578ed9 | 447 | # endif /* HAVE_DNSSD || HAVE_AVAHI */ |
82cc1f9a MS |
448 | *servername; /* Name of server in cert */ |
449 | cups_file_t *fp; /* Seed/info file */ | |
450 | int infofd; /* Info file descriptor */ | |
451 | ||
452 | ||
e1578ed9 | 453 | # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) |
82cc1f9a MS |
454 | if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) |
455 | { | |
456 | snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); | |
457 | servername = localname; | |
458 | } | |
459 | else | |
e1578ed9 | 460 | # endif /* HAVE_DNSSD || HAVE_AVAHI */ |
82cc1f9a MS |
461 | servername = con->servername; |
462 | ||
463 | /* | |
464 | * Run the "certtool" command to generate a self-signed certificate... | |
465 | */ | |
466 | ||
467 | if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) | |
468 | { | |
469 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
e1578ed9 | 470 | "No SSL certificate and certtool command not found."); |
82cc1f9a MS |
471 | return (0); |
472 | } | |
473 | ||
474 | /* | |
475 | * Create a file with the certificate information fields... | |
476 | * | |
477 | * Note: This assumes that the default questions are asked by the certtool | |
478 | * command... | |
479 | */ | |
480 | ||
481 | if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) | |
482 | { | |
483 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
484 | "Unable to create certificate information file %s - %s", | |
485 | infofile, strerror(errno)); | |
486 | return (0); | |
487 | } | |
488 | ||
489 | cupsFilePrintf(fp, | |
490 | "%s\n" /* Enter key and certificate label */ | |
491 | "r\n" /* Generate RSA key pair */ | |
492 | "2048\n" /* Key size in bits */ | |
493 | "y\n" /* OK (y = yes) */ | |
494 | "b\n" /* Usage (b=signing/encryption) */ | |
495 | "s\n" /* Sign with SHA1 */ | |
496 | "y\n" /* OK (y = yes) */ | |
497 | "%s\n" /* Common name */ | |
498 | "\n" /* Country (default) */ | |
499 | "\n" /* Organization (default) */ | |
500 | "\n" /* Organizational unit (default) */ | |
501 | "\n" /* State/Province (default) */ | |
502 | "%s\n" /* Email address */ | |
503 | "y\n", /* OK (y = yes) */ | |
504 | servername, servername, ServerAdmin); | |
505 | cupsFileClose(fp); | |
506 | ||
507 | cupsdLogMessage(CUPSD_LOG_INFO, | |
e1578ed9 | 508 | "Generating SSL server key and certificate."); |
82cc1f9a MS |
509 | |
510 | snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate); | |
511 | ||
512 | argv[0] = "certtool"; | |
513 | argv[1] = "c"; | |
514 | argv[2] = keychain; | |
515 | argv[3] = NULL; | |
516 | ||
517 | cupsdLoadEnv(envp, MAX_ENV); | |
518 | ||
519 | infofd = open(infofile, O_RDONLY); | |
520 | ||
521 | if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, | |
522 | NULL, &pid)) | |
523 | { | |
524 | close(infofd); | |
525 | unlink(infofile); | |
526 | return (0); | |
527 | } | |
528 | ||
529 | close(infofd); | |
530 | unlink(infofile); | |
531 | ||
532 | while (waitpid(pid, &status, 0) < 0) | |
533 | if (errno != EINTR) | |
534 | { | |
535 | status = 1; | |
536 | break; | |
537 | } | |
538 | ||
539 | cupsdFinishProcess(pid, command, sizeof(command), NULL); | |
540 | ||
541 | if (status) | |
542 | { | |
543 | if (WIFEXITED(status)) | |
544 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
545 | "Unable to create SSL server key and certificate - " | |
e1578ed9 | 546 | "the certtool command stopped with status %d.", |
82cc1f9a MS |
547 | WEXITSTATUS(status)); |
548 | else | |
549 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
550 | "Unable to create SSL server key and certificate - " | |
e1578ed9 | 551 | "the certtool command crashed on signal %d.", |
82cc1f9a MS |
552 | WTERMSIG(status)); |
553 | } | |
554 | else | |
555 | { | |
556 | cupsdLogMessage(CUPSD_LOG_INFO, | |
e1578ed9 | 557 | "Created SSL server certificate file \"%s\".", |
82cc1f9a MS |
558 | ServerCertificate); |
559 | } | |
560 | ||
561 | return (!status); | |
e1578ed9 | 562 | # endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ |
82cc1f9a MS |
563 | } |
564 | ||
565 | ||
566 | /* | |
567 | * End of "$Id$". | |
568 | */ |