Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/scheduler/ipp.c
1090 views
1
/*
2
* IPP routines for the CUPS scheduler.
3
*
4
* Copyright © 2020-2022 by OpenPrinting
5
* Copyright © 2007-2021 by Apple Inc.
6
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
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
/*
16
* Include necessary headers...
17
*/
18
19
#include "cupsd.h"
20
#include <cups/ppd-private.h>
21
22
#ifdef __APPLE__
23
# ifdef HAVE_MEMBERSHIP_H
24
# include <membership.h>
25
# endif /* HAVE_MEMBERSHIP_H */
26
extern int mbr_user_name_to_uuid(const char* name, uuid_t uu);
27
extern int mbr_group_name_to_uuid(const char* name, uuid_t uu);
28
extern int mbr_check_membership_by_id(uuid_t user, gid_t group, int* ismember);
29
#endif /* __APPLE__ */
30
31
32
/*
33
* Local functions...
34
*/
35
36
static void accept_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
37
static void add_class(cupsd_client_t *con, ipp_attribute_t *uri);
38
static int add_file(cupsd_client_t *con, cupsd_job_t *job,
39
mime_type_t *filetype, int compression);
40
static cupsd_job_t *add_job(cupsd_client_t *con, cupsd_printer_t *printer,
41
mime_type_t *filetype);
42
static void add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job);
43
static void add_job_uuid(cupsd_job_t *job);
44
static void add_printer(cupsd_client_t *con, ipp_attribute_t *uri);
45
static void add_printer_state_reasons(cupsd_client_t *con,
46
cupsd_printer_t *p);
47
static void add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p);
48
static void apply_printer_defaults(cupsd_printer_t *printer,
49
cupsd_job_t *job);
50
static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri);
51
static void cancel_all_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
52
static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri);
53
static void cancel_subscription(cupsd_client_t *con, int id);
54
static int check_rss_recipient(const char *recipient);
55
static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
56
static void close_job(cupsd_client_t *con, ipp_attribute_t *uri);
57
static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
58
ipp_tag_t group, int quickcopy,
59
cups_array_t *exclude);
60
static int copy_banner(cupsd_client_t *con, cupsd_job_t *job,
61
const char *name);
62
static int copy_file(const char *from, const char *to, mode_t mode);
63
static int copy_model(cupsd_client_t *con, const char *from,
64
const char *to);
65
static void copy_job_attrs(cupsd_client_t *con,
66
cupsd_job_t *job,
67
cups_array_t *ra, cups_array_t *exclude);
68
static void copy_printer_attrs(cupsd_client_t *con,
69
cupsd_printer_t *printer,
70
cups_array_t *ra);
71
static void copy_subscription_attrs(cupsd_client_t *con,
72
cupsd_subscription_t *sub,
73
cups_array_t *ra,
74
cups_array_t *exclude);
75
static void create_job(cupsd_client_t *con, ipp_attribute_t *uri);
76
static void *create_local_bg_thread(cupsd_printer_t *printer);
77
static void create_local_printer(cupsd_client_t *con);
78
static cups_array_t *create_requested_array(ipp_t *request);
79
static void create_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
80
static void delete_printer(cupsd_client_t *con, ipp_attribute_t *uri);
81
static void get_default(cupsd_client_t *con);
82
static void get_devices(cupsd_client_t *con);
83
static void get_document(cupsd_client_t *con, ipp_attribute_t *uri);
84
static void get_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
85
static void get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
86
static void get_notifications(cupsd_client_t *con);
87
static void get_ppd(cupsd_client_t *con, ipp_attribute_t *uri);
88
static void get_ppds(cupsd_client_t *con);
89
static void get_printers(cupsd_client_t *con, int type);
90
static void get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
91
static void get_printer_supported(cupsd_client_t *con, ipp_attribute_t *uri);
92
static void get_subscription_attrs(cupsd_client_t *con, int sub_id);
93
static void get_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
94
static const char *get_username(cupsd_client_t *con);
95
static void hold_job(cupsd_client_t *con, ipp_attribute_t *uri);
96
static void hold_new_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
97
static void move_job(cupsd_client_t *con, ipp_attribute_t *uri);
98
static int ppd_parse_line(const char *line, char *option, int olen,
99
char *choice, int clen);
100
static void print_job(cupsd_client_t *con, ipp_attribute_t *uri);
101
static void read_job_ticket(cupsd_client_t *con);
102
static void reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
103
static void release_held_new_jobs(cupsd_client_t *con,
104
ipp_attribute_t *uri);
105
static void release_job(cupsd_client_t *con, ipp_attribute_t *uri);
106
static void renew_subscription(cupsd_client_t *con, int sub_id);
107
static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri);
108
static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job,
109
ipp_attribute_t *auth_info);
110
static void send_document(cupsd_client_t *con, ipp_attribute_t *uri);
111
static void send_http_error(cupsd_client_t *con, http_status_t status,
112
cupsd_printer_t *printer);
113
static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4);
114
static void set_default(cupsd_client_t *con, ipp_attribute_t *uri);
115
static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
116
static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
117
static int set_printer_defaults(cupsd_client_t *con, cupsd_printer_t *printer);
118
static void start_printer(cupsd_client_t *con, ipp_attribute_t *uri);
119
static void stop_printer(cupsd_client_t *con, ipp_attribute_t *uri);
120
static void url_encode_attr(ipp_attribute_t *attr, char *buffer, size_t bufsize);
121
static char *url_encode_string(const char *s, char *buffer, size_t bufsize);
122
static int user_allowed(cupsd_printer_t *p, const char *username);
123
static void validate_job(cupsd_client_t *con, ipp_attribute_t *uri);
124
static int validate_name(const char *name);
125
static int validate_user(cupsd_job_t *job, cupsd_client_t *con, const char *owner, char *username, size_t userlen);
126
127
128
/*
129
* 'cupsdProcessIPPRequest()' - Process an incoming IPP request.
130
*/
131
132
int /* O - 1 on success, 0 on failure */
133
cupsdProcessIPPRequest(
134
cupsd_client_t *con) /* I - Client connection */
135
{
136
ipp_tag_t group; /* Current group tag */
137
ipp_attribute_t *attr; /* Current attribute */
138
ipp_attribute_t *charset; /* Character set attribute */
139
ipp_attribute_t *language; /* Language attribute */
140
ipp_attribute_t *uri = NULL; /* Printer or job URI attribute */
141
ipp_attribute_t *username; /* requesting-user-name attr */
142
int sub_id; /* Subscription ID */
143
int valid = 1; /* Valid request? */
144
145
146
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id));
147
148
if (LogLevel >= CUPSD_LOG_DEBUG2)
149
{
150
for (group = IPP_TAG_ZERO, attr = ippFirstAttribute(con->request); attr; attr = ippNextAttribute(con->request))
151
{
152
const char *name; /* Attribute name */
153
char value[1024]; /* Attribute value */
154
155
if (group != ippGetGroupTag(attr))
156
{
157
group = ippGetGroupTag(attr);
158
if (group != IPP_TAG_ZERO)
159
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s", ippTagString(group));
160
}
161
162
if ((name = ippGetName(attr)) == NULL)
163
continue;
164
165
ippAttributeString(attr, value, sizeof(value));
166
167
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s %s%s '%s'", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), value);
168
}
169
}
170
171
/*
172
* First build an empty response message for this request...
173
*/
174
175
con->response = ippNew();
176
177
con->response->request.status.version[0] = con->request->request.op.version[0];
178
con->response->request.status.version[1] = con->request->request.op.version[1];
179
con->response->request.status.request_id = con->request->request.op.request_id;
180
181
/*
182
* Then validate the request header and required attributes...
183
*/
184
185
if (con->request->request.any.version[0] != 1 && con->request->request.any.version[0] != 2)
186
{
187
/*
188
* Return an error, since we only support IPP 1.x and 2.x.
189
*/
190
191
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request version number %d.%d.", IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, con->http->hostname, con->request->request.any.version[0], con->request->request.any.version[1]);
192
193
send_ipp_status(con, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, _("Bad request version number %d.%d."), con->request->request.any.version[0], con->request->request.any.version[1]);
194
}
195
else if (con->request->request.any.request_id < 1)
196
{
197
/*
198
* Return an error, since request IDs must be between 1 and 2^31-1
199
*/
200
201
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request ID %d.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname, con->request->request.any.request_id);
202
203
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Bad request ID %d."), con->request->request.any.request_id);
204
}
205
else if (!con->request->attrs)
206
{
207
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s No attributes in request.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
208
209
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("No attributes in request."));
210
}
211
else
212
{
213
/*
214
* Make sure that the attributes are provided in the correct order and
215
* don't repeat groups...
216
*/
217
218
for (attr = con->request->attrs, group = attr->group_tag;
219
attr;
220
attr = attr->next)
221
if (attr->group_tag < group && attr->group_tag != IPP_TAG_ZERO)
222
{
223
/*
224
* Out of order; return an error...
225
*/
226
227
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Attribute groups are out of order", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
228
229
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute groups are out of order (%x < %x)."), attr->group_tag, group);
230
break;
231
}
232
else
233
group = attr->group_tag;
234
235
if (!attr)
236
{
237
/*
238
* Then make sure that the first three attributes are:
239
*
240
* attributes-charset
241
* attributes-natural-language
242
* printer-uri/job-uri
243
*/
244
245
attr = con->request->attrs;
246
if (attr && attr->name && !strcmp(attr->name, "attributes-charset") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET && attr->group_tag == IPP_TAG_OPERATION)
247
charset = attr;
248
else
249
charset = NULL;
250
251
if (attr)
252
attr = attr->next;
253
254
if (attr && attr->name && !strcmp(attr->name, "attributes-natural-language") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE && attr->group_tag == IPP_TAG_OPERATION)
255
{
256
language = attr;
257
258
/*
259
* Reset language for this request if different from Accept-Language.
260
*/
261
262
if (!con->language ||
263
strcmp(attr->values[0].string.text, con->language->language))
264
{
265
cupsLangFree(con->language);
266
con->language = cupsLangGet(attr->values[0].string.text);
267
}
268
}
269
else
270
language = NULL;
271
272
if ((attr = ippFindAttribute(con->request, "printer-uri", IPP_TAG_URI)) != NULL && attr->group_tag == IPP_TAG_OPERATION)
273
uri = attr;
274
else if ((attr = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI)) != NULL && attr->group_tag == IPP_TAG_OPERATION)
275
uri = attr;
276
else if (con->request->request.op.operation_id == CUPS_GET_PPD && (attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL && attr->group_tag == IPP_TAG_OPERATION)
277
uri = attr;
278
else
279
uri = NULL;
280
281
if (charset)
282
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, charset->values[0].string.text);
283
else
284
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8");
285
286
if (language)
287
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->values[0].string.text);
288
else
289
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, DefaultLanguage);
290
291
if (charset && _cups_strcasecmp(charset->values[0].string.text, "us-ascii") && _cups_strcasecmp(charset->values[0].string.text, "utf-8"))
292
{
293
/*
294
* Bad character set...
295
*/
296
297
cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported character set \"%s\"",
298
charset->values[0].string.text);
299
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Unsupported attributes-charset value \"%s\".", IPP_STATUS_ERROR_CHARSET, con->http->hostname, charset->values[0].string.text);
300
send_ipp_status(con, IPP_STATUS_ERROR_CHARSET, _("Unsupported character set \"%s\"."), charset->values[0].string.text);
301
}
302
else if (!charset || !language ||
303
(!uri &&
304
con->request->request.op.operation_id != CUPS_GET_DEFAULT &&
305
con->request->request.op.operation_id != CUPS_GET_PRINTERS &&
306
con->request->request.op.operation_id != CUPS_GET_CLASSES &&
307
con->request->request.op.operation_id != CUPS_GET_DEVICES &&
308
con->request->request.op.operation_id != CUPS_GET_PPDS))
309
{
310
/*
311
* Return an error, since attributes-charset,
312
* attributes-natural-language, and printer-uri/job-uri are required
313
* for all operations.
314
*/
315
316
if (!charset)
317
{
318
cupsdLogMessage(CUPSD_LOG_ERROR, "Missing attributes-charset attribute.");
319
320
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-charset attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
321
}
322
323
if (!language)
324
{
325
cupsdLogMessage(CUPSD_LOG_ERROR,
326
"Missing attributes-natural-language attribute.");
327
328
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-natural-language attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
329
}
330
331
if (!uri)
332
{
333
cupsdLogMessage(CUPSD_LOG_ERROR, "Missing printer-uri, job-uri, or ppd-name attribute.");
334
335
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing printer-uri, job-uri, or ppd-name attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
336
}
337
338
cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");
339
340
for (attr = con->request->attrs; attr; attr = attr->next)
341
cupsdLogMessage(CUPSD_LOG_DEBUG,
342
"attr \"%s\": group_tag = %x, value_tag = %x",
343
attr->name ? attr->name : "(null)", attr->group_tag,
344
attr->value_tag);
345
346
cupsdLogMessage(CUPSD_LOG_DEBUG, "End of attributes...");
347
348
send_ipp_status(con, IPP_BAD_REQUEST,
349
_("Missing required attributes."));
350
}
351
else
352
{
353
/*
354
* OK, all the checks pass so far; validate "requesting-user-name"
355
* attribute value...
356
*/
357
358
if ((username = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_ZERO)) != NULL)
359
{
360
/*
361
* Validate "requesting-user-name"...
362
*/
363
364
if (username->group_tag != IPP_TAG_OPERATION && StrictConformance)
365
{
366
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute in wrong group.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
367
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("\"requesting-user-name\" attribute in wrong group."));
368
valid = 0;
369
}
370
else if (username->value_tag != IPP_TAG_NAME && username->value_tag != IPP_TAG_NAMELANG)
371
{
372
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with wrong syntax.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname);
373
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax."));
374
if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL)
375
attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
376
valid = 0;
377
}
378
else if (!ippValidateAttribute(username))
379
{
380
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with bad value.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname);
381
382
if (StrictConformance)
383
{
384
/*
385
* Throw an error...
386
*/
387
388
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax."));
389
if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL)
390
attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
391
valid = 0;
392
}
393
else
394
{
395
/*
396
* Map bad "requesting-user-name" to 'anonymous'...
397
*/
398
399
ippSetString(con->request, &username, 0, "anonymous");
400
}
401
}
402
else if (!strcmp(username->values[0].string.text, "root") && _cups_strcasecmp(con->http->hostname, "localhost") && strcmp(con->username, "root"))
403
{
404
/*
405
* Remote unauthenticated user masquerading as local root...
406
*/
407
408
ippSetString(con->request, &username, 0, RemoteRoot);
409
}
410
}
411
412
if ((attr = ippFindAttribute(con->request, "notify-subscription-id", IPP_TAG_INTEGER)) != NULL)
413
sub_id = attr->values[0].integer;
414
else
415
sub_id = 0;
416
417
if (valid)
418
{
419
/*
420
* Try processing the operation...
421
*/
422
423
if (uri)
424
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s", ippOpString(con->request->request.op.operation_id), uri->values[0].string.text);
425
else
426
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s", ippOpString(con->request->request.op.operation_id));
427
428
switch (con->request->request.op.operation_id)
429
{
430
case IPP_OP_PRINT_JOB :
431
print_job(con, uri);
432
break;
433
434
case IPP_OP_VALIDATE_JOB :
435
validate_job(con, uri);
436
break;
437
438
case IPP_OP_CREATE_JOB :
439
create_job(con, uri);
440
break;
441
442
case IPP_OP_SEND_DOCUMENT :
443
send_document(con, uri);
444
break;
445
446
case IPP_OP_CANCEL_JOB :
447
cancel_job(con, uri);
448
break;
449
450
case IPP_OP_GET_JOB_ATTRIBUTES :
451
get_job_attrs(con, uri);
452
break;
453
454
case IPP_OP_GET_JOBS :
455
get_jobs(con, uri);
456
break;
457
458
case IPP_OP_GET_PRINTER_ATTRIBUTES :
459
get_printer_attrs(con, uri);
460
break;
461
462
case IPP_OP_GET_PRINTER_SUPPORTED_VALUES :
463
get_printer_supported(con, uri);
464
break;
465
466
case IPP_OP_HOLD_JOB :
467
hold_job(con, uri);
468
break;
469
470
case IPP_OP_RELEASE_JOB :
471
release_job(con, uri);
472
break;
473
474
case IPP_OP_RESTART_JOB :
475
restart_job(con, uri);
476
break;
477
478
case IPP_OP_PAUSE_PRINTER :
479
stop_printer(con, uri);
480
break;
481
482
case IPP_OP_RESUME_PRINTER :
483
start_printer(con, uri);
484
break;
485
486
case IPP_OP_PURGE_JOBS :
487
case IPP_OP_CANCEL_JOBS :
488
case IPP_OP_CANCEL_MY_JOBS :
489
cancel_all_jobs(con, uri);
490
break;
491
492
case IPP_OP_SET_JOB_ATTRIBUTES :
493
set_job_attrs(con, uri);
494
break;
495
496
case IPP_OP_SET_PRINTER_ATTRIBUTES :
497
set_printer_attrs(con, uri);
498
break;
499
500
case IPP_OP_HOLD_NEW_JOBS :
501
hold_new_jobs(con, uri);
502
break;
503
504
case IPP_OP_RELEASE_HELD_NEW_JOBS :
505
release_held_new_jobs(con, uri);
506
break;
507
508
case IPP_OP_CLOSE_JOB :
509
close_job(con, uri);
510
break;
511
512
case IPP_OP_CUPS_GET_DEFAULT :
513
get_default(con);
514
break;
515
516
case IPP_OP_CUPS_GET_PRINTERS :
517
get_printers(con, 0);
518
break;
519
520
case IPP_OP_CUPS_GET_CLASSES :
521
get_printers(con, CUPS_PRINTER_CLASS);
522
break;
523
524
case IPP_OP_CUPS_ADD_MODIFY_PRINTER :
525
add_printer(con, uri);
526
break;
527
528
case IPP_OP_CUPS_DELETE_PRINTER :
529
delete_printer(con, uri);
530
break;
531
532
case IPP_OP_CUPS_ADD_MODIFY_CLASS :
533
add_class(con, uri);
534
break;
535
536
case IPP_OP_CUPS_DELETE_CLASS :
537
delete_printer(con, uri);
538
break;
539
540
case IPP_OP_CUPS_ACCEPT_JOBS :
541
case IPP_OP_ENABLE_PRINTER :
542
accept_jobs(con, uri);
543
break;
544
545
case IPP_OP_CUPS_REJECT_JOBS :
546
case IPP_OP_DISABLE_PRINTER :
547
reject_jobs(con, uri);
548
break;
549
550
case IPP_OP_CUPS_SET_DEFAULT :
551
set_default(con, uri);
552
break;
553
554
case IPP_OP_CUPS_GET_DEVICES :
555
get_devices(con);
556
break;
557
558
case IPP_OP_CUPS_GET_DOCUMENT :
559
get_document(con, uri);
560
break;
561
562
case IPP_OP_CUPS_GET_PPD :
563
get_ppd(con, uri);
564
break;
565
566
case IPP_OP_CUPS_GET_PPDS :
567
get_ppds(con);
568
break;
569
570
case IPP_OP_CUPS_MOVE_JOB :
571
move_job(con, uri);
572
break;
573
574
case IPP_OP_CUPS_AUTHENTICATE_JOB :
575
authenticate_job(con, uri);
576
break;
577
578
case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS :
579
case IPP_OP_CREATE_JOB_SUBSCRIPTIONS :
580
create_subscriptions(con, uri);
581
break;
582
583
case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES :
584
get_subscription_attrs(con, sub_id);
585
break;
586
587
case IPP_OP_GET_SUBSCRIPTIONS :
588
get_subscriptions(con, uri);
589
break;
590
591
case IPP_OP_RENEW_SUBSCRIPTION :
592
renew_subscription(con, sub_id);
593
break;
594
595
case IPP_OP_CANCEL_SUBSCRIPTION :
596
cancel_subscription(con, sub_id);
597
break;
598
599
case IPP_OP_GET_NOTIFICATIONS :
600
get_notifications(con);
601
break;
602
603
case IPP_OP_CUPS_CREATE_LOCAL_PRINTER :
604
create_local_printer(con);
605
break;
606
607
default :
608
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Operation %04X (%s) not supported.", IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, con->http->hostname, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id));
609
610
send_ipp_status(con, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, _("%s not supported."), ippOpString(con->request->request.op.operation_id));
611
break;
612
}
613
}
614
}
615
}
616
}
617
618
if (con->response)
619
{
620
/*
621
* Sending data from the scheduler...
622
*/
623
624
cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.", ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname);
625
626
httpClearFields(con->http);
627
628
#ifdef CUPSD_USE_CHUNKING
629
/*
630
* Because older versions of CUPS (1.1.17 and older) and some IPP
631
* clients do not implement chunking properly, we cannot use
632
* chunking by default. This may become the default in future
633
* CUPS releases, or we might add a configuration directive for
634
* it.
635
*/
636
637
if (con->http->version == HTTP_1_1)
638
{
639
cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked");
640
cupsdSetLength(con->http, 0);
641
}
642
else
643
#endif /* CUPSD_USE_CHUNKING */
644
{
645
size_t length; /* Length of response */
646
647
648
length = ippLength(con->response);
649
650
if (con->file >= 0 && !con->pipe_pid)
651
{
652
struct stat fileinfo; /* File information */
653
654
if (!fstat(con->file, &fileinfo))
655
length += (size_t)fileinfo.st_size;
656
}
657
658
cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length);
659
httpSetLength(con->http, length);
660
}
661
662
if (cupsdSendHeader(con, HTTP_OK, "application/ipp", CUPSD_AUTH_NONE))
663
{
664
/*
665
* Tell the caller the response header was sent successfully...
666
*/
667
668
cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con);
669
670
return (1);
671
}
672
else
673
{
674
/*
675
* Tell the caller the response header could not be sent...
676
*/
677
678
return (0);
679
}
680
}
681
else
682
{
683
/*
684
* Sending data from a subprocess like cups-deviced; tell the caller
685
* everything is A-OK so far...
686
*/
687
688
return (1);
689
}
690
}
691
692
693
/*
694
* 'cupsdTimeoutJob()' - Timeout a job waiting on job files.
695
*/
696
697
int /* O - 0 on success, -1 on error */
698
cupsdTimeoutJob(cupsd_job_t *job) /* I - Job to timeout */
699
{
700
cupsd_printer_t *printer; /* Destination printer or class */
701
ipp_attribute_t *attr; /* job-sheets attribute */
702
int kbytes; /* Kilobytes in banner */
703
704
705
job->pending_timeout = 0;
706
707
/*
708
* See if we need to add the ending sheet...
709
*/
710
711
if (!cupsdLoadJob(job))
712
return (-1);
713
714
printer = cupsdFindDest(job->dest);
715
attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
716
717
if (printer && !(printer->type & CUPS_PRINTER_REMOTE) &&
718
attr && attr->num_values > 1)
719
{
720
/*
721
* Yes...
722
*/
723
724
cupsdLogJob(job, CUPSD_LOG_INFO, "Adding end banner page \"%s\".",
725
attr->values[1].string.text);
726
727
if ((kbytes = copy_banner(NULL, job, attr->values[1].string.text)) < 0)
728
return (-1);
729
730
cupsdUpdateQuota(printer, job->username, 0, kbytes);
731
}
732
733
return (0);
734
}
735
736
737
/*
738
* 'accept_jobs()' - Accept print jobs to a printer.
739
*/
740
741
static void
742
accept_jobs(cupsd_client_t *con, /* I - Client connection */
743
ipp_attribute_t *uri) /* I - Printer or class URI */
744
{
745
http_status_t status; /* Policy status */
746
cups_ptype_t dtype; /* Destination type (printer/class) */
747
cupsd_printer_t *printer; /* Printer data */
748
749
750
cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", con,
751
con->number, uri->values[0].string.text);
752
753
/*
754
* Is the destination valid?
755
*/
756
757
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
758
{
759
/*
760
* Bad URI...
761
*/
762
763
send_ipp_status(con, IPP_NOT_FOUND,
764
_("The printer or class does not exist."));
765
return;
766
}
767
768
/*
769
* Check policy...
770
*/
771
772
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
773
{
774
send_http_error(con, status, printer);
775
return;
776
}
777
778
/*
779
* Accept jobs sent to the printer...
780
*/
781
782
printer->accepting = 1;
783
printer->state_message[0] = '\0';
784
785
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
786
"Now accepting jobs.");
787
788
if (dtype & CUPS_PRINTER_CLASS)
789
{
790
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
791
792
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" now accepting jobs (\"%s\").",
793
printer->name, get_username(con));
794
}
795
else
796
{
797
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
798
799
cupsdLogMessage(CUPSD_LOG_INFO,
800
"Printer \"%s\" now accepting jobs (\"%s\").",
801
printer->name, get_username(con));
802
}
803
804
/*
805
* Everything was ok, so return OK status...
806
*/
807
808
con->response->request.status.status_code = IPP_OK;
809
}
810
811
812
/*
813
* 'add_class()' - Add a class to the system.
814
*/
815
816
static void
817
add_class(cupsd_client_t *con, /* I - Client connection */
818
ipp_attribute_t *uri) /* I - URI of class */
819
{
820
http_status_t status; /* Policy status */
821
int i; /* Looping var */
822
char scheme[HTTP_MAX_URI], /* Method portion of URI */
823
username[HTTP_MAX_URI], /* Username portion of URI */
824
host[HTTP_MAX_URI], /* Host portion of URI */
825
resource[HTTP_MAX_URI]; /* Resource portion of URI */
826
int port; /* Port portion of URI */
827
cupsd_printer_t *pclass, /* Class */
828
*member; /* Member printer/class */
829
cups_ptype_t dtype; /* Destination type */
830
ipp_attribute_t *attr; /* Printer attribute */
831
int modify; /* Non-zero if we just modified */
832
int need_restart_job; /* Need to restart job? */
833
834
835
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", con,
836
con->number, uri->values[0].string.text);
837
838
/*
839
* Do we have a valid URI?
840
*/
841
842
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
843
sizeof(scheme), username, sizeof(username), host,
844
sizeof(host), &port, resource, sizeof(resource));
845
846
847
if (strncmp(resource, "/classes/", 9) || strlen(resource) == 9)
848
{
849
/*
850
* No, return an error...
851
*/
852
853
send_ipp_status(con, IPP_BAD_REQUEST,
854
_("The printer-uri must be of the form "
855
"\"ipp://HOSTNAME/classes/CLASSNAME\"."));
856
return;
857
}
858
859
/*
860
* Do we have a valid printer name?
861
*/
862
863
if (!validate_name(resource + 9))
864
{
865
/*
866
* No, return an error...
867
*/
868
869
send_ipp_status(con, IPP_BAD_REQUEST,
870
_("The printer-uri \"%s\" contains invalid characters."),
871
uri->values[0].string.text);
872
return;
873
}
874
875
/*
876
* See if the class already exists; if not, create a new class...
877
*/
878
879
if ((pclass = cupsdFindClass(resource + 9)) == NULL)
880
{
881
/*
882
* Class doesn't exist; see if we have a printer of the same name...
883
*/
884
885
if (cupsdFindPrinter(resource + 9))
886
{
887
/*
888
* Yes, return an error...
889
*/
890
891
send_ipp_status(con, IPP_NOT_POSSIBLE,
892
_("A printer named \"%s\" already exists."),
893
resource + 9);
894
return;
895
}
896
897
/*
898
* No, check the default policy and then add the class...
899
*/
900
901
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
902
{
903
send_http_error(con, status, NULL);
904
return;
905
}
906
907
pclass = cupsdAddClass(resource + 9);
908
modify = 0;
909
910
pclass->printer_id = NextPrinterId ++;
911
}
912
else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con,
913
NULL)) != HTTP_OK)
914
{
915
send_http_error(con, status, pclass);
916
return;
917
}
918
else
919
modify = 1;
920
921
/*
922
* Look for attributes and copy them over as needed...
923
*/
924
925
need_restart_job = 0;
926
927
if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL)
928
cupsdSetString(&pclass->location, attr->values[0].string.text);
929
930
if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4))
931
cupsdSetString(&pclass->geo_location, attr->values[0].string.text);
932
933
if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL)
934
cupsdSetString(&pclass->organization, attr->values[0].string.text);
935
936
if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL)
937
cupsdSetString(&pclass->organizational_unit, attr->values[0].string.text);
938
939
if ((attr = ippFindAttribute(con->request, "printer-info",
940
IPP_TAG_TEXT)) != NULL)
941
cupsdSetString(&pclass->info, attr->values[0].string.text);
942
943
if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
944
IPP_TAG_BOOLEAN)) != NULL &&
945
attr->values[0].boolean != pclass->accepting)
946
{
947
cupsdLogMessage(CUPSD_LOG_INFO,
948
"Setting %s printer-is-accepting-jobs to %d (was %d.)",
949
pclass->name, attr->values[0].boolean, pclass->accepting);
950
951
pclass->accepting = attr->values[0].boolean;
952
953
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s accepting jobs.",
954
pclass->accepting ? "Now" : "No longer");
955
}
956
957
if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL)
958
{
959
if (pclass->type & CUPS_PRINTER_REMOTE)
960
{
961
/*
962
* Cannot re-share remote printers.
963
*/
964
965
send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues."));
966
if (!modify)
967
cupsdDeletePrinter(pclass, 0);
968
969
return;
970
}
971
972
if (pclass->shared && !ippGetBoolean(attr, 0))
973
cupsdDeregisterPrinter(pclass, 1);
974
975
cupsdLogMessage(CUPSD_LOG_INFO,
976
"Setting %s printer-is-shared to %d (was %d.)",
977
pclass->name, attr->values[0].boolean, pclass->shared);
978
979
pclass->shared = ippGetBoolean(attr, 0);
980
}
981
982
if ((attr = ippFindAttribute(con->request, "printer-state",
983
IPP_TAG_ENUM)) != NULL)
984
{
985
if (attr->values[0].integer != IPP_PRINTER_IDLE &&
986
attr->values[0].integer != IPP_PRINTER_STOPPED)
987
{
988
send_ipp_status(con, IPP_BAD_REQUEST,
989
_("Attempt to set %s printer-state to bad value %d."),
990
pclass->name, attr->values[0].integer);
991
if (!modify)
992
cupsdDeletePrinter(pclass, 0);
993
994
return;
995
}
996
997
cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
998
pclass->name, attr->values[0].integer, pclass->state);
999
1000
if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1001
cupsdStopPrinter(pclass, 0);
1002
else
1003
{
1004
cupsdSetPrinterState(pclass, (ipp_pstate_t)(attr->values[0].integer), 0);
1005
need_restart_job = 1;
1006
}
1007
}
1008
if ((attr = ippFindAttribute(con->request, "printer-state-message",
1009
IPP_TAG_TEXT)) != NULL)
1010
{
1011
strlcpy(pclass->state_message, attr->values[0].string.text,
1012
sizeof(pclass->state_message));
1013
1014
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s",
1015
pclass->state_message);
1016
}
1017
if ((attr = ippFindAttribute(con->request, "member-uris",
1018
IPP_TAG_URI)) != NULL)
1019
{
1020
/*
1021
* Clear the printer array as needed...
1022
*/
1023
1024
need_restart_job = 1;
1025
1026
if (pclass->num_printers > 0)
1027
{
1028
free(pclass->printers);
1029
pclass->num_printers = 0;
1030
}
1031
1032
/*
1033
* Add each printer or class that is listed...
1034
*/
1035
1036
for (i = 0; i < attr->num_values; i ++)
1037
{
1038
/*
1039
* Search for the printer or class URI...
1040
*/
1041
1042
if (!cupsdValidateDest(attr->values[i].string.text, &dtype, &member))
1043
{
1044
/*
1045
* Bad URI...
1046
*/
1047
1048
send_ipp_status(con, IPP_NOT_FOUND,
1049
_("The printer or class does not exist."));
1050
if (!modify)
1051
cupsdDeletePrinter(pclass, 0);
1052
1053
return;
1054
}
1055
else if (dtype & CUPS_PRINTER_CLASS)
1056
{
1057
send_ipp_status(con, IPP_BAD_REQUEST,
1058
_("Nested classes are not allowed."));
1059
if (!modify)
1060
cupsdDeletePrinter(pclass, 0);
1061
1062
return;
1063
}
1064
1065
/*
1066
* Add it to the class...
1067
*/
1068
1069
cupsdAddPrinterToClass(pclass, member);
1070
}
1071
}
1072
1073
if (!set_printer_defaults(con, pclass))
1074
{
1075
if (!modify)
1076
cupsdDeletePrinter(pclass, 0);
1077
1078
return;
1079
}
1080
1081
if ((attr = ippFindAttribute(con->request, "auth-info-required",
1082
IPP_TAG_KEYWORD)) != NULL)
1083
cupsdSetAuthInfoRequired(pclass, NULL, attr);
1084
1085
pclass->config_time = time(NULL);
1086
1087
/*
1088
* Update the printer class attributes and return...
1089
*/
1090
1091
cupsdSetPrinterAttrs(pclass);
1092
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
1093
1094
if (need_restart_job && pclass->job)
1095
{
1096
/*
1097
* Reset the current job to a "pending" status...
1098
*/
1099
1100
cupsdSetJobState(pclass->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
1101
"Job restarted because the class was modified.");
1102
}
1103
1104
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
1105
1106
if (modify)
1107
{
1108
cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED,
1109
pclass, NULL, "Class \"%s\" modified by \"%s\".",
1110
pclass->name, get_username(con));
1111
1112
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" modified by \"%s\".",
1113
pclass->name, get_username(con));
1114
}
1115
else
1116
{
1117
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED,
1118
pclass, NULL, "New class \"%s\" added by \"%s\".",
1119
pclass->name, get_username(con));
1120
1121
cupsdLogMessage(CUPSD_LOG_INFO, "New class \"%s\" added by \"%s\".",
1122
pclass->name, get_username(con));
1123
}
1124
1125
con->response->request.status.status_code = IPP_OK;
1126
}
1127
1128
1129
/*
1130
* 'add_file()' - Add a file to a job.
1131
*/
1132
1133
static int /* O - 0 on success, -1 on error */
1134
add_file(cupsd_client_t *con, /* I - Connection to client */
1135
cupsd_job_t *job, /* I - Job to add to */
1136
mime_type_t *filetype, /* I - Type of file */
1137
int compression) /* I - Compression */
1138
{
1139
mime_type_t **filetypes; /* New filetypes array... */
1140
int *compressions; /* New compressions array... */
1141
1142
1143
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1144
"add_file(con=%p[%d], job=%d, filetype=%s/%s, "
1145
"compression=%d)", con, con ? con->number : -1, job->id,
1146
filetype->super, filetype->type, compression);
1147
1148
/*
1149
* Add the file to the job...
1150
*/
1151
1152
if (job->num_files == 0)
1153
{
1154
compressions = (int *)malloc(sizeof(int));
1155
filetypes = (mime_type_t **)malloc(sizeof(mime_type_t *));
1156
}
1157
else
1158
{
1159
compressions = (int *)realloc(job->compressions,
1160
(size_t)(job->num_files + 1) * sizeof(int));
1161
filetypes = (mime_type_t **)realloc(job->filetypes,
1162
(size_t)(job->num_files + 1) *
1163
sizeof(mime_type_t *));
1164
}
1165
1166
if (compressions)
1167
job->compressions = compressions;
1168
1169
if (filetypes)
1170
job->filetypes = filetypes;
1171
1172
if (!compressions || !filetypes)
1173
{
1174
cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
1175
"Job aborted because the scheduler ran out of memory.");
1176
1177
if (con)
1178
send_ipp_status(con, IPP_INTERNAL_ERROR,
1179
_("Unable to allocate memory for file types."));
1180
1181
return (-1);
1182
}
1183
1184
job->compressions[job->num_files] = compression;
1185
job->filetypes[job->num_files] = filetype;
1186
1187
job->num_files ++;
1188
1189
job->dirty = 1;
1190
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
1191
1192
return (0);
1193
}
1194
1195
1196
/*
1197
* 'add_job()' - Add a job to a print queue.
1198
*/
1199
1200
static cupsd_job_t * /* O - Job object */
1201
add_job(cupsd_client_t *con, /* I - Client connection */
1202
cupsd_printer_t *printer, /* I - Destination printer */
1203
mime_type_t *filetype) /* I - First print file type, if any */
1204
{
1205
http_status_t status; /* Policy status */
1206
ipp_attribute_t *attr, /* Current attribute */
1207
*auth_info; /* auth-info attribute */
1208
const char *mandatory; /* Current mandatory job attribute */
1209
const char *val; /* Default option value */
1210
int priority; /* Job priority */
1211
cupsd_job_t *job; /* Current job */
1212
char job_uri[HTTP_MAX_URI]; /* Job URI */
1213
int kbytes; /* Size of print file */
1214
int i; /* Looping var */
1215
int lowerpagerange; /* Page range bound */
1216
int exact; /* Did we have an exact match? */
1217
ipp_attribute_t *media_col, /* media-col attribute */
1218
*media_margin; /* media-*-margin attribute */
1219
ipp_t *unsup_col; /* media-col in unsupported response */
1220
static const char * const readonly[] =/* List of read-only attributes */
1221
{
1222
"date-time-at-completed",
1223
"date-time-at-creation",
1224
"date-time-at-processing",
1225
"job-detailed-status-messages",
1226
"job-document-access-errors",
1227
"job-id",
1228
"job-impressions-completed",
1229
"job-k-octets-completed",
1230
"job-media-sheets-completed",
1231
"job-pages-completed",
1232
"job-printer-up-time",
1233
"job-printer-uri",
1234
"job-state",
1235
"job-state-message",
1236
"job-state-reasons",
1237
"job-uri",
1238
"number-of-documents",
1239
"number-of-intervening-jobs",
1240
"output-device-assigned",
1241
"time-at-completed",
1242
"time-at-creation",
1243
"time-at-processing"
1244
};
1245
1246
1247
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
1248
con, con->number, printer, printer->name,
1249
filetype, filetype ? filetype->super : "none",
1250
filetype ? filetype->type : "none");
1251
1252
/*
1253
* Check remote printing to non-shared printer...
1254
*/
1255
1256
if (!printer->shared &&
1257
_cups_strcasecmp(con->http->hostname, "localhost") &&
1258
_cups_strcasecmp(con->http->hostname, ServerName))
1259
{
1260
send_ipp_status(con, IPP_NOT_AUTHORIZED,
1261
_("The printer or class is not shared."));
1262
return (NULL);
1263
}
1264
1265
/*
1266
* Check policy...
1267
*/
1268
1269
auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
1270
1271
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
1272
{
1273
send_http_error(con, status, printer);
1274
return (NULL);
1275
}
1276
else if (printer->num_auth_info_required == 1 &&
1277
!strcmp(printer->auth_info_required[0], "negotiate") &&
1278
!con->username[0])
1279
{
1280
send_http_error(con, HTTP_UNAUTHORIZED, printer);
1281
return (NULL);
1282
}
1283
#ifdef HAVE_TLS
1284
else if (auth_info && !con->http->tls &&
1285
!httpAddrLocalhost(con->http->hostaddr))
1286
{
1287
/*
1288
* Require encryption of auth-info over non-local connections...
1289
*/
1290
1291
send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
1292
return (NULL);
1293
}
1294
#endif /* HAVE_TLS */
1295
1296
/*
1297
* See if the printer is accepting jobs...
1298
*/
1299
1300
if (!printer->accepting)
1301
{
1302
send_ipp_status(con, IPP_NOT_ACCEPTING,
1303
_("Destination \"%s\" is not accepting jobs."),
1304
printer->name);
1305
return (NULL);
1306
}
1307
1308
/*
1309
* Validate job template attributes; for now just document-format,
1310
* copies, job-sheets, number-up, page-ranges, mandatory attributes, and
1311
* media...
1312
*/
1313
1314
for (i = 0; i < (int)(sizeof(readonly) / sizeof(readonly[0])); i ++)
1315
{
1316
if ((attr = ippFindAttribute(con->request, readonly[i], IPP_TAG_ZERO)) != NULL)
1317
{
1318
ippDeleteAttribute(con->request, attr);
1319
1320
if (StrictConformance)
1321
{
1322
send_ipp_status(con, IPP_BAD_REQUEST, _("The '%s' Job Status attribute cannot be supplied in a job creation request."), readonly[i]);
1323
return (NULL);
1324
}
1325
1326
cupsdLogMessage(CUPSD_LOG_INFO, "Unexpected '%s' Job Status attribute in a job creation request.", readonly[i]);
1327
}
1328
}
1329
1330
if (printer->pc)
1331
{
1332
for (mandatory = (char *)cupsArrayFirst(printer->pc->mandatory);
1333
mandatory;
1334
mandatory = (char *)cupsArrayNext(printer->pc->mandatory))
1335
{
1336
if (!ippFindAttribute(con->request, mandatory, IPP_TAG_ZERO))
1337
{
1338
/*
1339
* Missing a required attribute...
1340
*/
1341
1342
send_ipp_status(con, IPP_CONFLICT,
1343
_("The \"%s\" attribute is required for print jobs."),
1344
mandatory);
1345
return (NULL);
1346
}
1347
}
1348
}
1349
1350
if (filetype && printer->filetypes &&
1351
!cupsArrayFind(printer->filetypes, filetype))
1352
{
1353
char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
1354
/* MIME media type string */
1355
1356
1357
snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
1358
filetype->type);
1359
1360
send_ipp_status(con, IPP_DOCUMENT_FORMAT,
1361
_("Unsupported format \"%s\"."), mimetype);
1362
1363
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
1364
"document-format", NULL, mimetype);
1365
1366
return (NULL);
1367
}
1368
1369
if ((attr = ippFindAttribute(con->request, "copies",
1370
IPP_TAG_INTEGER)) != NULL)
1371
{
1372
if (attr->values[0].integer < 1 || attr->values[0].integer > MaxCopies)
1373
{
1374
send_ipp_status(con, IPP_ATTRIBUTES, _("Bad copies value %d."),
1375
attr->values[0].integer);
1376
ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
1377
"copies", attr->values[0].integer);
1378
return (NULL);
1379
}
1380
}
1381
1382
if ((attr = ippFindAttribute(con->request, "job-sheets",
1383
IPP_TAG_ZERO)) != NULL)
1384
{
1385
if (attr->value_tag != IPP_TAG_KEYWORD &&
1386
attr->value_tag != IPP_TAG_NAME)
1387
{
1388
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value type."));
1389
return (NULL);
1390
}
1391
1392
if (attr->num_values > 2)
1393
{
1394
send_ipp_status(con, IPP_BAD_REQUEST,
1395
_("Too many job-sheets values (%d > 2)."),
1396
attr->num_values);
1397
return (NULL);
1398
}
1399
1400
for (i = 0; i < attr->num_values; i ++)
1401
if (strcmp(attr->values[i].string.text, "none") &&
1402
!cupsdFindBanner(attr->values[i].string.text))
1403
{
1404
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value \"%s\"."),
1405
attr->values[i].string.text);
1406
return (NULL);
1407
}
1408
}
1409
1410
if ((attr = ippFindAttribute(con->request, "number-up",
1411
IPP_TAG_INTEGER)) != NULL)
1412
{
1413
if (attr->values[0].integer != 1 &&
1414
attr->values[0].integer != 2 &&
1415
attr->values[0].integer != 4 &&
1416
attr->values[0].integer != 6 &&
1417
attr->values[0].integer != 9 &&
1418
attr->values[0].integer != 16)
1419
{
1420
send_ipp_status(con, IPP_ATTRIBUTES, _("Bad number-up value %d."),
1421
attr->values[0].integer);
1422
ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
1423
"number-up", attr->values[0].integer);
1424
return (NULL);
1425
}
1426
}
1427
1428
if ((attr = ippFindAttribute(con->request, "page-ranges",
1429
IPP_TAG_RANGE)) != NULL)
1430
{
1431
for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
1432
{
1433
if (attr->values[i].range.lower < lowerpagerange ||
1434
attr->values[i].range.lower > attr->values[i].range.upper)
1435
{
1436
send_ipp_status(con, IPP_BAD_REQUEST,
1437
_("Bad page-ranges values %d-%d."),
1438
attr->values[i].range.lower,
1439
attr->values[i].range.upper);
1440
return (NULL);
1441
}
1442
1443
lowerpagerange = attr->values[i].range.upper + 1;
1444
}
1445
}
1446
1447
/*
1448
* Do media selection as needed...
1449
*/
1450
1451
if (!ippFindAttribute(con->request, "PageRegion", IPP_TAG_ZERO) &&
1452
!ippFindAttribute(con->request, "PageSize", IPP_TAG_ZERO) &&
1453
_ppdCacheGetPageSize(printer->pc, con->request, NULL, &exact))
1454
{
1455
if (!exact &&
1456
(media_col = ippFindAttribute(con->request, "media-col",
1457
IPP_TAG_BEGIN_COLLECTION)) != NULL)
1458
{
1459
send_ipp_status(con, IPP_OK_SUBST, _("Unsupported margins."));
1460
1461
unsup_col = ippNew();
1462
if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1463
"media-bottom-margin",
1464
IPP_TAG_INTEGER)) != NULL)
1465
ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1466
"media-bottom-margin", media_margin->values[0].integer);
1467
1468
if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1469
"media-left-margin",
1470
IPP_TAG_INTEGER)) != NULL)
1471
ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1472
"media-left-margin", media_margin->values[0].integer);
1473
1474
if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1475
"media-right-margin",
1476
IPP_TAG_INTEGER)) != NULL)
1477
ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1478
"media-right-margin", media_margin->values[0].integer);
1479
1480
if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1481
"media-top-margin",
1482
IPP_TAG_INTEGER)) != NULL)
1483
ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1484
"media-top-margin", media_margin->values[0].integer);
1485
1486
ippAddCollection(con->response, IPP_TAG_UNSUPPORTED_GROUP, "media-col",
1487
unsup_col);
1488
ippDelete(unsup_col);
1489
}
1490
}
1491
1492
/*
1493
* Make sure we aren't over our limit...
1494
*/
1495
1496
if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs)
1497
cupsdCleanJobs();
1498
1499
if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs)
1500
{
1501
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Too many active jobs."));
1502
return (NULL);
1503
}
1504
1505
if ((i = check_quotas(con, printer)) < 0)
1506
{
1507
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
1508
return (NULL);
1509
}
1510
else if (i == 0)
1511
{
1512
send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
1513
return (NULL);
1514
}
1515
1516
/*
1517
* Create the job and set things up...
1518
*/
1519
1520
if ((attr = ippFindAttribute(con->request, "job-priority",
1521
IPP_TAG_INTEGER)) != NULL)
1522
priority = attr->values[0].integer;
1523
else
1524
{
1525
if ((val = cupsGetOption("job-priority", printer->num_options,
1526
printer->options)) != NULL)
1527
priority = atoi(val);
1528
else
1529
priority = 50;
1530
1531
ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
1532
priority);
1533
}
1534
1535
if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) == NULL)
1536
ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
1537
else if ((attr->value_tag != IPP_TAG_NAME &&
1538
attr->value_tag != IPP_TAG_NAMELANG) ||
1539
attr->num_values != 1)
1540
{
1541
send_ipp_status(con, IPP_ATTRIBUTES,
1542
_("Bad job-name value: Wrong type or count."));
1543
if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
1544
attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
1545
1546
if (StrictConformance)
1547
return (NULL);
1548
1549
/* Don't use invalid attribute */
1550
ippDeleteAttribute(con->request, attr);
1551
1552
ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
1553
}
1554
else if (!ippValidateAttribute(attr))
1555
{
1556
send_ipp_status(con, IPP_ATTRIBUTES, _("Bad job-name value: %s"),
1557
cupsLastErrorString());
1558
1559
if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
1560
attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
1561
1562
if (StrictConformance)
1563
return (NULL);
1564
1565
/* Don't use invalid attribute */
1566
ippDeleteAttribute(con->request, attr);
1567
1568
ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
1569
}
1570
1571
attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
1572
1573
if ((job = cupsdAddJob(priority, printer->name)) == NULL)
1574
{
1575
send_ipp_status(con, IPP_INTERNAL_ERROR,
1576
_("Unable to add job for destination \"%s\"."),
1577
printer->name);
1578
return (NULL);
1579
}
1580
1581
job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
1582
job->attrs = con->request;
1583
job->dirty = 1;
1584
con->request = ippNewRequest(job->attrs->request.op.operation_id);
1585
1586
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
1587
1588
add_job_uuid(job);
1589
apply_printer_defaults(printer, job);
1590
1591
if (con->username[0])
1592
{
1593
cupsdSetString(&job->username, con->username);
1594
1595
if (attr)
1596
ippSetString(job->attrs, &attr, 0, con->username);
1597
}
1598
else if (attr)
1599
{
1600
cupsdLogMessage(CUPSD_LOG_DEBUG,
1601
"add_job: requesting-user-name=\"%s\"",
1602
attr->values[0].string.text);
1603
1604
cupsdSetString(&job->username, attr->values[0].string.text);
1605
}
1606
else
1607
cupsdSetString(&job->username, "anonymous");
1608
1609
if (!attr)
1610
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
1611
"job-originating-user-name", NULL, job->username);
1612
else
1613
{
1614
ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
1615
ippSetName(job->attrs, &attr, "job-originating-user-name");
1616
}
1617
1618
if (con->username[0] || auth_info)
1619
{
1620
save_auth_info(con, job, auth_info);
1621
1622
/*
1623
* Remove the auth-info attribute from the attribute data...
1624
*/
1625
1626
if (auth_info)
1627
ippDeleteAttribute(job->attrs, auth_info);
1628
}
1629
1630
if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL)
1631
cupsdSetString(&(job->name), attr->values[0].string.text);
1632
1633
if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name",
1634
IPP_TAG_ZERO)) != NULL)
1635
{
1636
/*
1637
* Request contains a job-originating-host-name attribute; validate it...
1638
*/
1639
1640
if (attr->value_tag != IPP_TAG_NAME ||
1641
attr->num_values != 1 ||
1642
strcmp(con->http->hostname, "localhost"))
1643
{
1644
/*
1645
* Can't override the value if we aren't connected via localhost.
1646
* Also, we can only have 1 value and it must be a name value.
1647
*/
1648
1649
ippDeleteAttribute(job->attrs, attr);
1650
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http->hostname);
1651
}
1652
else
1653
ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
1654
}
1655
else
1656
{
1657
/*
1658
* No job-originating-host-name attribute, so use the hostname from
1659
* the connection...
1660
*/
1661
1662
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
1663
"job-originating-host-name", NULL, con->http->hostname);
1664
}
1665
1666
ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-completed");
1667
ippAddDate(job->attrs, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(time(NULL)));
1668
ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-processing");
1669
ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "time-at-completed");
1670
ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", time(NULL));
1671
ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "time-at-processing");
1672
1673
/*
1674
* Add remaining job attributes...
1675
*/
1676
1677
ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
1678
job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
1679
"job-state", IPP_JOB_STOPPED);
1680
job->state_value = (ipp_jstate_t)job->state->values[0].integer;
1681
job->reasons = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
1682
"job-state-reasons", NULL, "job-incoming");
1683
job->impressions = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", 0);
1684
job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
1685
"job-media-sheets-completed", 0);
1686
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
1687
printer->uri);
1688
1689
if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
1690
attr->values[0].integer = 0;
1691
else
1692
ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", 0);
1693
1694
if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
1695
IPP_TAG_KEYWORD)) == NULL)
1696
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
1697
if (!attr)
1698
{
1699
if ((val = cupsGetOption("job-hold-until", printer->num_options,
1700
printer->options)) == NULL)
1701
val = "no-hold";
1702
1703
attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
1704
"job-hold-until", NULL, val);
1705
}
1706
1707
if (printer->holding_new_jobs)
1708
{
1709
/*
1710
* Hold all new jobs on this printer...
1711
*/
1712
1713
if (attr && strcmp(attr->values[0].string.text, "no-hold"))
1714
cupsdSetJobHoldUntil(job, ippGetString(attr, 0, NULL), 0);
1715
else
1716
cupsdSetJobHoldUntil(job, "indefinite", 0);
1717
1718
job->state->values[0].integer = IPP_JOB_HELD;
1719
job->state_value = IPP_JOB_HELD;
1720
1721
ippSetString(job->attrs, &job->reasons, 0, "job-held-on-create");
1722
}
1723
else if (attr && strcmp(attr->values[0].string.text, "no-hold"))
1724
{
1725
/*
1726
* Hold job until specified time...
1727
*/
1728
1729
cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0);
1730
1731
job->state->values[0].integer = IPP_JOB_HELD;
1732
job->state_value = IPP_JOB_HELD;
1733
1734
ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified");
1735
}
1736
else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB)
1737
{
1738
job->hold_until = time(NULL) + MultipleOperationTimeout;
1739
job->state->values[0].integer = IPP_JOB_HELD;
1740
job->state_value = IPP_JOB_HELD;
1741
}
1742
else
1743
{
1744
job->state->values[0].integer = IPP_JOB_PENDING;
1745
job->state_value = IPP_JOB_PENDING;
1746
1747
ippSetString(job->attrs, &job->reasons, 0, "none");
1748
}
1749
1750
if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification)
1751
{
1752
/*
1753
* Add job sheets options...
1754
*/
1755
1756
if ((attr = ippFindAttribute(job->attrs, "job-sheets",
1757
IPP_TAG_ZERO)) == NULL)
1758
{
1759
cupsdLogMessage(CUPSD_LOG_DEBUG,
1760
"Adding default job-sheets values \"%s,%s\"...",
1761
printer->job_sheets[0], printer->job_sheets[1]);
1762
1763
attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
1764
2, NULL, NULL);
1765
ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
1766
ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
1767
}
1768
1769
job->job_sheets = attr;
1770
1771
/*
1772
* Enforce classification level if set...
1773
*/
1774
1775
if (Classification)
1776
{
1777
cupsdLogMessage(CUPSD_LOG_INFO,
1778
"Classification=\"%s\", ClassifyOverride=%d",
1779
Classification ? Classification : "(null)",
1780
ClassifyOverride);
1781
1782
if (ClassifyOverride)
1783
{
1784
if (!strcmp(attr->values[0].string.text, "none") &&
1785
(attr->num_values == 1 ||
1786
!strcmp(attr->values[1].string.text, "none")))
1787
{
1788
/*
1789
* Force the leading banner to have the classification on it...
1790
*/
1791
1792
ippSetString(job->attrs, &attr, 0, Classification);
1793
1794
cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
1795
"job-sheets=\"%s,none\", "
1796
"job-originating-user-name=\"%s\"",
1797
Classification, job->username);
1798
}
1799
else if (attr->num_values == 2 &&
1800
strcmp(attr->values[0].string.text,
1801
attr->values[1].string.text) &&
1802
strcmp(attr->values[0].string.text, "none") &&
1803
strcmp(attr->values[1].string.text, "none"))
1804
{
1805
/*
1806
* Can't put two different security markings on the same document!
1807
*/
1808
1809
ippSetString(job->attrs, &attr, 1, attr->values[0].string.text);
1810
1811
cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
1812
"job-sheets=\"%s,%s\", "
1813
"job-originating-user-name=\"%s\"",
1814
attr->values[0].string.text,
1815
attr->values[1].string.text, job->username);
1816
}
1817
else if (strcmp(attr->values[0].string.text, Classification) &&
1818
strcmp(attr->values[0].string.text, "none") &&
1819
(attr->num_values == 1 ||
1820
(strcmp(attr->values[1].string.text, Classification) &&
1821
strcmp(attr->values[1].string.text, "none"))))
1822
{
1823
if (attr->num_values == 1)
1824
cupsdLogJob(job, CUPSD_LOG_NOTICE,
1825
"CLASSIFICATION OVERRIDDEN "
1826
"job-sheets=\"%s\", "
1827
"job-originating-user-name=\"%s\"",
1828
attr->values[0].string.text, job->username);
1829
else
1830
cupsdLogJob(job, CUPSD_LOG_NOTICE,
1831
"CLASSIFICATION OVERRIDDEN "
1832
"job-sheets=\"%s,%s\",fffff "
1833
"job-originating-user-name=\"%s\"",
1834
attr->values[0].string.text,
1835
attr->values[1].string.text, job->username);
1836
}
1837
}
1838
else if (strcmp(attr->values[0].string.text, Classification) &&
1839
(attr->num_values == 1 ||
1840
strcmp(attr->values[1].string.text, Classification)))
1841
{
1842
/*
1843
* Force the banner to have the classification on it...
1844
*/
1845
1846
if (attr->num_values > 1 &&
1847
!strcmp(attr->values[0].string.text, attr->values[1].string.text))
1848
{
1849
ippSetString(job->attrs, &attr, 0, Classification);
1850
ippSetString(job->attrs, &attr, 1, Classification);
1851
}
1852
else
1853
{
1854
if (attr->num_values == 1 ||
1855
strcmp(attr->values[0].string.text, "none"))
1856
ippSetString(job->attrs, &attr, 0, Classification);
1857
1858
if (attr->num_values > 1 &&
1859
strcmp(attr->values[1].string.text, "none"))
1860
ippSetString(job->attrs, &attr, 1, Classification);
1861
}
1862
1863
if (attr->num_values > 1)
1864
cupsdLogJob(job, CUPSD_LOG_NOTICE,
1865
"CLASSIFICATION FORCED "
1866
"job-sheets=\"%s,%s\", "
1867
"job-originating-user-name=\"%s\"",
1868
attr->values[0].string.text,
1869
attr->values[1].string.text, job->username);
1870
else
1871
cupsdLogJob(job, CUPSD_LOG_NOTICE,
1872
"CLASSIFICATION FORCED "
1873
"job-sheets=\"%s\", "
1874
"job-originating-user-name=\"%s\"",
1875
Classification, job->username);
1876
}
1877
}
1878
1879
/*
1880
* See if we need to add the starting sheet...
1881
*/
1882
1883
if (!(printer->type & CUPS_PRINTER_REMOTE))
1884
{
1885
cupsdLogJob(job, CUPSD_LOG_INFO, "Adding start banner page \"%s\".",
1886
attr->values[0].string.text);
1887
1888
if ((kbytes = copy_banner(con, job, attr->values[0].string.text)) < 0)
1889
{
1890
cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
1891
"Aborting job because the start banner could not be "
1892
"copied.");
1893
return (NULL);
1894
}
1895
1896
cupsdUpdateQuota(printer, job->username, 0, kbytes);
1897
}
1898
}
1899
else if ((attr = ippFindAttribute(job->attrs, "job-sheets",
1900
IPP_TAG_ZERO)) != NULL)
1901
job->job_sheets = attr;
1902
1903
/*
1904
* Fill in the response info...
1905
*/
1906
1907
httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, con->clientname, con->clientport, "/jobs/%d", job->id);
1908
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri);
1909
1910
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
1911
1912
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
1913
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_TEXT, "job-state-message", NULL, "");
1914
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, job->reasons->values[0].string.text);
1915
1916
con->response->request.status.status_code = IPP_OK;
1917
1918
/*
1919
* Add any job subscriptions...
1920
*/
1921
1922
add_job_subscriptions(con, job);
1923
1924
/*
1925
* Set all but the first two attributes to the job attributes group...
1926
*/
1927
1928
for (attr = job->attrs->attrs->next->next; attr; attr = attr->next)
1929
attr->group_tag = IPP_TAG_JOB;
1930
1931
/*
1932
* Fire the "job created" event...
1933
*/
1934
1935
cupsdAddEvent(CUPSD_EVENT_JOB_CREATED, printer, job, "Job created.");
1936
1937
/*
1938
* Return the new job...
1939
*/
1940
1941
return (job);
1942
}
1943
1944
1945
/*
1946
* 'add_job_subscriptions()' - Add any subscriptions for a job.
1947
*/
1948
1949
static void
1950
add_job_subscriptions(
1951
cupsd_client_t *con, /* I - Client connection */
1952
cupsd_job_t *job) /* I - Newly created job */
1953
{
1954
int i; /* Looping var */
1955
ipp_attribute_t *prev, /* Previous attribute */
1956
*next, /* Next attribute */
1957
*attr; /* Current attribute */
1958
cupsd_subscription_t *sub; /* Subscription object */
1959
const char *recipient, /* notify-recipient-uri */
1960
*pullmethod; /* notify-pull-method */
1961
ipp_attribute_t *user_data; /* notify-user-data */
1962
int interval; /* notify-time-interval */
1963
unsigned mask; /* notify-events */
1964
1965
1966
/*
1967
* Find the first subscription group attribute; return if we have
1968
* none...
1969
*/
1970
1971
for (attr = job->attrs->attrs; attr; attr = attr->next)
1972
if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
1973
break;
1974
1975
if (!attr)
1976
return;
1977
1978
/*
1979
* Process the subscription attributes in the request...
1980
*/
1981
1982
while (attr)
1983
{
1984
recipient = NULL;
1985
pullmethod = NULL;
1986
user_data = NULL;
1987
interval = 0;
1988
mask = CUPSD_EVENT_NONE;
1989
1990
while (attr && attr->group_tag != IPP_TAG_ZERO)
1991
{
1992
if (!strcmp(attr->name, "notify-recipient-uri") &&
1993
attr->value_tag == IPP_TAG_URI)
1994
{
1995
/*
1996
* Validate the recipient scheme against the ServerBin/notifier
1997
* directory...
1998
*/
1999
2000
char notifier[1024], /* Notifier filename */
2001
scheme[HTTP_MAX_URI], /* Scheme portion of URI */
2002
userpass[HTTP_MAX_URI], /* Username portion of URI */
2003
host[HTTP_MAX_URI], /* Host portion of URI */
2004
resource[HTTP_MAX_URI]; /* Resource portion of URI */
2005
int port; /* Port portion of URI */
2006
struct stat info; /* File information */
2007
2008
recipient = attr->values[0].string.text;
2009
2010
if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
2011
scheme, sizeof(scheme), userpass, sizeof(userpass),
2012
host, sizeof(host), &port,
2013
resource, sizeof(resource)) < HTTP_URI_OK)
2014
{
2015
send_ipp_status(con, IPP_NOT_POSSIBLE,
2016
_("Bad notify-recipient-uri \"%s\"."), recipient);
2017
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2018
"notify-status-code", IPP_URI_SCHEME);
2019
return;
2020
}
2021
2022
snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, scheme);
2023
if (access(notifier, X_OK) || stat(notifier, &info) || !S_ISREG(info.st_mode))
2024
{
2025
send_ipp_status(con, IPP_NOT_POSSIBLE,
2026
_("notify-recipient-uri URI \"%s\" uses unknown "
2027
"scheme."), recipient);
2028
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2029
"notify-status-code", IPP_URI_SCHEME);
2030
return;
2031
}
2032
2033
if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient))
2034
{
2035
send_ipp_status(con, IPP_NOT_POSSIBLE,
2036
_("notify-recipient-uri URI \"%s\" is already used."),
2037
recipient);
2038
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2039
"notify-status-code", IPP_ATTRIBUTES);
2040
return;
2041
}
2042
}
2043
else if (!strcmp(attr->name, "notify-pull-method") &&
2044
attr->value_tag == IPP_TAG_KEYWORD)
2045
{
2046
pullmethod = attr->values[0].string.text;
2047
2048
if (strcmp(pullmethod, "ippget"))
2049
{
2050
send_ipp_status(con, IPP_NOT_POSSIBLE,
2051
_("Bad notify-pull-method \"%s\"."), pullmethod);
2052
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2053
"notify-status-code", IPP_ATTRIBUTES);
2054
return;
2055
}
2056
}
2057
else if (!strcmp(attr->name, "notify-charset") &&
2058
attr->value_tag == IPP_TAG_CHARSET &&
2059
strcmp(attr->values[0].string.text, "us-ascii") &&
2060
strcmp(attr->values[0].string.text, "utf-8"))
2061
{
2062
send_ipp_status(con, IPP_CHARSET,
2063
_("Character set \"%s\" not supported."),
2064
attr->values[0].string.text);
2065
return;
2066
}
2067
else if (!strcmp(attr->name, "notify-natural-language") &&
2068
(attr->value_tag != IPP_TAG_LANGUAGE ||
2069
strcmp(attr->values[0].string.text, DefaultLanguage)))
2070
{
2071
send_ipp_status(con, IPP_CHARSET,
2072
_("Language \"%s\" not supported."),
2073
attr->values[0].string.text);
2074
return;
2075
}
2076
else if (!strcmp(attr->name, "notify-user-data") &&
2077
attr->value_tag == IPP_TAG_STRING)
2078
{
2079
if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
2080
{
2081
send_ipp_status(con, IPP_REQUEST_VALUE,
2082
_("The notify-user-data value is too large "
2083
"(%d > 63 octets)."),
2084
attr->values[0].unknown.length);
2085
return;
2086
}
2087
2088
user_data = attr;
2089
}
2090
else if (!strcmp(attr->name, "notify-events") &&
2091
attr->value_tag == IPP_TAG_KEYWORD)
2092
{
2093
for (i = 0; i < attr->num_values; i ++)
2094
mask |= cupsdEventValue(attr->values[i].string.text);
2095
}
2096
else if (!strcmp(attr->name, "notify-lease-duration"))
2097
{
2098
send_ipp_status(con, IPP_BAD_REQUEST,
2099
_("The notify-lease-duration attribute cannot be "
2100
"used with job subscriptions."));
2101
return;
2102
}
2103
else if (!strcmp(attr->name, "notify-time-interval") &&
2104
attr->value_tag == IPP_TAG_INTEGER)
2105
interval = attr->values[0].integer;
2106
2107
attr = attr->next;
2108
}
2109
2110
if (!recipient && !pullmethod)
2111
break;
2112
2113
if (mask == CUPSD_EVENT_NONE)
2114
mask = CUPSD_EVENT_JOB_COMPLETED;
2115
2116
if ((sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job,
2117
recipient, 0)) != NULL)
2118
{
2119
sub->interval = interval;
2120
2121
cupsdSetString(&sub->owner, job->username);
2122
2123
if (user_data)
2124
{
2125
sub->user_data_len = user_data->values[0].unknown.length;
2126
memcpy(sub->user_data, user_data->values[0].unknown.data,
2127
(size_t)sub->user_data_len);
2128
}
2129
2130
ippAddSeparator(con->response);
2131
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
2132
"notify-subscription-id", sub->id);
2133
2134
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d",
2135
sub->id, job->id);
2136
}
2137
2138
if (attr)
2139
attr = attr->next;
2140
}
2141
2142
cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
2143
2144
/*
2145
* Remove all of the subscription attributes from the job request...
2146
*
2147
* TODO: Optimize this since subscription groups have to come at the
2148
* end of the request...
2149
*/
2150
2151
for (attr = job->attrs->attrs, prev = NULL; attr; attr = next)
2152
{
2153
next = attr->next;
2154
2155
if (attr->group_tag == IPP_TAG_SUBSCRIPTION ||
2156
attr->group_tag == IPP_TAG_ZERO)
2157
{
2158
/*
2159
* Free and remove this attribute...
2160
*/
2161
2162
ippDeleteAttribute(NULL, attr);
2163
2164
if (prev)
2165
prev->next = next;
2166
else
2167
job->attrs->attrs = next;
2168
}
2169
else
2170
prev = attr;
2171
}
2172
2173
job->attrs->last = prev;
2174
job->attrs->current = prev;
2175
}
2176
2177
2178
/*
2179
* 'add_job_uuid()' - Add job-uuid attribute to a job.
2180
*
2181
* See RFC 4122 for the definition of UUIDs and the format.
2182
*/
2183
2184
static void
2185
add_job_uuid(cupsd_job_t *job) /* I - Job */
2186
{
2187
char uuid[64]; /* job-uuid string */
2188
2189
2190
/*
2191
* Add a job-uuid attribute if none exists...
2192
*/
2193
2194
if (!ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI))
2195
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL,
2196
httpAssembleUUID(ServerName, RemotePort, job->dest, job->id,
2197
uuid, sizeof(uuid)));
2198
}
2199
2200
2201
/*
2202
* 'add_printer()' - Add a printer to the system.
2203
*/
2204
2205
static void
2206
add_printer(cupsd_client_t *con, /* I - Client connection */
2207
ipp_attribute_t *uri) /* I - URI of printer */
2208
{
2209
http_status_t status; /* Policy status */
2210
int i = 0; /* Looping var */
2211
char scheme[HTTP_MAX_URI], /* Method portion of URI */
2212
username[HTTP_MAX_URI], /* Username portion of URI */
2213
host[HTTP_MAX_URI], /* Host portion of URI */
2214
resource[HTTP_MAX_URI]; /* Resource portion of URI */
2215
int port; /* Port portion of URI */
2216
cupsd_printer_t *printer; /* Printer/class */
2217
ipp_attribute_t *attr; /* Printer attribute */
2218
cups_file_t *fp; /* Script/PPD file */
2219
char line[1024]; /* Line from file... */
2220
char srcfile[1024], /* Source Script/PPD file */
2221
dstfile[1024]; /* Destination Script/PPD file */
2222
int modify; /* Non-zero if we are modifying */
2223
int changed_driver, /* Changed the PPD? */
2224
need_restart_job, /* Need to restart job? */
2225
set_device_uri, /* Did we set the device URI? */
2226
set_port_monitor; /* Did we set the port monitor? */
2227
2228
2229
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con,
2230
con->number, uri->values[0].string.text);
2231
2232
/*
2233
* Do we have a valid URI?
2234
*/
2235
2236
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
2237
sizeof(scheme), username, sizeof(username), host,
2238
sizeof(host), &port, resource, sizeof(resource));
2239
2240
if (strncmp(resource, "/printers/", 10) || strlen(resource) == 10)
2241
{
2242
/*
2243
* No, return an error...
2244
*/
2245
2246
send_ipp_status(con, IPP_BAD_REQUEST,
2247
_("The printer-uri must be of the form "
2248
"\"ipp://HOSTNAME/printers/PRINTERNAME\"."));
2249
return;
2250
}
2251
2252
/*
2253
* Do we have a valid printer name?
2254
*/
2255
2256
if (!validate_name(resource + 10))
2257
{
2258
/*
2259
* No, return an error...
2260
*/
2261
2262
send_ipp_status(con, IPP_BAD_REQUEST,
2263
_("The printer-uri \"%s\" contains invalid characters."),
2264
uri->values[0].string.text);
2265
return;
2266
}
2267
2268
/*
2269
* See if the printer already exists; if not, create a new printer...
2270
*/
2271
2272
if ((printer = cupsdFindPrinter(resource + 10)) == NULL)
2273
{
2274
/*
2275
* Printer doesn't exist; see if we have a class of the same name...
2276
*/
2277
2278
if (cupsdFindClass(resource + 10))
2279
{
2280
/*
2281
* Yes, return an error...
2282
*/
2283
2284
send_ipp_status(con, IPP_NOT_POSSIBLE,
2285
_("A class named \"%s\" already exists."),
2286
resource + 10);
2287
return;
2288
}
2289
2290
/*
2291
* No, check the default policy then add the printer...
2292
*/
2293
2294
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
2295
{
2296
send_http_error(con, status, NULL);
2297
return;
2298
}
2299
2300
printer = cupsdAddPrinter(resource + 10);
2301
modify = 0;
2302
2303
printer->printer_id = NextPrinterId ++;
2304
}
2305
else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
2306
NULL)) != HTTP_OK)
2307
{
2308
send_http_error(con, status, printer);
2309
return;
2310
}
2311
else
2312
modify = 1;
2313
2314
/*
2315
* Look for attributes and copy them over as needed...
2316
*/
2317
2318
changed_driver = 0;
2319
need_restart_job = 0;
2320
2321
if ((attr = ippFindAttribute(con->request, "printer-is-temporary", IPP_TAG_BOOLEAN)) != NULL)
2322
printer->temporary = ippGetBoolean(attr, 0);
2323
2324
if ((attr = ippFindAttribute(con->request, "printer-location",
2325
IPP_TAG_TEXT)) != NULL)
2326
cupsdSetString(&printer->location, attr->values[0].string.text);
2327
2328
if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4))
2329
cupsdSetString(&printer->geo_location, attr->values[0].string.text);
2330
2331
if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL)
2332
cupsdSetString(&printer->organization, attr->values[0].string.text);
2333
2334
if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL)
2335
cupsdSetString(&printer->organizational_unit, attr->values[0].string.text);
2336
2337
if ((attr = ippFindAttribute(con->request, "printer-info",
2338
IPP_TAG_TEXT)) != NULL)
2339
cupsdSetString(&printer->info, attr->values[0].string.text);
2340
2341
set_device_uri = 0;
2342
2343
if ((attr = ippFindAttribute(con->request, "ColorModel", IPP_TAG_NAME)) != NULL)
2344
{
2345
const char * keyword = NULL;
2346
2347
if (!strcmp(attr->values[0].string.text, "FastGray") || !strcmp(attr->values[0].string.text, "Gray") || !strcmp(attr->values[0].string.text, "DeviceGray"))
2348
keyword = "monochrome";
2349
else
2350
keyword = "color";
2351
2352
printer->num_options = cupsAddOption("print-color-mode", keyword, printer->num_options, &printer->options);
2353
}
2354
2355
if ((attr = ippFindAttribute(con->request, "device-uri",
2356
IPP_TAG_URI)) != NULL)
2357
{
2358
/*
2359
* Do we have a valid device URI?
2360
*/
2361
2362
http_uri_status_t uri_status; /* URI separation status */
2363
char old_device_uri[1024];
2364
/* Old device URI */
2365
2366
need_restart_job = 1;
2367
2368
uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
2369
attr->values[0].string.text,
2370
scheme, sizeof(scheme),
2371
username, sizeof(username),
2372
host, sizeof(host), &port,
2373
resource, sizeof(resource));
2374
2375
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s device-uri: %s", printer->name, httpURIStatusString(uri_status));
2376
2377
if (uri_status < HTTP_URI_OK)
2378
{
2379
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"."),
2380
attr->values[0].string.text);
2381
if (!modify)
2382
cupsdDeletePrinter(printer, 0);
2383
2384
return;
2385
}
2386
2387
if (!strcmp(scheme, "file"))
2388
{
2389
/*
2390
* See if the administrator has enabled file devices...
2391
*/
2392
2393
if (!FileDevice && strcmp(resource, "/dev/null"))
2394
{
2395
/*
2396
* File devices are disabled and the URL is not file:/dev/null...
2397
*/
2398
2399
send_ipp_status(con, IPP_NOT_POSSIBLE,
2400
_("File device URIs have been disabled. "
2401
"To enable, see the FileDevice directive in "
2402
"\"%s/cups-files.conf\"."),
2403
ServerRoot);
2404
if (!modify)
2405
cupsdDeletePrinter(printer, 0);
2406
2407
return;
2408
}
2409
}
2410
else
2411
{
2412
/*
2413
* See if the backend exists and is executable...
2414
*/
2415
2416
snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin, scheme);
2417
if (access(srcfile, X_OK))
2418
{
2419
/*
2420
* Could not find device in list!
2421
*/
2422
2423
send_ipp_status(con, IPP_NOT_POSSIBLE,
2424
_("Bad device-uri scheme \"%s\"."), scheme);
2425
if (!modify)
2426
cupsdDeletePrinter(printer, 0);
2427
2428
return;
2429
}
2430
}
2431
2432
if (printer->sanitized_device_uri)
2433
strlcpy(old_device_uri, printer->sanitized_device_uri,
2434
sizeof(old_device_uri));
2435
else
2436
old_device_uri[0] = '\0';
2437
2438
cupsdSetDeviceURI(printer, attr->values[0].string.text);
2439
2440
cupsdLogMessage(CUPSD_LOG_INFO,
2441
"Setting %s device-uri to \"%s\" (was \"%s\".)",
2442
printer->name, printer->sanitized_device_uri,
2443
old_device_uri);
2444
2445
set_device_uri = 1;
2446
}
2447
2448
set_port_monitor = 0;
2449
2450
if ((attr = ippFindAttribute(con->request, "port-monitor",
2451
IPP_TAG_NAME)) != NULL)
2452
{
2453
ipp_attribute_t *supported; /* port-monitor-supported attribute */
2454
2455
2456
need_restart_job = 1;
2457
2458
supported = ippFindAttribute(printer->ppd_attrs, "port-monitor-supported",
2459
IPP_TAG_NAME);
2460
if (supported)
2461
{
2462
for (i = 0; i < supported->num_values; i ++)
2463
if (!strcmp(supported->values[i].string.text,
2464
attr->values[0].string.text))
2465
break;
2466
}
2467
2468
if (!supported || i >= supported->num_values)
2469
{
2470
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"."),
2471
attr->values[0].string.text);
2472
if (!modify)
2473
cupsdDeletePrinter(printer, 0);
2474
2475
return;
2476
}
2477
2478
cupsdLogMessage(CUPSD_LOG_INFO,
2479
"Setting %s port-monitor to \"%s\" (was \"%s\".)",
2480
printer->name, attr->values[0].string.text,
2481
printer->port_monitor ? printer->port_monitor : "none");
2482
2483
if (strcmp(attr->values[0].string.text, "none"))
2484
cupsdSetString(&printer->port_monitor, attr->values[0].string.text);
2485
else
2486
cupsdClearString(&printer->port_monitor);
2487
2488
set_port_monitor = 1;
2489
}
2490
2491
if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
2492
IPP_TAG_BOOLEAN)) != NULL &&
2493
attr->values[0].boolean != printer->accepting)
2494
{
2495
cupsdLogMessage(CUPSD_LOG_INFO,
2496
"Setting %s printer-is-accepting-jobs to %d (was %d.)",
2497
printer->name, attr->values[0].boolean, printer->accepting);
2498
2499
printer->accepting = attr->values[0].boolean;
2500
2501
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
2502
"%s accepting jobs.",
2503
printer->accepting ? "Now" : "No longer");
2504
}
2505
2506
if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL)
2507
{
2508
if (ippGetBoolean(attr, 0) &&
2509
printer->num_auth_info_required == 1 &&
2510
!strcmp(printer->auth_info_required[0], "negotiate"))
2511
{
2512
send_ipp_status(con, IPP_BAD_REQUEST,
2513
_("Cannot share a remote Kerberized printer."));
2514
if (!modify)
2515
cupsdDeletePrinter(printer, 0);
2516
2517
return;
2518
}
2519
2520
if (printer->type & CUPS_PRINTER_REMOTE)
2521
{
2522
/*
2523
* Cannot re-share remote printers.
2524
*/
2525
2526
send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues."));
2527
if (!modify)
2528
cupsdDeletePrinter(printer, 0);
2529
2530
return;
2531
}
2532
2533
if (printer->shared && !ippGetBoolean(attr, 0))
2534
cupsdDeregisterPrinter(printer, 1);
2535
2536
cupsdLogMessage(CUPSD_LOG_INFO,
2537
"Setting %s printer-is-shared to %d (was %d.)",
2538
printer->name, attr->values[0].boolean, printer->shared);
2539
2540
printer->shared = ippGetBoolean(attr, 0);
2541
if (printer->shared && printer->temporary)
2542
printer->temporary = 0;
2543
}
2544
2545
if ((attr = ippFindAttribute(con->request, "printer-state",
2546
IPP_TAG_ENUM)) != NULL)
2547
{
2548
if (attr->values[0].integer != IPP_PRINTER_IDLE &&
2549
attr->values[0].integer != IPP_PRINTER_STOPPED)
2550
{
2551
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d."),
2552
attr->values[0].integer);
2553
if (!modify)
2554
cupsdDeletePrinter(printer, 0);
2555
2556
return;
2557
}
2558
2559
cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
2560
printer->name, attr->values[0].integer, printer->state);
2561
2562
if (attr->values[0].integer == IPP_PRINTER_STOPPED)
2563
cupsdStopPrinter(printer, 0);
2564
else
2565
{
2566
need_restart_job = 1;
2567
cupsdSetPrinterState(printer, (ipp_pstate_t)(attr->values[0].integer), 0);
2568
}
2569
}
2570
2571
if ((attr = ippFindAttribute(con->request, "printer-state-message",
2572
IPP_TAG_TEXT)) != NULL)
2573
{
2574
strlcpy(printer->state_message, attr->values[0].string.text,
2575
sizeof(printer->state_message));
2576
2577
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, "%s",
2578
printer->state_message);
2579
}
2580
2581
if ((attr = ippFindAttribute(con->request, "printer-state-reasons",
2582
IPP_TAG_KEYWORD)) != NULL)
2583
{
2584
if (attr->num_values >
2585
(int)(sizeof(printer->reasons) / sizeof(printer->reasons[0])))
2586
{
2587
send_ipp_status(con, IPP_NOT_POSSIBLE,
2588
_("Too many printer-state-reasons values (%d > %d)."),
2589
attr->num_values,
2590
(int)(sizeof(printer->reasons) /
2591
sizeof(printer->reasons[0])));
2592
if (!modify)
2593
cupsdDeletePrinter(printer, 0);
2594
2595
return;
2596
}
2597
2598
for (i = 0; i < printer->num_reasons; i ++)
2599
_cupsStrFree(printer->reasons[i]);
2600
2601
printer->num_reasons = 0;
2602
for (i = 0; i < attr->num_values; i ++)
2603
{
2604
if (!strcmp(attr->values[i].string.text, "none"))
2605
continue;
2606
2607
printer->reasons[printer->num_reasons] = _cupsStrAlloc(attr->values[i].string.text);
2608
printer->num_reasons ++;
2609
2610
if (!strcmp(attr->values[i].string.text, "paused") &&
2611
printer->state != IPP_PRINTER_STOPPED)
2612
{
2613
cupsdLogMessage(CUPSD_LOG_INFO,
2614
"Setting %s printer-state to %d (was %d.)",
2615
printer->name, IPP_PRINTER_STOPPED, printer->state);
2616
cupsdStopPrinter(printer, 0);
2617
}
2618
}
2619
2620
if (PrintcapFormat == PRINTCAP_PLIST)
2621
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
2622
2623
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
2624
"Printer \"%s\" state changed.", printer->name);
2625
}
2626
2627
if (!set_printer_defaults(con, printer))
2628
{
2629
if (!modify)
2630
cupsdDeletePrinter(printer, 0);
2631
2632
return;
2633
}
2634
2635
if ((attr = ippFindAttribute(con->request, "auth-info-required",
2636
IPP_TAG_KEYWORD)) != NULL)
2637
cupsdSetAuthInfoRequired(printer, NULL, attr);
2638
2639
/*
2640
* See if we have all required attributes...
2641
*/
2642
2643
if (!printer->device_uri)
2644
cupsdSetString(&printer->device_uri, "file:///dev/null");
2645
2646
/*
2647
* See if we have a PPD file attached to the request...
2648
*/
2649
2650
if (con->filename)
2651
{
2652
need_restart_job = 1;
2653
changed_driver = 1;
2654
2655
strlcpy(srcfile, con->filename, sizeof(srcfile));
2656
2657
if ((fp = cupsFileOpen(srcfile, "rb")))
2658
{
2659
/*
2660
* Yes; get the first line from it...
2661
*/
2662
2663
line[0] = '\0';
2664
cupsFileGets(fp, line, sizeof(line));
2665
cupsFileClose(fp);
2666
2667
/*
2668
* Then see what kind of file it is...
2669
*/
2670
2671
if (strncmp(line, "*PPD-Adobe", 10))
2672
{
2673
send_ipp_status(con, IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED, _("Bad PPD file."));
2674
if (!modify)
2675
cupsdDeletePrinter(printer, 0);
2676
2677
return;
2678
}
2679
2680
snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
2681
printer->name);
2682
2683
/*
2684
* The new file is a PPD file, so move the file over to the ppd
2685
* directory...
2686
*/
2687
2688
if (copy_file(srcfile, dstfile, ConfigFilePerm))
2689
{
2690
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file - %s"), strerror(errno));
2691
if (!modify)
2692
cupsdDeletePrinter(printer, 0);
2693
2694
return;
2695
}
2696
2697
cupsdLogMessage(CUPSD_LOG_DEBUG, "Copied PPD file successfully");
2698
}
2699
}
2700
else if ((attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL)
2701
{
2702
const char *ppd_name = ippGetString(attr, 0, NULL);
2703
/* ppd-name value */
2704
2705
need_restart_job = 1;
2706
changed_driver = 1;
2707
2708
if (!strcmp(ppd_name, "everywhere"))
2709
{
2710
// Create IPP Everywhere PPD...
2711
if (!printer->device_uri || (strncmp(printer->device_uri, "dnssd://", 8) && strncmp(printer->device_uri, "ipp://", 6) && strncmp(printer->device_uri, "ipps://", 7) && strncmp(printer->device_uri, "ippusb://", 9)))
2712
{
2713
send_ipp_status(con, IPP_INTERNAL_ERROR, _("IPP Everywhere driver requires an IPP connection."));
2714
if (!modify)
2715
cupsdDeletePrinter(printer, 0);
2716
2717
return;
2718
}
2719
2720
// Run a background thread to create the PPD...
2721
_cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer);
2722
}
2723
else if (!strcmp(ppd_name, "raw"))
2724
{
2725
/*
2726
* Raw driver, remove any existing PPD file.
2727
*/
2728
2729
snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, printer->name);
2730
unlink(dstfile);
2731
}
2732
else if (strstr(ppd_name, "../"))
2733
{
2734
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Invalid ppd-name value."));
2735
if (!modify)
2736
cupsdDeletePrinter(printer, 0);
2737
2738
return;
2739
}
2740
else
2741
{
2742
/*
2743
* PPD model file...
2744
*/
2745
2746
snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, printer->name);
2747
2748
if (copy_model(con, ppd_name, dstfile))
2749
{
2750
if (!modify)
2751
cupsdDeletePrinter(printer, 0);
2752
2753
return;
2754
}
2755
2756
cupsdLogMessage(CUPSD_LOG_DEBUG, "Copied PPD file successfully");
2757
}
2758
}
2759
2760
if (changed_driver)
2761
{
2762
/*
2763
* If we changed the PPD, then remove the printer's cache file and clear the
2764
* printer-state-reasons...
2765
*/
2766
2767
char cache_name[1024]; /* Cache filename for printer attrs */
2768
2769
snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, printer->name);
2770
unlink(cache_name);
2771
2772
cupsdSetPrinterReasons(printer, "none");
2773
2774
/*
2775
* (Re)register color profiles...
2776
*/
2777
2778
cupsdRegisterColor(printer);
2779
}
2780
2781
/*
2782
* If we set the device URI but not the port monitor, check which port
2783
* monitor to use by default...
2784
*/
2785
2786
if (set_device_uri && !set_port_monitor)
2787
{
2788
ppd_file_t *ppd; /* PPD file */
2789
ppd_attr_t *ppdattr; /* cupsPortMonitor attribute */
2790
2791
2792
httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme,
2793
sizeof(scheme), username, sizeof(username), host,
2794
sizeof(host), &port, resource, sizeof(resource));
2795
2796
snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot,
2797
printer->name);
2798
if ((ppd = _ppdOpenFile(srcfile, _PPD_LOCALIZATION_NONE)) != NULL)
2799
{
2800
for (ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
2801
ppdattr;
2802
ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
2803
if (!strcmp(scheme, ppdattr->spec))
2804
{
2805
cupsdLogMessage(CUPSD_LOG_INFO,
2806
"Setting %s port-monitor to \"%s\" (was \"%s\".)",
2807
printer->name, ppdattr->value,
2808
printer->port_monitor ? printer->port_monitor
2809
: "none");
2810
2811
if (strcmp(ppdattr->value, "none"))
2812
cupsdSetString(&printer->port_monitor, ppdattr->value);
2813
else
2814
cupsdClearString(&printer->port_monitor);
2815
2816
break;
2817
}
2818
2819
ppdClose(ppd);
2820
}
2821
}
2822
2823
printer->config_time = time(NULL);
2824
2825
/*
2826
* Update the printer attributes and return...
2827
*/
2828
2829
if (!printer->temporary)
2830
{
2831
if (!printer->printer_id)
2832
printer->printer_id = NextPrinterId ++;
2833
2834
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
2835
}
2836
2837
cupsdSetPrinterAttrs(printer);
2838
2839
if (need_restart_job && printer->job)
2840
{
2841
/*
2842
* Restart the current job...
2843
*/
2844
2845
cupsdSetJobState(printer->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
2846
"Job restarted because the printer was modified.");
2847
}
2848
2849
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
2850
2851
if (modify)
2852
{
2853
cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED,
2854
printer, NULL, "Printer \"%s\" modified by \"%s\".",
2855
printer->name, get_username(con));
2856
2857
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".",
2858
printer->name, get_username(con));
2859
}
2860
else
2861
{
2862
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED,
2863
printer, NULL, "New printer \"%s\" added by \"%s\".",
2864
printer->name, get_username(con));
2865
2866
cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".",
2867
printer->name, get_username(con));
2868
}
2869
2870
con->response->request.status.status_code = IPP_OK;
2871
}
2872
2873
2874
/*
2875
* 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
2876
* based upon the printer state...
2877
*/
2878
2879
static void
2880
add_printer_state_reasons(
2881
cupsd_client_t *con, /* I - Client connection */
2882
cupsd_printer_t *p) /* I - Printer info */
2883
{
2884
cupsdLogMessage(CUPSD_LOG_DEBUG2,
2885
"add_printer_state_reasons(%p[%d], %p[%s])",
2886
con, con->number, p, p->name);
2887
2888
if (p->num_reasons == 0)
2889
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2890
"printer-state-reasons", NULL, "none");
2891
else
2892
ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2893
"printer-state-reasons", p->num_reasons, NULL,
2894
(const char * const *)p->reasons);
2895
}
2896
2897
2898
/*
2899
* 'add_queued_job_count()' - Add the "queued-job-count" attribute for
2900
* the specified printer or class.
2901
*/
2902
2903
static void
2904
add_queued_job_count(
2905
cupsd_client_t *con, /* I - Client connection */
2906
cupsd_printer_t *p) /* I - Printer or class */
2907
{
2908
int count; /* Number of jobs on destination */
2909
2910
2911
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])",
2912
con, con->number, p, p->name);
2913
2914
count = cupsdGetPrinterJobCount(p->name);
2915
2916
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2917
"queued-job-count", count);
2918
}
2919
2920
2921
/*
2922
* 'apply_printer_defaults()' - Apply printer default options to a job.
2923
*/
2924
2925
static void
2926
apply_printer_defaults(
2927
cupsd_printer_t *printer, /* I - Printer */
2928
cupsd_job_t *job) /* I - Job */
2929
{
2930
int i, /* Looping var */
2931
num_options; /* Number of default options */
2932
cups_option_t *options, /* Default options */
2933
*option; /* Current option */
2934
2935
2936
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Applying default options...");
2937
2938
/*
2939
* Collect all of the default options and add the missing ones to the
2940
* job object...
2941
*/
2942
2943
for (i = printer->num_options, num_options = 0, options = NULL,
2944
option = printer->options;
2945
i > 0;
2946
i --, option ++)
2947
if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO))
2948
{
2949
if (!strcmp(option->name, "media") && ippFindAttribute(job->attrs, "PageSize", IPP_TAG_NAME))
2950
continue; /* Don't override PageSize */
2951
2952
if (!strcmp(option->name, "output-bin") && ippFindAttribute(job->attrs, "OutputBin", IPP_TAG_NAME))
2953
continue; /* Don't override OutputBin */
2954
2955
if (!strcmp(option->name, "print-quality") && ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_NAME))
2956
continue; /* Don't override cupsPrintQuality */
2957
2958
if (!strcmp(option->name, "print-color-mode") && ippFindAttribute(job->attrs, "ColorModel", IPP_TAG_NAME))
2959
continue; /* Don't override ColorModel */
2960
2961
if (!strcmp(option->name, "sides") && ippFindAttribute(job->attrs, "Duplex", IPP_TAG_NAME))
2962
continue; /* Don't override Duplex */
2963
2964
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding default %s=%s", option->name, option->value);
2965
2966
num_options = cupsAddOption(option->name, option->value, num_options, &options);
2967
}
2968
2969
/*
2970
* Encode these options as attributes in the job object...
2971
*/
2972
2973
cupsEncodeOptions2(job->attrs, num_options, options, IPP_TAG_JOB);
2974
cupsFreeOptions(num_options, options);
2975
}
2976
2977
2978
/*
2979
* 'authenticate_job()' - Set job authentication info.
2980
*/
2981
2982
static void
2983
authenticate_job(cupsd_client_t *con, /* I - Client connection */
2984
ipp_attribute_t *uri) /* I - Job URI */
2985
{
2986
ipp_attribute_t *attr, /* job-id attribute */
2987
*auth_info; /* auth-info attribute */
2988
int jobid; /* Job ID */
2989
cupsd_job_t *job; /* Current job */
2990
char scheme[HTTP_MAX_URI],
2991
/* Method portion of URI */
2992
username[HTTP_MAX_URI],
2993
/* Username portion of URI */
2994
host[HTTP_MAX_URI],
2995
/* Host portion of URI */
2996
resource[HTTP_MAX_URI];
2997
/* Resource portion of URI */
2998
int port; /* Port portion of URI */
2999
3000
3001
cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)",
3002
con, con->number, uri->values[0].string.text);
3003
3004
/*
3005
* Start with "everything is OK" status...
3006
*/
3007
3008
con->response->request.status.status_code = IPP_OK;
3009
3010
/*
3011
* See if we have a job URI or a printer URI...
3012
*/
3013
3014
if (!strcmp(uri->name, "printer-uri"))
3015
{
3016
/*
3017
* Got a printer URI; see if we also have a job-id attribute...
3018
*/
3019
3020
if ((attr = ippFindAttribute(con->request, "job-id",
3021
IPP_TAG_INTEGER)) == NULL)
3022
{
3023
send_ipp_status(con, IPP_BAD_REQUEST,
3024
_("Got a printer-uri attribute but no job-id."));
3025
return;
3026
}
3027
3028
jobid = attr->values[0].integer;
3029
}
3030
else
3031
{
3032
/*
3033
* Got a job URI; parse it to get the job ID...
3034
*/
3035
3036
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
3037
sizeof(scheme), username, sizeof(username), host,
3038
sizeof(host), &port, resource, sizeof(resource));
3039
3040
if (strncmp(resource, "/jobs/", 6))
3041
{
3042
/*
3043
* Not a valid URI!
3044
*/
3045
3046
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
3047
uri->values[0].string.text);
3048
return;
3049
}
3050
3051
jobid = atoi(resource + 6);
3052
}
3053
3054
/*
3055
* See if the job exists...
3056
*/
3057
3058
if ((job = cupsdFindJob(jobid)) == NULL)
3059
{
3060
/*
3061
* Nope - return a "not found" error...
3062
*/
3063
3064
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
3065
return;
3066
}
3067
3068
/*
3069
* See if the job has been completed...
3070
*/
3071
3072
if (job->state_value != IPP_JOB_HELD)
3073
{
3074
/*
3075
* Return a "not-possible" error...
3076
*/
3077
3078
send_ipp_status(con, IPP_NOT_POSSIBLE,
3079
_("Job #%d is not held for authentication."),
3080
jobid);
3081
return;
3082
}
3083
3084
/*
3085
* See if we have already authenticated...
3086
*/
3087
3088
auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
3089
3090
if (!con->username[0] && !auth_info)
3091
{
3092
cupsd_printer_t *printer; /* Job destination */
3093
3094
/*
3095
* No auth data. If we need to authenticate via Kerberos, send a
3096
* HTTP auth challenge, otherwise just return an IPP error...
3097
*/
3098
3099
printer = cupsdFindDest(job->dest);
3100
3101
if (printer && printer->num_auth_info_required > 0 &&
3102
!strcmp(printer->auth_info_required[0], "negotiate"))
3103
send_http_error(con, HTTP_UNAUTHORIZED, printer);
3104
else
3105
send_ipp_status(con, IPP_NOT_AUTHORIZED,
3106
_("No authentication information provided."));
3107
return;
3108
}
3109
3110
/*
3111
* See if the job is owned by the requesting user...
3112
*/
3113
3114
if (!validate_user(job, con, job->username, username, sizeof(username)))
3115
{
3116
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
3117
cupsdFindDest(job->dest));
3118
return;
3119
}
3120
3121
/*
3122
* Save the authentication information for this job...
3123
*/
3124
3125
save_auth_info(con, job, auth_info);
3126
3127
/*
3128
* Reset the job-hold-until value to "no-hold"...
3129
*/
3130
3131
if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
3132
IPP_TAG_KEYWORD)) == NULL)
3133
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
3134
3135
if (attr)
3136
{
3137
ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
3138
ippSetString(job->attrs, &attr, 0, "no-hold");
3139
}
3140
3141
/*
3142
* Release the job and return...
3143
*/
3144
3145
cupsdReleaseJob(job);
3146
3147
cupsdAddEvent(CUPSD_EVENT_JOB_STATE, NULL, job, "Job authenticated by user");
3148
3149
cupsdLogJob(job, CUPSD_LOG_INFO, "Authenticated by \"%s\".", con->username);
3150
3151
cupsdCheckJobs();
3152
}
3153
3154
3155
/*
3156
* 'cancel_all_jobs()' - Cancel all or selected print jobs.
3157
*/
3158
3159
static void
3160
cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */
3161
ipp_attribute_t *uri) /* I - Job or Printer URI */
3162
{
3163
int i; /* Looping var */
3164
http_status_t status; /* Policy status */
3165
cups_ptype_t dtype; /* Destination type */
3166
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
3167
userpass[HTTP_MAX_URI], /* Username portion of URI */
3168
hostname[HTTP_MAX_URI], /* Host portion of URI */
3169
resource[HTTP_MAX_URI]; /* Resource portion of URI */
3170
int port; /* Port portion of URI */
3171
ipp_attribute_t *attr; /* Attribute in request */
3172
const char *username = NULL; /* Username */
3173
cupsd_jobaction_t purge = CUPSD_JOB_DEFAULT;
3174
/* Purge? */
3175
cupsd_printer_t *printer; /* Printer */
3176
ipp_attribute_t *job_ids; /* job-ids attribute */
3177
cupsd_job_t *job; /* Job */
3178
3179
3180
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con,
3181
con->number, uri->values[0].string.text);
3182
3183
/*
3184
* Get the jobs to cancel/purge...
3185
*/
3186
3187
switch (con->request->request.op.operation_id)
3188
{
3189
case IPP_PURGE_JOBS :
3190
/*
3191
* Get the username (if any) for the jobs we want to cancel (only if
3192
* "my-jobs" is specified...
3193
*/
3194
3195
if ((attr = ippFindAttribute(con->request, "my-jobs",
3196
IPP_TAG_BOOLEAN)) != NULL &&
3197
attr->values[0].boolean)
3198
{
3199
if ((attr = ippFindAttribute(con->request, "requesting-user-name",
3200
IPP_TAG_NAME)) != NULL)
3201
username = attr->values[0].string.text;
3202
else
3203
{
3204
send_ipp_status(con, IPP_BAD_REQUEST,
3205
_("Missing requesting-user-name attribute."));
3206
return;
3207
}
3208
}
3209
3210
/*
3211
* Look for the "purge-jobs" attribute...
3212
*/
3213
3214
if ((attr = ippFindAttribute(con->request, "purge-jobs",
3215
IPP_TAG_BOOLEAN)) != NULL)
3216
purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
3217
else
3218
purge = CUPSD_JOB_PURGE;
3219
break;
3220
3221
case IPP_CANCEL_MY_JOBS :
3222
if (con->username[0])
3223
username = con->username;
3224
else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
3225
IPP_TAG_NAME)) != NULL)
3226
username = attr->values[0].string.text;
3227
else
3228
{
3229
send_ipp_status(con, IPP_BAD_REQUEST,
3230
_("Missing requesting-user-name attribute."));
3231
return;
3232
}
3233
3234
default :
3235
break;
3236
}
3237
3238
job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
3239
3240
/*
3241
* See if we have a printer URI...
3242
*/
3243
3244
if (strcmp(uri->name, "printer-uri"))
3245
{
3246
send_ipp_status(con, IPP_BAD_REQUEST,
3247
_("The printer-uri attribute is required."));
3248
return;
3249
}
3250
3251
/*
3252
* And if the destination is valid...
3253
*/
3254
3255
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
3256
{
3257
/*
3258
* Bad URI?
3259
*/
3260
3261
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text,
3262
scheme, sizeof(scheme), userpass, sizeof(userpass),
3263
hostname, sizeof(hostname), &port,
3264
resource, sizeof(resource));
3265
3266
if ((!strncmp(resource, "/printers/", 10) && resource[10]) ||
3267
(!strncmp(resource, "/classes/", 9) && resource[9]))
3268
{
3269
send_ipp_status(con, IPP_NOT_FOUND,
3270
_("The printer or class does not exist."));
3271
return;
3272
}
3273
3274
/*
3275
* Check policy...
3276
*/
3277
3278
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
3279
{
3280
send_http_error(con, status, NULL);
3281
return;
3282
}
3283
3284
if (job_ids)
3285
{
3286
for (i = 0; i < job_ids->num_values; i ++)
3287
{
3288
if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL)
3289
break;
3290
3291
if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS &&
3292
_cups_strcasecmp(job->username, username))
3293
break;
3294
}
3295
3296
if (i < job_ids->num_values)
3297
{
3298
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
3299
job_ids->values[i].integer);
3300
return;
3301
}
3302
3303
for (i = 0; i < job_ids->num_values; i ++)
3304
{
3305
job = cupsdFindJob(job_ids->values[i].integer);
3306
3307
cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
3308
purge == CUPSD_JOB_PURGE ? "Job purged by user." :
3309
"Job canceled by user.");
3310
}
3311
3312
cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
3313
purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3314
get_username(con));
3315
}
3316
else
3317
{
3318
/*
3319
* Cancel all jobs on all printers...
3320
*/
3321
3322
cupsdCancelJobs(NULL, username, purge != CUPSD_JOB_DEFAULT);
3323
3324
cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".",
3325
purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3326
get_username(con));
3327
}
3328
}
3329
else
3330
{
3331
/*
3332
* Check policy...
3333
*/
3334
3335
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
3336
NULL)) != HTTP_OK)
3337
{
3338
send_http_error(con, status, printer);
3339
return;
3340
}
3341
3342
if (job_ids)
3343
{
3344
for (i = 0; i < job_ids->num_values; i ++)
3345
{
3346
if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL ||
3347
_cups_strcasecmp(job->dest, printer->name))
3348
break;
3349
3350
if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS &&
3351
_cups_strcasecmp(job->username, username))
3352
break;
3353
}
3354
3355
if (i < job_ids->num_values)
3356
{
3357
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
3358
job_ids->values[i].integer);
3359
return;
3360
}
3361
3362
for (i = 0; i < job_ids->num_values; i ++)
3363
{
3364
job = cupsdFindJob(job_ids->values[i].integer);
3365
3366
cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
3367
purge == CUPSD_JOB_PURGE ? "Job purged by user." :
3368
"Job canceled by user.");
3369
}
3370
3371
cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
3372
purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3373
get_username(con));
3374
}
3375
else
3376
{
3377
/*
3378
* Cancel all of the jobs on the named printer...
3379
*/
3380
3381
cupsdCancelJobs(printer->name, username, purge != CUPSD_JOB_DEFAULT);
3382
3383
cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".",
3384
printer->name,
3385
purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3386
get_username(con));
3387
}
3388
}
3389
3390
con->response->request.status.status_code = IPP_OK;
3391
3392
cupsdCheckJobs();
3393
}
3394
3395
3396
/*
3397
* 'cancel_job()' - Cancel a print job.
3398
*/
3399
3400
static void
3401
cancel_job(cupsd_client_t *con, /* I - Client connection */
3402
ipp_attribute_t *uri) /* I - Job or Printer URI */
3403
{
3404
ipp_attribute_t *attr; /* Current attribute */
3405
int jobid; /* Job ID */
3406
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
3407
username[HTTP_MAX_URI], /* Username portion of URI */
3408
host[HTTP_MAX_URI], /* Host portion of URI */
3409
resource[HTTP_MAX_URI]; /* Resource portion of URI */
3410
int port; /* Port portion of URI */
3411
cupsd_job_t *job; /* Job information */
3412
cups_ptype_t dtype; /* Destination type (printer/class) */
3413
cupsd_printer_t *printer; /* Printer data */
3414
cupsd_jobaction_t purge; /* Purge the job? */
3415
3416
3417
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", con,
3418
con->number, uri->values[0].string.text);
3419
3420
/*
3421
* See if we have a job URI or a printer URI...
3422
*/
3423
3424
if (!strcmp(uri->name, "printer-uri"))
3425
{
3426
/*
3427
* Got a printer URI; see if we also have a job-id attribute...
3428
*/
3429
3430
if ((attr = ippFindAttribute(con->request, "job-id",
3431
IPP_TAG_INTEGER)) == NULL)
3432
{
3433
send_ipp_status(con, IPP_BAD_REQUEST,
3434
_("Got a printer-uri attribute but no job-id."));
3435
return;
3436
}
3437
3438
if ((jobid = attr->values[0].integer) == 0)
3439
{
3440
/*
3441
* Find the current job on the specified printer...
3442
*/
3443
3444
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
3445
{
3446
/*
3447
* Bad URI...
3448
*/
3449
3450
send_ipp_status(con, IPP_NOT_FOUND,
3451
_("The printer or class does not exist."));
3452
return;
3453
}
3454
3455
/*
3456
* See if there are any pending jobs...
3457
*/
3458
3459
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
3460
job;
3461
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
3462
if (job->state_value <= IPP_JOB_PROCESSING &&
3463
!_cups_strcasecmp(job->dest, printer->name))
3464
break;
3465
3466
if (job)
3467
jobid = job->id;
3468
else
3469
{
3470
/*
3471
* No, try stopped jobs...
3472
*/
3473
3474
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
3475
job;
3476
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
3477
if (job->state_value == IPP_JOB_STOPPED &&
3478
!_cups_strcasecmp(job->dest, printer->name))
3479
break;
3480
3481
if (job)
3482
jobid = job->id;
3483
else
3484
{
3485
send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s."),
3486
printer->name);
3487
return;
3488
}
3489
}
3490
}
3491
}
3492
else
3493
{
3494
/*
3495
* Got a job URI; parse it to get the job ID...
3496
*/
3497
3498
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
3499
sizeof(scheme), username, sizeof(username), host,
3500
sizeof(host), &port, resource, sizeof(resource));
3501
3502
if (strncmp(resource, "/jobs/", 6))
3503
{
3504
/*
3505
* Not a valid URI!
3506
*/
3507
3508
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
3509
uri->values[0].string.text);
3510
return;
3511
}
3512
3513
jobid = atoi(resource + 6);
3514
}
3515
3516
/*
3517
* Look for the "purge-job" attribute...
3518
*/
3519
3520
if ((attr = ippFindAttribute(con->request, "purge-job",
3521
IPP_TAG_BOOLEAN)) != NULL)
3522
purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
3523
else
3524
purge = CUPSD_JOB_DEFAULT;
3525
3526
/*
3527
* See if the job exists...
3528
*/
3529
3530
if ((job = cupsdFindJob(jobid)) == NULL)
3531
{
3532
/*
3533
* Nope - return a "not found" error...
3534
*/
3535
3536
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
3537
return;
3538
}
3539
3540
/*
3541
* See if the job is owned by the requesting user...
3542
*/
3543
3544
if (!validate_user(job, con, job->username, username, sizeof(username)))
3545
{
3546
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
3547
cupsdFindDest(job->dest));
3548
return;
3549
}
3550
3551
/*
3552
* See if the job is already completed, canceled, or aborted; if so,
3553
* we can't cancel...
3554
*/
3555
3556
if (job->state_value >= IPP_JOB_CANCELED && purge != CUPSD_JOB_PURGE)
3557
{
3558
switch (job->state_value)
3559
{
3560
case IPP_JOB_CANCELED :
3561
send_ipp_status(con, IPP_NOT_POSSIBLE,
3562
_("Job #%d is already canceled - can\'t cancel."),
3563
jobid);
3564
break;
3565
3566
case IPP_JOB_ABORTED :
3567
send_ipp_status(con, IPP_NOT_POSSIBLE,
3568
_("Job #%d is already aborted - can\'t cancel."),
3569
jobid);
3570
break;
3571
3572
default :
3573
send_ipp_status(con, IPP_NOT_POSSIBLE,
3574
_("Job #%d is already completed - can\'t cancel."),
3575
jobid);
3576
break;
3577
}
3578
3579
return;
3580
}
3581
3582
/*
3583
* Cancel the job and return...
3584
*/
3585
3586
cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
3587
purge == CUPSD_JOB_PURGE ? "Job purged by \"%s\"" :
3588
"Job canceled by \"%s\"",
3589
username);
3590
cupsdCheckJobs();
3591
3592
if (purge == CUPSD_JOB_PURGE)
3593
cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Purged by \"%s\".", jobid,
3594
username);
3595
else
3596
cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Canceled by \"%s\".", jobid,
3597
username);
3598
3599
con->response->request.status.status_code = IPP_OK;
3600
}
3601
3602
3603
/*
3604
* 'cancel_subscription()' - Cancel a subscription.
3605
*/
3606
3607
static void
3608
cancel_subscription(
3609
cupsd_client_t *con, /* I - Client connection */
3610
int sub_id) /* I - Subscription ID */
3611
{
3612
http_status_t status; /* Policy status */
3613
cupsd_subscription_t *sub; /* Subscription */
3614
3615
3616
cupsdLogMessage(CUPSD_LOG_DEBUG2,
3617
"cancel_subscription(con=%p[%d], sub_id=%d)",
3618
con, con->number, sub_id);
3619
3620
/*
3621
* Is the subscription ID valid?
3622
*/
3623
3624
if ((sub = cupsdFindSubscription(sub_id)) == NULL)
3625
{
3626
/*
3627
* Bad subscription ID...
3628
*/
3629
3630
send_ipp_status(con, IPP_NOT_FOUND,
3631
_("Subscription #%d does not exist."), sub_id);
3632
return;
3633
}
3634
3635
/*
3636
* Check policy...
3637
*/
3638
3639
if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
3640
DefaultPolicyPtr,
3641
con, sub->owner)) != HTTP_OK)
3642
{
3643
send_http_error(con, status, sub->dest);
3644
return;
3645
}
3646
3647
/*
3648
* Cancel the subscription...
3649
*/
3650
3651
cupsdDeleteSubscription(sub, 1);
3652
3653
con->response->request.status.status_code = IPP_OK;
3654
}
3655
3656
3657
/*
3658
* 'check_rss_recipient()' - Check that we do not have a duplicate RSS feed URI.
3659
*/
3660
3661
static int /* O - 1 if OK, 0 if not */
3662
check_rss_recipient(
3663
const char *recipient) /* I - Recipient URI */
3664
{
3665
cupsd_subscription_t *sub; /* Current subscription */
3666
3667
3668
for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
3669
sub;
3670
sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
3671
if (sub->recipient)
3672
{
3673
/*
3674
* Compare the URIs up to the first ?...
3675
*/
3676
3677
const char *r1, *r2;
3678
3679
for (r1 = recipient, r2 = sub->recipient;
3680
*r1 == *r2 && *r1 && *r1 != '?' && *r2 && *r2 != '?';
3681
r1 ++, r2 ++);
3682
3683
if (*r1 == *r2)
3684
return (0);
3685
}
3686
3687
return (1);
3688
}
3689
3690
3691
/*
3692
* 'check_quotas()' - Check quotas for a printer and user.
3693
*/
3694
3695
static int /* O - 1 if OK, 0 if forbidden,
3696
-1 if limit reached */
3697
check_quotas(cupsd_client_t *con, /* I - Client connection */
3698
cupsd_printer_t *p) /* I - Printer or class */
3699
{
3700
char username[33], /* Username */
3701
*name; /* Current user name */
3702
cupsd_quota_t *q; /* Quota data */
3703
#ifdef HAVE_MBR_UID_TO_UUID
3704
/*
3705
* Use Apple membership APIs which require that all names represent
3706
* valid user account or group records accessible by the server.
3707
*/
3708
3709
uuid_t usr_uuid; /* UUID for job requesting user */
3710
uuid_t usr2_uuid; /* UUID for ACL user name entry */
3711
uuid_t grp_uuid; /* UUID for ACL group name entry */
3712
int mbr_err; /* Error from membership function */
3713
int is_member; /* Is this user a member? */
3714
#else
3715
/*
3716
* Use standard POSIX APIs for checking users and groups...
3717
*/
3718
3719
struct passwd *pw; /* User password data */
3720
#endif /* HAVE_MBR_UID_TO_UUID */
3721
3722
3723
cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])",
3724
con, con->number, p, p->name);
3725
3726
/*
3727
* Figure out who is printing...
3728
*/
3729
3730
strlcpy(username, get_username(con), sizeof(username));
3731
3732
if ((name = strchr(username, '@')) != NULL)
3733
*name = '\0'; /* Strip @REALM */
3734
3735
/*
3736
* Check global active job limits for printers and users...
3737
*/
3738
3739
if (MaxJobsPerPrinter)
3740
{
3741
/*
3742
* Check if there are too many pending jobs on this printer...
3743
*/
3744
3745
if (cupsdGetPrinterJobCount(p->name) >= MaxJobsPerPrinter)
3746
{
3747
cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for printer \"%s\"...",
3748
p->name);
3749
return (-1);
3750
}
3751
}
3752
3753
if (MaxJobsPerUser)
3754
{
3755
/*
3756
* Check if there are too many pending jobs for this user...
3757
*/
3758
3759
if (cupsdGetUserJobCount(username) >= MaxJobsPerUser)
3760
{
3761
cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for user \"%s\"...",
3762
username);
3763
return (-1);
3764
}
3765
}
3766
3767
/*
3768
* Check against users...
3769
*/
3770
3771
if (cupsArrayCount(p->users) == 0 && p->k_limit == 0 && p->page_limit == 0)
3772
return (1);
3773
3774
if (cupsArrayCount(p->users))
3775
{
3776
#ifdef HAVE_MBR_UID_TO_UUID
3777
/*
3778
* Get UUID for job requesting user...
3779
*/
3780
3781
if (mbr_user_name_to_uuid((char *)username, usr_uuid))
3782
{
3783
/*
3784
* Unknown user...
3785
*/
3786
3787
cupsdLogMessage(CUPSD_LOG_DEBUG,
3788
"check_quotas: UUID lookup failed for user \"%s\"",
3789
username);
3790
cupsdLogMessage(CUPSD_LOG_INFO,
3791
"Denying user \"%s\" access to printer \"%s\" "
3792
"(unknown user)...",
3793
username, p->name);
3794
return (0);
3795
}
3796
#else
3797
/*
3798
* Get UID and GID of requesting user...
3799
*/
3800
3801
pw = getpwnam(username);
3802
endpwent();
3803
#endif /* HAVE_MBR_UID_TO_UUID */
3804
3805
for (name = (char *)cupsArrayFirst(p->users);
3806
name;
3807
name = (char *)cupsArrayNext(p->users))
3808
if (name[0] == '@')
3809
{
3810
/*
3811
* Check group membership...
3812
*/
3813
3814
#ifdef HAVE_MBR_UID_TO_UUID
3815
if (name[1] == '#')
3816
{
3817
if (uuid_parse(name + 2, grp_uuid))
3818
uuid_clear(grp_uuid);
3819
}
3820
else if ((mbr_err = mbr_group_name_to_uuid(name + 1, grp_uuid)) != 0)
3821
{
3822
/*
3823
* Invalid ACL entries are ignored for matching; just record a
3824
* warning in the log...
3825
*/
3826
3827
cupsdLogMessage(CUPSD_LOG_DEBUG,
3828
"check_quotas: UUID lookup failed for ACL entry "
3829
"\"%s\" (err=%d)", name, mbr_err);
3830
cupsdLogMessage(CUPSD_LOG_WARN,
3831
"Access control entry \"%s\" not a valid group name; "
3832
"entry ignored", name);
3833
}
3834
3835
if ((mbr_err = mbr_check_membership(usr_uuid, grp_uuid,
3836
&is_member)) != 0)
3837
{
3838
/*
3839
* At this point, there should be no errors, but check anyways...
3840
*/
3841
3842
cupsdLogMessage(CUPSD_LOG_DEBUG,
3843
"check_quotas: group \"%s\" membership check "
3844
"failed (err=%d)", name + 1, mbr_err);
3845
is_member = 0;
3846
}
3847
3848
/*
3849
* Stop if we found a match...
3850
*/
3851
3852
if (is_member)
3853
break;
3854
3855
#else
3856
if (cupsdCheckGroup(username, pw, name + 1))
3857
break;
3858
#endif /* HAVE_MBR_UID_TO_UUID */
3859
}
3860
#ifdef HAVE_MBR_UID_TO_UUID
3861
else
3862
{
3863
if (name[0] == '#')
3864
{
3865
if (uuid_parse(name + 1, usr2_uuid))
3866
uuid_clear(usr2_uuid);
3867
}
3868
else if ((mbr_err = mbr_user_name_to_uuid(name, usr2_uuid)) != 0)
3869
{
3870
/*
3871
* Invalid ACL entries are ignored for matching; just record a
3872
* warning in the log...
3873
*/
3874
3875
cupsdLogMessage(CUPSD_LOG_DEBUG,
3876
"check_quotas: UUID lookup failed for ACL entry "
3877
"\"%s\" (err=%d)", name, mbr_err);
3878
cupsdLogMessage(CUPSD_LOG_WARN,
3879
"Access control entry \"%s\" not a valid user name; "
3880
"entry ignored", name);
3881
}
3882
3883
if (!uuid_compare(usr_uuid, usr2_uuid))
3884
break;
3885
}
3886
#else
3887
else if (!_cups_strcasecmp(username, name))
3888
break;
3889
#endif /* HAVE_MBR_UID_TO_UUID */
3890
3891
if ((name != NULL) == p->deny_users)
3892
{
3893
cupsdLogMessage(CUPSD_LOG_INFO,
3894
"Denying user \"%s\" access to printer \"%s\"...",
3895
username, p->name);
3896
return (0);
3897
}
3898
}
3899
3900
/*
3901
* Check quotas...
3902
*/
3903
3904
if (p->k_limit || p->page_limit)
3905
{
3906
if ((q = cupsdUpdateQuota(p, username, 0, 0)) == NULL)
3907
{
3908
cupsdLogMessage(CUPSD_LOG_ERROR,
3909
"Unable to allocate quota data for user \"%s\"",
3910
username);
3911
return (-1);
3912
}
3913
3914
if ((q->k_count >= p->k_limit && p->k_limit) ||
3915
(q->page_count >= p->page_limit && p->page_limit))
3916
{
3917
cupsdLogMessage(CUPSD_LOG_INFO, "User \"%s\" is over the quota limit...",
3918
username);
3919
return (-1);
3920
}
3921
}
3922
3923
/*
3924
* If we have gotten this far, we're done!
3925
*/
3926
3927
return (1);
3928
}
3929
3930
3931
/*
3932
* 'close_job()' - Close a multi-file job.
3933
*/
3934
3935
static void
3936
close_job(cupsd_client_t *con, /* I - Client connection */
3937
ipp_attribute_t *uri) /* I - Printer URI */
3938
{
3939
cupsd_job_t *job; /* Job */
3940
ipp_attribute_t *attr; /* Attribute */
3941
char job_uri[HTTP_MAX_URI],
3942
/* Job URI */
3943
username[256]; /* User name */
3944
3945
3946
cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con,
3947
con->number, uri->values[0].string.text);
3948
3949
/*
3950
* See if we have a job URI or a printer URI...
3951
*/
3952
3953
if (strcmp(uri->name, "printer-uri"))
3954
{
3955
/*
3956
* job-uri is not supported by Close-Job!
3957
*/
3958
3959
send_ipp_status(con, IPP_BAD_REQUEST,
3960
_("Close-Job doesn't support the job-uri attribute."));
3961
return;
3962
}
3963
3964
/*
3965
* Got a printer URI; see if we also have a job-id attribute...
3966
*/
3967
3968
if ((attr = ippFindAttribute(con->request, "job-id",
3969
IPP_TAG_INTEGER)) == NULL)
3970
{
3971
send_ipp_status(con, IPP_BAD_REQUEST,
3972
_("Got a printer-uri attribute but no job-id."));
3973
return;
3974
}
3975
3976
if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
3977
{
3978
/*
3979
* Nope - return a "not found" error...
3980
*/
3981
3982
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
3983
attr->values[0].integer);
3984
return;
3985
}
3986
3987
/*
3988
* See if the job is owned by the requesting user...
3989
*/
3990
3991
if (!validate_user(job, con, job->username, username, sizeof(username)))
3992
{
3993
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
3994
cupsdFindDest(job->dest));
3995
return;
3996
}
3997
3998
/*
3999
* Add any ending sheet...
4000
*/
4001
4002
if (cupsdTimeoutJob(job))
4003
return;
4004
4005
if (job->state_value == IPP_JOB_STOPPED)
4006
{
4007
job->state->values[0].integer = IPP_JOB_PENDING;
4008
job->state_value = IPP_JOB_PENDING;
4009
}
4010
else if (job->state_value == IPP_JOB_HELD)
4011
{
4012
if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
4013
IPP_TAG_KEYWORD)) == NULL)
4014
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
4015
4016
if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
4017
{
4018
job->state->values[0].integer = IPP_JOB_PENDING;
4019
job->state_value = IPP_JOB_PENDING;
4020
}
4021
}
4022
4023
job->dirty = 1;
4024
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
4025
4026
/*
4027
* Fill in the response info...
4028
*/
4029
4030
httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
4031
con->clientname, con->clientport, "/jobs/%d", job->id);
4032
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
4033
job_uri);
4034
4035
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
4036
4037
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
4038
4039
con->response->request.status.status_code = IPP_OK;
4040
4041
/*
4042
* Start the job if necessary...
4043
*/
4044
4045
cupsdCheckJobs();
4046
}
4047
4048
4049
/*
4050
* 'copy_attrs()' - Copy attributes from one request to another.
4051
*/
4052
4053
static void
4054
copy_attrs(ipp_t *to, /* I - Destination request */
4055
ipp_t *from, /* I - Source request */
4056
cups_array_t *ra, /* I - Requested attributes */
4057
ipp_tag_t group, /* I - Group to copy */
4058
int quickcopy, /* I - Do a quick copy? */
4059
cups_array_t *exclude) /* I - Attributes to exclude? */
4060
{
4061
ipp_attribute_t *fromattr; /* Source attribute */
4062
4063
4064
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4065
"copy_attrs(to=%p, from=%p, ra=%p, group=%x, quickcopy=%d)",
4066
to, from, ra, group, quickcopy);
4067
4068
if (!to || !from)
4069
return;
4070
4071
for (fromattr = from->attrs; fromattr; fromattr = fromattr->next)
4072
{
4073
/*
4074
* Filter attributes as needed...
4075
*/
4076
4077
if ((group != IPP_TAG_ZERO && fromattr->group_tag != group &&
4078
fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
4079
continue;
4080
4081
if (!strcmp(fromattr->name, "document-password") ||
4082
!strcmp(fromattr->name, "job-authorization-uri") ||
4083
!strcmp(fromattr->name, "job-password") ||
4084
!strcmp(fromattr->name, "job-password-encryption") ||
4085
!strcmp(fromattr->name, "job-printer-uri"))
4086
continue;
4087
4088
if (exclude &&
4089
(cupsArrayFind(exclude, fromattr->name) ||
4090
cupsArrayFind(exclude, "all")))
4091
{
4092
/*
4093
* We need to exclude this attribute for security reasons; we require the
4094
* job-id attribute regardless of the security settings for IPP
4095
* conformance.
4096
*
4097
* The job-printer-uri attribute is handled by copy_job_attrs().
4098
*
4099
* Subscription attribute security is handled by copy_subscription_attrs().
4100
*/
4101
4102
if (strcmp(fromattr->name, "job-id"))
4103
continue;
4104
}
4105
4106
if (!ra || cupsArrayFind(ra, fromattr->name))
4107
{
4108
/*
4109
* Don't send collection attributes by default to IPP/1.x clients
4110
* since many do not support collections. Also don't send
4111
* media-col-database unless specifically requested by the client.
4112
*/
4113
4114
if (fromattr->value_tag == IPP_TAG_BEGIN_COLLECTION &&
4115
!ra &&
4116
(to->request.status.version[0] == 1 ||
4117
!strcmp(fromattr->name, "media-col-database")))
4118
continue;
4119
4120
ippCopyAttribute(to, fromattr, quickcopy);
4121
}
4122
}
4123
}
4124
4125
4126
/*
4127
* 'copy_banner()' - Copy a banner file to the requests directory for the
4128
* specified job.
4129
*/
4130
4131
static int /* O - Size of banner file in kbytes */
4132
copy_banner(cupsd_client_t *con, /* I - Client connection */
4133
cupsd_job_t *job, /* I - Job information */
4134
const char *name) /* I - Name of banner */
4135
{
4136
int i; /* Looping var */
4137
int kbytes; /* Size of banner file in kbytes */
4138
char filename[1024]; /* Job filename */
4139
cupsd_banner_t *banner; /* Pointer to banner */
4140
cups_file_t *in; /* Input file */
4141
cups_file_t *out; /* Output file */
4142
int ch; /* Character from file */
4143
char attrname[255], /* Name of attribute */
4144
*s; /* Pointer into name */
4145
ipp_attribute_t *attr; /* Attribute */
4146
4147
4148
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4149
"copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")",
4150
con, con ? con->number : -1, job, job->id,
4151
name ? name : "(null)");
4152
4153
/*
4154
* Find the banner; return if not found or "none"...
4155
*/
4156
4157
if (!name || !strcmp(name, "none") ||
4158
(banner = cupsdFindBanner(name)) == NULL)
4159
return (0);
4160
4161
/*
4162
* Open the banner and job files...
4163
*/
4164
4165
if (add_file(con, job, banner->filetype, 0))
4166
return (-1);
4167
4168
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
4169
job->num_files);
4170
if ((out = cupsFileOpen(filename, "w")) == NULL)
4171
{
4172
cupsdLogMessage(CUPSD_LOG_ERROR,
4173
"Unable to create banner job file %s - %s",
4174
filename, strerror(errno));
4175
job->num_files --;
4176
return (0);
4177
}
4178
4179
fchmod(cupsFileNumber(out), 0640);
4180
fchown(cupsFileNumber(out), RunUser, Group);
4181
4182
/*
4183
* Try the localized banner file under the subdirectory...
4184
*/
4185
4186
strlcpy(attrname, job->attrs->attrs->next->values[0].string.text,
4187
sizeof(attrname));
4188
if (strlen(attrname) > 2 && attrname[2] == '-')
4189
{
4190
/*
4191
* Convert ll-cc to ll_CC...
4192
*/
4193
4194
attrname[2] = '_';
4195
attrname[3] = (char)toupper(attrname[3] & 255);
4196
attrname[4] = (char)toupper(attrname[4] & 255);
4197
}
4198
4199
snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
4200
attrname, name);
4201
4202
if (access(filename, 0) && strlen(attrname) > 2)
4203
{
4204
/*
4205
* Wasn't able to find "ll_CC" locale file; try the non-national
4206
* localization banner directory.
4207
*/
4208
4209
attrname[2] = '\0';
4210
4211
snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
4212
attrname, name);
4213
}
4214
4215
if (access(filename, 0))
4216
{
4217
/*
4218
* Use the non-localized banner file.
4219
*/
4220
4221
snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
4222
}
4223
4224
if ((in = cupsFileOpen(filename, "r")) == NULL)
4225
{
4226
cupsFileClose(out);
4227
unlink(filename);
4228
cupsdLogMessage(CUPSD_LOG_ERROR,
4229
"Unable to open banner template file %s - %s",
4230
filename, strerror(errno));
4231
job->num_files --;
4232
return (0);
4233
}
4234
4235
/*
4236
* Parse the file to the end...
4237
*/
4238
4239
while ((ch = cupsFileGetChar(in)) != EOF)
4240
if (ch == '{')
4241
{
4242
/*
4243
* Get an attribute name...
4244
*/
4245
4246
for (s = attrname; (ch = cupsFileGetChar(in)) != EOF;)
4247
if (!isalpha(ch & 255) && ch != '-' && ch != '?')
4248
break;
4249
else if (s < (attrname + sizeof(attrname) - 1))
4250
*s++ = (char)ch;
4251
else
4252
break;
4253
4254
*s = '\0';
4255
4256
if (ch != '}')
4257
{
4258
/*
4259
* Ignore { followed by stuff that is not an attribute name...
4260
*/
4261
4262
cupsFilePrintf(out, "{%s%c", attrname, ch);
4263
continue;
4264
}
4265
4266
/*
4267
* See if it is defined...
4268
*/
4269
4270
if (attrname[0] == '?')
4271
s = attrname + 1;
4272
else
4273
s = attrname;
4274
4275
if (!strcmp(s, "printer-name"))
4276
{
4277
cupsFilePuts(out, job->dest);
4278
continue;
4279
}
4280
else if ((attr = ippFindAttribute(job->attrs, s, IPP_TAG_ZERO)) == NULL)
4281
{
4282
/*
4283
* See if we have a leading question mark...
4284
*/
4285
4286
if (attrname[0] != '?')
4287
{
4288
/*
4289
* Nope, write to file as-is; probably a PostScript procedure...
4290
*/
4291
4292
cupsFilePrintf(out, "{%s}", attrname);
4293
}
4294
4295
continue;
4296
}
4297
4298
/*
4299
* Output value(s)...
4300
*/
4301
4302
for (i = 0; i < attr->num_values; i ++)
4303
{
4304
if (i)
4305
cupsFilePutChar(out, ',');
4306
4307
switch (attr->value_tag)
4308
{
4309
case IPP_TAG_INTEGER :
4310
case IPP_TAG_ENUM :
4311
if (!strncmp(s, "time-at-", 8))
4312
{
4313
struct timeval tv; /* Time value */
4314
4315
tv.tv_sec = attr->values[i].integer;
4316
tv.tv_usec = 0;
4317
4318
cupsFilePuts(out, cupsdGetDateTime(&tv, CUPSD_TIME_STANDARD));
4319
}
4320
else
4321
cupsFilePrintf(out, "%d", attr->values[i].integer);
4322
break;
4323
4324
case IPP_TAG_BOOLEAN :
4325
cupsFilePrintf(out, "%d", attr->values[i].boolean);
4326
break;
4327
4328
case IPP_TAG_NOVALUE :
4329
cupsFilePuts(out, "novalue");
4330
break;
4331
4332
case IPP_TAG_RANGE :
4333
cupsFilePrintf(out, "%d-%d", attr->values[i].range.lower,
4334
attr->values[i].range.upper);
4335
break;
4336
4337
case IPP_TAG_RESOLUTION :
4338
cupsFilePrintf(out, "%dx%d%s", attr->values[i].resolution.xres,
4339
attr->values[i].resolution.yres,
4340
attr->values[i].resolution.units == IPP_RES_PER_INCH ?
4341
"dpi" : "dpcm");
4342
break;
4343
4344
case IPP_TAG_URI :
4345
case IPP_TAG_STRING :
4346
case IPP_TAG_TEXT :
4347
case IPP_TAG_NAME :
4348
case IPP_TAG_KEYWORD :
4349
case IPP_TAG_CHARSET :
4350
case IPP_TAG_LANGUAGE :
4351
if (!_cups_strcasecmp(banner->filetype->type, "postscript"))
4352
{
4353
/*
4354
* Need to quote strings for PS banners...
4355
*/
4356
4357
const char *p;
4358
4359
for (p = attr->values[i].string.text; *p; p ++)
4360
{
4361
if (*p == '(' || *p == ')' || *p == '\\')
4362
{
4363
cupsFilePutChar(out, '\\');
4364
cupsFilePutChar(out, *p);
4365
}
4366
else if (*p < 32 || *p > 126)
4367
cupsFilePrintf(out, "\\%03o", *p & 255);
4368
else
4369
cupsFilePutChar(out, *p);
4370
}
4371
}
4372
else
4373
cupsFilePuts(out, attr->values[i].string.text);
4374
break;
4375
4376
default :
4377
break; /* anti-compiler-warning-code */
4378
}
4379
}
4380
}
4381
else if (ch == '\\') /* Quoted char */
4382
{
4383
ch = cupsFileGetChar(in);
4384
4385
if (ch != '{') /* Only do special handling for \{ */
4386
cupsFilePutChar(out, '\\');
4387
4388
cupsFilePutChar(out, ch);
4389
}
4390
else
4391
cupsFilePutChar(out, ch);
4392
4393
cupsFileClose(in);
4394
4395
kbytes = (cupsFileTell(out) + 1023) / 1024;
4396
4397
job->koctets += kbytes;
4398
4399
if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
4400
attr->values[0].integer += kbytes;
4401
4402
cupsFileClose(out);
4403
4404
return (kbytes);
4405
}
4406
4407
4408
/*
4409
* 'copy_file()' - Copy a PPD file...
4410
*/
4411
4412
static int /* O - 0 = success, -1 = error */
4413
copy_file(const char *from, /* I - Source file */
4414
const char *to, /* I - Destination file */
4415
mode_t mode) /* I - Permissions */
4416
{
4417
cups_file_t *src, /* Source file */
4418
*dst; /* Destination file */
4419
int bytes; /* Bytes to read/write */
4420
char buffer[2048]; /* Copy buffer */
4421
4422
4423
cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_file(\"%s\", \"%s\")", from, to);
4424
4425
/*
4426
* Open the source and destination file for a copy...
4427
*/
4428
4429
if ((src = cupsFileOpen(from, "rb")) == NULL)
4430
return (-1);
4431
4432
if ((dst = cupsdCreateConfFile(to, mode)) == NULL)
4433
{
4434
cupsFileClose(src);
4435
return (-1);
4436
}
4437
4438
/*
4439
* Copy the source file to the destination...
4440
*/
4441
4442
while ((bytes = cupsFileRead(src, buffer, sizeof(buffer))) > 0)
4443
if (cupsFileWrite(dst, buffer, (size_t)bytes) < bytes)
4444
{
4445
cupsFileClose(src);
4446
cupsFileClose(dst);
4447
return (-1);
4448
}
4449
4450
/*
4451
* Close both files and return...
4452
*/
4453
4454
cupsFileClose(src);
4455
4456
return (cupsdCloseCreatedConfFile(dst, to));
4457
}
4458
4459
4460
/*
4461
* 'copy_model()' - Copy a PPD model file, substituting default values
4462
* as needed...
4463
*/
4464
4465
static int /* O - 0 = success, -1 = error */
4466
copy_model(cupsd_client_t *con, /* I - Client connection */
4467
const char *from, /* I - Source file */
4468
const char *to) /* I - Destination file */
4469
{
4470
fd_set input; /* select() input set */
4471
struct timeval timeout; /* select() timeout */
4472
int maxfd; /* Max file descriptor for select() */
4473
char tempfile[1024]; /* Temporary PPD file */
4474
int tempfd; /* Temporary PPD file descriptor */
4475
int temppid; /* Process ID of cups-driverd */
4476
int temppipe[2]; /* Temporary pipes */
4477
char *argv[4], /* Command-line arguments */
4478
*envp[MAX_ENV]; /* Environment */
4479
cups_file_t *src, /* Source file */
4480
*dst; /* Destination file */
4481
ppd_file_t *ppd; /* PPD file */
4482
int bytes, /* Bytes from pipe */
4483
total; /* Total bytes from pipe */
4484
char buffer[2048]; /* Copy buffer */
4485
int i; /* Looping var */
4486
char option[PPD_MAX_NAME], /* Option name */
4487
choice[PPD_MAX_NAME]; /* Choice name */
4488
ppd_size_t *size; /* Default size */
4489
int num_defaults; /* Number of default options */
4490
cups_option_t *defaults; /* Default options */
4491
char cups_protocol[PPD_MAX_LINE];
4492
/* cupsProtocol attribute */
4493
4494
4495
cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_model(con=%p, from=\"%s\", to=\"%s\")", con, from, to);
4496
4497
/*
4498
* Run cups-driverd to get the PPD file...
4499
*/
4500
4501
argv[0] = "cups-driverd";
4502
argv[1] = "cat";
4503
argv[2] = (char *)from;
4504
argv[3] = NULL;
4505
4506
cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
4507
4508
snprintf(buffer, sizeof(buffer), "%s/daemon/cups-driverd", ServerBin);
4509
snprintf(tempfile, sizeof(tempfile), "%s/%d.ppd", TempDir, con->number);
4510
if ((tempfd = open(tempfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
4511
return (-1);
4512
if (cupsdOpenPipe(temppipe))
4513
{
4514
close(tempfd);
4515
unlink(tempfile);
4516
4517
return (-1);
4518
}
4519
4520
cupsdLogMessage(CUPSD_LOG_DEBUG,
4521
"copy_model: Running \"cups-driverd cat %s\"...", from);
4522
4523
if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1],
4524
-1, -1, 0, DefaultProfile, NULL, &temppid))
4525
{
4526
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to run cups-driverd: %s"), strerror(errno));
4527
close(tempfd);
4528
unlink(tempfile);
4529
4530
return (-1);
4531
}
4532
4533
close(temppipe[1]);
4534
4535
/*
4536
* Wait up to 30 seconds for the PPD file to be copied...
4537
*/
4538
4539
total = 0;
4540
4541
if (temppipe[0] > CGIPipes[0])
4542
maxfd = temppipe[0] + 1;
4543
else
4544
maxfd = CGIPipes[0] + 1;
4545
4546
for (;;)
4547
{
4548
/*
4549
* See if we have data ready...
4550
*/
4551
4552
FD_ZERO(&input);
4553
FD_SET(temppipe[0], &input);
4554
FD_SET(CGIPipes[0], &input);
4555
4556
timeout.tv_sec = 30;
4557
timeout.tv_usec = 0;
4558
4559
if ((i = select(maxfd, &input, NULL, NULL, &timeout)) < 0)
4560
{
4561
if (errno == EINTR)
4562
continue;
4563
else
4564
break;
4565
}
4566
else if (i == 0)
4567
{
4568
/*
4569
* We have timed out...
4570
*/
4571
4572
break;
4573
}
4574
4575
if (FD_ISSET(temppipe[0], &input))
4576
{
4577
/*
4578
* Read the PPD file from the pipe, and write it to the PPD file.
4579
*/
4580
4581
if ((bytes = read(temppipe[0], buffer, sizeof(buffer))) > 0)
4582
{
4583
if (write(tempfd, buffer, (size_t)bytes) < bytes)
4584
break;
4585
4586
total += bytes;
4587
}
4588
else
4589
break;
4590
}
4591
4592
if (FD_ISSET(CGIPipes[0], &input))
4593
cupsdUpdateCGI();
4594
}
4595
4596
close(temppipe[0]);
4597
close(tempfd);
4598
4599
if (!total)
4600
{
4601
/*
4602
* No data from cups-deviced...
4603
*/
4604
4605
cupsdLogMessage(CUPSD_LOG_ERROR, "copy_model: empty PPD file");
4606
send_ipp_status(con, IPP_INTERNAL_ERROR, _("cups-driverd failed to get PPD file - see error_log for details."));
4607
unlink(tempfile);
4608
return (-1);
4609
}
4610
4611
/*
4612
* Open the source file for a copy...
4613
*/
4614
4615
if ((src = cupsFileOpen(tempfile, "rb")) == NULL)
4616
{
4617
unlink(tempfile);
4618
return (-1);
4619
}
4620
4621
/*
4622
* Read the source file and see what page sizes are supported...
4623
*/
4624
4625
if ((ppd = _ppdOpen(src, _PPD_LOCALIZATION_NONE)) == NULL)
4626
{
4627
cupsFileClose(src);
4628
unlink(tempfile);
4629
return (-1);
4630
}
4631
4632
/*
4633
* Open the destination (if possible) and set the default options...
4634
*/
4635
4636
num_defaults = 0;
4637
defaults = NULL;
4638
cups_protocol[0] = '\0';
4639
4640
if ((dst = cupsFileOpen(to, "rb")) != NULL)
4641
{
4642
/*
4643
* Read all of the default lines from the old PPD...
4644
*/
4645
4646
while (cupsFileGets(dst, buffer, sizeof(buffer)))
4647
if (!strncmp(buffer, "*Default", 8))
4648
{
4649
/*
4650
* Add the default option...
4651
*/
4652
4653
if (!ppd_parse_line(buffer, option, sizeof(option),
4654
choice, sizeof(choice)))
4655
{
4656
ppd_option_t *ppdo; /* PPD option */
4657
4658
4659
/*
4660
* Only add the default if the default hasn't already been
4661
* set and the choice exists in the new PPD...
4662
*/
4663
4664
if (!cupsGetOption(option, num_defaults, defaults) &&
4665
(ppdo = ppdFindOption(ppd, option)) != NULL &&
4666
ppdFindChoice(ppdo, choice))
4667
num_defaults = cupsAddOption(option, choice, num_defaults,
4668
&defaults);
4669
}
4670
}
4671
else if (!strncmp(buffer, "*cupsProtocol:", 14))
4672
strlcpy(cups_protocol, buffer, sizeof(cups_protocol));
4673
4674
cupsFileClose(dst);
4675
}
4676
else if ((size = ppdPageSize(ppd, DefaultPaperSize)) != NULL)
4677
{
4678
/*
4679
* Add the default media sizes...
4680
*/
4681
4682
num_defaults = cupsAddOption("PageSize", size->name,
4683
num_defaults, &defaults);
4684
num_defaults = cupsAddOption("PageRegion", size->name,
4685
num_defaults, &defaults);
4686
num_defaults = cupsAddOption("PaperDimension", size->name,
4687
num_defaults, &defaults);
4688
num_defaults = cupsAddOption("ImageableArea", size->name,
4689
num_defaults, &defaults);
4690
}
4691
4692
ppdClose(ppd);
4693
4694
/*
4695
* Open the destination file for a copy...
4696
*/
4697
4698
if ((dst = cupsdCreateConfFile(to, ConfigFilePerm)) == NULL)
4699
{
4700
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to save PPD file: %s"), strerror(errno));
4701
cupsFreeOptions(num_defaults, defaults);
4702
cupsFileClose(src);
4703
unlink(tempfile);
4704
return (-1);
4705
}
4706
4707
/*
4708
* Copy the source file to the destination...
4709
*/
4710
4711
cupsFileRewind(src);
4712
4713
while (cupsFileGets(src, buffer, sizeof(buffer)))
4714
{
4715
if (!strncmp(buffer, "*Default", 8))
4716
{
4717
/*
4718
* Check for an previous default option choice...
4719
*/
4720
4721
if (!ppd_parse_line(buffer, option, sizeof(option),
4722
choice, sizeof(choice)))
4723
{
4724
const char *val; /* Default option value */
4725
4726
4727
if ((val = cupsGetOption(option, num_defaults, defaults)) != NULL)
4728
{
4729
/*
4730
* Substitute the previous choice...
4731
*/
4732
4733
snprintf(buffer, sizeof(buffer), "*Default%s: %s", option, val);
4734
}
4735
}
4736
}
4737
4738
cupsFilePrintf(dst, "%s\n", buffer);
4739
}
4740
4741
if (cups_protocol[0])
4742
cupsFilePrintf(dst, "%s\n", cups_protocol);
4743
4744
cupsFreeOptions(num_defaults, defaults);
4745
4746
/*
4747
* Close both files and return...
4748
*/
4749
4750
cupsFileClose(src);
4751
4752
unlink(tempfile);
4753
4754
if (cupsdCloseCreatedConfFile(dst, to))
4755
{
4756
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to commit PPD file: %s"), strerror(errno));
4757
return (-1);
4758
}
4759
else
4760
{
4761
return (0);
4762
}
4763
}
4764
4765
4766
/*
4767
* 'copy_job_attrs()' - Copy job attributes.
4768
*/
4769
4770
static void
4771
copy_job_attrs(cupsd_client_t *con, /* I - Client connection */
4772
cupsd_job_t *job, /* I - Job */
4773
cups_array_t *ra, /* I - Requested attributes array */
4774
cups_array_t *exclude) /* I - Private attributes array */
4775
{
4776
char job_uri[HTTP_MAX_URI]; /* Job URI */
4777
4778
4779
/*
4780
* Send the requested attributes for each job...
4781
*/
4782
4783
if (!cupsArrayFind(exclude, "all"))
4784
{
4785
if ((!exclude || !cupsArrayFind(exclude, "number-of-documents")) &&
4786
(!ra || cupsArrayFind(ra, "number-of-documents")))
4787
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
4788
"number-of-documents", job->num_files);
4789
4790
if ((!exclude || !cupsArrayFind(exclude, "job-media-progress")) &&
4791
(!ra || cupsArrayFind(ra, "job-media-progress")))
4792
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
4793
"job-media-progress", job->progress);
4794
4795
if ((!exclude || !cupsArrayFind(exclude, "job-more-info")) &&
4796
(!ra || cupsArrayFind(ra, "job-more-info")))
4797
{
4798
httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "http",
4799
NULL, con->clientname, con->clientport, "/jobs/%d",
4800
job->id);
4801
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
4802
"job-more-info", NULL, job_uri);
4803
}
4804
4805
if (job->state_value > IPP_JOB_PROCESSING &&
4806
(!exclude || !cupsArrayFind(exclude, "job-preserved")) &&
4807
(!ra || cupsArrayFind(ra, "job-preserved")))
4808
ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved",
4809
job->num_files > 0);
4810
4811
if ((!exclude || !cupsArrayFind(exclude, "job-printer-up-time")) &&
4812
(!ra || cupsArrayFind(ra, "job-printer-up-time")))
4813
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
4814
"job-printer-up-time", time(NULL));
4815
}
4816
4817
if (!ra || cupsArrayFind(ra, "job-printer-uri"))
4818
{
4819
httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
4820
con->clientname, con->clientport,
4821
(job->dtype & CUPS_PRINTER_CLASS) ? "/classes/%s" :
4822
"/printers/%s",
4823
job->dest);
4824
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
4825
"job-printer-uri", NULL, job_uri);
4826
}
4827
4828
if (!ra || cupsArrayFind(ra, "job-uri"))
4829
{
4830
httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
4831
con->clientname, con->clientport, "/jobs/%d",
4832
job->id);
4833
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
4834
"job-uri", NULL, job_uri);
4835
}
4836
4837
if (job->attrs)
4838
{
4839
copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude);
4840
}
4841
else
4842
{
4843
/*
4844
* Generate attributes from the job structure...
4845
*/
4846
4847
if (job->completed_time && (!ra || cupsArrayFind(ra, "date-time-at-completed")))
4848
ippAddDate(con->response, IPP_TAG_JOB, "date-time-at-completed", ippTimeToDate(job->completed_time));
4849
4850
if (job->creation_time && (!ra || cupsArrayFind(ra, "date-time-at-creation")))
4851
ippAddDate(con->response, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(job->creation_time));
4852
4853
if (!ra || cupsArrayFind(ra, "job-id"))
4854
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
4855
4856
if (!ra || cupsArrayFind(ra, "job-k-octets"))
4857
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", job->koctets);
4858
4859
if (job->name && (!ra || cupsArrayFind(ra, "job-name")))
4860
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, job->name);
4861
4862
if (job->username && (!ra || cupsArrayFind(ra, "job-originating-user-name")))
4863
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username);
4864
4865
if (!ra || cupsArrayFind(ra, "job-state"))
4866
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
4867
4868
if (!ra || cupsArrayFind(ra, "job-state-reasons"))
4869
{
4870
switch (job->state_value)
4871
{
4872
default : /* Should never get here for processing, pending, held, or stopped jobs since they don't get unloaded... */
4873
break;
4874
case IPP_JSTATE_ABORTED :
4875
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-aborted-by-system");
4876
break;
4877
case IPP_JSTATE_CANCELED :
4878
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-canceled-by-user");
4879
break;
4880
case IPP_JSTATE_COMPLETED :
4881
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-completed-successfully");
4882
break;
4883
}
4884
}
4885
4886
if (job->completed_time && (!ra || cupsArrayFind(ra, "time-at-completed")))
4887
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-completed", (int)job->completed_time);
4888
4889
if (job->creation_time && (!ra || cupsArrayFind(ra, "time-at-creation")))
4890
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)job->creation_time);
4891
}
4892
}
4893
4894
4895
/*
4896
* 'copy_printer_attrs()' - Copy printer attributes.
4897
*/
4898
4899
static void
4900
copy_printer_attrs(
4901
cupsd_client_t *con, /* I - Client connection */
4902
cupsd_printer_t *printer, /* I - Printer */
4903
cups_array_t *ra) /* I - Requested attributes array */
4904
{
4905
char uri[HTTP_MAX_URI]; /* URI value */
4906
time_t curtime; /* Current time */
4907
int i; /* Looping var */
4908
int is_encrypted = httpIsEncrypted(con->http);
4909
/* Is the connection encrypted? */
4910
4911
4912
/*
4913
* Copy the printer attributes to the response using requested-attributes
4914
* and document-format attributes that may be provided by the client.
4915
*/
4916
4917
_cupsRWLockRead(&printer->lock);
4918
4919
curtime = time(NULL);
4920
4921
if (!ra || cupsArrayFind(ra, "marker-change-time"))
4922
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "marker-change-time", printer->marker_time);
4923
4924
if (printer->num_printers > 0 && (!ra || cupsArrayFind(ra, "member-uris")))
4925
{
4926
ipp_attribute_t *member_uris; /* member-uris attribute */
4927
cupsd_printer_t *p2; /* Printer in class */
4928
ipp_attribute_t *p2_uri; /* printer-uri-supported for class printer */
4929
4930
4931
if ((member_uris = ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", printer->num_printers, NULL, NULL)) != NULL)
4932
{
4933
for (i = 0; i < printer->num_printers; i ++)
4934
{
4935
p2 = printer->printers[i];
4936
4937
if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported", IPP_TAG_URI)) != NULL)
4938
{
4939
member_uris->values[i].string.text = _cupsStrAlloc(p2_uri->values[0].string.text);
4940
}
4941
else
4942
{
4943
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (p2->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", p2->name);
4944
member_uris->values[i].string.text = _cupsStrAlloc(uri);
4945
}
4946
}
4947
}
4948
}
4949
4950
if (printer->alert && (!ra || cupsArrayFind(ra, "printer-alert")))
4951
ippAddOctetString(con->response, IPP_TAG_PRINTER, "printer-alert", printer->alert, (int)strlen(printer->alert));
4952
4953
if (printer->alert_description && (!ra || cupsArrayFind(ra, "printer-alert-description")))
4954
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-alert-description", NULL, printer->alert_description);
4955
4956
if (!ra || cupsArrayFind(ra, "printer-config-change-date-time"))
4957
ippAddDate(con->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time));
4958
4959
if (!ra || cupsArrayFind(ra, "printer-config-change-time"))
4960
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", printer->config_time);
4961
4962
if (!ra || cupsArrayFind(ra, "printer-current-time"))
4963
ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(curtime));
4964
4965
#ifdef HAVE_DNSSD
4966
if (!ra || cupsArrayFind(ra, "printer-dns-sd-name"))
4967
{
4968
if (printer->reg_name)
4969
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-dns-sd-name", NULL, printer->reg_name);
4970
else
4971
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "printer-dns-sd-name", 0);
4972
}
4973
#endif /* HAVE_DNSSD */
4974
4975
if (!ra || cupsArrayFind(ra, "printer-error-policy"))
4976
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-error-policy", NULL, printer->error_policy);
4977
4978
if (!ra || cupsArrayFind(ra, "printer-error-policy-supported"))
4979
{
4980
static const char * const errors[] =/* printer-error-policy-supported values */
4981
{
4982
"abort-job",
4983
"retry-current-job",
4984
"retry-job",
4985
"stop-printer"
4986
};
4987
4988
if (printer->type & CUPS_PRINTER_CLASS)
4989
ippAddString(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", NULL, "retry-current-job");
4990
else
4991
ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", sizeof(errors) / sizeof(errors[0]), NULL, errors);
4992
}
4993
4994
if (!ra || cupsArrayFind(ra, "printer-icons"))
4995
{
4996
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/icons/%s.png", printer->name);
4997
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons", NULL, uri);
4998
cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-icons=\"%s\"", uri);
4999
}
5000
5001
if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs"))
5002
ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
5003
5004
if (!ra || cupsArrayFind(ra, "printer-is-shared"))
5005
ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", (char)printer->shared);
5006
5007
if (!ra || cupsArrayFind(ra, "printer-is-temporary"))
5008
ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-temporary", (char)printer->temporary);
5009
5010
if (!ra || cupsArrayFind(ra, "printer-more-info"))
5011
{
5012
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name);
5013
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, uri);
5014
}
5015
5016
if (!ra || cupsArrayFind(ra, "printer-op-policy"))
5017
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-op-policy", NULL, printer->op_policy);
5018
5019
if (!ra || cupsArrayFind(ra, "printer-state"))
5020
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", (int)printer->state);
5021
5022
if (!ra || cupsArrayFind(ra, "printer-state-change-date-time"))
5023
ippAddDate(con->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time));
5024
5025
if (!ra || cupsArrayFind(ra, "printer-state-change-time"))
5026
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", printer->state_time);
5027
5028
if (!ra || cupsArrayFind(ra, "printer-state-message"))
5029
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message", NULL, printer->state_message);
5030
5031
if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
5032
add_printer_state_reasons(con, printer);
5033
5034
if (!ra || cupsArrayFind(ra, "printer-strings-uri"))
5035
{
5036
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/strings/%s.strings", printer->name);
5037
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-strings-uri", NULL, uri);
5038
cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-strings-uri=\"%s\"", uri);
5039
}
5040
5041
if (!ra || cupsArrayFind(ra, "printer-type"))
5042
{
5043
cups_ptype_t type; /* printer-type value */
5044
5045
/*
5046
* Add the CUPS-specific printer-type attribute...
5047
*/
5048
5049
type = printer->type;
5050
5051
if (printer == DefaultPrinter)
5052
type |= CUPS_PRINTER_DEFAULT;
5053
5054
if (!printer->accepting)
5055
type |= CUPS_PRINTER_REJECTING;
5056
5057
if (!printer->shared)
5058
type |= CUPS_PRINTER_NOT_SHARED;
5059
5060
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", (int)type);
5061
}
5062
5063
if (!ra || cupsArrayFind(ra, "printer-up-time"))
5064
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", curtime);
5065
5066
if (!ra || cupsArrayFind(ra, "printer-uri-supported"))
5067
{
5068
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name);
5069
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
5070
cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", uri);
5071
}
5072
5073
if (!ra || cupsArrayFind(ra, "queued-job-count"))
5074
add_queued_job_count(con, printer);
5075
5076
if (!ra || cupsArrayFind(ra, "uri-security-supported"))
5077
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "uri-security-supported", NULL, is_encrypted ? "tls" : "none");
5078
5079
copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0, NULL);
5080
if (printer->ppd_attrs)
5081
copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0, NULL);
5082
copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY, NULL);
5083
5084
_cupsRWUnlock(&printer->lock);
5085
}
5086
5087
5088
/*
5089
* 'copy_subscription_attrs()' - Copy subscription attributes.
5090
*/
5091
5092
static void
5093
copy_subscription_attrs(
5094
cupsd_client_t *con, /* I - Client connection */
5095
cupsd_subscription_t *sub, /* I - Subscription */
5096
cups_array_t *ra, /* I - Requested attributes array */
5097
cups_array_t *exclude) /* I - Private attributes array */
5098
{
5099
ipp_attribute_t *attr; /* Current attribute */
5100
char printer_uri[HTTP_MAX_URI];
5101
/* Printer URI */
5102
int count; /* Number of events */
5103
unsigned mask; /* Current event mask */
5104
const char *name; /* Current event name */
5105
5106
5107
cupsdLogMessage(CUPSD_LOG_DEBUG2,
5108
"copy_subscription_attrs(con=%p, sub=%p, ra=%p, exclude=%p)",
5109
con, sub, ra, exclude);
5110
5111
/*
5112
* Copy the subscription attributes to the response using the
5113
* requested-attributes attribute that may be provided by the client.
5114
*/
5115
5116
if (!exclude || !cupsArrayFind(exclude, "all"))
5117
{
5118
if ((!exclude || !cupsArrayFind(exclude, "notify-events")) &&
5119
(!ra || cupsArrayFind(ra, "notify-events")))
5120
{
5121
cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_subscription_attrs: notify-events");
5122
5123
if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
5124
{
5125
/*
5126
* Simple event list...
5127
*/
5128
5129
ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", NULL, name);
5130
}
5131
else
5132
{
5133
/*
5134
* Complex event list...
5135
*/
5136
5137
for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
5138
if (sub->mask & mask)
5139
count ++;
5140
5141
attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", count, NULL, NULL);
5142
5143
for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
5144
if (sub->mask & mask)
5145
{
5146
attr->values[count].string.text = (char *)cupsdEventName((cupsd_eventmask_t)mask);
5147
5148
count ++;
5149
}
5150
}
5151
}
5152
5153
if ((!exclude || !cupsArrayFind(exclude, "notify-lease-duration")) &&
5154
(!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration"))))
5155
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5156
"notify-lease-duration", sub->lease);
5157
5158
if ((!exclude || !cupsArrayFind(exclude, "notify-recipient-uri")) &&
5159
(sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri"))))
5160
ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
5161
"notify-recipient-uri", NULL, sub->recipient);
5162
else if ((!exclude || !cupsArrayFind(exclude, "notify-pull-method")) &&
5163
(!ra || cupsArrayFind(ra, "notify-pull-method")))
5164
ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
5165
"notify-pull-method", NULL, "ippget");
5166
5167
if ((!exclude || !cupsArrayFind(exclude, "notify-subscriber-user-name")) &&
5168
(!ra || cupsArrayFind(ra, "notify-subscriber-user-name")))
5169
ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME,
5170
"notify-subscriber-user-name", NULL, sub->owner);
5171
5172
if ((!exclude || !cupsArrayFind(exclude, "notify-time-interval")) &&
5173
(!ra || cupsArrayFind(ra, "notify-time-interval")))
5174
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5175
"notify-time-interval", sub->interval);
5176
5177
if (sub->user_data_len > 0 &&
5178
(!exclude || !cupsArrayFind(exclude, "notify-user-data")) &&
5179
(!ra || cupsArrayFind(ra, "notify-user-data")))
5180
ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data",
5181
sub->user_data, sub->user_data_len);
5182
}
5183
5184
if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id")))
5185
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5186
"notify-job-id", sub->job->id);
5187
5188
if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri")))
5189
{
5190
httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
5191
"ipp", NULL, con->clientname, con->clientport,
5192
"/printers/%s", sub->dest->name);
5193
ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
5194
"notify-printer-uri", NULL, printer_uri);
5195
}
5196
5197
if (!ra || cupsArrayFind(ra, "notify-subscription-id"))
5198
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5199
"notify-subscription-id", sub->id);
5200
}
5201
5202
5203
/*
5204
* 'create_job()' - Print a file to a printer or class.
5205
*/
5206
5207
static void
5208
create_job(cupsd_client_t *con, /* I - Client connection */
5209
ipp_attribute_t *uri) /* I - Printer URI */
5210
{
5211
int i; /* Looping var */
5212
cupsd_printer_t *printer; /* Printer */
5213
cupsd_job_t *job; /* New job */
5214
static const char * const forbidden_attrs[] =
5215
{ /* List of forbidden attributes */
5216
"compression",
5217
"document-format",
5218
"document-name",
5219
"document-natural-language"
5220
};
5221
5222
5223
cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con,
5224
con->number, uri->values[0].string.text);
5225
5226
/*
5227
* Is the destination valid?
5228
*/
5229
5230
if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer))
5231
{
5232
/*
5233
* Bad URI...
5234
*/
5235
5236
send_ipp_status(con, IPP_NOT_FOUND,
5237
_("The printer or class does not exist."));
5238
return;
5239
}
5240
5241
/*
5242
* Check for invalid Create-Job attributes and log a warning or error depending
5243
* on whether cupsd is running in "strict conformance" mode...
5244
*/
5245
5246
for (i = 0;
5247
i < (int)(sizeof(forbidden_attrs) / sizeof(forbidden_attrs[0]));
5248
i ++)
5249
if (ippFindAttribute(con->request, forbidden_attrs[i], IPP_TAG_ZERO))
5250
{
5251
if (StrictConformance)
5252
{
5253
send_ipp_status(con, IPP_BAD_REQUEST,
5254
_("The '%s' operation attribute cannot be supplied in a "
5255
"Create-Job request."), forbidden_attrs[i]);
5256
return;
5257
}
5258
5259
cupsdLogMessage(CUPSD_LOG_WARN,
5260
"Unexpected '%s' operation attribute in a Create-Job "
5261
"request.", forbidden_attrs[i]);
5262
}
5263
5264
/*
5265
* Create the job object...
5266
*/
5267
5268
if ((job = add_job(con, printer, NULL)) == NULL)
5269
return;
5270
5271
job->pending_timeout = 1;
5272
5273
/*
5274
* Save and log the job...
5275
*/
5276
5277
cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".",
5278
job->dest, job->username);
5279
}
5280
5281
5282
/*
5283
* 'create_local_bg_thread()' - Background thread for creating a local print queue.
5284
*/
5285
5286
static void * /* O - Exit status */
5287
create_local_bg_thread(
5288
cupsd_printer_t *printer) /* I - Printer */
5289
{
5290
cups_file_t *from, /* Source file */
5291
*to; /* Destination file */
5292
char fromppd[1024], /* Source PPD */
5293
toppd[1024], /* Destination PPD */
5294
scheme[32], /* URI scheme */
5295
userpass[256], /* User:pass */
5296
host[256], /* Hostname */
5297
resource[1024], /* Resource path */
5298
uri[1024], /* Resolved URI, if needed */
5299
line[1024]; /* Line from PPD */
5300
int port; /* Port number */
5301
http_encryption_t encryption; /* Type of encryption to use */
5302
http_t *http; /* Connection to printer */
5303
ipp_t *request, /* Request to printer */
5304
*response; /* Response from printer */
5305
ipp_attribute_t *attr; /* Attribute in response */
5306
ipp_status_t status; /* Status code */
5307
static const char * const pattrs[] = /* Printer attributes we need */
5308
{
5309
"all",
5310
"media-col-database"
5311
};
5312
5313
5314
/*
5315
* Try connecting to the printer...
5316
*/
5317
5318
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri);
5319
5320
5321
if (strstr(printer->device_uri, "._tcp"))
5322
{
5323
cupsdLogMessage(CUPSD_LOG_DEBUG2, "%s: Resolving mDNS URI \"%s\".", printer->name, printer->device_uri);
5324
5325
if (!_httpResolveURI(printer->device_uri, uri, sizeof(uri), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
5326
{
5327
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Couldn't resolve mDNS URI \"%s\".", printer->name, printer->device_uri);
5328
return (NULL);
5329
}
5330
5331
cupsdSetString(&printer->device_uri, uri);
5332
}
5333
5334
if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
5335
{
5336
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri);
5337
return (NULL);
5338
}
5339
5340
if (!strcmp(scheme, "ipps") || port == 443)
5341
encryption = HTTP_ENCRYPTION_ALWAYS;
5342
else
5343
encryption = HTTP_ENCRYPTION_IF_REQUESTED;
5344
5345
if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL)
5346
{
5347
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsLastErrorString());
5348
return (NULL);
5349
}
5350
5351
/*
5352
* Query the printer for its capabilities...
5353
*/
5354
5355
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Connected to %s:%d, sending Get-Printer-Attributes request...", printer->name, host, port);
5356
5357
request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
5358
ippSetVersion(request, 2, 0);
5359
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri);
5360
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
5361
5362
response = cupsDoRequest(http, request, resource);
5363
status = cupsLastError();
5364
5365
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString());
5366
5367
if (status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
5368
{
5369
/*
5370
* Try request using IPP/1.1, in case we are talking to an old CUPS server or
5371
* printer...
5372
*/
5373
5374
ippDelete(response);
5375
5376
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Re-sending Get-Printer-Attributes request using IPP/1.1...", printer->name);
5377
5378
request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
5379
ippSetVersion(request, 1, 1);
5380
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri);
5381
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all");
5382
5383
response = cupsDoRequest(http, request, resource);
5384
5385
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: IPP/1.1 Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString());
5386
}
5387
5388
// TODO: Grab printer icon file...
5389
httpClose(http);
5390
5391
/*
5392
* Write the PPD for the queue...
5393
*/
5394
5395
if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response))
5396
{
5397
_cupsRWLockWrite(&printer->lock);
5398
5399
if ((!printer->info || !*(printer->info)) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL)
5400
cupsdSetString(&printer->info, ippGetString(attr, 0, NULL));
5401
5402
if ((!printer->location || !*(printer->location)) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL)
5403
cupsdSetString(&printer->location, ippGetString(attr, 0, NULL));
5404
5405
if ((!printer->geo_location || !*(printer->geo_location)) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL)
5406
cupsdSetString(&printer->geo_location, ippGetString(attr, 0, NULL));
5407
5408
_cupsRWUnlock(&printer->lock);
5409
5410
if ((from = cupsFileOpen(fromppd, "r")) == NULL)
5411
{
5412
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno));
5413
ippDelete(response);
5414
return (NULL);
5415
}
5416
5417
snprintf(toppd, sizeof(toppd), "%s/ppd/%s.ppd", ServerRoot, printer->name);
5418
if ((to = cupsdCreateConfFile(toppd, ConfigFilePerm)) == NULL)
5419
{
5420
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to create PPD for printer: %s", printer->name, strerror(errno));
5421
ippDelete(response);
5422
cupsFileClose(from);
5423
return (NULL);
5424
}
5425
5426
while (cupsFileGets(from, line, sizeof(line)))
5427
cupsFilePrintf(to, "%s\n", line);
5428
5429
cupsFileClose(from);
5430
if (!cupsdCloseCreatedConfFile(to, toppd))
5431
{
5432
printer->config_time = time(NULL);
5433
printer->state = IPP_PSTATE_IDLE;
5434
printer->accepting = 1;
5435
5436
cupsdSetPrinterAttrs(printer);
5437
5438
cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name);
5439
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" is now available.", printer->name);
5440
}
5441
}
5442
else
5443
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed: %s", printer->name, cupsLastErrorString());
5444
5445
ippDelete(response);
5446
5447
return (NULL);
5448
}
5449
5450
5451
/*
5452
* 'create_local_printer()' - Create a local (temporary) print queue.
5453
*/
5454
5455
static void
5456
create_local_printer(
5457
cupsd_client_t *con) /* I - Client connection */
5458
{
5459
ipp_attribute_t *device_uri, /* device-uri attribute */
5460
*printer_geo_location, /* printer-geo-location attribute */
5461
*printer_info, /* printer-info attribute */
5462
*printer_location, /* printer-location attribute */
5463
*printer_name; /* printer-name attribute */
5464
cupsd_printer_t *printer; /* New printer */
5465
http_status_t status; /* Policy status */
5466
char name[128], /* Sanitized printer name */
5467
*nameptr, /* Pointer into name */
5468
uri[1024]; /* printer-uri-supported value */
5469
const char *ptr; /* Pointer into attribute value */
5470
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
5471
userpass[HTTP_MAX_URI], /* Username portion of URI */
5472
host[HTTP_MAX_URI], /* Host portion of URI */
5473
resource[HTTP_MAX_URI]; /* Resource portion of URI */
5474
int port; /* Port portion of URI */
5475
5476
5477
/*
5478
* Require local access to create a local printer...
5479
*/
5480
5481
if (!httpAddrLocalhost(httpGetAddress(con->http)))
5482
{
5483
send_ipp_status(con, IPP_STATUS_ERROR_FORBIDDEN, _("Only local users can create a local printer."));
5484
return;
5485
}
5486
5487
/*
5488
* Check any other policy limits...
5489
*/
5490
5491
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
5492
{
5493
send_http_error(con, status, NULL);
5494
return;
5495
}
5496
5497
/*
5498
* Grab needed attributes...
5499
*/
5500
5501
if ((printer_name = ippFindAttribute(con->request, "printer-name", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(printer_name) != IPP_TAG_PRINTER || ippGetValueTag(printer_name) != IPP_TAG_NAME)
5502
{
5503
if (!printer_name)
5504
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "printer-name");
5505
else if (ippGetGroupTag(printer_name) != IPP_TAG_PRINTER)
5506
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "printer-name");
5507
else
5508
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "printer-name");
5509
5510
return;
5511
}
5512
5513
for (nameptr = name, ptr = ippGetString(printer_name, 0, NULL); *ptr && nameptr < (name + sizeof(name) - 1); ptr ++)
5514
{
5515
/*
5516
* Sanitize the printer name...
5517
*/
5518
5519
if (_cups_isalnum(*ptr))
5520
*nameptr++ = *ptr;
5521
else if (nameptr == name || nameptr[-1] != '_')
5522
*nameptr++ = '_';
5523
}
5524
5525
*nameptr = '\0';
5526
5527
if ((device_uri = ippFindAttribute(con->request, "device-uri", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(device_uri) != IPP_TAG_PRINTER || ippGetValueTag(device_uri) != IPP_TAG_URI)
5528
{
5529
if (!device_uri)
5530
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "device-uri");
5531
else if (ippGetGroupTag(device_uri) != IPP_TAG_PRINTER)
5532
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "device-uri");
5533
else
5534
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "device-uri");
5535
5536
return;
5537
}
5538
5539
ptr = ippGetString(device_uri, 0, NULL);
5540
5541
if (!ptr || !ptr[0])
5542
{
5543
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" has empty value."), "device-uri");
5544
5545
return;
5546
}
5547
5548
printer_geo_location = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI);
5549
printer_info = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT);
5550
printer_location = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT);
5551
5552
/*
5553
* See if the printer already exists...
5554
*/
5555
5556
if ((printer = cupsdFindDest(name)) != NULL)
5557
{
5558
send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name);
5559
goto add_printer_attributes;
5560
}
5561
5562
/*
5563
* Create the printer...
5564
*/
5565
5566
if ((printer = cupsdAddPrinter(name)) == NULL)
5567
{
5568
send_ipp_status(con, IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer."));
5569
return;
5570
}
5571
5572
printer->shared = 0;
5573
printer->temporary = 1;
5574
5575
/*
5576
* Check device URI if it has the same hostname as we have, if so, replace
5577
* the hostname by localhost. This way we assure that local-only services
5578
* like ipp-usb or Printer Applications always work.
5579
*
5580
* When comparing our hostname with the one in the device URI,
5581
* consider names with or without trailing dot ('.') the same. Also
5582
* compare case-insensitively.
5583
*/
5584
5585
#ifdef HAVE_DNSSD
5586
if (DNSSDHostName)
5587
nameptr = DNSSDHostName;
5588
else
5589
#endif
5590
if (ServerName)
5591
nameptr = ServerName;
5592
else
5593
nameptr = NULL;
5594
5595
if (nameptr)
5596
{
5597
size_t host_len,
5598
server_name_len;
5599
5600
/* Get host name of device URI */
5601
httpSeparateURI(HTTP_URI_CODING_ALL, ptr,
5602
scheme, sizeof(scheme), userpass, sizeof(userpass), host,
5603
sizeof(host), &port, resource, sizeof(resource));
5604
5605
/* Take trailing dot out of comparison */
5606
host_len = strlen(host);
5607
if (host_len > 1 && host[host_len - 1] == '.')
5608
host_len --;
5609
5610
server_name_len = strlen(nameptr);
5611
if (server_name_len > 1 && nameptr[server_name_len - 1] == '.')
5612
server_name_len --;
5613
5614
/*
5615
* If we have no DNSSDHostName but only a ServerName (if we are not
5616
* sharing printers, Browsing = Off) the ServerName has no ".local"
5617
* but the requested device URI has. Take this into account.
5618
*/
5619
5620
if (nameptr == ServerName && host_len >= 6 && (server_name_len < 6 || strcmp(nameptr + server_name_len - 6, ".local") != 0) && strcmp(host + host_len - 6, ".local") == 0)
5621
host_len -= 6;
5622
5623
if (host_len == server_name_len && strncasecmp(host, nameptr, host_len) == 0)
5624
ptr = "localhost";
5625
else
5626
ptr = host;
5627
5628
httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, userpass,
5629
ptr, port, resource);
5630
cupsdSetDeviceURI(printer, uri);
5631
}
5632
else
5633
cupsdSetDeviceURI(printer, ptr);
5634
5635
if (printer_geo_location)
5636
cupsdSetString(&printer->geo_location, ippGetString(printer_geo_location, 0, NULL));
5637
if (printer_info)
5638
cupsdSetString(&printer->info, ippGetString(printer_info, 0, NULL));
5639
if (printer_location)
5640
cupsdSetString(&printer->location, ippGetString(printer_location, 0, NULL));
5641
5642
cupsdSetPrinterAttrs(printer);
5643
5644
/*
5645
* Run a background thread to create the PPD...
5646
*/
5647
5648
_cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer);
5649
5650
/*
5651
* Return printer attributes...
5652
*/
5653
5654
send_ipp_status(con, IPP_STATUS_OK, _("Local printer created."));
5655
5656
add_printer_attributes:
5657
5658
ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
5659
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", (int)printer->state);
5660
add_printer_state_reasons(con, printer);
5661
5662
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name);
5663
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
5664
}
5665
5666
5667
/*
5668
* 'create_requested_array()' - Create an array for the requested-attributes.
5669
*/
5670
5671
static cups_array_t * /* O - Array of attributes or NULL */
5672
create_requested_array(ipp_t *request) /* I - IPP request */
5673
{
5674
cups_array_t *ra; /* Requested attributes array */
5675
5676
5677
/*
5678
* Create the array for standard attributes...
5679
*/
5680
5681
ra = ippCreateRequestedArray(request);
5682
5683
/*
5684
* Add CUPS defaults as needed...
5685
*/
5686
5687
if (cupsArrayFind(ra, "printer-defaults"))
5688
{
5689
/*
5690
* Include user-set defaults...
5691
*/
5692
5693
char *name; /* Option name */
5694
5695
cupsArrayRemove(ra, "printer-defaults");
5696
5697
for (name = (char *)cupsArrayFirst(CommonDefaults);
5698
name;
5699
name = (char *)cupsArrayNext(CommonDefaults))
5700
if (!cupsArrayFind(ra, name))
5701
cupsArrayAdd(ra, name);
5702
}
5703
5704
return (ra);
5705
}
5706
5707
5708
/*
5709
* 'create_subscriptions()' - Create one or more notification subscriptions.
5710
*/
5711
5712
static void
5713
create_subscriptions(
5714
cupsd_client_t *con, /* I - Client connection */
5715
ipp_attribute_t *uri) /* I - Printer URI */
5716
{
5717
http_status_t status; /* Policy status */
5718
int i; /* Looping var */
5719
ipp_attribute_t *attr; /* Current attribute */
5720
cups_ptype_t dtype; /* Destination type (printer/class) */
5721
char scheme[HTTP_MAX_URI],
5722
/* Scheme portion of URI */
5723
userpass[HTTP_MAX_URI],
5724
/* Username portion of URI */
5725
host[HTTP_MAX_URI],
5726
/* Host portion of URI */
5727
resource[HTTP_MAX_URI];
5728
/* Resource portion of URI */
5729
int port; /* Port portion of URI */
5730
cupsd_printer_t *printer; /* Printer/class */
5731
cupsd_job_t *job; /* Job */
5732
int jobid; /* Job ID */
5733
cupsd_subscription_t *sub; /* Subscription object */
5734
const char *username, /* requesting-user-name or
5735
authenticated username */
5736
*recipient, /* notify-recipient-uri */
5737
*pullmethod; /* notify-pull-method */
5738
ipp_attribute_t *user_data; /* notify-user-data */
5739
int interval, /* notify-time-interval */
5740
lease; /* notify-lease-duration */
5741
unsigned mask; /* notify-events */
5742
ipp_attribute_t *notify_events,/* notify-events(-default) */
5743
*notify_lease; /* notify-lease-duration(-default) */
5744
5745
5746
#ifdef DEBUG
5747
for (attr = con->request->attrs; attr; attr = attr->next)
5748
{
5749
if (attr->group_tag != IPP_TAG_ZERO)
5750
cupsdLogMessage(CUPSD_LOG_DEBUG2, "g%04x v%04x %s", attr->group_tag,
5751
attr->value_tag, attr->name);
5752
else
5753
cupsdLogMessage(CUPSD_LOG_DEBUG2, "----SEP----");
5754
}
5755
#endif /* DEBUG */
5756
5757
/*
5758
* Is the destination valid?
5759
*/
5760
5761
cupsdLogMessage(CUPSD_LOG_DEBUG, "create_subscriptions(con=%p(%d), uri=\"%s\")", con, con->number, uri->values[0].string.text);
5762
5763
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
5764
sizeof(scheme), userpass, sizeof(userpass), host,
5765
sizeof(host), &port, resource, sizeof(resource));
5766
5767
if (!strcmp(resource, "/"))
5768
{
5769
dtype = (cups_ptype_t)0;
5770
printer = NULL;
5771
}
5772
else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
5773
{
5774
dtype = (cups_ptype_t)0;
5775
printer = NULL;
5776
}
5777
else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
5778
{
5779
dtype = CUPS_PRINTER_CLASS;
5780
printer = NULL;
5781
}
5782
else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
5783
{
5784
/*
5785
* Bad URI...
5786
*/
5787
5788
send_ipp_status(con, IPP_NOT_FOUND,
5789
_("The printer or class does not exist."));
5790
return;
5791
}
5792
5793
/*
5794
* Check policy...
5795
*/
5796
5797
if (printer)
5798
{
5799
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
5800
NULL)) != HTTP_OK)
5801
{
5802
send_http_error(con, status, printer);
5803
return;
5804
}
5805
}
5806
else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
5807
{
5808
send_http_error(con, status, NULL);
5809
return;
5810
}
5811
5812
/*
5813
* Get the user that is requesting the subscription...
5814
*/
5815
5816
username = get_username(con);
5817
5818
/*
5819
* Find the first subscription group attribute; return if we have
5820
* none...
5821
*/
5822
5823
for (attr = con->request->attrs; attr; attr = attr->next)
5824
if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
5825
break;
5826
5827
if (!attr)
5828
{
5829
send_ipp_status(con, IPP_BAD_REQUEST,
5830
_("No subscription attributes in request."));
5831
return;
5832
}
5833
5834
/*
5835
* Process the subscription attributes in the request...
5836
*/
5837
5838
con->response->request.status.status_code = IPP_BAD_REQUEST;
5839
5840
while (attr)
5841
{
5842
recipient = NULL;
5843
pullmethod = NULL;
5844
user_data = NULL;
5845
interval = 0;
5846
lease = DefaultLeaseDuration;
5847
jobid = 0;
5848
mask = CUPSD_EVENT_NONE;
5849
5850
if (printer)
5851
{
5852
notify_events = ippFindAttribute(printer->attrs, "notify-events-default",
5853
IPP_TAG_KEYWORD);
5854
notify_lease = ippFindAttribute(printer->attrs,
5855
"notify-lease-duration-default",
5856
IPP_TAG_INTEGER);
5857
5858
if (notify_lease)
5859
lease = notify_lease->values[0].integer;
5860
}
5861
else
5862
{
5863
notify_events = NULL;
5864
notify_lease = NULL;
5865
}
5866
5867
while (attr && attr->group_tag != IPP_TAG_ZERO)
5868
{
5869
if (!strcmp(attr->name, "notify-recipient-uri") &&
5870
attr->value_tag == IPP_TAG_URI)
5871
{
5872
/*
5873
* Validate the recipient scheme against the ServerBin/notifier
5874
* directory...
5875
*/
5876
5877
char notifier[1024]; /* Notifier filename */
5878
5879
5880
recipient = attr->values[0].string.text;
5881
5882
if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
5883
scheme, sizeof(scheme), userpass, sizeof(userpass),
5884
host, sizeof(host), &port,
5885
resource, sizeof(resource)) < HTTP_URI_OK)
5886
{
5887
send_ipp_status(con, IPP_NOT_POSSIBLE,
5888
_("Bad notify-recipient-uri \"%s\"."), recipient);
5889
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5890
"notify-status-code", IPP_URI_SCHEME);
5891
return;
5892
}
5893
5894
snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin,
5895
scheme);
5896
if (access(notifier, X_OK) || !strcmp(scheme, ".") || !strcmp(scheme, ".."))
5897
{
5898
send_ipp_status(con, IPP_NOT_POSSIBLE,
5899
_("notify-recipient-uri URI \"%s\" uses unknown "
5900
"scheme."), recipient);
5901
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5902
"notify-status-code", IPP_URI_SCHEME);
5903
return;
5904
}
5905
5906
if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient))
5907
{
5908
send_ipp_status(con, IPP_NOT_POSSIBLE,
5909
_("notify-recipient-uri URI \"%s\" is already used."),
5910
recipient);
5911
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5912
"notify-status-code", IPP_ATTRIBUTES);
5913
return;
5914
}
5915
}
5916
else if (!strcmp(attr->name, "notify-pull-method") &&
5917
attr->value_tag == IPP_TAG_KEYWORD)
5918
{
5919
pullmethod = attr->values[0].string.text;
5920
5921
if (strcmp(pullmethod, "ippget"))
5922
{
5923
send_ipp_status(con, IPP_NOT_POSSIBLE,
5924
_("Bad notify-pull-method \"%s\"."), pullmethod);
5925
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5926
"notify-status-code", IPP_ATTRIBUTES);
5927
return;
5928
}
5929
}
5930
else if (!strcmp(attr->name, "notify-charset") &&
5931
attr->value_tag == IPP_TAG_CHARSET &&
5932
strcmp(attr->values[0].string.text, "us-ascii") &&
5933
strcmp(attr->values[0].string.text, "utf-8"))
5934
{
5935
send_ipp_status(con, IPP_CHARSET,
5936
_("Character set \"%s\" not supported."),
5937
attr->values[0].string.text);
5938
return;
5939
}
5940
else if (!strcmp(attr->name, "notify-natural-language") &&
5941
(attr->value_tag != IPP_TAG_LANGUAGE ||
5942
strcmp(attr->values[0].string.text, DefaultLanguage)))
5943
{
5944
send_ipp_status(con, IPP_CHARSET,
5945
_("Language \"%s\" not supported."),
5946
attr->values[0].string.text);
5947
return;
5948
}
5949
else if (!strcmp(attr->name, "notify-user-data") &&
5950
attr->value_tag == IPP_TAG_STRING)
5951
{
5952
if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
5953
{
5954
send_ipp_status(con, IPP_REQUEST_VALUE,
5955
_("The notify-user-data value is too large "
5956
"(%d > 63 octets)."),
5957
attr->values[0].unknown.length);
5958
return;
5959
}
5960
5961
user_data = attr;
5962
}
5963
else if (!strcmp(attr->name, "notify-events") &&
5964
attr->value_tag == IPP_TAG_KEYWORD)
5965
notify_events = attr;
5966
else if (!strcmp(attr->name, "notify-lease-duration") &&
5967
attr->value_tag == IPP_TAG_INTEGER)
5968
lease = attr->values[0].integer;
5969
else if (!strcmp(attr->name, "notify-time-interval") &&
5970
attr->value_tag == IPP_TAG_INTEGER)
5971
interval = attr->values[0].integer;
5972
else if (!strcmp(attr->name, "notify-job-id") &&
5973
attr->value_tag == IPP_TAG_INTEGER)
5974
jobid = attr->values[0].integer;
5975
5976
attr = attr->next;
5977
}
5978
5979
if (notify_events)
5980
{
5981
for (i = 0; i < notify_events->num_values; i ++)
5982
mask |= cupsdEventValue(notify_events->values[i].string.text);
5983
}
5984
5985
if (recipient)
5986
{
5987
cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient);
5988
5989
5990
if (!strncmp(recipient, "mailto:", 7) && user_data)
5991
{
5992
char temp[64]; /* Temporary string */
5993
5994
memcpy(temp, user_data->values[0].unknown.data, (size_t)user_data->values[0].unknown.length);
5995
temp[user_data->values[0].unknown.length] = '\0';
5996
5997
if (httpSeparateURI(HTTP_URI_CODING_ALL, temp, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_OK)
5998
{
5999
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad notify-user-data \"%s\"."), temp);
6000
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES);
6001
return;
6002
}
6003
}
6004
}
6005
6006
if (pullmethod)
6007
cupsdLogMessage(CUPSD_LOG_DEBUG, "pullmethod=\"%s\"", pullmethod);
6008
cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-lease-duration=%d", lease);
6009
cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-time-interval=%d", interval);
6010
6011
if (!recipient && !pullmethod)
6012
break;
6013
6014
if (mask == CUPSD_EVENT_NONE)
6015
{
6016
if (jobid)
6017
mask = CUPSD_EVENT_JOB_COMPLETED;
6018
else if (printer)
6019
mask = CUPSD_EVENT_PRINTER_STATE_CHANGED;
6020
else
6021
{
6022
send_ipp_status(con, IPP_BAD_REQUEST,
6023
_("notify-events not specified."));
6024
return;
6025
}
6026
}
6027
6028
if (MaxLeaseDuration && (lease == 0 || lease > MaxLeaseDuration))
6029
{
6030
cupsdLogMessage(CUPSD_LOG_INFO,
6031
"create_subscriptions: Limiting notify-lease-duration to "
6032
"%d seconds.",
6033
MaxLeaseDuration);
6034
lease = MaxLeaseDuration;
6035
}
6036
6037
if (jobid)
6038
{
6039
if ((job = cupsdFindJob(jobid)) == NULL)
6040
{
6041
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
6042
jobid);
6043
return;
6044
}
6045
}
6046
else
6047
job = NULL;
6048
6049
if ((sub = cupsdAddSubscription(mask, printer, job, recipient, 0)) == NULL)
6050
{
6051
send_ipp_status(con, IPP_TOO_MANY_SUBSCRIPTIONS,
6052
_("There are too many subscriptions."));
6053
return;
6054
}
6055
6056
if (job)
6057
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for job %d.",
6058
sub->id, job->id);
6059
else if (printer)
6060
cupsdLogMessage(CUPSD_LOG_DEBUG,
6061
"Added subscription #%d for printer \"%s\".",
6062
sub->id, printer->name);
6063
else
6064
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for server.",
6065
sub->id);
6066
6067
sub->interval = interval;
6068
sub->lease = lease;
6069
sub->expire = lease ? time(NULL) + lease : 0;
6070
6071
cupsdSetString(&sub->owner, username);
6072
6073
if (user_data)
6074
{
6075
sub->user_data_len = user_data->values[0].unknown.length;
6076
memcpy(sub->user_data, user_data->values[0].unknown.data,
6077
(size_t)sub->user_data_len);
6078
}
6079
6080
ippAddSeparator(con->response);
6081
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
6082
"notify-subscription-id", sub->id);
6083
6084
con->response->request.status.status_code = IPP_OK;
6085
6086
if (attr)
6087
attr = attr->next;
6088
}
6089
6090
cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
6091
}
6092
6093
6094
/*
6095
* 'delete_printer()' - Remove a printer or class from the system.
6096
*/
6097
6098
static void
6099
delete_printer(cupsd_client_t *con, /* I - Client connection */
6100
ipp_attribute_t *uri) /* I - URI of printer or class */
6101
{
6102
http_status_t status; /* Policy status */
6103
cups_ptype_t dtype; /* Destination type (printer/class) */
6104
cupsd_printer_t *printer; /* Printer/class */
6105
char filename[1024]; /* Script/PPD filename */
6106
int temporary; /* Temporary queue? */
6107
6108
6109
cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con,
6110
con->number, uri->values[0].string.text);
6111
6112
/*
6113
* Do we have a valid URI?
6114
*/
6115
6116
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
6117
{
6118
/*
6119
* Bad URI...
6120
*/
6121
6122
send_ipp_status(con, IPP_NOT_FOUND,
6123
_("The printer or class does not exist."));
6124
return;
6125
}
6126
6127
/*
6128
* Check policy...
6129
*/
6130
6131
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
6132
{
6133
send_http_error(con, status, NULL);
6134
return;
6135
}
6136
6137
/*
6138
* Remove old jobs...
6139
*/
6140
6141
cupsdCancelJobs(printer->name, NULL, 1);
6142
6143
/*
6144
* Remove old subscriptions and send a "deleted printer" event...
6145
*/
6146
6147
cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, printer, NULL,
6148
"%s \"%s\" deleted by \"%s\".",
6149
(dtype & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
6150
printer->name, get_username(con));
6151
6152
cupsdExpireSubscriptions(printer, NULL);
6153
6154
/*
6155
* Remove any old PPD or script files...
6156
*/
6157
6158
snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
6159
printer->name);
6160
unlink(filename);
6161
snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd.O", ServerRoot,
6162
printer->name);
6163
unlink(filename);
6164
6165
snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, printer->name);
6166
unlink(filename);
6167
6168
snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
6169
unlink(filename);
6170
6171
/*
6172
* Unregister color profiles...
6173
*/
6174
6175
cupsdUnregisterColor(printer);
6176
6177
temporary = printer->temporary;
6178
6179
if (dtype & CUPS_PRINTER_CLASS)
6180
{
6181
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".",
6182
printer->name, get_username(con));
6183
6184
cupsdDeletePrinter(printer, 0);
6185
if (!temporary)
6186
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
6187
}
6188
else
6189
{
6190
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".",
6191
printer->name, get_username(con));
6192
6193
if (cupsdDeletePrinter(printer, 0) && !temporary)
6194
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
6195
6196
if (!temporary)
6197
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
6198
}
6199
6200
if (!temporary)
6201
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
6202
6203
/*
6204
* Return with no errors...
6205
*/
6206
6207
con->response->request.status.status_code = IPP_OK;
6208
}
6209
6210
6211
/*
6212
* 'get_default()' - Get the default destination.
6213
*/
6214
6215
static void
6216
get_default(cupsd_client_t *con) /* I - Client connection */
6217
{
6218
http_status_t status; /* Policy status */
6219
cups_array_t *ra; /* Requested attributes array */
6220
6221
6222
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->number);
6223
6224
/*
6225
* Check policy...
6226
*/
6227
6228
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
6229
{
6230
send_http_error(con, status, NULL);
6231
return;
6232
}
6233
6234
if (DefaultPrinter)
6235
{
6236
ra = create_requested_array(con->request);
6237
6238
copy_printer_attrs(con, DefaultPrinter, ra);
6239
6240
cupsArrayDelete(ra);
6241
6242
con->response->request.status.status_code = IPP_OK;
6243
}
6244
else
6245
send_ipp_status(con, IPP_NOT_FOUND, _("No default printer."));
6246
}
6247
6248
6249
/*
6250
* 'get_devices()' - Get the list of available devices on the local system.
6251
*/
6252
6253
static void
6254
get_devices(cupsd_client_t *con) /* I - Client connection */
6255
{
6256
http_status_t status; /* Policy status */
6257
ipp_attribute_t *limit, /* limit attribute */
6258
*timeout, /* timeout attribute */
6259
*requested, /* requested-attributes attribute */
6260
*exclude, /* exclude-schemes attribute */
6261
*include; /* include-schemes attribute */
6262
char command[1024], /* cups-deviced command */
6263
options[2048], /* Options to pass to command */
6264
requested_str[256],
6265
/* String for requested attributes */
6266
exclude_str[512],
6267
/* String for excluded schemes */
6268
include_str[512];
6269
/* String for included schemes */
6270
6271
6272
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->number);
6273
6274
/*
6275
* Check policy...
6276
*/
6277
6278
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
6279
{
6280
send_http_error(con, status, NULL);
6281
return;
6282
}
6283
6284
/*
6285
* Run cups-deviced command with the given options...
6286
*/
6287
6288
limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
6289
timeout = ippFindAttribute(con->request, "timeout", IPP_TAG_INTEGER);
6290
requested = ippFindAttribute(con->request, "requested-attributes",
6291
IPP_TAG_KEYWORD);
6292
exclude = ippFindAttribute(con->request, "exclude-schemes", IPP_TAG_NAME);
6293
include = ippFindAttribute(con->request, "include-schemes", IPP_TAG_NAME);
6294
6295
if (requested)
6296
url_encode_attr(requested, requested_str, sizeof(requested_str));
6297
else
6298
strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
6299
6300
if (exclude)
6301
url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
6302
else
6303
exclude_str[0] = '\0';
6304
6305
if (include)
6306
url_encode_attr(include, include_str, sizeof(include_str));
6307
else
6308
include_str[0] = '\0';
6309
6310
snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin);
6311
snprintf(options, sizeof(options),
6312
"%d+%d+%d+%d+%s%s%s%s%s",
6313
con->request->request.op.request_id,
6314
limit ? limit->values[0].integer : 0,
6315
timeout ? timeout->values[0].integer : 15,
6316
(int)User,
6317
requested_str,
6318
exclude_str[0] ? "%20" : "", exclude_str,
6319
include_str[0] ? "%20" : "", include_str);
6320
6321
if (cupsdSendCommand(con, command, options, 1))
6322
{
6323
/*
6324
* Command started successfully, don't send an IPP response here...
6325
*/
6326
6327
ippDelete(con->response);
6328
con->response = NULL;
6329
}
6330
else
6331
{
6332
/*
6333
* Command failed, return "internal error" so the user knows something
6334
* went wrong...
6335
*/
6336
6337
send_ipp_status(con, IPP_INTERNAL_ERROR,
6338
_("cups-deviced failed to execute."));
6339
}
6340
}
6341
6342
6343
/*
6344
* 'get_document()' - Get a copy of a job file.
6345
*/
6346
6347
static void
6348
get_document(cupsd_client_t *con, /* I - Client connection */
6349
ipp_attribute_t *uri) /* I - Job URI */
6350
{
6351
http_status_t status; /* Policy status */
6352
ipp_attribute_t *attr; /* Current attribute */
6353
int jobid; /* Job ID */
6354
int docnum; /* Document number */
6355
cupsd_job_t *job; /* Current job */
6356
char scheme[HTTP_MAX_URI], /* Method portion of URI */
6357
username[HTTP_MAX_URI], /* Username portion of URI */
6358
host[HTTP_MAX_URI], /* Host portion of URI */
6359
resource[HTTP_MAX_URI]; /* Resource portion of URI */
6360
int port; /* Port portion of URI */
6361
char filename[1024], /* Filename for document */
6362
format[1024]; /* Format for document */
6363
6364
6365
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", con,
6366
con->number, uri->values[0].string.text);
6367
6368
/*
6369
* See if we have a job URI or a printer URI...
6370
*/
6371
6372
if (!strcmp(uri->name, "printer-uri"))
6373
{
6374
/*
6375
* Got a printer URI; see if we also have a job-id attribute...
6376
*/
6377
6378
if ((attr = ippFindAttribute(con->request, "job-id",
6379
IPP_TAG_INTEGER)) == NULL)
6380
{
6381
send_ipp_status(con, IPP_BAD_REQUEST,
6382
_("Got a printer-uri attribute but no job-id."));
6383
return;
6384
}
6385
6386
jobid = attr->values[0].integer;
6387
}
6388
else
6389
{
6390
/*
6391
* Got a job URI; parse it to get the job ID...
6392
*/
6393
6394
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
6395
sizeof(scheme), username, sizeof(username), host,
6396
sizeof(host), &port, resource, sizeof(resource));
6397
6398
if (strncmp(resource, "/jobs/", 6))
6399
{
6400
/*
6401
* Not a valid URI!
6402
*/
6403
6404
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
6405
uri->values[0].string.text);
6406
return;
6407
}
6408
6409
jobid = atoi(resource + 6);
6410
}
6411
6412
/*
6413
* See if the job exists...
6414
*/
6415
6416
if ((job = cupsdFindJob(jobid)) == NULL)
6417
{
6418
/*
6419
* Nope - return a "not found" error...
6420
*/
6421
6422
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
6423
return;
6424
}
6425
6426
/*
6427
* Check policy...
6428
*/
6429
6430
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con,
6431
job->username)) != HTTP_OK)
6432
{
6433
send_http_error(con, status, NULL);
6434
return;
6435
}
6436
6437
/*
6438
* Get the document number...
6439
*/
6440
6441
if ((attr = ippFindAttribute(con->request, "document-number",
6442
IPP_TAG_INTEGER)) == NULL)
6443
{
6444
send_ipp_status(con, IPP_BAD_REQUEST,
6445
_("Missing document-number attribute."));
6446
return;
6447
}
6448
6449
if ((docnum = attr->values[0].integer) < 1 || docnum > job->num_files ||
6450
attr->num_values > 1)
6451
{
6452
send_ipp_status(con, IPP_NOT_FOUND,
6453
_("Document #%d does not exist in job #%d."), docnum,
6454
jobid);
6455
return;
6456
}
6457
6458
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, jobid,
6459
docnum);
6460
if ((con->file = open(filename, O_RDONLY)) == -1)
6461
{
6462
cupsdLogMessage(CUPSD_LOG_ERROR,
6463
"Unable to open document %d in job %d - %s", docnum, jobid,
6464
strerror(errno));
6465
send_ipp_status(con, IPP_NOT_FOUND,
6466
_("Unable to open document #%d in job #%d."), docnum,
6467
jobid);
6468
return;
6469
}
6470
6471
fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
6472
6473
cupsdLoadJob(job);
6474
6475
snprintf(format, sizeof(format), "%s/%s", job->filetypes[docnum - 1]->super,
6476
job->filetypes[docnum - 1]->type);
6477
6478
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
6479
NULL, format);
6480
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "document-number",
6481
docnum);
6482
if ((attr = ippFindAttribute(job->attrs, "document-name",
6483
IPP_TAG_NAME)) != NULL)
6484
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "document-name",
6485
NULL, attr->values[0].string.text);
6486
}
6487
6488
6489
/*
6490
* 'get_job_attrs()' - Get job attributes.
6491
*/
6492
6493
static void
6494
get_job_attrs(cupsd_client_t *con, /* I - Client connection */
6495
ipp_attribute_t *uri) /* I - Job URI */
6496
{
6497
http_status_t status; /* Policy status */
6498
ipp_attribute_t *attr; /* Current attribute */
6499
int jobid; /* Job ID */
6500
cupsd_job_t *job; /* Current job */
6501
cupsd_printer_t *printer; /* Current printer */
6502
cupsd_policy_t *policy; /* Current security policy */
6503
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
6504
username[HTTP_MAX_URI], /* Username portion of URI */
6505
host[HTTP_MAX_URI], /* Host portion of URI */
6506
resource[HTTP_MAX_URI]; /* Resource portion of URI */
6507
int port; /* Port portion of URI */
6508
cups_array_t *ra, /* Requested attributes array */
6509
*exclude; /* Private attributes array */
6510
6511
6512
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con,
6513
con->number, uri->values[0].string.text);
6514
6515
/*
6516
* See if we have a job URI or a printer URI...
6517
*/
6518
6519
if (!strcmp(uri->name, "printer-uri"))
6520
{
6521
/*
6522
* Got a printer URI; see if we also have a job-id attribute...
6523
*/
6524
6525
if ((attr = ippFindAttribute(con->request, "job-id",
6526
IPP_TAG_INTEGER)) == NULL)
6527
{
6528
send_ipp_status(con, IPP_BAD_REQUEST,
6529
_("Got a printer-uri attribute but no job-id."));
6530
return;
6531
}
6532
6533
jobid = attr->values[0].integer;
6534
}
6535
else
6536
{
6537
/*
6538
* Got a job URI; parse it to get the job ID...
6539
*/
6540
6541
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
6542
sizeof(scheme), username, sizeof(username), host,
6543
sizeof(host), &port, resource, sizeof(resource));
6544
6545
if (strncmp(resource, "/jobs/", 6))
6546
{
6547
/*
6548
* Not a valid URI!
6549
*/
6550
6551
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
6552
uri->values[0].string.text);
6553
return;
6554
}
6555
6556
jobid = atoi(resource + 6);
6557
}
6558
6559
/*
6560
* See if the job exists...
6561
*/
6562
6563
if ((job = cupsdFindJob(jobid)) == NULL)
6564
{
6565
/*
6566
* Nope - return a "not found" error...
6567
*/
6568
6569
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
6570
return;
6571
}
6572
6573
/*
6574
* Check policy...
6575
*/
6576
6577
if ((printer = job->printer) == NULL)
6578
printer = cupsdFindDest(job->dest);
6579
6580
if (printer)
6581
policy = printer->op_policy_ptr;
6582
else
6583
policy = DefaultPolicyPtr;
6584
6585
if ((status = cupsdCheckPolicy(policy, con, job->username)) != HTTP_OK)
6586
{
6587
send_http_error(con, status, NULL);
6588
return;
6589
}
6590
6591
exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
6592
6593
/*
6594
* Copy attributes...
6595
*/
6596
6597
cupsdLoadJob(job);
6598
6599
ra = create_requested_array(con->request);
6600
copy_job_attrs(con, job, ra, exclude);
6601
cupsArrayDelete(ra);
6602
6603
con->response->request.status.status_code = IPP_OK;
6604
}
6605
6606
6607
/*
6608
* 'get_jobs()' - Get a list of jobs for the specified printer.
6609
*/
6610
6611
static void
6612
get_jobs(cupsd_client_t *con, /* I - Client connection */
6613
ipp_attribute_t *uri) /* I - Printer URI */
6614
{
6615
http_status_t status; /* Policy status */
6616
ipp_attribute_t *attr; /* Current attribute */
6617
const char *dest; /* Destination */
6618
cups_ptype_t dtype; /* Destination type (printer/class) */
6619
cups_ptype_t dmask; /* Destination type mask */
6620
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
6621
username[HTTP_MAX_URI], /* Username portion of URI */
6622
host[HTTP_MAX_URI], /* Host portion of URI */
6623
resource[HTTP_MAX_URI]; /* Resource portion of URI */
6624
int port; /* Port portion of URI */
6625
int job_comparison; /* Job comparison */
6626
ipp_jstate_t job_state; /* job-state value */
6627
int first_job_id = 1, /* First job ID */
6628
first_index = 1, /* First index */
6629
limit = 0, /* Maximum number of jobs to return */
6630
count, /* Number of jobs that match */
6631
need_load_job = 0; /* Do we need to load the job? */
6632
const char *job_attr; /* Job attribute requested */
6633
ipp_attribute_t *job_ids; /* job-ids attribute */
6634
cupsd_job_t *job; /* Current job pointer */
6635
cupsd_printer_t *printer; /* Printer */
6636
cups_array_t *list; /* Which job list... */
6637
int delete_list = 0; /* Delete the list afterwards? */
6638
cups_array_t *ra, /* Requested attributes array */
6639
*exclude; /* Private attributes array */
6640
cupsd_policy_t *policy; /* Current policy */
6641
6642
6643
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->number,
6644
uri->values[0].string.text);
6645
6646
/*
6647
* Is the destination valid?
6648
*/
6649
6650
if (strcmp(uri->name, "printer-uri"))
6651
{
6652
send_ipp_status(con, IPP_BAD_REQUEST, _("No printer-uri in request."));
6653
return;
6654
}
6655
6656
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
6657
sizeof(scheme), username, sizeof(username), host,
6658
sizeof(host), &port, resource, sizeof(resource));
6659
6660
if (!strcmp(resource, "/") || !strcmp(resource, "/jobs"))
6661
{
6662
dest = NULL;
6663
dtype = (cups_ptype_t)0;
6664
dmask = (cups_ptype_t)0;
6665
printer = NULL;
6666
}
6667
else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
6668
{
6669
dest = NULL;
6670
dtype = (cups_ptype_t)0;
6671
dmask = CUPS_PRINTER_CLASS;
6672
printer = NULL;
6673
}
6674
else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
6675
{
6676
dest = NULL;
6677
dtype = CUPS_PRINTER_CLASS;
6678
dmask = CUPS_PRINTER_CLASS;
6679
printer = NULL;
6680
}
6681
else if ((dest = cupsdValidateDest(uri->values[0].string.text, &dtype,
6682
&printer)) == NULL)
6683
{
6684
/*
6685
* Bad URI...
6686
*/
6687
6688
send_ipp_status(con, IPP_NOT_FOUND,
6689
_("The printer or class does not exist."));
6690
return;
6691
}
6692
else
6693
{
6694
dtype &= CUPS_PRINTER_CLASS;
6695
dmask = CUPS_PRINTER_CLASS;
6696
}
6697
6698
/*
6699
* Check policy...
6700
*/
6701
6702
if (printer)
6703
policy = printer->op_policy_ptr;
6704
else
6705
policy = DefaultPolicyPtr;
6706
6707
if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
6708
{
6709
send_http_error(con, status, NULL);
6710
return;
6711
}
6712
6713
job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
6714
6715
/*
6716
* See if the "which-jobs" attribute have been specified...
6717
*/
6718
6719
if ((attr = ippFindAttribute(con->request, "which-jobs",
6720
IPP_TAG_KEYWORD)) != NULL && job_ids)
6721
{
6722
send_ipp_status(con, IPP_CONFLICT,
6723
_("The %s attribute cannot be provided with job-ids."),
6724
"which-jobs");
6725
return;
6726
}
6727
else if (!attr || !strcmp(attr->values[0].string.text, "not-completed"))
6728
{
6729
job_comparison = -1;
6730
job_state = IPP_JOB_STOPPED;
6731
list = ActiveJobs;
6732
}
6733
else if (!strcmp(attr->values[0].string.text, "completed"))
6734
{
6735
job_comparison = 1;
6736
job_state = IPP_JOB_CANCELED;
6737
list = cupsdGetCompletedJobs(printer);
6738
delete_list = 1;
6739
}
6740
else if (!strcmp(attr->values[0].string.text, "aborted"))
6741
{
6742
job_comparison = 0;
6743
job_state = IPP_JOB_ABORTED;
6744
list = cupsdGetCompletedJobs(printer);
6745
delete_list = 1;
6746
}
6747
else if (!strcmp(attr->values[0].string.text, "all"))
6748
{
6749
job_comparison = 1;
6750
job_state = IPP_JOB_PENDING;
6751
list = Jobs;
6752
}
6753
else if (!strcmp(attr->values[0].string.text, "canceled"))
6754
{
6755
job_comparison = 0;
6756
job_state = IPP_JOB_CANCELED;
6757
list = cupsdGetCompletedJobs(printer);
6758
delete_list = 1;
6759
}
6760
else if (!strcmp(attr->values[0].string.text, "pending"))
6761
{
6762
job_comparison = 0;
6763
job_state = IPP_JOB_PENDING;
6764
list = ActiveJobs;
6765
}
6766
else if (!strcmp(attr->values[0].string.text, "pending-held"))
6767
{
6768
job_comparison = 0;
6769
job_state = IPP_JOB_HELD;
6770
list = ActiveJobs;
6771
}
6772
else if (!strcmp(attr->values[0].string.text, "processing"))
6773
{
6774
job_comparison = 0;
6775
job_state = IPP_JOB_PROCESSING;
6776
list = PrintingJobs;
6777
}
6778
else if (!strcmp(attr->values[0].string.text, "processing-stopped"))
6779
{
6780
job_comparison = 0;
6781
job_state = IPP_JOB_STOPPED;
6782
list = ActiveJobs;
6783
}
6784
else
6785
{
6786
send_ipp_status(con, IPP_ATTRIBUTES,
6787
_("The which-jobs value \"%s\" is not supported."),
6788
attr->values[0].string.text);
6789
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
6790
"which-jobs", NULL, attr->values[0].string.text);
6791
return;
6792
}
6793
6794
/*
6795
* See if they want to limit the number of jobs reported...
6796
*/
6797
6798
if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL)
6799
{
6800
if (job_ids)
6801
{
6802
send_ipp_status(con, IPP_CONFLICT,
6803
_("The %s attribute cannot be provided with job-ids."),
6804
"limit");
6805
return;
6806
}
6807
6808
limit = attr->values[0].integer;
6809
}
6810
6811
if ((attr = ippFindAttribute(con->request, "first-index", IPP_TAG_INTEGER)) != NULL)
6812
{
6813
if (job_ids)
6814
{
6815
send_ipp_status(con, IPP_CONFLICT,
6816
_("The %s attribute cannot be provided with job-ids."),
6817
"first-index");
6818
return;
6819
}
6820
6821
first_index = attr->values[0].integer;
6822
}
6823
else if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL)
6824
{
6825
if (job_ids)
6826
{
6827
send_ipp_status(con, IPP_CONFLICT,
6828
_("The %s attribute cannot be provided with job-ids."),
6829
"first-job-id");
6830
return;
6831
}
6832
6833
first_job_id = attr->values[0].integer;
6834
}
6835
6836
/*
6837
* See if we only want to see jobs for a specific user...
6838
*/
6839
6840
if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && job_ids)
6841
{
6842
send_ipp_status(con, IPP_CONFLICT,
6843
_("The %s attribute cannot be provided with job-ids."),
6844
"my-jobs");
6845
return;
6846
}
6847
else if (attr && attr->values[0].boolean)
6848
strlcpy(username, get_username(con), sizeof(username));
6849
else
6850
username[0] = '\0';
6851
6852
ra = create_requested_array(con->request);
6853
for (job_attr = (char *)cupsArrayFirst(ra); job_attr; job_attr = (char *)cupsArrayNext(ra))
6854
if (strcmp(job_attr, "job-id") &&
6855
strcmp(job_attr, "job-k-octets") &&
6856
strcmp(job_attr, "job-media-progress") &&
6857
strcmp(job_attr, "job-more-info") &&
6858
strcmp(job_attr, "job-name") &&
6859
strcmp(job_attr, "job-originating-user-name") &&
6860
strcmp(job_attr, "job-preserved") &&
6861
strcmp(job_attr, "job-printer-up-time") &&
6862
strcmp(job_attr, "job-printer-uri") &&
6863
strcmp(job_attr, "job-state") &&
6864
strcmp(job_attr, "job-state-reasons") &&
6865
strcmp(job_attr, "job-uri") &&
6866
strcmp(job_attr, "time-at-completed") &&
6867
strcmp(job_attr, "time-at-creation") &&
6868
strcmp(job_attr, "number-of-documents"))
6869
{
6870
need_load_job = 1;
6871
break;
6872
}
6873
6874
if (need_load_job && (limit == 0 || limit > 500) && (list == Jobs || delete_list))
6875
{
6876
/*
6877
* Limit expensive Get-Jobs for job history to 500 jobs...
6878
*/
6879
6880
ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "limit", 500);
6881
6882
if (limit)
6883
ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "limit", limit);
6884
6885
limit = 500;
6886
6887
cupsdLogClient(con, CUPSD_LOG_INFO, "Limiting Get-Jobs response to %d jobs.", limit);
6888
}
6889
6890
/*
6891
* OK, build a list of jobs for this printer...
6892
*/
6893
6894
if (job_ids)
6895
{
6896
int i; /* Looping var */
6897
6898
for (i = 0; i < job_ids->num_values; i ++)
6899
{
6900
if (!cupsdFindJob(job_ids->values[i].integer))
6901
break;
6902
}
6903
6904
if (i < job_ids->num_values)
6905
{
6906
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
6907
job_ids->values[i].integer);
6908
cupsArrayDelete(ra);
6909
return;
6910
}
6911
6912
for (i = 0; i < job_ids->num_values; i ++)
6913
{
6914
job = cupsdFindJob(job_ids->values[i].integer);
6915
6916
if (need_load_job && !job->attrs)
6917
{
6918
cupsdLoadJob(job);
6919
6920
if (!job->attrs)
6921
{
6922
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id);
6923
continue;
6924
}
6925
}
6926
6927
if (i > 0)
6928
ippAddSeparator(con->response);
6929
6930
exclude = cupsdGetPrivateAttrs(job->printer ?
6931
job->printer->op_policy_ptr :
6932
policy, con, job->printer,
6933
job->username);
6934
6935
copy_job_attrs(con, job, ra, exclude);
6936
}
6937
}
6938
else
6939
{
6940
if (first_index > 1)
6941
job = (cupsd_job_t *)cupsArrayIndex(list, first_index - 1);
6942
else
6943
job = (cupsd_job_t *)cupsArrayFirst(list);
6944
6945
for (count = 0; (limit <= 0 || count < limit) && job; job = (cupsd_job_t *)cupsArrayNext(list))
6946
{
6947
/*
6948
* Filter out jobs that don't match...
6949
*/
6950
6951
cupsdLogMessage(CUPSD_LOG_DEBUG2,
6952
"get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", "
6953
"state_value=%d, attrs=%p", job->id, job->dest,
6954
job->username, job->state_value, job->attrs);
6955
6956
if (!job->dest || !job->username)
6957
cupsdLoadJob(job);
6958
6959
if (!job->dest || !job->username)
6960
continue;
6961
6962
if ((dest && strcmp(job->dest, dest)) &&
6963
(!job->printer || !dest || strcmp(job->printer->name, dest)))
6964
continue;
6965
if ((job->dtype & dmask) != dtype &&
6966
(!job->printer || (job->printer->type & dmask) != dtype))
6967
continue;
6968
6969
if ((job_comparison < 0 && job->state_value > job_state) ||
6970
(job_comparison == 0 && job->state_value != job_state) ||
6971
(job_comparison > 0 && job->state_value < job_state))
6972
continue;
6973
6974
if (job->id < first_job_id)
6975
continue;
6976
6977
if (need_load_job && !job->attrs)
6978
{
6979
cupsdLoadJob(job);
6980
6981
if (!job->attrs)
6982
{
6983
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id);
6984
continue;
6985
}
6986
}
6987
6988
if (username[0] && _cups_strcasecmp(username, job->username))
6989
continue;
6990
6991
if (count > 0)
6992
ippAddSeparator(con->response);
6993
6994
count ++;
6995
6996
exclude = cupsdGetPrivateAttrs(job->printer ?
6997
job->printer->op_policy_ptr :
6998
policy, con, job->printer,
6999
job->username);
7000
7001
copy_job_attrs(con, job, ra, exclude);
7002
}
7003
7004
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count);
7005
}
7006
7007
cupsArrayDelete(ra);
7008
7009
if (delete_list)
7010
cupsArrayDelete(list);
7011
7012
con->response->request.status.status_code = IPP_OK;
7013
}
7014
7015
7016
/*
7017
* 'get_notifications()' - Get events for a subscription.
7018
*/
7019
7020
static void
7021
get_notifications(cupsd_client_t *con) /* I - Client connection */
7022
{
7023
int i, j; /* Looping vars */
7024
http_status_t status; /* Policy status */
7025
cupsd_subscription_t *sub; /* Subscription */
7026
ipp_attribute_t *ids, /* notify-subscription-ids */
7027
*sequences; /* notify-sequence-numbers */
7028
int min_seq; /* Minimum sequence number */
7029
int interval; /* Poll interval */
7030
7031
7032
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_notifications(con=%p[%d])",
7033
con, con->number);
7034
7035
/*
7036
* Get subscription attributes...
7037
*/
7038
7039
ids = ippFindAttribute(con->request, "notify-subscription-ids",
7040
IPP_TAG_INTEGER);
7041
sequences = ippFindAttribute(con->request, "notify-sequence-numbers",
7042
IPP_TAG_INTEGER);
7043
7044
if (!ids)
7045
{
7046
send_ipp_status(con, IPP_BAD_REQUEST,
7047
_("Missing notify-subscription-ids attribute."));
7048
return;
7049
}
7050
7051
/*
7052
* Are the subscription IDs valid?
7053
*/
7054
7055
for (i = 0, interval = 60; i < ids->num_values; i ++)
7056
{
7057
if ((sub = cupsdFindSubscription(ids->values[i].integer)) == NULL)
7058
{
7059
/*
7060
* Bad subscription ID...
7061
*/
7062
7063
send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
7064
ids->values[i].integer);
7065
return;
7066
}
7067
7068
/*
7069
* Check policy...
7070
*/
7071
7072
if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
7073
DefaultPolicyPtr,
7074
con, sub->owner)) != HTTP_OK)
7075
{
7076
send_http_error(con, status, sub->dest);
7077
return;
7078
}
7079
7080
/*
7081
* Check the subscription type and update the interval accordingly.
7082
*/
7083
7084
if (sub->job && sub->job->state_value == IPP_JOB_PROCESSING &&
7085
interval > 10)
7086
interval = 10;
7087
else if (sub->job && sub->job->state_value >= IPP_JOB_STOPPED)
7088
interval = 0;
7089
else if (sub->dest && sub->dest->state == IPP_PRINTER_PROCESSING &&
7090
interval > 30)
7091
interval = 30;
7092
}
7093
7094
/*
7095
* Tell the client to poll again in N seconds...
7096
*/
7097
7098
if (interval > 0)
7099
ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
7100
"notify-get-interval", interval);
7101
7102
ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
7103
"printer-up-time", time(NULL));
7104
7105
/*
7106
* Copy the subscription event attributes to the response.
7107
*/
7108
7109
con->response->request.status.status_code =
7110
interval ? IPP_OK : IPP_OK_EVENTS_COMPLETE;
7111
7112
for (i = 0; i < ids->num_values; i ++)
7113
{
7114
/*
7115
* Get the subscription and sequence number...
7116
*/
7117
7118
sub = cupsdFindSubscription(ids->values[i].integer);
7119
7120
if (sequences && i < sequences->num_values)
7121
min_seq = sequences->values[i].integer;
7122
else
7123
min_seq = 1;
7124
7125
/*
7126
* If we don't have any new events, nothing to do here...
7127
*/
7128
7129
if (min_seq > (sub->first_event_id + cupsArrayCount(sub->events)))
7130
continue;
7131
7132
/*
7133
* Otherwise copy all of the new events...
7134
*/
7135
7136
if (sub->first_event_id > min_seq)
7137
j = 0;
7138
else
7139
j = min_seq - sub->first_event_id;
7140
7141
for (; j < cupsArrayCount(sub->events); j ++)
7142
{
7143
ippAddSeparator(con->response);
7144
7145
copy_attrs(con->response,
7146
((cupsd_event_t *)cupsArrayIndex(sub->events, j))->attrs, NULL,
7147
IPP_TAG_EVENT_NOTIFICATION, 0, NULL);
7148
}
7149
}
7150
}
7151
7152
7153
/*
7154
* 'get_ppd()' - Get a named PPD from the local system.
7155
*/
7156
7157
static void
7158
get_ppd(cupsd_client_t *con, /* I - Client connection */
7159
ipp_attribute_t *uri) /* I - Printer URI or PPD name */
7160
{
7161
http_status_t status; /* Policy status */
7162
cupsd_printer_t *dest; /* Destination */
7163
cups_ptype_t dtype; /* Destination type */
7164
7165
7166
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con,
7167
con->number, uri, uri->name, uri->values[0].string.text);
7168
7169
if (!strcmp(ippGetName(uri), "ppd-name"))
7170
{
7171
/*
7172
* Return a PPD file from cups-driverd...
7173
*/
7174
7175
const char *ppd_name = ippGetString(uri, 0, NULL);
7176
/* ppd-name value */
7177
char command[1024], /* cups-driverd command */
7178
options[1024], /* Options to pass to command */
7179
oppd_name[1024]; /* Escaped ppd-name */
7180
7181
/*
7182
* Check policy...
7183
*/
7184
7185
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
7186
{
7187
send_http_error(con, status, NULL);
7188
return;
7189
}
7190
7191
/*
7192
* Check ppd-name value...
7193
*/
7194
7195
if (strstr(ppd_name, "../"))
7196
{
7197
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Invalid ppd-name value."));
7198
return;
7199
}
7200
7201
/*
7202
* Run cups-driverd command with the given options...
7203
*/
7204
7205
snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
7206
url_encode_string(ppd_name, oppd_name, sizeof(oppd_name));
7207
snprintf(options, sizeof(options), "get+%d+%s", ippGetRequestId(con->request), oppd_name);
7208
7209
if (cupsdSendCommand(con, command, options, 0))
7210
{
7211
/*
7212
* Command started successfully, don't send an IPP response here...
7213
*/
7214
7215
ippDelete(con->response);
7216
con->response = NULL;
7217
}
7218
else
7219
{
7220
/*
7221
* Command failed, return "internal error" so the user knows something
7222
* went wrong...
7223
*/
7224
7225
send_ipp_status(con, IPP_INTERNAL_ERROR, _("cups-driverd failed to execute."));
7226
}
7227
}
7228
else if (!strcmp(ippGetName(uri), "printer-uri") && cupsdValidateDest(ippGetString(uri, 0, NULL), &dtype, &dest))
7229
{
7230
int i; /* Looping var */
7231
char filename[1024]; /* PPD filename */
7232
7233
/*
7234
* Check policy...
7235
*/
7236
7237
if ((status = cupsdCheckPolicy(dest->op_policy_ptr, con, NULL)) != HTTP_OK)
7238
{
7239
send_http_error(con, status, dest);
7240
return;
7241
}
7242
7243
/*
7244
* See if we need the PPD for a class or remote printer...
7245
*/
7246
7247
snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest->name);
7248
7249
if ((dtype & CUPS_PRINTER_REMOTE) && access(filename, 0))
7250
{
7251
send_ipp_status(con, IPP_STATUS_CUPS_SEE_OTHER, _("See remote printer."));
7252
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, dest->uri);
7253
return;
7254
}
7255
else if (dtype & CUPS_PRINTER_CLASS)
7256
{
7257
for (i = 0; i < dest->num_printers; i ++)
7258
if (!(dest->printers[i]->type & CUPS_PRINTER_CLASS))
7259
{
7260
snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest->printers[i]->name);
7261
7262
if (!access(filename, 0))
7263
break;
7264
}
7265
7266
if (i < dest->num_printers)
7267
dest = dest->printers[i];
7268
else
7269
{
7270
send_ipp_status(con, IPP_STATUS_CUPS_SEE_OTHER, _("See remote printer."));
7271
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, dest->printers[0]->uri);
7272
return;
7273
}
7274
}
7275
7276
/*
7277
* Found the printer with the PPD file, now see if there is one...
7278
*/
7279
7280
if ((con->file = open(filename, O_RDONLY)) < 0)
7281
{
7282
send_ipp_status(con, IPP_STATUS_ERROR_NOT_FOUND, _("The PPD file \"%s\" could not be opened: %s"), ippGetString(uri, 0, NULL), strerror(errno));
7283
return;
7284
}
7285
7286
fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
7287
7288
con->pipe_pid = 0;
7289
7290
ippSetStatusCode(con->response, IPP_STATUS_OK);
7291
}
7292
else
7293
send_ipp_status(con, IPP_STATUS_ERROR_NOT_FOUND, _("The PPD file \"%s\" could not be found."), ippGetString(uri, 0, NULL));
7294
}
7295
7296
7297
/*
7298
* 'get_ppds()' - Get the list of PPD files on the local system.
7299
*/
7300
7301
static void
7302
get_ppds(cupsd_client_t *con) /* I - Client connection */
7303
{
7304
http_status_t status; /* Policy status */
7305
ipp_attribute_t *limit, /* Limit attribute */
7306
*device, /* ppd-device-id attribute */
7307
*language, /* ppd-natural-language attribute */
7308
*make, /* ppd-make attribute */
7309
*model, /* ppd-make-and-model attribute */
7310
*model_number, /* ppd-model-number attribute */
7311
*product, /* ppd-product attribute */
7312
*psversion, /* ppd-psverion attribute */
7313
*type, /* ppd-type attribute */
7314
*requested, /* requested-attributes attribute */
7315
*exclude, /* exclude-schemes attribute */
7316
*include; /* include-schemes attribute */
7317
char command[1024], /* cups-driverd command */
7318
options[4096], /* Options to pass to command */
7319
device_str[256],/* Escaped ppd-device-id string */
7320
language_str[256],
7321
/* Escaped ppd-natural-language */
7322
make_str[256], /* Escaped ppd-make string */
7323
model_str[256], /* Escaped ppd-make-and-model string */
7324
model_number_str[256],
7325
/* ppd-model-number string */
7326
product_str[256],
7327
/* Escaped ppd-product string */
7328
psversion_str[256],
7329
/* Escaped ppd-psversion string */
7330
type_str[256], /* Escaped ppd-type string */
7331
requested_str[256],
7332
/* String for requested attributes */
7333
exclude_str[512],
7334
/* String for excluded schemes */
7335
include_str[512];
7336
/* String for included schemes */
7337
7338
7339
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->number);
7340
7341
/*
7342
* Check policy...
7343
*/
7344
7345
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
7346
{
7347
send_http_error(con, status, NULL);
7348
return;
7349
}
7350
7351
/*
7352
* Run cups-driverd command with the given options...
7353
*/
7354
7355
limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
7356
device = ippFindAttribute(con->request, "ppd-device-id", IPP_TAG_TEXT);
7357
language = ippFindAttribute(con->request, "ppd-natural-language",
7358
IPP_TAG_LANGUAGE);
7359
make = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
7360
model = ippFindAttribute(con->request, "ppd-make-and-model",
7361
IPP_TAG_TEXT);
7362
model_number = ippFindAttribute(con->request, "ppd-model-number",
7363
IPP_TAG_INTEGER);
7364
product = ippFindAttribute(con->request, "ppd-product", IPP_TAG_TEXT);
7365
psversion = ippFindAttribute(con->request, "ppd-psversion", IPP_TAG_TEXT);
7366
type = ippFindAttribute(con->request, "ppd-type", IPP_TAG_KEYWORD);
7367
requested = ippFindAttribute(con->request, "requested-attributes",
7368
IPP_TAG_KEYWORD);
7369
exclude = ippFindAttribute(con->request, "exclude-schemes",
7370
IPP_TAG_NAME);
7371
include = ippFindAttribute(con->request, "include-schemes",
7372
IPP_TAG_NAME);
7373
7374
if (requested)
7375
url_encode_attr(requested, requested_str, sizeof(requested_str));
7376
else
7377
strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
7378
7379
if (device)
7380
url_encode_attr(device, device_str, sizeof(device_str));
7381
else
7382
device_str[0] = '\0';
7383
7384
if (language)
7385
url_encode_attr(language, language_str, sizeof(language_str));
7386
else
7387
language_str[0] = '\0';
7388
7389
if (make)
7390
url_encode_attr(make, make_str, sizeof(make_str));
7391
else
7392
make_str[0] = '\0';
7393
7394
if (model)
7395
url_encode_attr(model, model_str, sizeof(model_str));
7396
else
7397
model_str[0] = '\0';
7398
7399
if (model_number)
7400
snprintf(model_number_str, sizeof(model_number_str), "ppd-model-number=%d",
7401
model_number->values[0].integer);
7402
else
7403
model_number_str[0] = '\0';
7404
7405
if (product)
7406
url_encode_attr(product, product_str, sizeof(product_str));
7407
else
7408
product_str[0] = '\0';
7409
7410
if (psversion)
7411
url_encode_attr(psversion, psversion_str, sizeof(psversion_str));
7412
else
7413
psversion_str[0] = '\0';
7414
7415
if (type)
7416
url_encode_attr(type, type_str, sizeof(type_str));
7417
else
7418
type_str[0] = '\0';
7419
7420
if (exclude)
7421
url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
7422
else
7423
exclude_str[0] = '\0';
7424
7425
if (include)
7426
url_encode_attr(include, include_str, sizeof(include_str));
7427
else
7428
include_str[0] = '\0';
7429
7430
snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
7431
snprintf(options, sizeof(options),
7432
"list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
7433
con->request->request.op.request_id,
7434
limit ? limit->values[0].integer : 0,
7435
requested_str,
7436
device ? "%20" : "", device_str,
7437
language ? "%20" : "", language_str,
7438
make ? "%20" : "", make_str,
7439
model ? "%20" : "", model_str,
7440
model_number ? "%20" : "", model_number_str,
7441
product ? "%20" : "", product_str,
7442
psversion ? "%20" : "", psversion_str,
7443
type ? "%20" : "", type_str,
7444
exclude_str[0] ? "%20" : "", exclude_str,
7445
include_str[0] ? "%20" : "", include_str);
7446
7447
if (cupsdSendCommand(con, command, options, 0))
7448
{
7449
/*
7450
* Command started successfully, don't send an IPP response here...
7451
*/
7452
7453
ippDelete(con->response);
7454
con->response = NULL;
7455
}
7456
else
7457
{
7458
/*
7459
* Command failed, return "internal error" so the user knows something
7460
* went wrong...
7461
*/
7462
7463
send_ipp_status(con, IPP_INTERNAL_ERROR,
7464
_("cups-driverd failed to execute."));
7465
}
7466
}
7467
7468
7469
/*
7470
* 'get_printer_attrs()' - Get printer attributes.
7471
*/
7472
7473
static void
7474
get_printer_attrs(cupsd_client_t *con, /* I - Client connection */
7475
ipp_attribute_t *uri) /* I - Printer URI */
7476
{
7477
http_status_t status; /* Policy status */
7478
cups_ptype_t dtype; /* Destination type (printer/class) */
7479
cupsd_printer_t *printer; /* Printer/class */
7480
cups_array_t *ra; /* Requested attributes array */
7481
7482
7483
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", con,
7484
con->number, uri->values[0].string.text);
7485
7486
/*
7487
* Is the destination valid?
7488
*/
7489
7490
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
7491
{
7492
/*
7493
* Bad URI...
7494
*/
7495
7496
send_ipp_status(con, IPP_NOT_FOUND,
7497
_("The printer or class does not exist."));
7498
return;
7499
}
7500
7501
/*
7502
* Check policy...
7503
*/
7504
7505
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
7506
{
7507
send_http_error(con, status, printer);
7508
return;
7509
}
7510
7511
/*
7512
* Send the attributes...
7513
*/
7514
7515
ra = create_requested_array(con->request);
7516
7517
copy_printer_attrs(con, printer, ra);
7518
7519
cupsArrayDelete(ra);
7520
7521
con->response->request.status.status_code = IPP_OK;
7522
}
7523
7524
7525
/*
7526
* 'get_printer_supported()' - Get printer supported values.
7527
*/
7528
7529
static void
7530
get_printer_supported(
7531
cupsd_client_t *con, /* I - Client connection */
7532
ipp_attribute_t *uri) /* I - Printer URI */
7533
{
7534
http_status_t status; /* Policy status */
7535
cups_ptype_t dtype; /* Destination type (printer/class) */
7536
cupsd_printer_t *printer; /* Printer/class */
7537
7538
7539
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_supported(%p[%d], %s)", con,
7540
con->number, uri->values[0].string.text);
7541
7542
/*
7543
* Is the destination valid?
7544
*/
7545
7546
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
7547
{
7548
/*
7549
* Bad URI...
7550
*/
7551
7552
send_ipp_status(con, IPP_NOT_FOUND,
7553
_("The printer or class does not exist."));
7554
return;
7555
}
7556
7557
/*
7558
* Check policy...
7559
*/
7560
7561
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
7562
{
7563
send_http_error(con, status, printer);
7564
return;
7565
}
7566
7567
/*
7568
* Return a list of attributes that can be set via Set-Printer-Attributes.
7569
*/
7570
7571
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7572
"printer-geo-location", 0);
7573
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7574
"printer-info", 0);
7575
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7576
"printer-location", 0);
7577
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7578
"printer-organization", 0);
7579
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7580
"printer-organizational-unit", 0);
7581
7582
con->response->request.status.status_code = IPP_OK;
7583
}
7584
7585
7586
/*
7587
* 'get_printers()' - Get a list of printers or classes.
7588
*/
7589
7590
static void
7591
get_printers(cupsd_client_t *con, /* I - Client connection */
7592
int type) /* I - 0 or CUPS_PRINTER_CLASS */
7593
{
7594
http_status_t status; /* Policy status */
7595
ipp_attribute_t *attr; /* Current attribute */
7596
int limit; /* Max number of printers to return */
7597
int count; /* Number of printers that match */
7598
int printer_id; /* Printer we are interested in */
7599
cupsd_printer_t *printer; /* Current printer pointer */
7600
cups_ptype_t printer_type, /* printer-type attribute */
7601
printer_mask; /* printer-type-mask attribute */
7602
char *location; /* Location string */
7603
const char *username; /* Current user */
7604
char *first_printer_name; /* first-printer-name attribute */
7605
cups_array_t *ra; /* Requested attributes array */
7606
int local; /* Local connection? */
7607
7608
7609
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con,
7610
con->number, type);
7611
7612
/*
7613
* Check policy...
7614
*/
7615
7616
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
7617
{
7618
send_http_error(con, status, NULL);
7619
return;
7620
}
7621
7622
/*
7623
* Check for printers...
7624
*/
7625
7626
if (!Printers || !cupsArrayCount(Printers))
7627
{
7628
send_ipp_status(con, IPP_NOT_FOUND, _("No destinations added."));
7629
return;
7630
}
7631
7632
/*
7633
* See if they want to limit the number of printers reported...
7634
*/
7635
7636
if ((attr = ippFindAttribute(con->request, "limit",
7637
IPP_TAG_INTEGER)) != NULL)
7638
limit = attr->values[0].integer;
7639
else
7640
limit = 10000000;
7641
7642
if ((attr = ippFindAttribute(con->request, "first-printer-name",
7643
IPP_TAG_NAME)) != NULL)
7644
first_printer_name = attr->values[0].string.text;
7645
else
7646
first_printer_name = NULL;
7647
7648
/*
7649
* Support filtering...
7650
*/
7651
7652
if ((attr = ippFindAttribute(con->request, "printer-id", IPP_TAG_INTEGER)) != NULL)
7653
{
7654
if ((printer_id = ippGetInteger(attr, 0)) <= 0)
7655
{
7656
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad \"printer-id\" value %d."), printer_id);
7657
return;
7658
}
7659
}
7660
else
7661
printer_id = 0;
7662
7663
if ((attr = ippFindAttribute(con->request, "printer-type",
7664
IPP_TAG_ENUM)) != NULL)
7665
printer_type = (cups_ptype_t)attr->values[0].integer;
7666
else
7667
printer_type = (cups_ptype_t)0;
7668
7669
if ((attr = ippFindAttribute(con->request, "printer-type-mask",
7670
IPP_TAG_ENUM)) != NULL)
7671
printer_mask = (cups_ptype_t)attr->values[0].integer;
7672
else
7673
printer_mask = (cups_ptype_t)0;
7674
7675
local = httpAddrLocalhost(&(con->clientaddr));
7676
7677
if ((attr = ippFindAttribute(con->request, "printer-location",
7678
IPP_TAG_TEXT)) != NULL)
7679
location = attr->values[0].string.text;
7680
else
7681
location = NULL;
7682
7683
if (con->username[0])
7684
username = con->username;
7685
else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
7686
IPP_TAG_NAME)) != NULL)
7687
username = attr->values[0].string.text;
7688
else
7689
username = NULL;
7690
7691
ra = create_requested_array(con->request);
7692
7693
/*
7694
* OK, build a list of printers for this printer...
7695
*/
7696
7697
if (first_printer_name)
7698
{
7699
if ((printer = cupsdFindDest(first_printer_name)) == NULL)
7700
printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
7701
}
7702
else
7703
printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
7704
7705
for (count = 0;
7706
count < limit && printer;
7707
printer = (cupsd_printer_t *)cupsArrayNext(Printers))
7708
{
7709
if (!local && !printer->shared)
7710
continue;
7711
7712
if (printer_id && printer->printer_id != printer_id)
7713
continue;
7714
7715
if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) &&
7716
(printer->type & printer_mask) == printer_type &&
7717
(!location ||
7718
(printer->location && !_cups_strcasecmp(printer->location, location))))
7719
{
7720
/*
7721
* If a username is specified, see if it is allowed or denied
7722
* access...
7723
*/
7724
7725
if (cupsArrayCount(printer->users) && username &&
7726
!user_allowed(printer, username))
7727
continue;
7728
7729
/*
7730
* Add the group separator as needed...
7731
*/
7732
7733
if (count > 0)
7734
ippAddSeparator(con->response);
7735
7736
count ++;
7737
7738
/*
7739
* Send the attributes...
7740
*/
7741
7742
copy_printer_attrs(con, printer, ra);
7743
}
7744
}
7745
7746
cupsArrayDelete(ra);
7747
7748
con->response->request.status.status_code = IPP_OK;
7749
}
7750
7751
7752
/*
7753
* 'get_subscription_attrs()' - Get subscription attributes.
7754
*/
7755
7756
static void
7757
get_subscription_attrs(
7758
cupsd_client_t *con, /* I - Client connection */
7759
int sub_id) /* I - Subscription ID */
7760
{
7761
http_status_t status; /* Policy status */
7762
cupsd_subscription_t *sub; /* Subscription */
7763
cupsd_policy_t *policy; /* Current security policy */
7764
cups_array_t *ra, /* Requested attributes array */
7765
*exclude; /* Private attributes array */
7766
7767
7768
cupsdLogMessage(CUPSD_LOG_DEBUG2,
7769
"get_subscription_attrs(con=%p[%d], sub_id=%d)",
7770
con, con->number, sub_id);
7771
7772
/*
7773
* Expire subscriptions as needed...
7774
*/
7775
7776
cupsdExpireSubscriptions(NULL, NULL);
7777
7778
/*
7779
* Is the subscription ID valid?
7780
*/
7781
7782
if ((sub = cupsdFindSubscription(sub_id)) == NULL)
7783
{
7784
/*
7785
* Bad subscription ID...
7786
*/
7787
7788
send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
7789
sub_id);
7790
return;
7791
}
7792
7793
/*
7794
* Check policy...
7795
*/
7796
7797
if (sub->dest)
7798
policy = sub->dest->op_policy_ptr;
7799
else
7800
policy = DefaultPolicyPtr;
7801
7802
if ((status = cupsdCheckPolicy(policy, con, sub->owner)) != HTTP_OK)
7803
{
7804
send_http_error(con, status, sub->dest);
7805
return;
7806
}
7807
7808
exclude = cupsdGetPrivateAttrs(policy, con, sub->dest, sub->owner);
7809
7810
/*
7811
* Copy the subscription attributes to the response using the
7812
* requested-attributes attribute that may be provided by the client.
7813
*/
7814
7815
ra = create_requested_array(con->request);
7816
7817
copy_subscription_attrs(con, sub, ra, exclude);
7818
7819
cupsArrayDelete(ra);
7820
7821
con->response->request.status.status_code = IPP_OK;
7822
}
7823
7824
7825
/*
7826
* 'get_subscriptions()' - Get subscriptions.
7827
*/
7828
7829
static void
7830
get_subscriptions(cupsd_client_t *con, /* I - Client connection */
7831
ipp_attribute_t *uri) /* I - Printer/job URI */
7832
{
7833
http_status_t status; /* Policy status */
7834
int count; /* Number of subscriptions */
7835
int limit; /* Limit */
7836
cupsd_subscription_t *sub; /* Subscription */
7837
cups_array_t *ra; /* Requested attributes array */
7838
ipp_attribute_t *attr; /* Attribute */
7839
cups_ptype_t dtype; /* Destination type (printer/class) */
7840
char scheme[HTTP_MAX_URI],
7841
/* Scheme portion of URI */
7842
username[HTTP_MAX_URI],
7843
/* Username portion of URI */
7844
host[HTTP_MAX_URI],
7845
/* Host portion of URI */
7846
resource[HTTP_MAX_URI];
7847
/* Resource portion of URI */
7848
int port; /* Port portion of URI */
7849
cupsd_job_t *job; /* Job pointer */
7850
cupsd_printer_t *printer; /* Printer */
7851
cupsd_policy_t *policy; /* Policy */
7852
cups_array_t *exclude; /* Private attributes array */
7853
7854
7855
cupsdLogMessage(CUPSD_LOG_DEBUG2,
7856
"get_subscriptions(con=%p[%d], uri=%s)",
7857
con, con->number, uri->values[0].string.text);
7858
7859
/*
7860
* Is the destination valid?
7861
*/
7862
7863
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
7864
sizeof(scheme), username, sizeof(username), host,
7865
sizeof(host), &port, resource, sizeof(resource));
7866
7867
if (!strcmp(resource, "/") ||
7868
(!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6) ||
7869
(!strncmp(resource, "/printers", 9) && strlen(resource) <= 10) ||
7870
(!strncmp(resource, "/classes", 8) && strlen(resource) <= 9))
7871
{
7872
printer = NULL;
7873
job = NULL;
7874
}
7875
else if (!strncmp(resource, "/jobs/", 6) && resource[6])
7876
{
7877
int job_id = atoi(resource + 6);
7878
printer = NULL;
7879
job = cupsdFindJob(job_id);
7880
7881
if (!job)
7882
{
7883
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
7884
job_id);
7885
return;
7886
}
7887
}
7888
else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
7889
{
7890
/*
7891
* Bad URI...
7892
*/
7893
7894
send_ipp_status(con, IPP_NOT_FOUND,
7895
_("The printer or class does not exist."));
7896
return;
7897
}
7898
else if ((attr = ippFindAttribute(con->request, "notify-job-id",
7899
IPP_TAG_INTEGER)) != NULL)
7900
{
7901
job = cupsdFindJob(attr->values[0].integer);
7902
7903
if (!job)
7904
{
7905
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
7906
attr->values[0].integer);
7907
return;
7908
}
7909
}
7910
else
7911
job = NULL;
7912
7913
/*
7914
* Check policy...
7915
*/
7916
7917
if (printer)
7918
policy = printer->op_policy_ptr;
7919
else
7920
policy = DefaultPolicyPtr;
7921
7922
if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
7923
{
7924
send_http_error(con, status, printer);
7925
return;
7926
}
7927
7928
/*
7929
* Expire subscriptions as needed...
7930
*/
7931
7932
cupsdExpireSubscriptions(NULL, NULL);
7933
7934
/*
7935
* Copy the subscription attributes to the response using the
7936
* requested-attributes attribute that may be provided by the client.
7937
*/
7938
7939
ra = create_requested_array(con->request);
7940
7941
if ((attr = ippFindAttribute(con->request, "limit",
7942
IPP_TAG_INTEGER)) != NULL)
7943
limit = attr->values[0].integer;
7944
else
7945
limit = 0;
7946
7947
/*
7948
* See if we only want to see subscriptions for a specific user...
7949
*/
7950
7951
if ((attr = ippFindAttribute(con->request, "my-subscriptions",
7952
IPP_TAG_BOOLEAN)) != NULL &&
7953
attr->values[0].boolean)
7954
strlcpy(username, get_username(con), sizeof(username));
7955
else
7956
username[0] = '\0';
7957
7958
for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0;
7959
sub;
7960
sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
7961
if ((!printer || sub->dest == printer) && (!job || sub->job == job) &&
7962
(!username[0] || !_cups_strcasecmp(username, sub->owner)))
7963
{
7964
ippAddSeparator(con->response);
7965
7966
exclude = cupsdGetPrivateAttrs(sub->dest ? sub->dest->op_policy_ptr :
7967
policy, con, sub->dest,
7968
sub->owner);
7969
7970
copy_subscription_attrs(con, sub, ra, exclude);
7971
7972
count ++;
7973
if (limit && count >= limit)
7974
break;
7975
}
7976
7977
cupsArrayDelete(ra);
7978
7979
if (count)
7980
con->response->request.status.status_code = IPP_OK;
7981
else
7982
send_ipp_status(con, IPP_NOT_FOUND, _("No subscriptions found."));
7983
}
7984
7985
7986
/*
7987
* 'get_username()' - Get the username associated with a request.
7988
*/
7989
7990
static const char * /* O - Username */
7991
get_username(cupsd_client_t *con) /* I - Connection */
7992
{
7993
ipp_attribute_t *attr; /* Attribute */
7994
7995
7996
if (con->username[0])
7997
return (con->username);
7998
else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
7999
IPP_TAG_NAME)) != NULL)
8000
return (attr->values[0].string.text);
8001
else
8002
return ("anonymous");
8003
}
8004
8005
8006
/*
8007
* 'hold_job()' - Hold a print job.
8008
*/
8009
8010
static void
8011
hold_job(cupsd_client_t *con, /* I - Client connection */
8012
ipp_attribute_t *uri) /* I - Job or Printer URI */
8013
{
8014
ipp_attribute_t *attr; /* Current job-hold-until */
8015
const char *when; /* New value */
8016
int jobid; /* Job ID */
8017
char scheme[HTTP_MAX_URI], /* Method portion of URI */
8018
username[HTTP_MAX_URI], /* Username portion of URI */
8019
host[HTTP_MAX_URI], /* Host portion of URI */
8020
resource[HTTP_MAX_URI]; /* Resource portion of URI */
8021
int port; /* Port portion of URI */
8022
cupsd_job_t *job; /* Job information */
8023
8024
8025
cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", con, con->number,
8026
uri->values[0].string.text);
8027
8028
/*
8029
* See if we have a job URI or a printer URI...
8030
*/
8031
8032
if (!strcmp(uri->name, "printer-uri"))
8033
{
8034
/*
8035
* Got a printer URI; see if we also have a job-id attribute...
8036
*/
8037
8038
if ((attr = ippFindAttribute(con->request, "job-id",
8039
IPP_TAG_INTEGER)) == NULL)
8040
{
8041
send_ipp_status(con, IPP_BAD_REQUEST,
8042
_("Got a printer-uri attribute but no job-id."));
8043
return;
8044
}
8045
8046
jobid = attr->values[0].integer;
8047
}
8048
else
8049
{
8050
/*
8051
* Got a job URI; parse it to get the job ID...
8052
*/
8053
8054
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
8055
sizeof(scheme), username, sizeof(username), host,
8056
sizeof(host), &port, resource, sizeof(resource));
8057
8058
if (strncmp(resource, "/jobs/", 6))
8059
{
8060
/*
8061
* Not a valid URI!
8062
*/
8063
8064
send_ipp_status(con, IPP_BAD_REQUEST,
8065
_("Bad job-uri \"%s\"."),
8066
uri->values[0].string.text);
8067
return;
8068
}
8069
8070
jobid = atoi(resource + 6);
8071
}
8072
8073
/*
8074
* See if the job exists...
8075
*/
8076
8077
if ((job = cupsdFindJob(jobid)) == NULL)
8078
{
8079
/*
8080
* Nope - return a "not found" error...
8081
*/
8082
8083
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
8084
return;
8085
}
8086
8087
/*
8088
* See if the job is owned by the requesting user...
8089
*/
8090
8091
if (!validate_user(job, con, job->username, username, sizeof(username)))
8092
{
8093
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
8094
cupsdFindDest(job->dest));
8095
return;
8096
}
8097
8098
/*
8099
* See if the job is in a state that allows holding...
8100
*/
8101
8102
if (job->state_value > IPP_JOB_STOPPED)
8103
{
8104
/*
8105
* Return a "not-possible" error...
8106
*/
8107
8108
send_ipp_status(con, IPP_NOT_POSSIBLE,
8109
_("Job #%d is finished and cannot be altered."),
8110
job->id);
8111
return;
8112
}
8113
8114
/*
8115
* Hold the job and return...
8116
*/
8117
8118
if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL)
8119
{
8120
if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr))
8121
{
8122
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value."));
8123
ippCopyAttribute(con->response, attr, 0);
8124
return;
8125
}
8126
8127
when = ippGetString(attr, 0, NULL);
8128
8129
cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
8130
"Job job-hold-until value changed by user.");
8131
}
8132
else
8133
when = "indefinite";
8134
8135
cupsdSetJobHoldUntil(job, when, 1);
8136
cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".",
8137
username);
8138
8139
con->response->request.status.status_code = IPP_OK;
8140
}
8141
8142
8143
/*
8144
* 'hold_new_jobs()' - Hold pending/new jobs on a printer or class.
8145
*/
8146
8147
static void
8148
hold_new_jobs(cupsd_client_t *con, /* I - Connection */
8149
ipp_attribute_t *uri) /* I - Printer URI */
8150
{
8151
http_status_t status; /* Policy status */
8152
cups_ptype_t dtype; /* Destination type (printer/class) */
8153
cupsd_printer_t *printer; /* Printer data */
8154
8155
8156
cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", con,
8157
con->number, uri->values[0].string.text);
8158
8159
/*
8160
* Is the destination valid?
8161
*/
8162
8163
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
8164
{
8165
/*
8166
* Bad URI...
8167
*/
8168
8169
send_ipp_status(con, IPP_NOT_FOUND,
8170
_("The printer or class does not exist."));
8171
return;
8172
}
8173
8174
/*
8175
* Check policy...
8176
*/
8177
8178
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
8179
{
8180
send_http_error(con, status, printer);
8181
return;
8182
}
8183
8184
/*
8185
* Hold pending/new jobs sent to the printer...
8186
*/
8187
8188
printer->holding_new_jobs = 1;
8189
8190
cupsdSetPrinterReasons(printer, "+hold-new-jobs");
8191
8192
if (dtype & CUPS_PRINTER_CLASS)
8193
cupsdLogMessage(CUPSD_LOG_INFO,
8194
"Class \"%s\" now holding pending/new jobs (\"%s\").",
8195
printer->name, get_username(con));
8196
else
8197
cupsdLogMessage(CUPSD_LOG_INFO,
8198
"Printer \"%s\" now holding pending/new jobs (\"%s\").",
8199
printer->name, get_username(con));
8200
8201
/*
8202
* Everything was ok, so return OK status...
8203
*/
8204
8205
con->response->request.status.status_code = IPP_OK;
8206
}
8207
8208
8209
/*
8210
* 'move_job()' - Move a job to a new destination.
8211
*/
8212
8213
static void
8214
move_job(cupsd_client_t *con, /* I - Client connection */
8215
ipp_attribute_t *uri) /* I - Job URI */
8216
{
8217
http_status_t status; /* Policy status */
8218
ipp_attribute_t *attr; /* Current attribute */
8219
int jobid; /* Job ID */
8220
cupsd_job_t *job; /* Current job */
8221
const char *src; /* Source printer/class */
8222
cups_ptype_t stype, /* Source type (printer or class) */
8223
dtype; /* Destination type (printer/class) */
8224
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
8225
username[HTTP_MAX_URI], /* Username portion of URI */
8226
host[HTTP_MAX_URI], /* Host portion of URI */
8227
resource[HTTP_MAX_URI]; /* Resource portion of URI */
8228
int port; /* Port portion of URI */
8229
cupsd_printer_t *sprinter, /* Source printer */
8230
*dprinter; /* Destination printer */
8231
8232
8233
cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", con, con->number,
8234
uri->values[0].string.text);
8235
8236
/*
8237
* Get the new printer or class...
8238
*/
8239
8240
if ((attr = ippFindAttribute(con->request, "job-printer-uri",
8241
IPP_TAG_URI)) == NULL)
8242
{
8243
/*
8244
* Need job-printer-uri...
8245
*/
8246
8247
send_ipp_status(con, IPP_BAD_REQUEST,
8248
_("job-printer-uri attribute missing."));
8249
return;
8250
}
8251
8252
if (!cupsdValidateDest(attr->values[0].string.text, &dtype, &dprinter))
8253
{
8254
/*
8255
* Bad URI...
8256
*/
8257
8258
send_ipp_status(con, IPP_NOT_FOUND,
8259
_("The printer or class does not exist."));
8260
return;
8261
}
8262
8263
/*
8264
* See if we have a job URI or a printer URI...
8265
*/
8266
8267
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
8268
sizeof(scheme), username, sizeof(username), host,
8269
sizeof(host), &port, resource, sizeof(resource));
8270
8271
if (!strcmp(uri->name, "printer-uri"))
8272
{
8273
/*
8274
* Got a printer URI; see if we also have a job-id attribute...
8275
*/
8276
8277
if ((attr = ippFindAttribute(con->request, "job-id",
8278
IPP_TAG_INTEGER)) == NULL)
8279
{
8280
/*
8281
* Move all jobs...
8282
*/
8283
8284
if ((src = cupsdValidateDest(uri->values[0].string.text, &stype,
8285
&sprinter)) == NULL)
8286
{
8287
/*
8288
* Bad URI...
8289
*/
8290
8291
send_ipp_status(con, IPP_NOT_FOUND,
8292
_("The printer or class does not exist."));
8293
return;
8294
}
8295
8296
job = NULL;
8297
}
8298
else
8299
{
8300
/*
8301
* Otherwise, just move a single job...
8302
*/
8303
8304
if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
8305
{
8306
/*
8307
* Nope - return a "not found" error...
8308
*/
8309
8310
send_ipp_status(con, IPP_NOT_FOUND,
8311
_("Job #%d does not exist."), attr->values[0].integer);
8312
return;
8313
}
8314
else
8315
{
8316
/*
8317
* Job found, initialize source pointers...
8318
*/
8319
8320
src = NULL;
8321
sprinter = NULL;
8322
}
8323
}
8324
}
8325
else
8326
{
8327
/*
8328
* Got a job URI; parse it to get the job ID...
8329
*/
8330
8331
if (strncmp(resource, "/jobs/", 6))
8332
{
8333
/*
8334
* Not a valid URI!
8335
*/
8336
8337
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
8338
uri->values[0].string.text);
8339
return;
8340
}
8341
8342
/*
8343
* See if the job exists...
8344
*/
8345
8346
jobid = atoi(resource + 6);
8347
8348
if ((job = cupsdFindJob(jobid)) == NULL)
8349
{
8350
/*
8351
* Nope - return a "not found" error...
8352
*/
8353
8354
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
8355
return;
8356
}
8357
else
8358
{
8359
/*
8360
* Job found, initialize source pointers...
8361
*/
8362
8363
src = NULL;
8364
sprinter = NULL;
8365
}
8366
}
8367
8368
/*
8369
* Check the policy of the destination printer...
8370
*/
8371
8372
if ((status = cupsdCheckPolicy(dprinter->op_policy_ptr, con,
8373
job ? job->username : NULL)) != HTTP_OK)
8374
{
8375
send_http_error(con, status, dprinter);
8376
return;
8377
}
8378
8379
/*
8380
* Now move the job or jobs...
8381
*/
8382
8383
if (job)
8384
{
8385
/*
8386
* See if the job has been completed...
8387
*/
8388
8389
if (job->state_value > IPP_JOB_STOPPED)
8390
{
8391
/*
8392
* Return a "not-possible" error...
8393
*/
8394
8395
send_ipp_status(con, IPP_NOT_POSSIBLE,
8396
_("Job #%d is finished and cannot be altered."),
8397
job->id);
8398
return;
8399
}
8400
8401
/*
8402
* See if the job is owned by the requesting user...
8403
*/
8404
8405
if (!validate_user(job, con, job->username, username, sizeof(username)))
8406
{
8407
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
8408
cupsdFindDest(job->dest));
8409
return;
8410
}
8411
8412
/*
8413
* Move the job to a different printer or class...
8414
*/
8415
8416
cupsdMoveJob(job, dprinter);
8417
}
8418
else
8419
{
8420
/*
8421
* Got the source printer, now look through the jobs...
8422
*/
8423
8424
for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
8425
job;
8426
job = (cupsd_job_t *)cupsArrayNext(Jobs))
8427
{
8428
/*
8429
* See if the job is pointing at the source printer or has not been
8430
* completed...
8431
*/
8432
8433
if (_cups_strcasecmp(job->dest, src) ||
8434
job->state_value > IPP_JOB_STOPPED)
8435
continue;
8436
8437
/*
8438
* See if the job can be moved by the requesting user...
8439
*/
8440
8441
if (!validate_user(job, con, job->username, username, sizeof(username)))
8442
continue;
8443
8444
/*
8445
* Move the job to a different printer or class...
8446
*/
8447
8448
cupsdMoveJob(job, dprinter);
8449
}
8450
}
8451
8452
/*
8453
* Start jobs if possible...
8454
*/
8455
8456
cupsdCheckJobs();
8457
8458
/*
8459
* Return with "everything is OK" status...
8460
*/
8461
8462
con->response->request.status.status_code = IPP_OK;
8463
}
8464
8465
8466
/*
8467
* 'ppd_parse_line()' - Parse a PPD default line.
8468
*/
8469
8470
static int /* O - 0 on success, -1 on failure */
8471
ppd_parse_line(const char *line, /* I - Line */
8472
char *option, /* O - Option name */
8473
int olen, /* I - Size of option name */
8474
char *choice, /* O - Choice name */
8475
int clen) /* I - Size of choice name */
8476
{
8477
/*
8478
* Verify this is a default option line...
8479
*/
8480
8481
if (strncmp(line, "*Default", 8))
8482
return (-1);
8483
8484
/*
8485
* Read the option name...
8486
*/
8487
8488
for (line += 8, olen --;
8489
*line > ' ' && *line < 0x7f && *line != ':' && *line != '/';
8490
line ++)
8491
if (olen > 0)
8492
{
8493
*option++ = *line;
8494
olen --;
8495
}
8496
8497
*option = '\0';
8498
8499
/*
8500
* Skip everything else up to the colon (:)...
8501
*/
8502
8503
while (*line && *line != ':')
8504
line ++;
8505
8506
if (!*line)
8507
return (-1);
8508
8509
line ++;
8510
8511
/*
8512
* Now grab the option choice, skipping leading whitespace...
8513
*/
8514
8515
while (isspace(*line & 255))
8516
line ++;
8517
8518
for (clen --;
8519
*line > ' ' && *line < 0x7f && *line != ':' && *line != '/';
8520
line ++)
8521
if (clen > 0)
8522
{
8523
*choice++ = *line;
8524
clen --;
8525
}
8526
8527
*choice = '\0';
8528
8529
/*
8530
* Return with no errors...
8531
*/
8532
8533
return (0);
8534
}
8535
8536
8537
/*
8538
* 'print_job()' - Print a file to a printer or class.
8539
*/
8540
8541
static void
8542
print_job(cupsd_client_t *con, /* I - Client connection */
8543
ipp_attribute_t *uri) /* I - Printer URI */
8544
{
8545
ipp_attribute_t *attr; /* Current attribute */
8546
ipp_attribute_t *doc_name; /* document-name attribute */
8547
ipp_attribute_t *format; /* Document-format attribute */
8548
const char *default_format; /* document-format-default value */
8549
cupsd_job_t *job; /* New job */
8550
char filename[1024]; /* Job filename */
8551
mime_type_t *filetype; /* Type of file */
8552
char super[MIME_MAX_SUPER], /* Supertype of file */
8553
type[MIME_MAX_TYPE], /* Subtype of file */
8554
mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
8555
/* Textual name of mime type */
8556
cupsd_printer_t *printer; /* Printer data */
8557
struct stat fileinfo; /* File information */
8558
int kbytes; /* Size of file */
8559
int compression; /* Document compression */
8560
8561
8562
cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->number,
8563
uri->values[0].string.text);
8564
8565
/*
8566
* Validate print file attributes, for now just document-format and
8567
* compression (CUPS only supports "none" and "gzip")...
8568
*/
8569
8570
compression = CUPS_FILE_NONE;
8571
8572
if ((attr = ippFindAttribute(con->request, "compression",
8573
IPP_TAG_KEYWORD)) != NULL)
8574
{
8575
if (strcmp(attr->values[0].string.text, "none")
8576
#ifdef HAVE_LIBZ
8577
&& strcmp(attr->values[0].string.text, "gzip")
8578
#endif /* HAVE_LIBZ */
8579
)
8580
{
8581
send_ipp_status(con, IPP_ATTRIBUTES,
8582
_("Unsupported compression \"%s\"."),
8583
attr->values[0].string.text);
8584
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
8585
"compression", NULL, attr->values[0].string.text);
8586
return;
8587
}
8588
8589
#ifdef HAVE_LIBZ
8590
if (!strcmp(attr->values[0].string.text, "gzip"))
8591
compression = CUPS_FILE_GZIP;
8592
#endif /* HAVE_LIBZ */
8593
}
8594
8595
/*
8596
* Do we have a file to print?
8597
*/
8598
8599
if (!con->filename)
8600
{
8601
send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request."));
8602
return;
8603
}
8604
8605
/*
8606
* Is the destination valid?
8607
*/
8608
8609
if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer))
8610
{
8611
/*
8612
* Bad URI...
8613
*/
8614
8615
send_ipp_status(con, IPP_NOT_FOUND,
8616
_("The printer or class does not exist."));
8617
return;
8618
}
8619
8620
/*
8621
* Is it a format we support?
8622
*/
8623
8624
doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
8625
if (doc_name)
8626
ippSetName(con->request, &doc_name, "document-name-supplied");
8627
8628
if ((format = ippFindAttribute(con->request, "document-format",
8629
IPP_TAG_MIMETYPE)) != NULL)
8630
{
8631
/*
8632
* Grab format from client...
8633
*/
8634
8635
if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super,
8636
type) != 2)
8637
{
8638
send_ipp_status(con, IPP_BAD_REQUEST,
8639
_("Bad document-format \"%s\"."),
8640
format->values[0].string.text);
8641
return;
8642
}
8643
8644
ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, ippGetString(format, 0, NULL));
8645
}
8646
else if ((default_format = cupsGetOption("document-format",
8647
printer->num_options,
8648
printer->options)) != NULL)
8649
{
8650
/*
8651
* Use default document format...
8652
*/
8653
8654
if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2)
8655
{
8656
send_ipp_status(con, IPP_BAD_REQUEST,
8657
_("Bad document-format \"%s\"."),
8658
default_format);
8659
return;
8660
}
8661
}
8662
else
8663
{
8664
/*
8665
* Auto-type it!
8666
*/
8667
8668
strlcpy(super, "application", sizeof(super));
8669
strlcpy(type, "octet-stream", sizeof(type));
8670
}
8671
8672
_cupsRWLockRead(&MimeDatabase->lock);
8673
8674
if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
8675
{
8676
/*
8677
* Auto-type the file...
8678
*/
8679
8680
cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job ???] Auto-typing file...");
8681
8682
8683
filetype = mimeFileType(MimeDatabase, con->filename,
8684
doc_name ? doc_name->values[0].string.text : NULL,
8685
&compression);
8686
8687
if (!filetype)
8688
filetype = mimeType(MimeDatabase, super, type);
8689
8690
cupsdLogMessage(CUPSD_LOG_INFO, "[Job ???] Request file type is %s/%s.",
8691
filetype->super, filetype->type);
8692
8693
snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, filetype->type);
8694
ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, mimetype);
8695
}
8696
else
8697
filetype = mimeType(MimeDatabase, super, type);
8698
8699
_cupsRWUnlock(&MimeDatabase->lock);
8700
8701
if (filetype &&
8702
(!format ||
8703
(!strcmp(super, "application") && !strcmp(type, "octet-stream"))))
8704
{
8705
/*
8706
* Replace the document-format attribute value with the auto-typed or
8707
* default one.
8708
*/
8709
8710
snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
8711
filetype->type);
8712
8713
if (format)
8714
ippSetString(con->request, &format, 0, mimetype);
8715
else
8716
ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
8717
"document-format", NULL, mimetype);
8718
}
8719
else if (!filetype)
8720
{
8721
send_ipp_status(con, IPP_DOCUMENT_FORMAT,
8722
_("Unsupported document-format \"%s\"."),
8723
format ? format->values[0].string.text :
8724
"application/octet-stream");
8725
cupsdLogMessage(CUPSD_LOG_INFO,
8726
"Hint: Do you have the raw file printing rules enabled?");
8727
8728
if (format)
8729
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
8730
"document-format", NULL, format->values[0].string.text);
8731
8732
return;
8733
}
8734
8735
/*
8736
* Read any embedded job ticket info from PS files...
8737
*/
8738
8739
if (!_cups_strcasecmp(filetype->super, "application") &&
8740
(!_cups_strcasecmp(filetype->type, "postscript") ||
8741
!_cups_strcasecmp(filetype->type, "pdf")))
8742
read_job_ticket(con);
8743
8744
/*
8745
* Create the job object...
8746
*/
8747
8748
if ((job = add_job(con, printer, filetype)) == NULL)
8749
return;
8750
8751
/*
8752
* Update quota data...
8753
*/
8754
8755
if (stat(con->filename, &fileinfo))
8756
kbytes = 0;
8757
else
8758
kbytes = (fileinfo.st_size + 1023) / 1024;
8759
8760
cupsdUpdateQuota(printer, job->username, 0, kbytes);
8761
8762
job->koctets += kbytes;
8763
8764
if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
8765
attr->values[0].integer += kbytes;
8766
8767
/*
8768
* Add the job file...
8769
*/
8770
8771
if (add_file(con, job, filetype, compression))
8772
return;
8773
8774
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, job->num_files);
8775
if (rename(con->filename, filename))
8776
{
8777
cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to rename job document file \"%s\": %s", filename, strerror(errno));
8778
8779
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to rename job document file."));
8780
return;
8781
}
8782
8783
cupsdClearString(&con->filename);
8784
8785
/*
8786
* See if we need to add the ending sheet...
8787
*/
8788
8789
if (cupsdTimeoutJob(job))
8790
return;
8791
8792
/*
8793
* Log and save the job...
8794
*/
8795
8796
cupsdLogJob(job, CUPSD_LOG_INFO,
8797
"File of type %s/%s queued by \"%s\".",
8798
filetype->super, filetype->type, job->username);
8799
cupsdLogJob(job, CUPSD_LOG_DEBUG, "hold_until=%d", (int)job->hold_until);
8800
cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".",
8801
job->dest, job->username);
8802
8803
/*
8804
* Start the job if possible...
8805
*/
8806
8807
cupsdCheckJobs();
8808
}
8809
8810
8811
/*
8812
* 'read_job_ticket()' - Read a job ticket embedded in a print file.
8813
*
8814
* This function only gets called when printing a single PDF or PostScript
8815
* file using the Print-Job operation. It doesn't work for Create-Job +
8816
* Send-File, since the job attributes need to be set at job creation
8817
* time for banners to work. The embedded job ticket stuff is here
8818
* primarily to allow the Windows printer driver for CUPS to pass in JCL
8819
* options and IPP attributes which otherwise would be lost.
8820
*
8821
* The format of a job ticket is simple:
8822
*
8823
* %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
8824
*
8825
* %cupsJobTicket: attr1=value1
8826
* %cupsJobTicket: attr2=value2
8827
* ...
8828
* %cupsJobTicket: attrN=valueN
8829
*
8830
* Job ticket lines must appear immediately after the first line that
8831
* specifies PostScript (%!PS-Adobe-3.0) or PDF (%PDF) format, and CUPS
8832
* stops looking for job ticket info when it finds a line that does not begin
8833
* with "%cupsJobTicket:".
8834
*
8835
* The maximum length of a job ticket line, including the prefix, is
8836
* 255 characters to conform with the Adobe DSC.
8837
*
8838
* Read-only attributes are rejected with a notice to the error log in
8839
* case a malicious user tries anything. Since the job ticket is read
8840
* prior to attribute validation in print_job(), job ticket attributes
8841
* will go through the same validation as IPP attributes...
8842
*/
8843
8844
static void
8845
read_job_ticket(cupsd_client_t *con) /* I - Client connection */
8846
{
8847
cups_file_t *fp; /* File to read from */
8848
char line[256]; /* Line data */
8849
int num_options; /* Number of options */
8850
cups_option_t *options; /* Options */
8851
ipp_t *ticket; /* New attributes */
8852
ipp_attribute_t *attr, /* Current attribute */
8853
*attr2, /* Job attribute */
8854
*prev2; /* Previous job attribute */
8855
8856
8857
/*
8858
* First open the print file...
8859
*/
8860
8861
if ((fp = cupsFileOpen(con->filename, "rb")) == NULL)
8862
{
8863
cupsdLogMessage(CUPSD_LOG_ERROR,
8864
"Unable to open print file for job ticket - %s",
8865
strerror(errno));
8866
return;
8867
}
8868
8869
/*
8870
* Skip the first line...
8871
*/
8872
8873
if (cupsFileGets(fp, line, sizeof(line)) == NULL)
8874
{
8875
cupsdLogMessage(CUPSD_LOG_ERROR,
8876
"Unable to read from print file for job ticket - %s",
8877
strerror(errno));
8878
cupsFileClose(fp);
8879
return;
8880
}
8881
8882
if (strncmp(line, "%!PS-Adobe-", 11) && strncmp(line, "%PDF-", 5))
8883
{
8884
/*
8885
* Not a DSC-compliant file, so no job ticket info will be available...
8886
*/
8887
8888
cupsFileClose(fp);
8889
return;
8890
}
8891
8892
/*
8893
* Read job ticket info from the file...
8894
*/
8895
8896
num_options = 0;
8897
options = NULL;
8898
8899
while (cupsFileGets(fp, line, sizeof(line)))
8900
{
8901
/*
8902
* Stop at the first non-ticket line...
8903
*/
8904
8905
if (strncmp(line, "%cupsJobTicket:", 15))
8906
break;
8907
8908
/*
8909
* Add the options to the option array...
8910
*/
8911
8912
num_options = cupsParseOptions(line + 15, num_options, &options);
8913
}
8914
8915
/*
8916
* Done with the file; see if we have any options...
8917
*/
8918
8919
cupsFileClose(fp);
8920
8921
if (num_options == 0)
8922
return;
8923
8924
/*
8925
* OK, convert the options to an attribute list, and apply them to
8926
* the request...
8927
*/
8928
8929
ticket = ippNew();
8930
cupsEncodeOptions(ticket, num_options, options);
8931
8932
/*
8933
* See what the user wants to change.
8934
*/
8935
8936
for (attr = ticket->attrs; attr; attr = attr->next)
8937
{
8938
if (attr->group_tag != IPP_TAG_JOB || !attr->name)
8939
continue;
8940
8941
if (!strncmp(attr->name, "date-time-at-", 13) ||
8942
!strcmp(attr->name, "job-impressions-completed") ||
8943
!strcmp(attr->name, "job-media-sheets-completed") ||
8944
!strncmp(attr->name, "job-k-octets", 12) ||
8945
!strcmp(attr->name, "job-id") ||
8946
!strcmp(attr->name, "job-originating-host-name") ||
8947
!strcmp(attr->name, "job-originating-user-name") ||
8948
!strcmp(attr->name, "job-pages-completed") ||
8949
!strcmp(attr->name, "job-printer-uri") ||
8950
!strncmp(attr->name, "job-state", 9) ||
8951
!strcmp(attr->name, "job-uri") ||
8952
!strncmp(attr->name, "time-at-", 8))
8953
continue; /* Read-only attrs */
8954
8955
if ((attr2 = ippFindAttribute(con->request, attr->name,
8956
IPP_TAG_ZERO)) != NULL)
8957
{
8958
/*
8959
* Some other value; first free the old value...
8960
*/
8961
8962
if (con->request->attrs == attr2)
8963
{
8964
con->request->attrs = attr2->next;
8965
prev2 = NULL;
8966
}
8967
else
8968
{
8969
for (prev2 = con->request->attrs; prev2; prev2 = prev2->next)
8970
if (prev2->next == attr2)
8971
{
8972
prev2->next = attr2->next;
8973
break;
8974
}
8975
}
8976
8977
if (con->request->last == attr2)
8978
con->request->last = prev2;
8979
8980
ippDeleteAttribute(NULL, attr2);
8981
}
8982
8983
/*
8984
* Add new option by copying it...
8985
*/
8986
8987
ippCopyAttribute(con->request, attr, 0);
8988
}
8989
8990
/*
8991
* Then free the attribute list and option array...
8992
*/
8993
8994
ippDelete(ticket);
8995
cupsFreeOptions(num_options, options);
8996
}
8997
8998
8999
/*
9000
* 'reject_jobs()' - Reject print jobs to a printer.
9001
*/
9002
9003
static void
9004
reject_jobs(cupsd_client_t *con, /* I - Client connection */
9005
ipp_attribute_t *uri) /* I - Printer or class URI */
9006
{
9007
http_status_t status; /* Policy status */
9008
cups_ptype_t dtype; /* Destination type (printer/class) */
9009
cupsd_printer_t *printer; /* Printer data */
9010
ipp_attribute_t *attr; /* printer-state-message text */
9011
9012
9013
cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", con,
9014
con->number, uri->values[0].string.text);
9015
9016
/*
9017
* Is the destination valid?
9018
*/
9019
9020
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
9021
{
9022
/*
9023
* Bad URI...
9024
*/
9025
9026
send_ipp_status(con, IPP_NOT_FOUND,
9027
_("The printer or class does not exist."));
9028
return;
9029
}
9030
9031
/*
9032
* Check policy...
9033
*/
9034
9035
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
9036
{
9037
send_http_error(con, status, printer);
9038
return;
9039
}
9040
9041
/*
9042
* Reject jobs sent to the printer...
9043
*/
9044
9045
printer->accepting = 0;
9046
9047
if ((attr = ippFindAttribute(con->request, "printer-state-message",
9048
IPP_TAG_TEXT)) == NULL)
9049
strlcpy(printer->state_message, "Rejecting Jobs",
9050
sizeof(printer->state_message));
9051
else
9052
strlcpy(printer->state_message, attr->values[0].string.text,
9053
sizeof(printer->state_message));
9054
9055
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
9056
"No longer accepting jobs.");
9057
9058
if (dtype & CUPS_PRINTER_CLASS)
9059
{
9060
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
9061
9062
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").",
9063
printer->name, get_username(con));
9064
}
9065
else
9066
{
9067
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
9068
9069
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" rejecting jobs (\"%s\").",
9070
printer->name, get_username(con));
9071
}
9072
9073
/*
9074
* Everything was ok, so return OK status...
9075
*/
9076
9077
con->response->request.status.status_code = IPP_OK;
9078
}
9079
9080
9081
/*
9082
* 'release_held_new_jobs()' - Release pending/new jobs on a printer or class.
9083
*/
9084
9085
static void
9086
release_held_new_jobs(
9087
cupsd_client_t *con, /* I - Connection */
9088
ipp_attribute_t *uri) /* I - Printer URI */
9089
{
9090
http_status_t status; /* Policy status */
9091
cups_ptype_t dtype; /* Destination type (printer/class) */
9092
cupsd_printer_t *printer; /* Printer data */
9093
9094
9095
cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", con,
9096
con->number, uri->values[0].string.text);
9097
9098
/*
9099
* Is the destination valid?
9100
*/
9101
9102
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
9103
{
9104
/*
9105
* Bad URI...
9106
*/
9107
9108
send_ipp_status(con, IPP_NOT_FOUND,
9109
_("The printer or class does not exist."));
9110
return;
9111
}
9112
9113
/*
9114
* Check policy...
9115
*/
9116
9117
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
9118
{
9119
send_http_error(con, status, printer);
9120
return;
9121
}
9122
9123
/*
9124
* Hold pending/new jobs sent to the printer...
9125
*/
9126
9127
printer->holding_new_jobs = 0;
9128
9129
cupsdSetPrinterReasons(printer, "-hold-new-jobs");
9130
9131
if (dtype & CUPS_PRINTER_CLASS)
9132
cupsdLogMessage(CUPSD_LOG_INFO,
9133
"Class \"%s\" now printing pending/new jobs (\"%s\").",
9134
printer->name, get_username(con));
9135
else
9136
cupsdLogMessage(CUPSD_LOG_INFO,
9137
"Printer \"%s\" now printing pending/new jobs (\"%s\").",
9138
printer->name, get_username(con));
9139
9140
cupsdCheckJobs();
9141
9142
/*
9143
* Everything was ok, so return OK status...
9144
*/
9145
9146
con->response->request.status.status_code = IPP_OK;
9147
}
9148
9149
9150
/*
9151
* 'release_job()' - Release a held print job.
9152
*/
9153
9154
static void
9155
release_job(cupsd_client_t *con, /* I - Client connection */
9156
ipp_attribute_t *uri) /* I - Job or Printer URI */
9157
{
9158
ipp_attribute_t *attr; /* Current attribute */
9159
int jobid; /* Job ID */
9160
char scheme[HTTP_MAX_URI], /* Method portion of URI */
9161
username[HTTP_MAX_URI], /* Username portion of URI */
9162
host[HTTP_MAX_URI], /* Host portion of URI */
9163
resource[HTTP_MAX_URI]; /* Resource portion of URI */
9164
int port; /* Port portion of URI */
9165
cupsd_job_t *job; /* Job information */
9166
9167
9168
cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", con,
9169
con->number, uri->values[0].string.text);
9170
9171
/*
9172
* See if we have a job URI or a printer URI...
9173
*/
9174
9175
if (!strcmp(uri->name, "printer-uri"))
9176
{
9177
/*
9178
* Got a printer URI; see if we also have a job-id attribute...
9179
*/
9180
9181
if ((attr = ippFindAttribute(con->request, "job-id",
9182
IPP_TAG_INTEGER)) == NULL)
9183
{
9184
send_ipp_status(con, IPP_BAD_REQUEST,
9185
_("Got a printer-uri attribute but no job-id."));
9186
return;
9187
}
9188
9189
jobid = attr->values[0].integer;
9190
}
9191
else
9192
{
9193
/*
9194
* Got a job URI; parse it to get the job ID...
9195
*/
9196
9197
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
9198
sizeof(scheme), username, sizeof(username), host,
9199
sizeof(host), &port, resource, sizeof(resource));
9200
9201
if (strncmp(resource, "/jobs/", 6))
9202
{
9203
/*
9204
* Not a valid URI!
9205
*/
9206
9207
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
9208
uri->values[0].string.text);
9209
return;
9210
}
9211
9212
jobid = atoi(resource + 6);
9213
}
9214
9215
/*
9216
* See if the job exists...
9217
*/
9218
9219
if ((job = cupsdFindJob(jobid)) == NULL)
9220
{
9221
/*
9222
* Nope - return a "not found" error...
9223
*/
9224
9225
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
9226
return;
9227
}
9228
9229
/*
9230
* See if job is "held"...
9231
*/
9232
9233
if (job->state_value != IPP_JOB_HELD)
9234
{
9235
/*
9236
* Nope - return a "not possible" error...
9237
*/
9238
9239
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not held."), jobid);
9240
return;
9241
}
9242
9243
/*
9244
* See if the job is owned by the requesting user...
9245
*/
9246
9247
if (!validate_user(job, con, job->username, username, sizeof(username)))
9248
{
9249
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
9250
cupsdFindDest(job->dest));
9251
return;
9252
}
9253
9254
/*
9255
* Reset the job-hold-until value to "no-hold"...
9256
*/
9257
9258
if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
9259
IPP_TAG_KEYWORD)) == NULL)
9260
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
9261
9262
if (attr)
9263
{
9264
ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
9265
ippSetString(job->attrs, &attr, 0, "no-hold");
9266
9267
cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
9268
"Job job-hold-until value changed by user.");
9269
ippSetString(job->attrs, &job->reasons, 0, "none");
9270
}
9271
9272
/*
9273
* Release the job and return...
9274
*/
9275
9276
cupsdReleaseJob(job);
9277
9278
cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job,
9279
"Job released by user.");
9280
9281
cupsdLogJob(job, CUPSD_LOG_INFO, "Released by \"%s\".", username);
9282
9283
con->response->request.status.status_code = IPP_OK;
9284
9285
cupsdCheckJobs();
9286
}
9287
9288
9289
/*
9290
* 'renew_subscription()' - Renew an existing subscription...
9291
*/
9292
9293
static void
9294
renew_subscription(
9295
cupsd_client_t *con, /* I - Client connection */
9296
int sub_id) /* I - Subscription ID */
9297
{
9298
http_status_t status; /* Policy status */
9299
cupsd_subscription_t *sub; /* Subscription */
9300
ipp_attribute_t *lease; /* notify-lease-duration */
9301
9302
9303
cupsdLogMessage(CUPSD_LOG_DEBUG2,
9304
"renew_subscription(con=%p[%d], sub_id=%d)",
9305
con, con->number, sub_id);
9306
9307
/*
9308
* Is the subscription ID valid?
9309
*/
9310
9311
if ((sub = cupsdFindSubscription(sub_id)) == NULL)
9312
{
9313
/*
9314
* Bad subscription ID...
9315
*/
9316
9317
send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
9318
sub_id);
9319
return;
9320
}
9321
9322
if (sub->job)
9323
{
9324
/*
9325
* Job subscriptions cannot be renewed...
9326
*/
9327
9328
send_ipp_status(con, IPP_NOT_POSSIBLE,
9329
_("Job subscriptions cannot be renewed."));
9330
return;
9331
}
9332
9333
/*
9334
* Check policy...
9335
*/
9336
9337
if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
9338
DefaultPolicyPtr,
9339
con, sub->owner)) != HTTP_OK)
9340
{
9341
send_http_error(con, status, sub->dest);
9342
return;
9343
}
9344
9345
/*
9346
* Renew the subscription...
9347
*/
9348
9349
lease = ippFindAttribute(con->request, "notify-lease-duration",
9350
IPP_TAG_INTEGER);
9351
9352
sub->lease = lease ? lease->values[0].integer : DefaultLeaseDuration;
9353
9354
if (MaxLeaseDuration && (sub->lease == 0 || sub->lease > MaxLeaseDuration))
9355
{
9356
cupsdLogMessage(CUPSD_LOG_INFO,
9357
"renew_subscription: Limiting notify-lease-duration to "
9358
"%d seconds.",
9359
MaxLeaseDuration);
9360
sub->lease = MaxLeaseDuration;
9361
}
9362
9363
sub->expire = sub->lease ? time(NULL) + sub->lease : 0;
9364
9365
cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
9366
9367
con->response->request.status.status_code = IPP_OK;
9368
9369
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
9370
"notify-lease-duration", sub->lease);
9371
}
9372
9373
9374
/*
9375
* 'restart_job()' - Restart an old print job.
9376
*/
9377
9378
static void
9379
restart_job(cupsd_client_t *con, /* I - Client connection */
9380
ipp_attribute_t *uri) /* I - Job or Printer URI */
9381
{
9382
ipp_attribute_t *attr; /* Current attribute */
9383
int jobid; /* Job ID */
9384
cupsd_job_t *job; /* Job information */
9385
char scheme[HTTP_MAX_URI], /* Method portion of URI */
9386
username[HTTP_MAX_URI], /* Username portion of URI */
9387
host[HTTP_MAX_URI], /* Host portion of URI */
9388
resource[HTTP_MAX_URI]; /* Resource portion of URI */
9389
int port; /* Port portion of URI */
9390
9391
9392
cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", con,
9393
con->number, uri->values[0].string.text);
9394
9395
/*
9396
* See if we have a job URI or a printer URI...
9397
*/
9398
9399
if (!strcmp(uri->name, "printer-uri"))
9400
{
9401
/*
9402
* Got a printer URI; see if we also have a job-id attribute...
9403
*/
9404
9405
if ((attr = ippFindAttribute(con->request, "job-id",
9406
IPP_TAG_INTEGER)) == NULL)
9407
{
9408
send_ipp_status(con, IPP_BAD_REQUEST,
9409
_("Got a printer-uri attribute but no job-id."));
9410
return;
9411
}
9412
9413
jobid = attr->values[0].integer;
9414
}
9415
else
9416
{
9417
/*
9418
* Got a job URI; parse it to get the job ID...
9419
*/
9420
9421
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
9422
sizeof(scheme), username, sizeof(username), host,
9423
sizeof(host), &port, resource, sizeof(resource));
9424
9425
if (strncmp(resource, "/jobs/", 6))
9426
{
9427
/*
9428
* Not a valid URI!
9429
*/
9430
9431
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
9432
uri->values[0].string.text);
9433
return;
9434
}
9435
9436
jobid = atoi(resource + 6);
9437
}
9438
9439
/*
9440
* See if the job exists...
9441
*/
9442
9443
if ((job = cupsdFindJob(jobid)) == NULL)
9444
{
9445
/*
9446
* Nope - return a "not found" error...
9447
*/
9448
9449
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
9450
return;
9451
}
9452
9453
/*
9454
* See if job is in any of the "completed" states...
9455
*/
9456
9457
if (job->state_value <= IPP_JOB_PROCESSING)
9458
{
9459
/*
9460
* Nope - return a "not possible" error...
9461
*/
9462
9463
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not complete."),
9464
jobid);
9465
return;
9466
}
9467
9468
/*
9469
* See if we have retained the job files...
9470
*/
9471
9472
cupsdLoadJob(job);
9473
9474
if (!job->attrs || job->num_files == 0)
9475
{
9476
/*
9477
* Nope - return a "not possible" error...
9478
*/
9479
9480
send_ipp_status(con, IPP_NOT_POSSIBLE,
9481
_("Job #%d cannot be restarted - no files."), jobid);
9482
return;
9483
}
9484
9485
/*
9486
* See if the job is owned by the requesting user...
9487
*/
9488
9489
if (!validate_user(job, con, job->username, username, sizeof(username)))
9490
{
9491
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
9492
cupsdFindDest(job->dest));
9493
return;
9494
}
9495
9496
/*
9497
* See if the job-hold-until attribute is specified...
9498
*/
9499
9500
if ((attr = ippFindAttribute(con->request, "job-hold-until",
9501
IPP_TAG_KEYWORD)) == NULL)
9502
attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME);
9503
9504
if (attr && strcmp(attr->values[0].string.text, "no-hold"))
9505
{
9506
/*
9507
* Return the job to a held state...
9508
*/
9509
9510
cupsdLogJob(job, CUPSD_LOG_DEBUG,
9511
"Restarted by \"%s\" with job-hold-until=%s.",
9512
username, attr->values[0].string.text);
9513
cupsdSetJobHoldUntil(job, attr->values[0].string.text, 1);
9514
cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT,
9515
"Job restarted by user with job-hold-until=%s",
9516
attr->values[0].string.text);
9517
}
9518
else
9519
{
9520
/*
9521
* Restart the job...
9522
*/
9523
9524
cupsdRestartJob(job);
9525
cupsdCheckJobs();
9526
}
9527
9528
cupsdLogJob(job, CUPSD_LOG_INFO, "Restarted by \"%s\".", username);
9529
9530
con->response->request.status.status_code = IPP_OK;
9531
}
9532
9533
9534
/*
9535
* 'save_auth_info()' - Save authentication information for a job.
9536
*/
9537
9538
static void
9539
save_auth_info(
9540
cupsd_client_t *con, /* I - Client connection */
9541
cupsd_job_t *job, /* I - Job */
9542
ipp_attribute_t *auth_info) /* I - auth-info attribute, if any */
9543
{
9544
int i; /* Looping var */
9545
char filename[1024]; /* Job authentication filename */
9546
cups_file_t *fp; /* Job authentication file */
9547
char line[65536]; /* Line for file */
9548
cupsd_printer_t *dest; /* Destination printer/class */
9549
9550
9551
/*
9552
* This function saves the in-memory authentication information for
9553
* a job so that it can be used to authenticate with a remote host.
9554
* The information is stored in a file that is readable only by the
9555
* root user. The fields are Base-64 encoded, each on a separate line,
9556
* followed by random number (up to 1024) of newlines to limit the
9557
* amount of information that is exposed.
9558
*
9559
* Because of the potential for exposing of authentication information,
9560
* this functionality is only enabled when running cupsd as root.
9561
*
9562
* This caching only works for the Basic and BasicDigest authentication
9563
* types. Digest authentication cannot be cached this way, and in
9564
* the future Kerberos authentication may make all of this obsolete.
9565
*
9566
* Authentication information is saved whenever an authenticated
9567
* Print-Job, Create-Job, or CUPS-Authenticate-Job operation is
9568
* performed.
9569
*
9570
* This information is deleted after a job is completed or canceled,
9571
* so reprints may require subsequent re-authentication.
9572
*/
9573
9574
if (RunUser)
9575
return;
9576
9577
if ((dest = cupsdFindDest(job->dest)) == NULL)
9578
return;
9579
9580
/*
9581
* Create the authentication file and change permissions...
9582
*/
9583
9584
snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id);
9585
if ((fp = cupsFileOpen(filename, "w")) == NULL)
9586
{
9587
cupsdLogMessage(CUPSD_LOG_ERROR,
9588
"Unable to save authentication info to \"%s\" - %s",
9589
filename, strerror(errno));
9590
return;
9591
}
9592
9593
fchown(cupsFileNumber(fp), 0, 0);
9594
fchmod(cupsFileNumber(fp), 0400);
9595
9596
cupsFilePuts(fp, "CUPSD-AUTH-V3\n");
9597
9598
for (i = 0;
9599
i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
9600
i ++)
9601
cupsdClearString(job->auth_env + i);
9602
9603
if (auth_info && auth_info->num_values == dest->num_auth_info_required)
9604
{
9605
/*
9606
* Write 1 to 3 auth values...
9607
*/
9608
9609
for (i = 0;
9610
i < auth_info->num_values &&
9611
i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
9612
i ++)
9613
{
9614
if (strcmp(dest->auth_info_required[i], "negotiate"))
9615
{
9616
httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text, (int)strlen(auth_info->values[i].string.text));
9617
cupsFilePutConf(fp, dest->auth_info_required[i], line);
9618
}
9619
else
9620
cupsFilePutConf(fp, dest->auth_info_required[i],
9621
auth_info->values[i].string.text);
9622
9623
if (!strcmp(dest->auth_info_required[i], "username"))
9624
cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s",
9625
auth_info->values[i].string.text);
9626
else if (!strcmp(dest->auth_info_required[i], "domain"))
9627
cupsdSetStringf(job->auth_env + i, "AUTH_DOMAIN=%s",
9628
auth_info->values[i].string.text);
9629
else if (!strcmp(dest->auth_info_required[i], "password"))
9630
cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s",
9631
auth_info->values[i].string.text);
9632
else if (!strcmp(dest->auth_info_required[i], "negotiate"))
9633
cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s",
9634
auth_info->values[i].string.text);
9635
else
9636
i --;
9637
}
9638
}
9639
else if (auth_info && auth_info->num_values == 2 &&
9640
dest->num_auth_info_required == 1 &&
9641
!strcmp(dest->auth_info_required[0], "negotiate"))
9642
{
9643
/*
9644
* Allow fallback to username+password for Kerberized queues...
9645
*/
9646
9647
httpEncode64_2(line, sizeof(line), auth_info->values[0].string.text, (int)strlen(auth_info->values[0].string.text));
9648
cupsFilePutConf(fp, "username", line);
9649
9650
cupsdSetStringf(job->auth_env + 0, "AUTH_USERNAME=%s",
9651
auth_info->values[0].string.text);
9652
9653
httpEncode64_2(line, sizeof(line), auth_info->values[1].string.text, (int)strlen(auth_info->values[1].string.text));
9654
cupsFilePutConf(fp, "password", line);
9655
9656
cupsdSetStringf(job->auth_env + 1, "AUTH_PASSWORD=%s",
9657
auth_info->values[1].string.text);
9658
}
9659
else if (con->username[0])
9660
{
9661
/*
9662
* Write the authenticated username...
9663
*/
9664
9665
httpEncode64_2(line, sizeof(line), con->username, (int)strlen(con->username));
9666
cupsFilePutConf(fp, "username", line);
9667
9668
cupsdSetStringf(job->auth_env + 0, "AUTH_USERNAME=%s", con->username);
9669
9670
/*
9671
* Write the authenticated password...
9672
*/
9673
9674
httpEncode64_2(line, sizeof(line), con->password, (int)strlen(con->password));
9675
cupsFilePutConf(fp, "password", line);
9676
9677
cupsdSetStringf(job->auth_env + 1, "AUTH_PASSWORD=%s", con->password);
9678
}
9679
9680
#ifdef HAVE_GSSAPI
9681
if (con->gss_uid > 0)
9682
{
9683
cupsFilePrintf(fp, "uid %d\n", (int)con->gss_uid);
9684
cupsdSetStringf(&job->auth_uid, "AUTH_UID=%d", (int)con->gss_uid);
9685
}
9686
#endif /* HAVE_GSSAPI */
9687
9688
/*
9689
* Write a random number of newlines to the end of the file...
9690
*/
9691
9692
for (i = (CUPS_RAND() % 1024); i >= 0; i --)
9693
cupsFilePutChar(fp, '\n');
9694
9695
/*
9696
* Close the file and return...
9697
*/
9698
9699
cupsFileClose(fp);
9700
}
9701
9702
9703
/*
9704
* 'send_document()' - Send a file to a printer or class.
9705
*/
9706
9707
static void
9708
send_document(cupsd_client_t *con, /* I - Client connection */
9709
ipp_attribute_t *uri) /* I - Printer URI */
9710
{
9711
ipp_attribute_t *attr; /* Current attribute */
9712
ipp_attribute_t *format; /* Request's document-format attribute */
9713
ipp_attribute_t *jformat; /* Job's document-format attribute */
9714
const char *default_format;/* document-format-default value */
9715
int jobid; /* Job ID number */
9716
cupsd_job_t *job; /* Current job */
9717
char job_uri[HTTP_MAX_URI],
9718
/* Job URI */
9719
scheme[HTTP_MAX_URI],
9720
/* Method portion of URI */
9721
username[HTTP_MAX_URI],
9722
/* Username portion of URI */
9723
host[HTTP_MAX_URI],
9724
/* Host portion of URI */
9725
resource[HTTP_MAX_URI];
9726
/* Resource portion of URI */
9727
int port; /* Port portion of URI */
9728
mime_type_t *filetype; /* Type of file */
9729
char super[MIME_MAX_SUPER],
9730
/* Supertype of file */
9731
type[MIME_MAX_TYPE],
9732
/* Subtype of file */
9733
mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
9734
/* Textual name of mime type */
9735
char filename[1024]; /* Job filename */
9736
cupsd_printer_t *printer; /* Current printer */
9737
struct stat fileinfo; /* File information */
9738
int kbytes; /* Size of file */
9739
int compression; /* Type of compression */
9740
int start_job; /* Start the job? */
9741
9742
9743
cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", con,
9744
con->number, uri->values[0].string.text);
9745
9746
/*
9747
* See if we have a job URI or a printer URI...
9748
*/
9749
9750
if (!strcmp(uri->name, "printer-uri"))
9751
{
9752
/*
9753
* Got a printer URI; see if we also have a job-id attribute...
9754
*/
9755
9756
if ((attr = ippFindAttribute(con->request, "job-id",
9757
IPP_TAG_INTEGER)) == NULL)
9758
{
9759
send_ipp_status(con, IPP_BAD_REQUEST,
9760
_("Got a printer-uri attribute but no job-id."));
9761
return;
9762
}
9763
9764
jobid = attr->values[0].integer;
9765
}
9766
else
9767
{
9768
/*
9769
* Got a job URI; parse it to get the job ID...
9770
*/
9771
9772
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
9773
sizeof(scheme), username, sizeof(username), host,
9774
sizeof(host), &port, resource, sizeof(resource));
9775
9776
if (strncmp(resource, "/jobs/", 6))
9777
{
9778
/*
9779
* Not a valid URI!
9780
*/
9781
9782
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
9783
uri->values[0].string.text);
9784
return;
9785
}
9786
9787
jobid = atoi(resource + 6);
9788
}
9789
9790
/*
9791
* See if the job exists...
9792
*/
9793
9794
if ((job = cupsdFindJob(jobid)) == NULL)
9795
{
9796
/*
9797
* Nope - return a "not found" error...
9798
*/
9799
9800
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
9801
return;
9802
}
9803
9804
printer = cupsdFindDest(job->dest);
9805
9806
/*
9807
* See if the job is owned by the requesting user...
9808
*/
9809
9810
if (!validate_user(job, con, job->username, username, sizeof(username)))
9811
{
9812
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
9813
cupsdFindDest(job->dest));
9814
return;
9815
}
9816
9817
/*
9818
* OK, see if the client is sending the document compressed - CUPS
9819
* only supports "none" and "gzip".
9820
*/
9821
9822
compression = CUPS_FILE_NONE;
9823
9824
if ((attr = ippFindAttribute(con->request, "compression",
9825
IPP_TAG_KEYWORD)) != NULL)
9826
{
9827
if (strcmp(attr->values[0].string.text, "none")
9828
#ifdef HAVE_LIBZ
9829
&& strcmp(attr->values[0].string.text, "gzip")
9830
#endif /* HAVE_LIBZ */
9831
)
9832
{
9833
send_ipp_status(con, IPP_ATTRIBUTES, _("Unsupported compression \"%s\"."),
9834
attr->values[0].string.text);
9835
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
9836
"compression", NULL, attr->values[0].string.text);
9837
return;
9838
}
9839
9840
#ifdef HAVE_LIBZ
9841
if (!strcmp(attr->values[0].string.text, "gzip"))
9842
compression = CUPS_FILE_GZIP;
9843
#endif /* HAVE_LIBZ */
9844
}
9845
9846
/*
9847
* Do we have a file to print?
9848
*/
9849
9850
if ((attr = ippFindAttribute(con->request, "last-document",
9851
IPP_TAG_BOOLEAN)) == NULL)
9852
{
9853
send_ipp_status(con, IPP_BAD_REQUEST,
9854
_("Missing last-document attribute in request."));
9855
return;
9856
}
9857
9858
if (!con->filename)
9859
{
9860
/*
9861
* Check for an empty request with "last-document" set to true, which is
9862
* used to close an "open" job by RFC 2911, section 3.3.2.
9863
*/
9864
9865
if (job->num_files > 0 && attr->values[0].boolean)
9866
goto last_document;
9867
9868
send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request."));
9869
return;
9870
}
9871
9872
/*
9873
* Is it a format we support?
9874
*/
9875
9876
cupsdLoadJob(job);
9877
9878
if ((format = ippFindAttribute(con->request, "document-format",
9879
IPP_TAG_MIMETYPE)) != NULL)
9880
{
9881
/*
9882
* Grab format from client...
9883
*/
9884
9885
if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]",
9886
super, type) != 2)
9887
{
9888
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."),
9889
format->values[0].string.text);
9890
return;
9891
}
9892
9893
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, ippGetString(format, 0, NULL));
9894
}
9895
else if ((default_format = cupsGetOption("document-format",
9896
printer->num_options,
9897
printer->options)) != NULL)
9898
{
9899
/*
9900
* Use default document format...
9901
*/
9902
9903
if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2)
9904
{
9905
send_ipp_status(con, IPP_BAD_REQUEST,
9906
_("Bad document-format-default \"%s\"."), default_format);
9907
return;
9908
}
9909
}
9910
else
9911
{
9912
/*
9913
* No document format attribute? Auto-type it!
9914
*/
9915
9916
strlcpy(super, "application", sizeof(super));
9917
strlcpy(type, "octet-stream", sizeof(type));
9918
}
9919
9920
_cupsRWLockRead(&MimeDatabase->lock);
9921
9922
if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
9923
{
9924
/*
9925
* Auto-type the file...
9926
*/
9927
9928
ipp_attribute_t *doc_name; /* document-name attribute */
9929
9930
9931
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Auto-typing file...");
9932
9933
doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
9934
filetype = mimeFileType(MimeDatabase, con->filename,
9935
doc_name ? doc_name->values[0].string.text : NULL,
9936
&compression);
9937
9938
if (!filetype)
9939
filetype = mimeType(MimeDatabase, super, type);
9940
9941
if (filetype)
9942
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Request file type is %s/%s.",
9943
filetype->super, filetype->type);
9944
9945
snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, filetype->type);
9946
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, mimetype);
9947
}
9948
else
9949
filetype = mimeType(MimeDatabase, super, type);
9950
9951
_cupsRWUnlock(&MimeDatabase->lock);
9952
9953
if (filetype)
9954
{
9955
/*
9956
* Replace the document-format attribute value with the auto-typed or
9957
* default one.
9958
*/
9959
9960
snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
9961
filetype->type);
9962
9963
if ((jformat = ippFindAttribute(job->attrs, "document-format",
9964
IPP_TAG_MIMETYPE)) != NULL)
9965
ippSetString(job->attrs, &jformat, 0, mimetype);
9966
else
9967
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
9968
"document-format", NULL, mimetype);
9969
}
9970
else if (!filetype)
9971
{
9972
send_ipp_status(con, IPP_DOCUMENT_FORMAT,
9973
_("Unsupported document-format \"%s/%s\"."), super, type);
9974
cupsdLogMessage(CUPSD_LOG_INFO,
9975
"Hint: Do you have the raw file printing rules enabled?");
9976
9977
if (format)
9978
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
9979
"document-format", NULL, format->values[0].string.text);
9980
9981
return;
9982
}
9983
9984
if (printer->filetypes && !cupsArrayFind(printer->filetypes, filetype))
9985
{
9986
snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
9987
filetype->type);
9988
9989
send_ipp_status(con, IPP_DOCUMENT_FORMAT,
9990
_("Unsupported document-format \"%s\"."), mimetype);
9991
9992
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
9993
"document-format", NULL, mimetype);
9994
9995
return;
9996
}
9997
9998
/*
9999
* Add the file to the job...
10000
*/
10001
10002
if (add_file(con, job, filetype, compression))
10003
return;
10004
10005
if ((attr = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME)) != NULL)
10006
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "document-name-supplied", NULL, ippGetString(attr, 0, NULL));
10007
10008
if (stat(con->filename, &fileinfo))
10009
kbytes = 0;
10010
else
10011
kbytes = (fileinfo.st_size + 1023) / 1024;
10012
10013
cupsdUpdateQuota(printer, job->username, 0, kbytes);
10014
10015
job->koctets += kbytes;
10016
10017
if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
10018
attr->values[0].integer += kbytes;
10019
10020
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, job->num_files);
10021
if (rename(con->filename, filename))
10022
{
10023
cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to rename job document file \"%s\": %s", filename, strerror(errno));
10024
10025
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to rename job document file."));
10026
return;
10027
}
10028
10029
cupsdClearString(&con->filename);
10030
10031
cupsdLogJob(job, CUPSD_LOG_INFO, "File of type %s/%s queued by \"%s\".",
10032
filetype->super, filetype->type, job->username);
10033
10034
/*
10035
* Start the job if this is the last document...
10036
*/
10037
10038
last_document:
10039
10040
if ((attr = ippFindAttribute(con->request, "last-document",
10041
IPP_TAG_BOOLEAN)) != NULL &&
10042
attr->values[0].boolean)
10043
{
10044
/*
10045
* See if we need to add the ending sheet...
10046
*/
10047
10048
if (cupsdTimeoutJob(job))
10049
return;
10050
10051
if (job->state_value == IPP_JOB_STOPPED)
10052
{
10053
job->state->values[0].integer = IPP_JOB_PENDING;
10054
job->state_value = IPP_JOB_PENDING;
10055
10056
ippSetString(job->attrs, &job->reasons, 0, "none");
10057
}
10058
else if (job->state_value == IPP_JOB_HELD)
10059
{
10060
if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
10061
IPP_TAG_KEYWORD)) == NULL)
10062
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
10063
10064
if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
10065
{
10066
job->state->values[0].integer = IPP_JOB_PENDING;
10067
job->state_value = IPP_JOB_PENDING;
10068
10069
ippSetString(job->attrs, &job->reasons, 0, "none");
10070
}
10071
else
10072
ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified");
10073
}
10074
10075
job->dirty = 1;
10076
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
10077
10078
start_job = 1;
10079
}
10080
else
10081
{
10082
if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
10083
IPP_TAG_KEYWORD)) == NULL)
10084
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
10085
10086
if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
10087
{
10088
job->state->values[0].integer = IPP_JOB_HELD;
10089
job->state_value = IPP_JOB_HELD;
10090
job->hold_until = time(NULL) + MultipleOperationTimeout;
10091
10092
ippSetString(job->attrs, &job->reasons, 0, "job-incoming");
10093
10094
job->dirty = 1;
10095
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
10096
}
10097
10098
start_job = 0;
10099
}
10100
10101
/*
10102
* Fill in the response info...
10103
*/
10104
10105
httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, con->clientname, con->clientport, "/jobs/%d", jobid);
10106
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri);
10107
10108
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", jobid);
10109
10110
ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
10111
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, job->reasons->values[0].string.text);
10112
10113
con->response->request.status.status_code = IPP_OK;
10114
10115
/*
10116
* Start the job if necessary...
10117
*/
10118
10119
if (start_job)
10120
cupsdCheckJobs();
10121
}
10122
10123
10124
/*
10125
* 'send_http_error()' - Send a HTTP error back to the IPP client.
10126
*/
10127
10128
static void
10129
send_http_error(
10130
cupsd_client_t *con, /* I - Client connection */
10131
http_status_t status, /* I - HTTP status code */
10132
cupsd_printer_t *printer) /* I - Printer, if any */
10133
{
10134
ipp_attribute_t *uri; /* Request URI, if any */
10135
10136
10137
if ((uri = ippFindAttribute(con->request, "printer-uri",
10138
IPP_TAG_URI)) == NULL)
10139
uri = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI);
10140
10141
cupsdLogMessage(status == HTTP_FORBIDDEN ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG,
10142
"[Client %d] Returning HTTP %s for %s (%s) from %s",
10143
con->number, httpStatus(status),
10144
con->request ?
10145
ippOpString(con->request->request.op.operation_id) :
10146
"no operation-id",
10147
uri ? uri->values[0].string.text : "no URI",
10148
con->http->hostname);
10149
10150
if (printer)
10151
{
10152
int auth_type; /* Type of authentication required */
10153
10154
10155
auth_type = CUPSD_AUTH_NONE;
10156
10157
if (status == HTTP_UNAUTHORIZED &&
10158
printer->num_auth_info_required > 0 &&
10159
!strcmp(printer->auth_info_required[0], "negotiate") &&
10160
con->request &&
10161
(con->request->request.op.operation_id == IPP_PRINT_JOB ||
10162
con->request->request.op.operation_id == IPP_CREATE_JOB ||
10163
con->request->request.op.operation_id == CUPS_AUTHENTICATE_JOB))
10164
{
10165
/*
10166
* Creating and authenticating jobs requires Kerberos...
10167
*/
10168
10169
auth_type = CUPSD_AUTH_NEGOTIATE;
10170
}
10171
else
10172
{
10173
/*
10174
* Use policy/location-defined authentication requirements...
10175
*/
10176
10177
char resource[HTTP_MAX_URI]; /* Resource portion of URI */
10178
cupsd_location_t *auth; /* Pointer to authentication element */
10179
10180
10181
if (printer->type & CUPS_PRINTER_CLASS)
10182
snprintf(resource, sizeof(resource), "/classes/%s", printer->name);
10183
else
10184
snprintf(resource, sizeof(resource), "/printers/%s", printer->name);
10185
10186
if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
10187
auth->type == CUPSD_AUTH_NONE)
10188
auth = cupsdFindPolicyOp(printer->op_policy_ptr,
10189
con->request ?
10190
con->request->request.op.operation_id :
10191
IPP_PRINT_JOB);
10192
10193
if (auth)
10194
{
10195
if (auth->type == CUPSD_AUTH_DEFAULT)
10196
auth_type = cupsdDefaultAuthType();
10197
else
10198
auth_type = auth->type;
10199
}
10200
}
10201
10202
cupsdSendError(con, status, auth_type);
10203
}
10204
else
10205
cupsdSendError(con, status, CUPSD_AUTH_NONE);
10206
10207
ippDelete(con->response);
10208
con->response = NULL;
10209
10210
return;
10211
}
10212
10213
10214
/*
10215
* 'send_ipp_status()' - Send a status back to the IPP client.
10216
*/
10217
10218
static void
10219
send_ipp_status(cupsd_client_t *con, /* I - Client connection */
10220
ipp_status_t status, /* I - IPP status code */
10221
const char *message,/* I - Status message */
10222
...) /* I - Additional args as needed */
10223
{
10224
va_list ap; /* Pointer to additional args */
10225
char formatted[1024]; /* Formatted error message */
10226
10227
10228
va_start(ap, message);
10229
vsnprintf(formatted, sizeof(formatted),
10230
_cupsLangString(con->language, message), ap);
10231
va_end(ap);
10232
10233
cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s: %s",
10234
ippOpString(con->request->request.op.operation_id),
10235
ippErrorString(status), formatted);
10236
10237
con->response->request.status.status_code = status;
10238
10239
if (ippFindAttribute(con->response, "attributes-charset",
10240
IPP_TAG_ZERO) == NULL)
10241
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
10242
"attributes-charset", NULL, "utf-8");
10243
10244
if (ippFindAttribute(con->response, "attributes-natural-language",
10245
IPP_TAG_ZERO) == NULL)
10246
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
10247
"attributes-natural-language", NULL, DefaultLanguage);
10248
10249
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
10250
"status-message", NULL, formatted);
10251
}
10252
10253
10254
/*
10255
* 'set_default()' - Set the default destination...
10256
*/
10257
10258
static void
10259
set_default(cupsd_client_t *con, /* I - Client connection */
10260
ipp_attribute_t *uri) /* I - Printer URI */
10261
{
10262
http_status_t status; /* Policy status */
10263
cups_ptype_t dtype; /* Destination type (printer/class) */
10264
cupsd_printer_t *printer, /* Printer */
10265
*oldprinter; /* Old default printer */
10266
10267
10268
cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", con,
10269
con->number, uri->values[0].string.text);
10270
10271
/*
10272
* Is the destination valid?
10273
*/
10274
10275
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
10276
{
10277
/*
10278
* Bad URI...
10279
*/
10280
10281
send_ipp_status(con, IPP_NOT_FOUND,
10282
_("The printer or class does not exist."));
10283
return;
10284
}
10285
10286
/*
10287
* Check policy...
10288
*/
10289
10290
if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
10291
{
10292
send_http_error(con, status, NULL);
10293
return;
10294
}
10295
10296
/*
10297
* Set it as the default...
10298
*/
10299
10300
oldprinter = DefaultPrinter;
10301
DefaultPrinter = printer;
10302
10303
if (oldprinter)
10304
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, oldprinter, NULL,
10305
"%s is no longer the default printer.", oldprinter->name);
10306
10307
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
10308
"%s is now the default printer.", printer->name);
10309
10310
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS | CUPSD_DIRTY_CLASSES |
10311
CUPSD_DIRTY_PRINTCAP);
10312
10313
cupsdLogMessage(CUPSD_LOG_INFO,
10314
"Default destination set to \"%s\" by \"%s\".",
10315
printer->name, get_username(con));
10316
10317
/*
10318
* Everything was ok, so return OK status...
10319
*/
10320
10321
con->response->request.status.status_code = IPP_OK;
10322
}
10323
10324
10325
/*
10326
* 'set_job_attrs()' - Set job attributes.
10327
*/
10328
10329
static void
10330
set_job_attrs(cupsd_client_t *con, /* I - Client connection */
10331
ipp_attribute_t *uri) /* I - Job URI */
10332
{
10333
ipp_attribute_t *attr, /* Current attribute */
10334
*attr2; /* Job attribute */
10335
int jobid; /* Job ID */
10336
cupsd_job_t *job; /* Current job */
10337
char scheme[HTTP_MAX_URI],
10338
/* Method portion of URI */
10339
username[HTTP_MAX_URI],
10340
/* Username portion of URI */
10341
host[HTTP_MAX_URI],
10342
/* Host portion of URI */
10343
resource[HTTP_MAX_URI];
10344
/* Resource portion of URI */
10345
int port; /* Port portion of URI */
10346
int event; /* Events? */
10347
int check_jobs; /* Check jobs? */
10348
10349
10350
cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con,
10351
con->number, uri->values[0].string.text);
10352
10353
/*
10354
* Start with "everything is OK" status...
10355
*/
10356
10357
con->response->request.status.status_code = IPP_OK;
10358
10359
/*
10360
* See if we have a job URI or a printer URI...
10361
*/
10362
10363
if (!strcmp(uri->name, "printer-uri"))
10364
{
10365
/*
10366
* Got a printer URI; see if we also have a job-id attribute...
10367
*/
10368
10369
if ((attr = ippFindAttribute(con->request, "job-id",
10370
IPP_TAG_INTEGER)) == NULL)
10371
{
10372
send_ipp_status(con, IPP_BAD_REQUEST,
10373
_("Got a printer-uri attribute but no job-id."));
10374
return;
10375
}
10376
10377
jobid = attr->values[0].integer;
10378
}
10379
else
10380
{
10381
/*
10382
* Got a job URI; parse it to get the job ID...
10383
*/
10384
10385
httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
10386
sizeof(scheme), username, sizeof(username), host,
10387
sizeof(host), &port, resource, sizeof(resource));
10388
10389
if (strncmp(resource, "/jobs/", 6))
10390
{
10391
/*
10392
* Not a valid URI!
10393
*/
10394
10395
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
10396
uri->values[0].string.text);
10397
return;
10398
}
10399
10400
jobid = atoi(resource + 6);
10401
}
10402
10403
/*
10404
* See if the job exists...
10405
*/
10406
10407
if ((job = cupsdFindJob(jobid)) == NULL)
10408
{
10409
/*
10410
* Nope - return a "not found" error...
10411
*/
10412
10413
send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
10414
return;
10415
}
10416
10417
/*
10418
* See if the job has been completed...
10419
*/
10420
10421
if (job->state_value > IPP_JOB_STOPPED)
10422
{
10423
/*
10424
* Return a "not-possible" error...
10425
*/
10426
10427
send_ipp_status(con, IPP_NOT_POSSIBLE,
10428
_("Job #%d is finished and cannot be altered."), jobid);
10429
return;
10430
}
10431
10432
/*
10433
* See if the job is owned by the requesting user...
10434
*/
10435
10436
if (!validate_user(job, con, job->username, username, sizeof(username)))
10437
{
10438
send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
10439
cupsdFindDest(job->dest));
10440
return;
10441
}
10442
10443
/*
10444
* See what the user wants to change.
10445
*/
10446
10447
cupsdLoadJob(job);
10448
10449
check_jobs = 0;
10450
event = 0;
10451
10452
for (attr = con->request->attrs; attr; attr = attr->next)
10453
{
10454
if (attr->group_tag != IPP_TAG_JOB || !attr->name)
10455
continue;
10456
10457
if (!strcmp(attr->name, "attributes-charset") ||
10458
!strcmp(attr->name, "attributes-natural-language") ||
10459
!strncmp(attr->name, "date-time-at-", 13) ||
10460
!strncmp(attr->name, "document-compression", 20) ||
10461
!strncmp(attr->name, "document-format", 15) ||
10462
!strcmp(attr->name, "job-detailed-status-messages") ||
10463
!strcmp(attr->name, "job-document-access-errors") ||
10464
!strcmp(attr->name, "job-id") ||
10465
!strcmp(attr->name, "job-impressions-completed") ||
10466
!strcmp(attr->name, "job-k-octets-completed") ||
10467
!strcmp(attr->name, "job-media-sheets-completed") ||
10468
!strcmp(attr->name, "job-originating-host-name") ||
10469
!strcmp(attr->name, "job-originating-user-name") ||
10470
!strcmp(attr->name, "job-pages-completed") ||
10471
!strcmp(attr->name, "job-printer-up-time") ||
10472
!strcmp(attr->name, "job-printer-uri") ||
10473
!strcmp(attr->name, "job-sheets") ||
10474
!strcmp(attr->name, "job-state-message") ||
10475
!strcmp(attr->name, "job-state-reasons") ||
10476
!strcmp(attr->name, "job-uri") ||
10477
!strcmp(attr->name, "number-of-documents") ||
10478
!strcmp(attr->name, "number-of-intervening-jobs") ||
10479
!strcmp(attr->name, "output-device-assigned") ||
10480
!strncmp(attr->name, "time-at-", 8))
10481
{
10482
/*
10483
* Read-only attrs!
10484
*/
10485
10486
send_ipp_status(con, IPP_ATTRIBUTES_NOT_SETTABLE,
10487
_("%s cannot be changed."), attr->name);
10488
10489
attr2 = ippCopyAttribute(con->response, attr, 0);
10490
ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP);
10491
continue;
10492
}
10493
10494
if (!ippValidateAttribute(attr))
10495
{
10496
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad '%s' value."), attr->name);
10497
ippCopyAttribute(con->response, attr, 0);
10498
return;
10499
}
10500
10501
if (!strcmp(attr->name, "job-hold-until"))
10502
{
10503
const char *when = ippGetString(attr, 0, NULL);
10504
/* job-hold-until value */
10505
10506
if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1)
10507
{
10508
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value."));
10509
ippCopyAttribute(con->response, attr, 0);
10510
return;
10511
}
10512
10513
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", when);
10514
cupsdSetJobHoldUntil(job, when, 0);
10515
10516
if (!strcmp(when, "no-hold"))
10517
{
10518
cupsdReleaseJob(job);
10519
check_jobs = 1;
10520
}
10521
else
10522
cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".", username);
10523
10524
event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
10525
}
10526
else if (!strcmp(attr->name, "job-priority"))
10527
{
10528
/*
10529
* Change the job priority...
10530
*/
10531
10532
if (attr->value_tag != IPP_TAG_INTEGER)
10533
{
10534
send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value."));
10535
10536
attr2 = ippCopyAttribute(con->response, attr, 0);
10537
ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP);
10538
}
10539
else if (job->state_value >= IPP_JOB_PROCESSING)
10540
{
10541
send_ipp_status(con, IPP_NOT_POSSIBLE,
10542
_("Job is completed and cannot be changed."));
10543
return;
10544
}
10545
else if (con->response->request.status.status_code == IPP_OK)
10546
{
10547
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-priority to %d",
10548
attr->values[0].integer);
10549
cupsdSetJobPriority(job, attr->values[0].integer);
10550
10551
check_jobs = 1;
10552
event |= CUPSD_EVENT_JOB_CONFIG_CHANGED |
10553
CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED;
10554
}
10555
}
10556
else if (!strcmp(attr->name, "job-state"))
10557
{
10558
/*
10559
* Change the job state...
10560
*/
10561
10562
if (attr->value_tag != IPP_TAG_ENUM)
10563
{
10564
send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value."));
10565
10566
attr2 = ippCopyAttribute(con->response, attr, 0);
10567
ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP);
10568
}
10569
else
10570
{
10571
switch (attr->values[0].integer)
10572
{
10573
case IPP_JOB_PENDING :
10574
case IPP_JOB_HELD :
10575
if (job->state_value > IPP_JOB_HELD)
10576
{
10577
send_ipp_status(con, IPP_NOT_POSSIBLE,
10578
_("Job state cannot be changed."));
10579
return;
10580
}
10581
else if (con->response->request.status.status_code == IPP_OK)
10582
{
10583
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
10584
attr->values[0].integer);
10585
cupsdSetJobState(job, (ipp_jstate_t)attr->values[0].integer, CUPSD_JOB_DEFAULT, "Job state changed by \"%s\"", username);
10586
check_jobs = 1;
10587
}
10588
break;
10589
10590
case IPP_JOB_PROCESSING :
10591
case IPP_JOB_STOPPED :
10592
if (job->state_value != (ipp_jstate_t)attr->values[0].integer)
10593
{
10594
send_ipp_status(con, IPP_NOT_POSSIBLE,
10595
_("Job state cannot be changed."));
10596
return;
10597
}
10598
break;
10599
10600
case IPP_JOB_CANCELED :
10601
case IPP_JOB_ABORTED :
10602
case IPP_JOB_COMPLETED :
10603
if (job->state_value > IPP_JOB_PROCESSING)
10604
{
10605
send_ipp_status(con, IPP_NOT_POSSIBLE,
10606
_("Job state cannot be changed."));
10607
return;
10608
}
10609
else if (con->response->request.status.status_code == IPP_OK)
10610
{
10611
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
10612
attr->values[0].integer);
10613
cupsdSetJobState(job, (ipp_jstate_t)attr->values[0].integer,
10614
CUPSD_JOB_DEFAULT,
10615
"Job state changed by \"%s\"", username);
10616
check_jobs = 1;
10617
}
10618
break;
10619
}
10620
}
10621
}
10622
else if (con->response->request.status.status_code != IPP_OK)
10623
continue;
10624
else if ((attr2 = ippFindAttribute(job->attrs, attr->name,
10625
IPP_TAG_ZERO)) != NULL)
10626
{
10627
/*
10628
* Some other value; first free the old value...
10629
*/
10630
10631
if (job->attrs->prev)
10632
job->attrs->prev->next = attr2->next;
10633
else
10634
job->attrs->attrs = attr2->next;
10635
10636
if (job->attrs->last == attr2)
10637
job->attrs->last = job->attrs->prev;
10638
10639
ippDeleteAttribute(NULL, attr2);
10640
10641
/*
10642
* Then copy the attribute...
10643
*/
10644
10645
ippCopyAttribute(job->attrs, attr, 0);
10646
}
10647
else if (attr->value_tag == IPP_TAG_DELETEATTR)
10648
{
10649
/*
10650
* Delete the attribute...
10651
*/
10652
10653
if ((attr2 = ippFindAttribute(job->attrs, attr->name,
10654
IPP_TAG_ZERO)) != NULL)
10655
{
10656
if (job->attrs->prev)
10657
job->attrs->prev->next = attr2->next;
10658
else
10659
job->attrs->attrs = attr2->next;
10660
10661
if (attr2 == job->attrs->last)
10662
job->attrs->last = job->attrs->prev;
10663
10664
ippDeleteAttribute(NULL, attr2);
10665
10666
event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
10667
}
10668
}
10669
else
10670
{
10671
/*
10672
* Add new option by copying it...
10673
*/
10674
10675
ippCopyAttribute(job->attrs, attr, 0);
10676
10677
event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
10678
}
10679
}
10680
10681
/*
10682
* Save the job...
10683
*/
10684
10685
job->dirty = 1;
10686
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
10687
10688
/*
10689
* Send events as needed...
10690
*/
10691
10692
if (event & CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED)
10693
cupsdAddEvent(CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED,
10694
cupsdFindDest(job->dest), job,
10695
"Job priority changed by user.");
10696
10697
if (event & CUPSD_EVENT_JOB_STATE)
10698
cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job,
10699
job->state_value == IPP_JOB_HELD ?
10700
"Job held by user." : "Job restarted by user.");
10701
10702
if (event & CUPSD_EVENT_JOB_CONFIG_CHANGED)
10703
cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
10704
"Job options changed by user.");
10705
10706
/*
10707
* Start jobs if possible...
10708
*/
10709
10710
if (check_jobs)
10711
cupsdCheckJobs();
10712
}
10713
10714
10715
/*
10716
* 'set_printer_attrs()' - Set printer attributes.
10717
*/
10718
10719
static void
10720
set_printer_attrs(cupsd_client_t *con, /* I - Client connection */
10721
ipp_attribute_t *uri) /* I - Printer */
10722
{
10723
http_status_t status; /* Policy status */
10724
cups_ptype_t dtype; /* Destination type (printer/class) */
10725
cupsd_printer_t *printer; /* Printer/class */
10726
ipp_attribute_t *attr; /* Printer attribute */
10727
int changed = 0; /* Was anything changed? */
10728
10729
10730
cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", con,
10731
con->number, uri->values[0].string.text);
10732
10733
/*
10734
* Is the destination valid?
10735
*/
10736
10737
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
10738
{
10739
/*
10740
* Bad URI...
10741
*/
10742
10743
send_ipp_status(con, IPP_NOT_FOUND,
10744
_("The printer or class does not exist."));
10745
return;
10746
}
10747
10748
/*
10749
* Check policy...
10750
*/
10751
10752
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
10753
{
10754
send_http_error(con, status, printer);
10755
return;
10756
}
10757
10758
/*
10759
* Return a list of attributes that can be set via Set-Printer-Attributes.
10760
*/
10761
10762
if ((attr = ippFindAttribute(con->request, "printer-location",
10763
IPP_TAG_TEXT)) != NULL)
10764
{
10765
cupsdSetString(&printer->location, attr->values[0].string.text);
10766
changed = 1;
10767
}
10768
10769
if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4))
10770
{
10771
cupsdSetString(&printer->geo_location, attr->values[0].string.text);
10772
changed = 1;
10773
}
10774
10775
if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL)
10776
{
10777
cupsdSetString(&printer->organization, attr->values[0].string.text);
10778
changed = 1;
10779
}
10780
10781
if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL)
10782
{
10783
cupsdSetString(&printer->organizational_unit, attr->values[0].string.text);
10784
changed = 1;
10785
}
10786
10787
if ((attr = ippFindAttribute(con->request, "printer-info",
10788
IPP_TAG_TEXT)) != NULL)
10789
{
10790
cupsdSetString(&printer->info, attr->values[0].string.text);
10791
changed = 1;
10792
}
10793
10794
/*
10795
* Update the printer attributes and return...
10796
*/
10797
10798
if (changed)
10799
{
10800
printer->config_time = time(NULL);
10801
10802
cupsdSetPrinterAttrs(printer);
10803
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
10804
10805
cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL,
10806
"Printer \"%s\" description or location changed by \"%s\".",
10807
printer->name, get_username(con));
10808
10809
cupsdLogMessage(CUPSD_LOG_INFO,
10810
"Printer \"%s\" description or location changed by \"%s\".",
10811
printer->name, get_username(con));
10812
}
10813
10814
con->response->request.status.status_code = IPP_OK;
10815
}
10816
10817
10818
/*
10819
* 'set_printer_defaults()' - Set printer default options from a request.
10820
*/
10821
10822
static int /* O - 1 on success, 0 on failure */
10823
set_printer_defaults(
10824
cupsd_client_t *con, /* I - Client connection */
10825
cupsd_printer_t *printer) /* I - Printer */
10826
{
10827
int i; /* Looping var */
10828
ipp_attribute_t *attr; /* Current attribute */
10829
size_t namelen; /* Length of attribute name */
10830
char name[256], /* New attribute name */
10831
value[256]; /* String version of integer attrs */
10832
10833
10834
for (attr = con->request->attrs; attr; attr = attr->next)
10835
{
10836
/*
10837
* Skip non-printer attributes...
10838
*/
10839
10840
if (attr->group_tag != IPP_TAG_PRINTER || !attr->name)
10841
continue;
10842
10843
cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_defaults: %s", attr->name);
10844
10845
if (!strcmp(attr->name, "job-sheets-default"))
10846
{
10847
/*
10848
* Only allow keywords and names...
10849
*/
10850
10851
if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
10852
continue;
10853
10854
/*
10855
* Only allow job-sheets-default to be set when running without a
10856
* system high classification level...
10857
*/
10858
10859
if (Classification)
10860
continue;
10861
10862
cupsdSetString(&printer->job_sheets[0], attr->values[0].string.text);
10863
10864
if (attr->num_values > 1)
10865
cupsdSetString(&printer->job_sheets[1], attr->values[1].string.text);
10866
else
10867
cupsdSetString(&printer->job_sheets[1], "none");
10868
}
10869
else if (!strcmp(attr->name, "requesting-user-name-allowed"))
10870
{
10871
cupsdFreeStrings(&(printer->users));
10872
10873
printer->deny_users = 0;
10874
10875
if (attr->value_tag == IPP_TAG_NAME &&
10876
(attr->num_values > 1 ||
10877
strcmp(attr->values[0].string.text, "all")))
10878
{
10879
for (i = 0; i < attr->num_values; i ++)
10880
cupsdAddString(&(printer->users), attr->values[i].string.text);
10881
}
10882
}
10883
else if (!strcmp(attr->name, "requesting-user-name-denied"))
10884
{
10885
cupsdFreeStrings(&(printer->users));
10886
10887
printer->deny_users = 1;
10888
10889
if (attr->value_tag == IPP_TAG_NAME &&
10890
(attr->num_values > 1 ||
10891
strcmp(attr->values[0].string.text, "none")))
10892
{
10893
for (i = 0; i < attr->num_values; i ++)
10894
cupsdAddString(&(printer->users), attr->values[i].string.text);
10895
}
10896
}
10897
else if (!strcmp(attr->name, "job-quota-period"))
10898
{
10899
if (attr->value_tag != IPP_TAG_INTEGER)
10900
continue;
10901
10902
cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-quota-period to %d...",
10903
attr->values[0].integer);
10904
cupsdFreeQuotas(printer);
10905
10906
printer->quota_period = attr->values[0].integer;
10907
}
10908
else if (!strcmp(attr->name, "job-k-limit"))
10909
{
10910
if (attr->value_tag != IPP_TAG_INTEGER)
10911
continue;
10912
10913
cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-k-limit to %d...",
10914
attr->values[0].integer);
10915
cupsdFreeQuotas(printer);
10916
10917
printer->k_limit = attr->values[0].integer;
10918
}
10919
else if (!strcmp(attr->name, "job-page-limit"))
10920
{
10921
if (attr->value_tag != IPP_TAG_INTEGER)
10922
continue;
10923
10924
cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-page-limit to %d...",
10925
attr->values[0].integer);
10926
cupsdFreeQuotas(printer);
10927
10928
printer->page_limit = attr->values[0].integer;
10929
}
10930
else if (!strcmp(attr->name, "printer-op-policy"))
10931
{
10932
cupsd_policy_t *p; /* Policy */
10933
10934
10935
if (attr->value_tag != IPP_TAG_NAME)
10936
continue;
10937
10938
if ((p = cupsdFindPolicy(attr->values[0].string.text)) != NULL)
10939
{
10940
cupsdLogMessage(CUPSD_LOG_DEBUG,
10941
"Setting printer-op-policy to \"%s\"...",
10942
attr->values[0].string.text);
10943
cupsdSetString(&printer->op_policy, attr->values[0].string.text);
10944
printer->op_policy_ptr = p;
10945
}
10946
else
10947
{
10948
send_ipp_status(con, IPP_NOT_POSSIBLE,
10949
_("Unknown printer-op-policy \"%s\"."),
10950
attr->values[0].string.text);
10951
return (0);
10952
}
10953
}
10954
else if (!strcmp(attr->name, "printer-error-policy"))
10955
{
10956
if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
10957
continue;
10958
10959
if (strcmp(attr->values[0].string.text, "retry-current-job") &&
10960
((printer->type & CUPS_PRINTER_CLASS) ||
10961
(strcmp(attr->values[0].string.text, "abort-job") &&
10962
strcmp(attr->values[0].string.text, "retry-job") &&
10963
strcmp(attr->values[0].string.text, "stop-printer"))))
10964
{
10965
send_ipp_status(con, IPP_NOT_POSSIBLE,
10966
_("Unknown printer-error-policy \"%s\"."),
10967
attr->values[0].string.text);
10968
return (0);
10969
}
10970
10971
cupsdLogMessage(CUPSD_LOG_DEBUG,
10972
"Setting printer-error-policy to \"%s\"...",
10973
attr->values[0].string.text);
10974
cupsdSetString(&printer->error_policy, attr->values[0].string.text);
10975
}
10976
10977
/*
10978
* Skip any other non-default attributes...
10979
*/
10980
10981
namelen = strlen(attr->name);
10982
if (namelen < 9 || strcmp(attr->name + namelen - 8, "-default") ||
10983
namelen > (sizeof(name) - 1) || attr->num_values != 1)
10984
continue;
10985
10986
/*
10987
* OK, anything else must be a user-defined default...
10988
*/
10989
10990
strlcpy(name, attr->name, sizeof(name));
10991
name[namelen - 8] = '\0'; /* Strip "-default" */
10992
10993
switch (attr->value_tag)
10994
{
10995
case IPP_TAG_DELETEATTR :
10996
printer->num_options = cupsRemoveOption(name,
10997
printer->num_options,
10998
&(printer->options));
10999
cupsdLogMessage(CUPSD_LOG_DEBUG,
11000
"Deleting %s", attr->name);
11001
break;
11002
11003
case IPP_TAG_NAME :
11004
case IPP_TAG_TEXT :
11005
case IPP_TAG_KEYWORD :
11006
case IPP_TAG_URI :
11007
printer->num_options = cupsAddOption(name,
11008
attr->values[0].string.text,
11009
printer->num_options,
11010
&(printer->options));
11011
cupsdLogMessage(CUPSD_LOG_DEBUG,
11012
"Setting %s to \"%s\"...", attr->name,
11013
attr->values[0].string.text);
11014
break;
11015
11016
case IPP_TAG_BOOLEAN :
11017
printer->num_options = cupsAddOption(name,
11018
attr->values[0].boolean ?
11019
"true" : "false",
11020
printer->num_options,
11021
&(printer->options));
11022
cupsdLogMessage(CUPSD_LOG_DEBUG,
11023
"Setting %s to %s...", attr->name,
11024
attr->values[0].boolean ? "true" : "false");
11025
break;
11026
11027
case IPP_TAG_INTEGER :
11028
case IPP_TAG_ENUM :
11029
printer->num_options = cupsAddIntegerOption(name, attr->values[0].integer, printer->num_options, &(printer->options));
11030
cupsdLogMessage(CUPSD_LOG_DEBUG,
11031
"Setting %s to %s...", attr->name, value);
11032
break;
11033
11034
case IPP_TAG_RANGE :
11035
snprintf(value, sizeof(value), "%d-%d", attr->values[0].range.lower, attr->values[0].range.upper);
11036
printer->num_options = cupsAddOption(name, value,
11037
printer->num_options,
11038
&(printer->options));
11039
cupsdLogMessage(CUPSD_LOG_DEBUG,
11040
"Setting %s to %s...", attr->name, value);
11041
break;
11042
11043
case IPP_TAG_RESOLUTION :
11044
snprintf(value, sizeof(value), "%dx%d%s", attr->values[0].resolution.xres, attr->values[0].resolution.yres, attr->values[0].resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
11045
printer->num_options = cupsAddOption(name, value,
11046
printer->num_options,
11047
&(printer->options));
11048
cupsdLogMessage(CUPSD_LOG_DEBUG,
11049
"Setting %s to %s...", attr->name, value);
11050
break;
11051
11052
default :
11053
/* Do nothing for other values */
11054
break;
11055
}
11056
}
11057
11058
return (1);
11059
}
11060
11061
11062
/*
11063
* 'start_printer()' - Start a printer.
11064
*/
11065
11066
static void
11067
start_printer(cupsd_client_t *con, /* I - Client connection */
11068
ipp_attribute_t *uri) /* I - Printer URI */
11069
{
11070
int i; /* Temporary variable */
11071
http_status_t status; /* Policy status */
11072
cups_ptype_t dtype; /* Destination type (printer/class) */
11073
cupsd_printer_t *printer; /* Printer data */
11074
11075
11076
cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", con,
11077
con->number, uri->values[0].string.text);
11078
11079
/*
11080
* Is the destination valid?
11081
*/
11082
11083
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
11084
{
11085
/*
11086
* Bad URI...
11087
*/
11088
11089
send_ipp_status(con, IPP_NOT_FOUND,
11090
_("The printer or class does not exist."));
11091
return;
11092
}
11093
11094
/*
11095
* Check policy...
11096
*/
11097
11098
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
11099
{
11100
send_http_error(con, status, printer);
11101
return;
11102
}
11103
11104
/*
11105
* Start the printer...
11106
*/
11107
11108
printer->state_message[0] = '\0';
11109
11110
cupsdStartPrinter(printer, 1);
11111
11112
if (dtype & CUPS_PRINTER_CLASS)
11113
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".",
11114
printer->name, get_username(con));
11115
else
11116
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".",
11117
printer->name, get_username(con));
11118
11119
cupsdCheckJobs();
11120
11121
/*
11122
* Check quotas...
11123
*/
11124
11125
if ((i = check_quotas(con, printer)) < 0)
11126
{
11127
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
11128
return;
11129
}
11130
else if (i == 0)
11131
{
11132
send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
11133
return;
11134
}
11135
11136
/*
11137
* Everything was ok, so return OK status...
11138
*/
11139
11140
con->response->request.status.status_code = IPP_OK;
11141
}
11142
11143
11144
/*
11145
* 'stop_printer()' - Stop a printer.
11146
*/
11147
11148
static void
11149
stop_printer(cupsd_client_t *con, /* I - Client connection */
11150
ipp_attribute_t *uri) /* I - Printer URI */
11151
{
11152
http_status_t status; /* Policy status */
11153
cups_ptype_t dtype; /* Destination type (printer/class) */
11154
cupsd_printer_t *printer; /* Printer data */
11155
ipp_attribute_t *attr; /* printer-state-message attribute */
11156
11157
11158
cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", con,
11159
con->number, uri->values[0].string.text);
11160
11161
/*
11162
* Is the destination valid?
11163
*/
11164
11165
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
11166
{
11167
/*
11168
* Bad URI...
11169
*/
11170
11171
send_ipp_status(con, IPP_NOT_FOUND,
11172
_("The printer or class does not exist."));
11173
return;
11174
}
11175
11176
/*
11177
* Check policy...
11178
*/
11179
11180
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
11181
{
11182
send_http_error(con, status, printer);
11183
return;
11184
}
11185
11186
/*
11187
* Stop the printer...
11188
*/
11189
11190
if ((attr = ippFindAttribute(con->request, "printer-state-message",
11191
IPP_TAG_TEXT)) == NULL)
11192
strlcpy(printer->state_message, "Paused", sizeof(printer->state_message));
11193
else
11194
{
11195
strlcpy(printer->state_message, attr->values[0].string.text,
11196
sizeof(printer->state_message));
11197
}
11198
11199
cupsdStopPrinter(printer, 1);
11200
11201
if (dtype & CUPS_PRINTER_CLASS)
11202
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".",
11203
printer->name, get_username(con));
11204
else
11205
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".",
11206
printer->name, get_username(con));
11207
11208
/*
11209
* Everything was ok, so return OK status...
11210
*/
11211
11212
con->response->request.status.status_code = IPP_OK;
11213
}
11214
11215
11216
/*
11217
* 'url_encode_attr()' - URL-encode a string attribute.
11218
*/
11219
11220
static void
11221
url_encode_attr(ipp_attribute_t *attr, /* I - Attribute */
11222
char *buffer,/* I - String buffer */
11223
size_t bufsize)/* I - Size of buffer */
11224
{
11225
int i; /* Looping var */
11226
char *bufptr, /* Pointer into buffer */
11227
*bufend; /* End of buffer */
11228
11229
11230
strlcpy(buffer, attr->name, bufsize);
11231
bufptr = buffer + strlen(buffer);
11232
bufend = buffer + bufsize - 1;
11233
11234
for (i = 0; i < attr->num_values; i ++)
11235
{
11236
if (bufptr >= bufend)
11237
break;
11238
11239
if (i)
11240
*bufptr++ = ',';
11241
else
11242
*bufptr++ = '=';
11243
11244
if (bufptr >= bufend)
11245
break;
11246
11247
*bufptr++ = '\'';
11248
11249
bufptr = url_encode_string(attr->values[i].string.text, bufptr, (size_t)(bufend - bufptr + 1));
11250
11251
if (bufptr >= bufend)
11252
break;
11253
11254
*bufptr++ = '\'';
11255
}
11256
11257
*bufptr = '\0';
11258
}
11259
11260
11261
/*
11262
* 'url_encode_string()' - URL-encode a string.
11263
*/
11264
11265
static char * /* O - End of string */
11266
url_encode_string(const char *s, /* I - String */
11267
char *buffer, /* I - String buffer */
11268
size_t bufsize) /* I - Size of buffer */
11269
{
11270
char *bufptr, /* Pointer into buffer */
11271
*bufend; /* End of buffer */
11272
static const char *hex = "0123456789ABCDEF";
11273
/* Hex digits */
11274
11275
11276
bufptr = buffer;
11277
bufend = buffer + bufsize - 1;
11278
11279
while (*s && bufptr < bufend)
11280
{
11281
if (*s == ' ' || *s == '%' || *s == '+')
11282
{
11283
if (bufptr >= (bufend - 2))
11284
break;
11285
11286
*bufptr++ = '%';
11287
*bufptr++ = hex[(*s >> 4) & 15];
11288
*bufptr++ = hex[*s & 15];
11289
11290
s ++;
11291
}
11292
else if (*s == '\'' || *s == '\\')
11293
{
11294
if (bufptr >= (bufend - 1))
11295
break;
11296
11297
*bufptr++ = '\\';
11298
*bufptr++ = *s++;
11299
}
11300
else
11301
*bufptr++ = *s++;
11302
}
11303
11304
*bufptr = '\0';
11305
11306
return (bufptr);
11307
}
11308
11309
11310
/*
11311
* 'user_allowed()' - See if a user is allowed to print to a queue.
11312
*/
11313
11314
static int /* O - 0 if not allowed, 1 if allowed */
11315
user_allowed(cupsd_printer_t *p, /* I - Printer or class */
11316
const char *username) /* I - Username */
11317
{
11318
struct passwd *pw; /* User password data */
11319
char baseuser[256], /* Base username */
11320
*baseptr, /* Pointer to "@" in base username */
11321
*name; /* Current user name */
11322
11323
11324
if (cupsArrayCount(p->users) == 0)
11325
return (1);
11326
11327
if (!strcmp(username, "root"))
11328
return (1);
11329
11330
if (strchr(username, '@'))
11331
{
11332
/*
11333
* Strip @REALM for username check...
11334
*/
11335
11336
strlcpy(baseuser, username, sizeof(baseuser));
11337
11338
if ((baseptr = strchr(baseuser, '@')) != NULL)
11339
*baseptr = '\0';
11340
11341
username = baseuser;
11342
}
11343
11344
pw = getpwnam(username);
11345
endpwent();
11346
11347
for (name = (char *)cupsArrayFirst(p->users);
11348
name;
11349
name = (char *)cupsArrayNext(p->users))
11350
{
11351
if (name[0] == '@')
11352
{
11353
/*
11354
* Check group membership...
11355
*/
11356
11357
if (cupsdCheckGroup(username, pw, name + 1))
11358
break;
11359
}
11360
else if (name[0] == '#')
11361
{
11362
/*
11363
* Check UUID...
11364
*/
11365
11366
if (cupsdCheckGroup(username, pw, name))
11367
break;
11368
}
11369
else if (!_cups_strcasecmp(username, name))
11370
break;
11371
}
11372
11373
return ((name != NULL) != p->deny_users);
11374
}
11375
11376
11377
/*
11378
* 'validate_job()' - Validate printer options and destination.
11379
*/
11380
11381
static void
11382
validate_job(cupsd_client_t *con, /* I - Client connection */
11383
ipp_attribute_t *uri) /* I - Printer URI */
11384
{
11385
http_status_t status; /* Policy status */
11386
ipp_attribute_t *attr; /* Current attribute */
11387
#ifdef HAVE_TLS
11388
ipp_attribute_t *auth_info; /* auth-info attribute */
11389
#endif /* HAVE_TLS */
11390
ipp_attribute_t *format, /* Document-format attribute */
11391
*name; /* Job-name attribute */
11392
cups_ptype_t dtype; /* Destination type (printer/class) */
11393
char super[MIME_MAX_SUPER],
11394
/* Supertype of file */
11395
type[MIME_MAX_TYPE];
11396
/* Subtype of file */
11397
cupsd_printer_t *printer; /* Printer */
11398
11399
11400
cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con,
11401
con->number, uri->values[0].string.text);
11402
11403
/*
11404
* OK, see if the client is sending the document compressed - CUPS
11405
* doesn't support compression yet...
11406
*/
11407
11408
if ((attr = ippFindAttribute(con->request, "compression",
11409
IPP_TAG_KEYWORD)) != NULL)
11410
{
11411
if (strcmp(attr->values[0].string.text, "none")
11412
#ifdef HAVE_LIBZ
11413
&& strcmp(attr->values[0].string.text, "gzip")
11414
#endif /* HAVE_LIBZ */
11415
)
11416
{
11417
send_ipp_status(con, IPP_ATTRIBUTES,
11418
_("Unsupported 'compression' value \"%s\"."),
11419
attr->values[0].string.text);
11420
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
11421
"compression", NULL, attr->values[0].string.text);
11422
return;
11423
}
11424
}
11425
11426
/*
11427
* Is it a format we support?
11428
*/
11429
11430
if ((format = ippFindAttribute(con->request, "document-format",
11431
IPP_TAG_MIMETYPE)) != NULL)
11432
{
11433
if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]",
11434
super, type) != 2)
11435
{
11436
send_ipp_status(con, IPP_BAD_REQUEST,
11437
_("Bad 'document-format' value \"%s\"."),
11438
format->values[0].string.text);
11439
return;
11440
}
11441
11442
_cupsRWLockRead(&MimeDatabase->lock);
11443
11444
if ((strcmp(super, "application") || strcmp(type, "octet-stream")) &&
11445
!mimeType(MimeDatabase, super, type))
11446
{
11447
cupsdLogMessage(CUPSD_LOG_INFO,
11448
"Hint: Do you have the raw file printing rules enabled?");
11449
send_ipp_status(con, IPP_DOCUMENT_FORMAT,
11450
_("Unsupported 'document-format' value \"%s\"."),
11451
format->values[0].string.text);
11452
ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
11453
"document-format", NULL, format->values[0].string.text);
11454
11455
_cupsRWUnlock(&MimeDatabase->lock);
11456
11457
return;
11458
}
11459
11460
_cupsRWUnlock(&MimeDatabase->lock);
11461
}
11462
11463
/*
11464
* Is the job-hold-until value valid?
11465
*/
11466
11467
if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL && ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr)))
11468
{
11469
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value."));
11470
ippCopyAttribute(con->response, attr, 0);
11471
return;
11472
}
11473
11474
/*
11475
* Is the job-name valid?
11476
*/
11477
11478
if ((name = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) != NULL)
11479
{
11480
if ((name->value_tag != IPP_TAG_NAME && name->value_tag != IPP_TAG_NAMELANG) ||
11481
name->num_values != 1 || !ippValidateAttribute(name))
11482
{
11483
if (StrictConformance)
11484
{
11485
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-name' value."));
11486
ippCopyAttribute(con->response, name, 0);
11487
return;
11488
}
11489
else
11490
{
11491
cupsdLogMessage(CUPSD_LOG_WARN, "Unsupported 'job-name' value, deleting from request.");
11492
ippDeleteAttribute(con->request, name);
11493
}
11494
}
11495
}
11496
11497
/*
11498
* Is the destination valid?
11499
*/
11500
11501
if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
11502
{
11503
/*
11504
* Bad URI...
11505
*/
11506
11507
send_ipp_status(con, IPP_NOT_FOUND,
11508
_("The printer or class does not exist."));
11509
return;
11510
}
11511
11512
/*
11513
* Check policy...
11514
*/
11515
11516
#ifdef HAVE_TLS
11517
auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
11518
#endif /* HAVE_TLS */
11519
11520
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
11521
{
11522
send_http_error(con, status, printer);
11523
return;
11524
}
11525
else if (printer->num_auth_info_required == 1 &&
11526
!strcmp(printer->auth_info_required[0], "negotiate") &&
11527
!con->username[0])
11528
{
11529
send_http_error(con, HTTP_UNAUTHORIZED, printer);
11530
return;
11531
}
11532
#ifdef HAVE_TLS
11533
else if (auth_info && !con->http->tls &&
11534
!httpAddrLocalhost(con->http->hostaddr))
11535
{
11536
/*
11537
* Require encryption of auth-info over non-local connections...
11538
*/
11539
11540
send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
11541
return;
11542
}
11543
#endif /* HAVE_TLS */
11544
11545
/*
11546
* Everything was ok, so return OK status...
11547
*/
11548
11549
con->response->request.status.status_code = IPP_OK;
11550
}
11551
11552
11553
/*
11554
* 'validate_name()' - Make sure the printer name only contains valid chars.
11555
*/
11556
11557
static int /* O - 0 if name is no good, 1 if good */
11558
validate_name(const char *name) /* I - Name to check */
11559
{
11560
const char *ptr; /* Pointer into name */
11561
11562
11563
/*
11564
* Scan the whole name...
11565
*/
11566
11567
for (ptr = name; *ptr; ptr ++)
11568
if ((*ptr > 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
11569
return (0);
11570
11571
/*
11572
* All the characters are good; validate the length, too...
11573
*/
11574
11575
return ((ptr - name) < 128);
11576
}
11577
11578
11579
/*
11580
* 'validate_user()' - Validate the user for the request.
11581
*/
11582
11583
static int /* O - 1 if permitted, 0 otherwise */
11584
validate_user(cupsd_job_t *job, /* I - Job */
11585
cupsd_client_t *con, /* I - Client connection */
11586
const char *owner, /* I - Owner of job/resource */
11587
char *username, /* O - Authenticated username */
11588
size_t userlen) /* I - Length of username */
11589
{
11590
cupsd_printer_t *printer; /* Printer for job */
11591
11592
11593
cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=" CUPS_LLFMT ")", job->id, con ? con->number : 0, owner ? owner : "(null)", username, CUPS_LLCAST userlen);
11594
11595
/*
11596
* Validate input...
11597
*/
11598
11599
if (!con || !owner || !username || userlen <= 0)
11600
return (0);
11601
11602
/*
11603
* Get the best authenticated username that is available.
11604
*/
11605
11606
strlcpy(username, get_username(con), userlen);
11607
11608
/*
11609
* Check the username against the owner...
11610
*/
11611
11612
printer = cupsdFindDest(job->dest);
11613
11614
return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr,
11615
con, owner) == HTTP_OK);
11616
}
11617
11618