]>
Commit | Line | Data |
---|---|---|
a129ddbd | 1 | /* |
b5cb0608 | 2 | * "$Id: dirsvc.c,v 1.73.2.2 2001/05/13 18:38:35 mike Exp $" |
a129ddbd | 3 | * |
d6de4648 | 4 | * Directory services routines for the Common UNIX Printing System (CUPS). |
a129ddbd | 5 | * |
d2935a0f | 6 | * Copyright 1997-2001 by Easy Software Products, all rights reserved. |
a129ddbd | 7 | * |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
8784b6a6 | 17 | * 44141 Airport View Drive, Suite 204 |
a129ddbd | 18 | * Hollywood, Maryland 20636-3111 USA |
19 | * | |
20 | * Voice: (301) 373-9603 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * Contents: | |
25 | * | |
cbbfcc63 | 26 | * StartBrowsing() - Start sending and receiving broadcast information. |
27 | * StopBrowsing() - Stop sending and receiving broadcast information. | |
28 | * UpdateBrowseList() - Update the browse lists for any new browse data. | |
29 | * SendBrowseList() - Send new browsing information. | |
03081fd2 | 30 | * StartPolling() - Start polling servers as needed. |
31 | * StopPolling() - Stop polling servers as needed. | |
a129ddbd | 32 | */ |
33 | ||
34 | /* | |
35 | * Include necessary headers... | |
36 | */ | |
37 | ||
fd8b1cf8 | 38 | #include "cupsd.h" |
7a91f14b | 39 | #include <grp.h> |
fd8b1cf8 | 40 | |
41 | ||
d6de4648 | 42 | /* |
43 | * 'StartBrowsing()' - Start sending and receiving broadcast information. | |
44 | */ | |
45 | ||
fd8b1cf8 | 46 | void |
47 | StartBrowsing(void) | |
48 | { | |
d6de4648 | 49 | int val; /* Socket option value */ |
50 | struct sockaddr_in addr; /* Broadcast address */ | |
51 | ||
52 | ||
8828fd5f | 53 | if (!Browsing) |
d6de4648 | 54 | return; |
55 | ||
56 | /* | |
57 | * Create the broadcast socket... | |
58 | */ | |
59 | ||
900b10ea | 60 | if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
d6de4648 | 61 | { |
5ea8888e | 62 | LogMessage(L_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.", |
d6de4648 | 63 | strerror(errno)); |
58218b2c | 64 | Browsing = 0; |
d6de4648 | 65 | return; |
66 | } | |
67 | ||
68 | /* | |
900b10ea | 69 | * Set the "broadcast" flag... |
d6de4648 | 70 | */ |
71 | ||
72 | val = 1; | |
e9e40963 | 73 | if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) |
fd3ece61 | 74 | { |
5ea8888e | 75 | LogMessage(L_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.", |
fd3ece61 | 76 | strerror(errno)); |
77 | ||
78 | #if defined(WIN32) || defined(__EMX__) | |
79 | closesocket(BrowseSocket); | |
80 | #else | |
81 | close(BrowseSocket); | |
82 | #endif /* WIN32 || __EMX__ */ | |
83 | ||
84 | BrowseSocket = -1; | |
58218b2c | 85 | Browsing = 0; |
fd3ece61 | 86 | return; |
87 | } | |
d6de4648 | 88 | |
d6de4648 | 89 | /* |
90 | * Bind the socket to browse port... | |
91 | */ | |
92 | ||
d6de4648 | 93 | memset(&addr, 0, sizeof(addr)); |
94 | addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
95 | addr.sin_family = AF_INET; | |
96 | addr.sin_port = htons(BrowsePort); | |
97 | ||
16b0a852 | 98 | if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr))) |
d6de4648 | 99 | { |
5ea8888e | 100 | LogMessage(L_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.", |
d6de4648 | 101 | strerror(errno)); |
102 | ||
103 | #if defined(WIN32) || defined(__EMX__) | |
104 | closesocket(BrowseSocket); | |
105 | #else | |
106 | close(BrowseSocket); | |
107 | #endif /* WIN32 || __EMX__ */ | |
108 | ||
109 | BrowseSocket = -1; | |
58218b2c | 110 | Browsing = 0; |
d6de4648 | 111 | return; |
112 | } | |
113 | ||
114 | /* | |
115 | * Finally, add the socket to the input selection set... | |
116 | */ | |
117 | ||
118 | FD_SET(BrowseSocket, &InputSet); | |
fd8b1cf8 | 119 | } |
120 | ||
121 | ||
d6de4648 | 122 | /* |
123 | * 'StopBrowsing()' - Stop sending and receiving broadcast information. | |
124 | */ | |
125 | ||
fd8b1cf8 | 126 | void |
127 | StopBrowsing(void) | |
128 | { | |
8828fd5f | 129 | if (!Browsing) |
d6de4648 | 130 | return; |
131 | ||
132 | /* | |
133 | * Close the socket and remove it from the input selection set. | |
134 | */ | |
135 | ||
3c7bb4a2 | 136 | if (BrowseSocket >= 0) |
137 | { | |
d6de4648 | 138 | #if defined(WIN32) || defined(__EMX__) |
3c7bb4a2 | 139 | closesocket(BrowseSocket); |
d6de4648 | 140 | #else |
3c7bb4a2 | 141 | close(BrowseSocket); |
d6de4648 | 142 | #endif /* WIN32 || __EMX__ */ |
143 | ||
3c7bb4a2 | 144 | FD_CLR(BrowseSocket, &InputSet); |
f63a2256 | 145 | BrowseSocket = 0; |
3c7bb4a2 | 146 | } |
fd8b1cf8 | 147 | } |
148 | ||
149 | ||
d6de4648 | 150 | /* |
151 | * 'UpdateBrowseList()' - Update the browse lists for any new browse data. | |
152 | */ | |
153 | ||
fd8b1cf8 | 154 | void |
155 | UpdateBrowseList(void) | |
156 | { | |
8b43895a | 157 | int i; /* Looping var */ |
20e0a4cb | 158 | int update; /* Update printer attributes? */ |
e5ebb675 | 159 | int auth; /* Authorization status */ |
eef5ad1b | 160 | int len, /* Length of name string */ |
161 | offset; /* Offset in name string */ | |
d6de4648 | 162 | int bytes; /* Number of bytes left */ |
20e0a4cb | 163 | char packet[1540], /* Broadcast packet */ |
164 | *pptr; /* Pointer into packet */ | |
99de6da0 | 165 | http_addr_t srcaddr; /* Source address */ |
e5ebb675 | 166 | char srcname[1024]; /* Source hostname */ |
99de6da0 | 167 | unsigned address[4], /* Source address */ |
168 | temp; /* Temporary address var (host order) */ | |
d6de4648 | 169 | cups_ptype_t type; /* Printer type */ |
170 | ipp_pstate_t state; /* Printer state */ | |
171 | char uri[HTTP_MAX_URI], /* Printer URI */ | |
172 | method[HTTP_MAX_URI], /* Method portion of URI */ | |
173 | username[HTTP_MAX_URI], /* Username portion of URI */ | |
174 | host[HTTP_MAX_URI], /* Host portion of URI */ | |
a2c6b8b1 | 175 | resource[HTTP_MAX_URI], /* Resource portion of URI */ |
176 | info[IPP_MAX_NAME], /* Information string */ | |
177 | location[IPP_MAX_NAME], /* Location string */ | |
178 | make_model[IPP_MAX_NAME];/* Make and model string */ | |
d6de4648 | 179 | int port; /* Port portion of URI */ |
180 | char name[IPP_MAX_NAME], /* Name of printer */ | |
8b43895a | 181 | *hptr, /* Pointer into hostname */ |
182 | *sptr; /* Pointer into ServerName */ | |
183 | printer_t *p, /* Printer information */ | |
184 | *pclass, /* Printer class */ | |
b5cb0608 | 185 | *first, /* First printer in class */ |
186 | *next; /* Next printer in list */ | |
d6de4648 | 187 | |
188 | ||
189 | /* | |
190 | * Read a packet from the browse socket... | |
191 | */ | |
192 | ||
e5ebb675 | 193 | len = sizeof(srcaddr); |
16b0a852 | 194 | if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet), 0, |
e5ebb675 | 195 | (struct sockaddr *)&srcaddr, &len)) <= 0) |
18d7d592 | 196 | { |
89db771d | 197 | /* |
198 | * "Connection refused" is returned under Linux if the destination port | |
199 | * or address is unreachable from a previous sendto(); check for the | |
200 | * error here and ignore it for now... | |
201 | */ | |
202 | ||
203 | if (errno != ECONNREFUSED) | |
204 | { | |
205 | LogMessage(L_ERROR, "Browse recv failed - %s.", strerror(errno)); | |
206 | LogMessage(L_ERROR, "Browsing turned off."); | |
207 | ||
208 | StopBrowsing(); | |
209 | Browsing = 0; | |
210 | } | |
1a5606a3 | 211 | |
18d7d592 | 212 | return; |
213 | } | |
214 | ||
215 | packet[bytes] = '\0'; | |
e5ebb675 | 216 | |
217 | /* | |
218 | * Figure out where it came from... | |
219 | */ | |
220 | ||
99de6da0 | 221 | #ifdef AF_INET6 |
222 | if (srcaddr.addr.sa_family == AF_INET6) | |
223 | { | |
224 | address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]); | |
225 | address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]); | |
226 | address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]); | |
227 | address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]); | |
228 | } | |
e5ebb675 | 229 | else |
99de6da0 | 230 | #endif /* AF_INET6 */ |
f9bacabb | 231 | { |
99de6da0 | 232 | temp = ntohl(srcaddr.ipv4.sin_addr.s_addr); |
233 | ||
234 | address[3] = temp & 255; | |
235 | temp >>= 8; | |
236 | address[2] = temp & 255; | |
237 | temp >>= 8; | |
238 | address[1] = temp & 255; | |
239 | temp >>= 8; | |
240 | address[0] = temp & 255; | |
e5ebb675 | 241 | } |
1a5606a3 | 242 | |
99de6da0 | 243 | if (HostNameLookups) |
244 | httpAddrLookup(&srcaddr, srcname, sizeof(srcname)); | |
245 | else | |
246 | httpAddrString(&srcaddr, srcname, sizeof(srcname)); | |
247 | ||
e5ebb675 | 248 | len = strlen(srcname); |
249 | ||
250 | /* | |
251 | * Do ACL stuff... | |
252 | */ | |
253 | ||
254 | if (BrowseACL) | |
255 | { | |
99de6da0 | 256 | if (httpAddrLocalhost(&srcaddr) || strcasecmp(srcname, "localhost") == 0) |
e5ebb675 | 257 | { |
258 | /* | |
259 | * Access from localhost (127.0.0.1) is always allowed... | |
260 | */ | |
261 | ||
262 | auth = AUTH_ALLOW; | |
263 | } | |
264 | else | |
265 | { | |
266 | /* | |
267 | * Do authorization checks on the domain/address... | |
268 | */ | |
269 | ||
d21a7597 | 270 | switch (BrowseACL->order_type) |
e5ebb675 | 271 | { |
d21a7597 | 272 | default : |
273 | auth = AUTH_DENY; /* anti-compiler-warning-code */ | |
274 | break; | |
275 | ||
e5ebb675 | 276 | case AUTH_ALLOW : /* Order Deny,Allow */ |
d21a7597 | 277 | auth = AUTH_ALLOW; |
278 | ||
e5ebb675 | 279 | if (CheckAuth(address, srcname, len, |
280 | BrowseACL->num_deny, BrowseACL->deny)) | |
281 | auth = AUTH_DENY; | |
282 | ||
283 | if (CheckAuth(address, srcname, len, | |
284 | BrowseACL->num_allow, BrowseACL->allow)) | |
285 | auth = AUTH_ALLOW; | |
286 | break; | |
287 | ||
288 | case AUTH_DENY : /* Order Allow,Deny */ | |
d21a7597 | 289 | auth = AUTH_DENY; |
290 | ||
e5ebb675 | 291 | if (CheckAuth(address, srcname, len, |
292 | BrowseACL->num_allow, BrowseACL->allow)) | |
293 | auth = AUTH_ALLOW; | |
294 | ||
295 | if (CheckAuth(address, srcname, len, | |
296 | BrowseACL->num_deny, BrowseACL->deny)) | |
297 | auth = AUTH_DENY; | |
298 | break; | |
299 | } | |
300 | } | |
301 | } | |
302 | else | |
303 | auth = AUTH_ALLOW; | |
304 | ||
305 | if (auth == AUTH_DENY) | |
306 | { | |
307 | LogMessage(L_DEBUG, "UpdateBrowseList: Refused %d bytes from %s", bytes, | |
308 | srcname); | |
d6de4648 | 309 | return; |
f9bacabb | 310 | } |
d6de4648 | 311 | |
58e8cf34 | 312 | LogMessage(L_DEBUG2, "UpdateBrowseList: (%d bytes from %s) %s", bytes, srcname, |
e5ebb675 | 313 | packet); |
314 | ||
315 | /* | |
316 | * Parse packet... | |
317 | */ | |
d6de4648 | 318 | |
20e0a4cb | 319 | update = 0; |
a2c6b8b1 | 320 | |
20e0a4cb | 321 | if (sscanf(packet, "%x%x%1023s", (unsigned *)&type, (unsigned *)&state, |
322 | uri) < 3) | |
d6de4648 | 323 | { |
5ea8888e | 324 | LogMessage(L_WARN, "UpdateBrowseList: Garbled browse packet - %s", |
d6de4648 | 325 | packet); |
326 | return; | |
327 | } | |
328 | ||
20e0a4cb | 329 | strcpy(location, "Location Unknown"); |
330 | strcpy(info, "No Information Available"); | |
331 | make_model[0] = '\0'; | |
332 | ||
333 | if ((pptr = strchr(packet, '\"')) != NULL) | |
334 | { | |
335 | /* | |
336 | * Have extended information; can't use sscanf for it because not all | |
337 | * sscanf's allow empty strings with %[^\"]... | |
338 | */ | |
339 | ||
340 | for (i = 0, pptr ++; | |
341 | i < (sizeof(location) - 1) && *pptr && *pptr != '\"'; | |
342 | i ++, pptr ++) | |
343 | location[i] = *pptr; | |
344 | ||
345 | if (i) | |
346 | location[i] = '\0'; | |
347 | ||
348 | if (*pptr == '\"') | |
349 | pptr ++; | |
350 | ||
351 | while (*pptr && isspace(*pptr)) | |
352 | pptr ++; | |
353 | ||
05156f4e | 354 | if (*pptr == '\"') |
355 | { | |
356 | for (i = 0, pptr ++; | |
357 | i < (sizeof(info) - 1) && *pptr && *pptr != '\"'; | |
358 | i ++, pptr ++) | |
359 | info[i] = *pptr; | |
20e0a4cb | 360 | |
05156f4e | 361 | if (i) |
362 | info[i] = '\0'; | |
20e0a4cb | 363 | |
05156f4e | 364 | if (*pptr == '\"') |
365 | pptr ++; | |
20e0a4cb | 366 | |
05156f4e | 367 | while (*pptr && isspace(*pptr)) |
368 | pptr ++; | |
20e0a4cb | 369 | |
05156f4e | 370 | if (*pptr == '\"') |
371 | { | |
372 | for (i = 0, pptr ++; | |
373 | i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"'; | |
374 | i ++, pptr ++) | |
375 | make_model[i] = *pptr; | |
20e0a4cb | 376 | |
05156f4e | 377 | if (i) |
378 | make_model[i] = '\0'; | |
379 | } | |
380 | } | |
20e0a4cb | 381 | } |
382 | ||
383 | DEBUG_puts(packet); | |
a2c6b8b1 | 384 | DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n" |
385 | "location=\"%s\", info=\"%s\", make_model=\"%s\"\n", | |
386 | type, state, uri, location, info, make_model)); | |
a8b216d5 | 387 | |
d6de4648 | 388 | /* |
389 | * Pull the URI apart to see if this is a local or remote printer... | |
390 | */ | |
391 | ||
392 | httpSeparate(uri, method, username, host, &port, resource); | |
393 | ||
a8b216d5 | 394 | DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName)); |
395 | ||
d6de4648 | 396 | if (strcasecmp(host, ServerName) == 0) |
397 | return; | |
398 | ||
e5ebb675 | 399 | /* |
400 | * Do relaying... | |
401 | */ | |
402 | ||
403 | for (i = 0; i < NumRelays; i ++) | |
404 | if (CheckAuth(address, srcname, len, 1, &(Relays[i].from))) | |
405 | if (sendto(BrowseSocket, packet, bytes, 0, | |
406 | (struct sockaddr *)&(Relays[i].to), | |
99de6da0 | 407 | sizeof(http_addr_t)) <= 0) |
e5ebb675 | 408 | { |
409 | LogMessage(L_ERROR, "UpdateBrowseList: sendto failed for relay %d - %s.", | |
410 | i + 1, strerror(errno)); | |
411 | return; | |
412 | } | |
413 | ||
d6de4648 | 414 | /* |
415 | * OK, this isn't a local printer; see if we already have it listed in | |
416 | * the Printers list, and add it if not... | |
417 | */ | |
418 | ||
8b43895a | 419 | hptr = strchr(host, '.'); |
420 | sptr = strchr(ServerName, '.'); | |
421 | ||
9fe0309f | 422 | if (sptr != NULL && hptr != NULL) |
423 | { | |
424 | /* | |
425 | * Strip the common domain name components... | |
426 | */ | |
427 | ||
428 | while (hptr != NULL) | |
429 | { | |
430 | if (strcasecmp(hptr, sptr) == 0) | |
431 | { | |
432 | *hptr = '\0'; | |
433 | break; | |
434 | } | |
435 | else | |
436 | hptr = strchr(hptr + 1, '.'); | |
437 | } | |
438 | } | |
d6de4648 | 439 | |
c7fa9d06 | 440 | if (type & CUPS_PRINTER_CLASS) |
d6de4648 | 441 | { |
442 | /* | |
c7fa9d06 | 443 | * Remote destination is a class... |
d6de4648 | 444 | */ |
445 | ||
c7fa9d06 | 446 | if (strncmp(resource, "/classes/", 9) == 0) |
04de52f8 | 447 | snprintf(name, sizeof(name), "%s@%s", resource + 9, host); |
c7fa9d06 | 448 | else |
449 | return; | |
450 | ||
d6f1ff9a | 451 | if ((p = FindClass(name)) == NULL && BrowseShortNames) |
0c2ea277 | 452 | { |
d6f1ff9a | 453 | if ((p = FindClass(resource + 9)) != NULL) |
454 | { | |
93d2f0c0 | 455 | if (strcasecmp(p->hostname, host) != 0 && p->hostname[0]) |
d6f1ff9a | 456 | { |
457 | /* | |
458 | * Nope, this isn't the same host; if the hostname isn't the local host, | |
459 | * add it to the other class and then find a class using the full host | |
460 | * name... | |
461 | */ | |
462 | ||
463 | if (p->type & CUPS_PRINTER_REMOTE) | |
464 | { | |
f4660d94 | 465 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 466 | strncat(p->name, "@", sizeof(p->name) - 1); |
467 | strncat(p->name, p->hostname, sizeof(p->name) - 1); | |
d6f1ff9a | 468 | SetPrinterAttrs(p); |
469 | SortPrinters(); | |
470 | } | |
471 | ||
472 | p = NULL; | |
473 | } | |
93d2f0c0 | 474 | else if (!p->hostname[0]) |
475 | { | |
f4660d94 | 476 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 477 | strncpy(p->hostname, host, sizeof(p->hostname) - 1); |
478 | strncpy(p->uri, uri, sizeof(p->uri) - 1); | |
479 | strncpy(p->more_info, uri, sizeof(p->more_info) - 1); | |
480 | strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1); | |
481 | update = 1; | |
482 | } | |
d6f1ff9a | 483 | } |
484 | else | |
485 | { | |
486 | strncpy(name, resource + 9, sizeof(name) - 1); | |
487 | name[sizeof(name) - 1] = '\0'; | |
488 | } | |
0c2ea277 | 489 | } |
93d2f0c0 | 490 | else if (!p->hostname[0]) |
491 | { | |
f4660d94 | 492 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 493 | strncpy(p->hostname, host, sizeof(p->hostname) - 1); |
494 | strncpy(p->uri, uri, sizeof(p->uri) - 1); | |
495 | strncpy(p->more_info, uri, sizeof(p->more_info) - 1); | |
496 | strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1); | |
497 | update = 1; | |
498 | } | |
d6f1ff9a | 499 | |
500 | if (p == NULL) | |
c7fa9d06 | 501 | { |
502 | /* | |
503 | * Class doesn't exist; add it... | |
504 | */ | |
d6de4648 | 505 | |
782359ca | 506 | p = AddClass(name); |
c7fa9d06 | 507 | |
508 | /* | |
782359ca | 509 | * Force the URI to point to the real server... |
c7fa9d06 | 510 | */ |
511 | ||
5057ad3b | 512 | p->type = type; |
f4660d94 | 513 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 514 | strncpy(p->uri, uri, sizeof(p->uri) - 1); |
515 | strncpy(p->more_info, uri, sizeof(p->more_info) - 1); | |
516 | strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1); | |
517 | strncpy(p->hostname, host, sizeof(p->hostname) - 1); | |
a2c6b8b1 | 518 | |
20e0a4cb | 519 | update = 1; |
c7fa9d06 | 520 | } |
521 | } | |
522 | else | |
523 | { | |
d6de4648 | 524 | /* |
c7fa9d06 | 525 | * Remote destination is a printer... |
d6de4648 | 526 | */ |
527 | ||
c7fa9d06 | 528 | if (strncmp(resource, "/printers/", 10) == 0) |
04de52f8 | 529 | snprintf(name, sizeof(name), "%s@%s", resource + 10, host); |
c7fa9d06 | 530 | else |
531 | return; | |
532 | ||
d6f1ff9a | 533 | if ((p = FindPrinter(name)) == NULL && BrowseShortNames) |
0c2ea277 | 534 | { |
d6f1ff9a | 535 | if ((p = FindPrinter(resource + 10)) != NULL) |
536 | { | |
93d2f0c0 | 537 | if (strcasecmp(p->hostname, host) != 0 && p->hostname[0]) |
d6f1ff9a | 538 | { |
539 | /* | |
540 | * Nope, this isn't the same host; if the hostname isn't the local host, | |
541 | * add it to the other printer and then find a printer using the full host | |
542 | * name... | |
543 | */ | |
544 | ||
545 | if (p->type & CUPS_PRINTER_REMOTE) | |
546 | { | |
f4660d94 | 547 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 548 | strncat(p->name, "@", sizeof(p->name) - 1); |
549 | strncat(p->name, p->hostname, sizeof(p->name) - 1); | |
d6f1ff9a | 550 | SetPrinterAttrs(p); |
551 | SortPrinters(); | |
552 | } | |
553 | ||
554 | p = NULL; | |
555 | } | |
93d2f0c0 | 556 | else if (!p->hostname[0]) |
557 | { | |
f4660d94 | 558 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 559 | strncpy(p->hostname, host, sizeof(p->hostname) - 1); |
560 | strncpy(p->uri, uri, sizeof(p->uri) - 1); | |
561 | strncpy(p->more_info, uri, sizeof(p->more_info) - 1); | |
562 | strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1); | |
563 | update = 1; | |
564 | } | |
d6f1ff9a | 565 | } |
566 | else | |
567 | { | |
568 | strncpy(name, resource + 10, sizeof(name) - 1); | |
569 | name[sizeof(name) - 1] = '\0'; | |
570 | } | |
0c2ea277 | 571 | } |
93d2f0c0 | 572 | else if (!p->hostname[0]) |
573 | { | |
f4660d94 | 574 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 575 | strncpy(p->hostname, host, sizeof(p->hostname) - 1); |
576 | strncpy(p->uri, uri, sizeof(p->uri) - 1); | |
577 | strncpy(p->more_info, uri, sizeof(p->more_info) - 1); | |
578 | strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1); | |
579 | update = 1; | |
580 | } | |
d6f1ff9a | 581 | |
582 | if (p == NULL) | |
c7fa9d06 | 583 | { |
584 | /* | |
585 | * Printer doesn't exist; add it... | |
586 | */ | |
587 | ||
588 | p = AddPrinter(name); | |
589 | ||
590 | /* | |
5057ad3b | 591 | * Force the URI to point to the real server... |
c7fa9d06 | 592 | */ |
593 | ||
5057ad3b | 594 | p->type = type; |
f4660d94 | 595 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
93d2f0c0 | 596 | strncpy(p->hostname, host, sizeof(p->hostname) - 1); |
597 | strncpy(p->uri, uri, sizeof(p->uri) - 1); | |
598 | strncpy(p->more_info, uri, sizeof(p->more_info) - 1); | |
599 | strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1); | |
a2c6b8b1 | 600 | |
20e0a4cb | 601 | update = 1; |
c7fa9d06 | 602 | } |
d6de4648 | 603 | } |
604 | ||
605 | /* | |
606 | * Update the state... | |
607 | */ | |
608 | ||
d6de4648 | 609 | p->state = state; |
0948b55b | 610 | p->accepting = state != IPP_PRINTER_STOPPED; |
d6de4648 | 611 | p->browse_time = time(NULL); |
8b43895a | 612 | |
20e0a4cb | 613 | if (p->type != type) |
614 | { | |
615 | p->type = type; | |
616 | update = 1; | |
617 | } | |
618 | ||
a6988fb1 | 619 | if (strcmp(p->location, location)) |
20e0a4cb | 620 | { |
f4660d94 | 621 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
622 | strncpy(p->location, location, sizeof(p->location) - 1); | |
20e0a4cb | 623 | update = 1; |
624 | } | |
625 | ||
a6988fb1 | 626 | if (strcmp(p->info, info)) |
20e0a4cb | 627 | { |
f4660d94 | 628 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
629 | strncpy(p->info, info, sizeof(p->info) - 1); | |
20e0a4cb | 630 | update = 1; |
631 | } | |
632 | ||
633 | if (!make_model[0]) | |
634 | { | |
635 | if (type & CUPS_PRINTER_CLASS) | |
04de52f8 | 636 | snprintf(make_model, sizeof(p->make_model), "Remote Class on %s", |
20e0a4cb | 637 | host); |
638 | else | |
04de52f8 | 639 | snprintf(make_model, sizeof(p->make_model), "Remote Printer on %s", |
20e0a4cb | 640 | host); |
641 | } | |
642 | else | |
643 | { | |
644 | strncat(make_model, " on ", sizeof(make_model) - 1); | |
645 | strncat(make_model, host, sizeof(make_model) - 1); | |
646 | make_model[sizeof(make_model) - 1] = '\0'; | |
647 | } | |
648 | ||
649 | if (strcmp(p->make_model, make_model)) | |
650 | { | |
f4660d94 | 651 | /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */ |
652 | strncpy(p->make_model, make_model, sizeof(p->make_model) - 1); | |
20e0a4cb | 653 | update = 1; |
654 | } | |
655 | ||
656 | if (update) | |
657 | SetPrinterAttrs(p); | |
a2c6b8b1 | 658 | |
fb00e262 | 659 | /* |
4621b86f | 660 | * See if we have a default printer... If not, make the first printer the |
661 | * default. | |
fb00e262 | 662 | */ |
663 | ||
664 | if (DefaultPrinter == NULL && Printers != NULL) | |
665 | DefaultPrinter = Printers; | |
666 | ||
8b43895a | 667 | /* |
668 | * Do auto-classing if needed... | |
669 | */ | |
670 | ||
671 | if (ImplicitClasses) | |
672 | { | |
673 | /* | |
674 | * Loop through all available printers and create classes as needed... | |
675 | */ | |
676 | ||
d21a7597 | 677 | for (p = Printers, len = 0, offset = 0, first = NULL; |
678 | p != NULL; | |
b5cb0608 | 679 | p = next) |
8b43895a | 680 | { |
b5cb0608 | 681 | /* |
682 | * Get next printer in list... | |
683 | */ | |
684 | ||
685 | next = p->next; | |
686 | ||
8b43895a | 687 | /* |
688 | * Skip classes... | |
689 | */ | |
690 | ||
49089166 | 691 | if (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) |
8b43895a | 692 | { |
693 | len = 0; | |
694 | continue; | |
695 | } | |
696 | ||
697 | /* | |
698 | * If len == 0, get the length of this printer name up to the "@" | |
699 | * sign (if any). | |
700 | */ | |
701 | ||
702 | if (len > 0 && | |
eef5ad1b | 703 | strncasecmp(p->name, name + offset, len) == 0 && |
8b43895a | 704 | (p->name[len] == '\0' || p->name[len] == '@')) |
705 | { | |
706 | /* | |
707 | * We have more than one printer with the same name; see if | |
708 | * we have a class, and if this printer is a member... | |
709 | */ | |
710 | ||
a2c6b8b1 | 711 | if ((pclass = FindPrinter(name)) == NULL) |
18d7d592 | 712 | { |
4139b718 | 713 | /* |
714 | * Need to add the class... | |
715 | */ | |
716 | ||
a2c6b8b1 | 717 | pclass = AddPrinter(name); |
4139b718 | 718 | pclass->type |= CUPS_PRINTER_IMPLICIT; |
719 | pclass->accepting = 1; | |
720 | pclass->state = IPP_PRINTER_IDLE; | |
721 | ||
722 | SetPrinterAttrs(pclass); | |
20da3efb | 723 | |
724 | DEBUG_printf(("Added new class \"%s\", type = %x\n", name, | |
725 | pclass->type)); | |
18d7d592 | 726 | } |
8b43895a | 727 | |
728 | if (first != NULL) | |
729 | { | |
730 | for (i = 0; i < pclass->num_printers; i ++) | |
731 | if (pclass->printers[i] == first) | |
732 | break; | |
733 | ||
734 | if (i >= pclass->num_printers) | |
735 | AddPrinterToClass(pclass, first); | |
736 | ||
737 | first = NULL; | |
738 | } | |
739 | ||
740 | for (i = 0; i < pclass->num_printers; i ++) | |
741 | if (pclass->printers[i] == p) | |
742 | break; | |
743 | ||
744 | if (i >= pclass->num_printers) | |
745 | AddPrinterToClass(pclass, p); | |
746 | } | |
747 | else | |
748 | { | |
749 | /* | |
750 | * First time around; just get name length and mark it as first | |
751 | * in the list... | |
752 | */ | |
753 | ||
754 | if ((hptr = strchr(p->name, '@')) != NULL) | |
755 | len = hptr - p->name; | |
756 | else | |
757 | len = strlen(p->name); | |
758 | ||
782359ca | 759 | strncpy(name, p->name, len); |
760 | name[len] = '\0'; | |
eef5ad1b | 761 | offset = 0; |
782359ca | 762 | |
a2c6b8b1 | 763 | if ((pclass = FindPrinter(name)) != NULL && |
764 | !(pclass->type & CUPS_PRINTER_IMPLICIT)) | |
782359ca | 765 | { |
766 | /* | |
767 | * Can't use same name as printer; add "Any" to the front of the | |
768 | * name... | |
769 | */ | |
770 | ||
771 | strcpy(name, "Any"); | |
772 | strncpy(name + 3, p->name, len); | |
773 | name[len + 3] = '\0'; | |
eef5ad1b | 774 | offset = 3; |
782359ca | 775 | } |
776 | ||
8b43895a | 777 | first = p; |
778 | } | |
779 | } | |
780 | } | |
fd8b1cf8 | 781 | } |
782 | ||
783 | ||
d6de4648 | 784 | /* |
785 | * 'SendBrowseList()' - Send new browsing information. | |
786 | */ | |
787 | ||
fd8b1cf8 | 788 | void |
789 | SendBrowseList(void) | |
790 | { | |
d6de4648 | 791 | int i; /* Looping var */ |
792 | printer_t *p, /* Current printer */ | |
793 | *np; /* Next printer */ | |
f9d6449d | 794 | time_t ut, /* Minimum update time */ |
795 | to; /* Timeout time */ | |
d6de4648 | 796 | int bytes; /* Length of packet */ |
a2c6b8b1 | 797 | char packet[1453]; |
d6de4648 | 798 | /* Browse data packet */ |
799 | ||
800 | ||
be0ad10c | 801 | if (!Browsing) |
f63a2256 | 802 | return; |
803 | ||
d6de4648 | 804 | /* |
805 | * Compute the update time... | |
806 | */ | |
807 | ||
f9d6449d | 808 | ut = time(NULL) - BrowseInterval; |
809 | to = time(NULL) - BrowseTimeout; | |
d6de4648 | 810 | |
811 | /* | |
812 | * Loop through all of the printers and send local updates as needed... | |
813 | */ | |
814 | ||
815 | for (p = Printers; p != NULL; p = np) | |
816 | { | |
817 | np = p->next; | |
818 | ||
819 | if (p->type & CUPS_PRINTER_REMOTE) | |
820 | { | |
821 | /* | |
822 | * See if this printer needs to be timed out... | |
823 | */ | |
824 | ||
f9d6449d | 825 | if (p->browse_time < to) |
e63d9801 | 826 | { |
5ea8888e | 827 | LogMessage(L_INFO, "Remote destination \"%s\" has timed out; deleting it...", |
d62e9bdd | 828 | p->name); |
d6de4648 | 829 | DeletePrinter(p); |
e63d9801 | 830 | } |
d6de4648 | 831 | } |
be0ad10c | 832 | else if (p->browse_time < ut && !(p->type & CUPS_PRINTER_IMPLICIT) && |
833 | BrowseInterval > 0) | |
d6de4648 | 834 | { |
835 | /* | |
836 | * Need to send an update... | |
837 | */ | |
838 | ||
839 | p->browse_time = time(NULL); | |
840 | ||
04de52f8 | 841 | snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n", |
a2c6b8b1 | 842 | p->type | CUPS_PRINTER_REMOTE, p->state, p->uri, |
843 | p->location, p->info, p->make_model); | |
844 | ||
d6de4648 | 845 | bytes = strlen(packet); |
05156f4e | 846 | LogMessage(L_DEBUG2, "SendBrowseList: (%d bytes) %s", bytes, packet); |
d6de4648 | 847 | |
848 | /* | |
849 | * Send a packet to each browse address... | |
850 | */ | |
851 | ||
852 | for (i = 0; i < NumBrowsers; i ++) | |
16b0a852 | 853 | if (sendto(BrowseSocket, packet, bytes, 0, |
854 | (struct sockaddr *)Browsers + i, sizeof(Browsers[0])) <= 0) | |
f63a2256 | 855 | { |
5ea8888e | 856 | LogMessage(L_ERROR, "SendBrowseList: sendto failed for browser %d - %s.", |
fd3ece61 | 857 | i + 1, strerror(errno)); |
f63a2256 | 858 | LogMessage(L_ERROR, "Browsing turned off."); |
859 | ||
860 | StopBrowsing(); | |
861 | Browsing = 0; | |
862 | return; | |
863 | } | |
d6de4648 | 864 | } |
865 | } | |
fd8b1cf8 | 866 | } |
a129ddbd | 867 | |
868 | ||
869 | /* | |
03081fd2 | 870 | * 'StartPolling()' - Start polling servers as needed. |
871 | */ | |
872 | ||
873 | void | |
874 | StartPolling(void) | |
875 | { | |
e5ebb675 | 876 | int i; /* Looping var */ |
877 | dirsvc_poll_t *poll; /* Current polling server */ | |
878 | int pid; /* New process ID */ | |
879 | char sport[10]; /* Server port */ | |
880 | char bport[10]; /* Browser port */ | |
881 | char interval[10]; /* Poll interval */ | |
882 | ||
883 | ||
884 | sprintf(bport, "%d", BrowsePort); | |
b1ac1113 | 885 | |
886 | if (BrowseInterval) | |
887 | sprintf(interval, "%d", BrowseInterval); | |
888 | else | |
889 | strcpy(interval, "30"); | |
e5ebb675 | 890 | |
891 | for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++) | |
892 | { | |
893 | sprintf(sport, "%d", poll->port); | |
894 | ||
895 | if ((pid = fork()) == 0) | |
896 | { | |
897 | /* | |
898 | * Child... | |
899 | */ | |
900 | ||
5aeb433c | 901 | if (getuid() == 0) |
902 | { | |
903 | /* | |
904 | * Running as root, so change to non-priviledged user... | |
905 | */ | |
906 | ||
907 | if (setgid(Group)) | |
908 | exit(errno); | |
909 | ||
910 | if (setuid(User)) | |
911 | exit(errno); | |
912 | } | |
913 | ||
914 | /* | |
915 | * Reset group membership to just the main one we belong to. | |
916 | */ | |
917 | ||
918 | setgroups(0, NULL); | |
919 | ||
920 | /* | |
921 | * Execute the polling daemon... | |
922 | */ | |
e5ebb675 | 923 | |
924 | execl(CUPS_SERVERBIN "/daemon/cups-polld", "cups-polld", poll->hostname, | |
925 | sport, interval, bport, NULL); | |
926 | exit(errno); | |
927 | } | |
928 | else if (pid < 0) | |
929 | { | |
930 | LogMessage(L_ERROR, "StartPolling: Unable to fork polling daemon - %s", | |
931 | strerror(errno)); | |
932 | poll->pid = 0; | |
933 | break; | |
934 | } | |
935 | else | |
936 | { | |
937 | poll->pid = pid; | |
938 | LogMessage(L_DEBUG, "StartPolling: Started polling daemon for %s:%d, pid = %d", | |
939 | poll->hostname, poll->port, pid); | |
940 | } | |
941 | } | |
03081fd2 | 942 | } |
943 | ||
944 | ||
945 | /* | |
946 | * 'StopPolling()' - Stop polling servers as needed. | |
947 | */ | |
948 | ||
949 | void | |
950 | StopPolling(void) | |
951 | { | |
e5ebb675 | 952 | int i; /* Looping var */ |
953 | dirsvc_poll_t *poll; /* Current polling server */ | |
954 | ||
955 | ||
956 | for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++) | |
957 | if (poll->pid) | |
958 | kill(poll->pid, SIGTERM); | |
03081fd2 | 959 | } |
960 | ||
961 | ||
962 | /* | |
b5cb0608 | 963 | * End of "$Id: dirsvc.c,v 1.73.2.2 2001/05/13 18:38:35 mike Exp $". |
a129ddbd | 964 | */ |