]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/dirsvc.c
Security fixes - scanf, sprintf, strcpy.
[thirdparty/cups.git] / scheduler / dirsvc.c
CommitLineData
a129ddbd 1/*
1a5606a3 2 * "$Id: dirsvc.c,v 1.41 1999/09/17 19:11:46 mike Exp $"
a129ddbd 3 *
d6de4648 4 * Directory services routines for the Common UNIX Printing System (CUPS).
a129ddbd 5 *
a9de544f 6 * Copyright 1997-1999 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.
a129ddbd 30 */
31
32/*
33 * Include necessary headers...
34 */
35
fd8b1cf8 36#include "cupsd.h"
37
38
d6de4648 39/*
40 * 'StartBrowsing()' - Start sending and receiving broadcast information.
41 */
42
fd8b1cf8 43void
44StartBrowsing(void)
45{
d6de4648 46 int val; /* Socket option value */
47 struct sockaddr_in addr; /* Broadcast address */
48
49
8828fd5f 50 if (!Browsing)
d6de4648 51 return;
52
53 /*
54 * Create the broadcast socket...
55 */
56
900b10ea 57 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
d6de4648 58 {
59 LogMessage(LOG_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.",
60 strerror(errno));
61 return;
62 }
63
64 /*
900b10ea 65 * Set the "broadcast" flag...
d6de4648 66 */
67
68 val = 1;
e9e40963 69 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
fd3ece61 70 {
71 LogMessage(LOG_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.",
72 strerror(errno));
73
74#if defined(WIN32) || defined(__EMX__)
75 closesocket(BrowseSocket);
76#else
77 close(BrowseSocket);
78#endif /* WIN32 || __EMX__ */
79
80 BrowseSocket = -1;
81 return;
82 }
d6de4648 83
d6de4648 84 /*
85 * Bind the socket to browse port...
86 */
87
d6de4648 88 memset(&addr, 0, sizeof(addr));
89 addr.sin_addr.s_addr = htonl(INADDR_ANY);
90 addr.sin_family = AF_INET;
91 addr.sin_port = htons(BrowsePort);
92
16b0a852 93 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
d6de4648 94 {
95 LogMessage(LOG_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.",
96 strerror(errno));
97
98#if defined(WIN32) || defined(__EMX__)
99 closesocket(BrowseSocket);
100#else
101 close(BrowseSocket);
102#endif /* WIN32 || __EMX__ */
103
104 BrowseSocket = -1;
105 return;
106 }
107
108 /*
109 * Finally, add the socket to the input selection set...
110 */
111
112 FD_SET(BrowseSocket, &InputSet);
fd8b1cf8 113}
114
115
d6de4648 116/*
117 * 'StopBrowsing()' - Stop sending and receiving broadcast information.
118 */
119
fd8b1cf8 120void
121StopBrowsing(void)
122{
8828fd5f 123 if (!Browsing)
d6de4648 124 return;
125
126 /*
127 * Close the socket and remove it from the input selection set.
128 */
129
3c7bb4a2 130 if (BrowseSocket >= 0)
131 {
d6de4648 132#if defined(WIN32) || defined(__EMX__)
3c7bb4a2 133 closesocket(BrowseSocket);
d6de4648 134#else
3c7bb4a2 135 close(BrowseSocket);
d6de4648 136#endif /* WIN32 || __EMX__ */
137
3c7bb4a2 138 FD_CLR(BrowseSocket, &InputSet);
139 }
fd8b1cf8 140}
141
142
d6de4648 143/*
144 * 'UpdateBrowseList()' - Update the browse lists for any new browse data.
145 */
146
fd8b1cf8 147void
148UpdateBrowseList(void)
149{
8b43895a 150 int i; /* Looping var */
eef5ad1b 151 int len, /* Length of name string */
152 offset; /* Offset in name string */
d6de4648 153 int bytes; /* Number of bytes left */
154 char packet[1540]; /* Broadcast packet */
155 cups_ptype_t type; /* Printer type */
156 ipp_pstate_t state; /* Printer state */
157 char uri[HTTP_MAX_URI], /* Printer URI */
158 method[HTTP_MAX_URI], /* Method portion of URI */
159 username[HTTP_MAX_URI], /* Username portion of URI */
160 host[HTTP_MAX_URI], /* Host portion of URI */
161 resource[HTTP_MAX_URI]; /* Resource portion of URI */
162 int port; /* Port portion of URI */
163 char name[IPP_MAX_NAME], /* Name of printer */
8b43895a 164 *hptr, /* Pointer into hostname */
165 *sptr; /* Pointer into ServerName */
166 printer_t *p, /* Printer information */
167 *pclass, /* Printer class */
168 *first; /* First printer in class */
d6de4648 169
170
171 /*
172 * Read a packet from the browse socket...
173 */
174
18d7d592 175#ifdef DEBUG
176 struct sockaddr_in addr;
18d7d592 177
178
179 len = sizeof(addr);
16b0a852 180 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet), 0,
181 (struct sockaddr *)&addr, &len)) <= 0)
18d7d592 182 {
1a5606a3 183 LogMessage(LOG_ERROR, "Browse recv failed - %s.",
18d7d592 184 strerror(errno));
1a5606a3 185 LogMessage(LOG_ERROR, "Browsing turned off.");
186
187 StopBrowsing();
188 Browsing = 0;
18d7d592 189 return;
190 }
191
192 packet[bytes] = '\0';
193 printf("UpdateBrowseList: (%d bytes from %08x) %s", bytes,
194 ntohl(addr.sin_addr.s_addr), packet);
195#else
d6de4648 196 if ((bytes = recv(BrowseSocket, packet, sizeof(packet), 0)) <= 0)
f9bacabb 197 {
1a5606a3 198 LogMessage(LOG_ERROR, "Browse recv failed - %s.",
8828fd5f 199 strerror(errno));
1a5606a3 200 LogMessage(LOG_ERROR, "Browsing turned off.");
201
202 StopBrowsing();
203 Browsing = 0;
d6de4648 204 return;
f9bacabb 205 }
d6de4648 206
207 packet[bytes] = '\0';
18d7d592 208#endif /* DEBUG */
d6de4648 209
210 if (sscanf(packet, "%x%x%s", &type, &state, uri) != 3)
211 {
212 LogMessage(LOG_WARN, "UpdateBrowseList: Garbled browse packet - %s",
213 packet);
214 return;
215 }
216
a8b216d5 217 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n", type, state, uri));
218
d6de4648 219 /*
220 * Pull the URI apart to see if this is a local or remote printer...
221 */
222
223 httpSeparate(uri, method, username, host, &port, resource);
224
a8b216d5 225 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
226
d6de4648 227 if (strcasecmp(host, ServerName) == 0)
228 return;
229
230 /*
231 * OK, this isn't a local printer; see if we already have it listed in
232 * the Printers list, and add it if not...
233 */
234
8b43895a 235 hptr = strchr(host, '.');
236 sptr = strchr(ServerName, '.');
237
238 if (hptr != NULL && sptr != NULL &&
239 strcasecmp(hptr, sptr) == 0)
240 *hptr = '\0';
d6de4648 241
c7fa9d06 242 if (type & CUPS_PRINTER_CLASS)
d6de4648 243 {
244 /*
c7fa9d06 245 * Remote destination is a class...
d6de4648 246 */
247
c7fa9d06 248 if (strncmp(resource, "/classes/", 9) == 0)
a71f40c4 249 sprintf(name, "%s@%s", resource + 9, host);
c7fa9d06 250 else
251 return;
252
253 if ((p = FindClass(name)) == NULL)
a71f40c4 254 if ((p = FindClass(resource + 9)) != NULL)
eef5ad1b 255 {
a71f40c4 256 if (strcasecmp(p->hostname, host) != 0)
257 {
258 /*
259 * Nope, this isn't the same host; if the hostname isn't the local host,
260 * add it to the other class and then find a class using the full host
261 * name...
262 */
263
18d7d592 264 if (p->type & CUPS_PRINTER_REMOTE)
a71f40c4 265 {
266 strcat(p->name, "@");
267 strcat(p->name, p->hostname);
23050703 268 SetPrinterAttrs(p);
1cab4605 269 SortPrinters();
a71f40c4 270 }
271
272 p = NULL;
273 }
eef5ad1b 274 }
275 else
276 strcpy(name, resource + 9);
a71f40c4 277
278 if (p == NULL)
c7fa9d06 279 {
280 /*
281 * Class doesn't exist; add it...
282 */
d6de4648 283
782359ca 284 p = AddClass(name);
c7fa9d06 285
286 /*
782359ca 287 * Force the URI to point to the real server...
c7fa9d06 288 */
289
5057ad3b 290 p->type = type;
c7fa9d06 291 strcpy(p->uri, uri);
292 strcpy(p->device_uri, uri);
67a6c918 293 strcpy(p->hostname, host);
5057ad3b 294 SetPrinterAttrs(p);
c7fa9d06 295 }
296 }
297 else
298 {
d6de4648 299 /*
c7fa9d06 300 * Remote destination is a printer...
d6de4648 301 */
302
c7fa9d06 303 if (strncmp(resource, "/printers/", 10) == 0)
a71f40c4 304 sprintf(name, "%s@%s", resource + 10, host);
c7fa9d06 305 else
306 return;
307
308 if ((p = FindPrinter(name)) == NULL)
a71f40c4 309 if ((p = FindPrinter(resource + 10)) != NULL)
eef5ad1b 310 {
a71f40c4 311 if (strcasecmp(p->hostname, host) != 0)
312 {
313 /*
314 * Nope, this isn't the same host; if the hostname isn't the local host,
315 * add it to the other printer and then find a printer using the full host
316 * name...
317 */
318
18d7d592 319 if (p->type & CUPS_PRINTER_REMOTE)
a71f40c4 320 {
321 strcat(p->name, "@");
322 strcat(p->name, p->hostname);
23050703 323 SetPrinterAttrs(p);
1cab4605 324 SortPrinters();
a71f40c4 325 }
326
327 p = NULL;
328 }
eef5ad1b 329 }
330 else
331 strcpy(name, resource + 10);
a71f40c4 332
333 if (p == NULL)
c7fa9d06 334 {
335 /*
336 * Printer doesn't exist; add it...
337 */
338
339 p = AddPrinter(name);
340
341 /*
5057ad3b 342 * Force the URI to point to the real server...
c7fa9d06 343 */
344
5057ad3b 345 p->type = type;
c7fa9d06 346 strcpy(p->uri, uri);
347 strcpy(p->device_uri, uri);
67a6c918 348 strcpy(p->hostname, host);
5057ad3b 349 SetPrinterAttrs(p);
c7fa9d06 350 }
d6de4648 351 }
352
353 /*
354 * Update the state...
355 */
356
f925c8de 357 p->type = type;
d6de4648 358 p->state = state;
0948b55b 359 p->accepting = state != IPP_PRINTER_STOPPED;
d6de4648 360 p->browse_time = time(NULL);
8b43895a 361
fb00e262 362 /*
4621b86f 363 * See if we have a default printer... If not, make the first printer the
364 * default.
fb00e262 365 */
366
367 if (DefaultPrinter == NULL && Printers != NULL)
368 DefaultPrinter = Printers;
369
8b43895a 370 /*
371 * Do auto-classing if needed...
372 */
373
374 if (ImplicitClasses)
375 {
376 /*
377 * Loop through all available printers and create classes as needed...
378 */
379
eef5ad1b 380 for (p = Printers, len = 0, offset = 0; p != NULL; p = p->next)
8b43895a 381 {
382 /*
383 * Skip classes...
384 */
385
386 if (p->type & CUPS_PRINTER_CLASS)
387 {
388 len = 0;
389 continue;
390 }
391
392 /*
393 * If len == 0, get the length of this printer name up to the "@"
394 * sign (if any).
395 */
396
397 if (len > 0 &&
eef5ad1b 398 strncasecmp(p->name, name + offset, len) == 0 &&
8b43895a 399 (p->name[len] == '\0' || p->name[len] == '@'))
400 {
401 /*
402 * We have more than one printer with the same name; see if
403 * we have a class, and if this printer is a member...
404 */
405
406 if ((pclass = FindClass(name)) == NULL)
18d7d592 407 {
4139b718 408 /*
409 * Need to add the class...
410 */
411
8b43895a 412 pclass = AddClass(name);
4139b718 413 pclass->type |= CUPS_PRINTER_IMPLICIT;
414 pclass->accepting = 1;
415 pclass->state = IPP_PRINTER_IDLE;
416
417 SetPrinterAttrs(pclass);
20da3efb 418
419 DEBUG_printf(("Added new class \"%s\", type = %x\n", name,
420 pclass->type));
18d7d592 421 }
8b43895a 422
423 if (first != NULL)
424 {
425 for (i = 0; i < pclass->num_printers; i ++)
426 if (pclass->printers[i] == first)
427 break;
428
429 if (i >= pclass->num_printers)
430 AddPrinterToClass(pclass, first);
431
432 first = NULL;
433 }
434
435 for (i = 0; i < pclass->num_printers; i ++)
436 if (pclass->printers[i] == p)
437 break;
438
439 if (i >= pclass->num_printers)
440 AddPrinterToClass(pclass, p);
441 }
442 else
443 {
444 /*
445 * First time around; just get name length and mark it as first
446 * in the list...
447 */
448
449 if ((hptr = strchr(p->name, '@')) != NULL)
450 len = hptr - p->name;
451 else
452 len = strlen(p->name);
453
782359ca 454 strncpy(name, p->name, len);
455 name[len] = '\0';
eef5ad1b 456 offset = 0;
782359ca 457
458 if (FindPrinter(name) != NULL)
459 {
460 /*
461 * Can't use same name as printer; add "Any" to the front of the
462 * name...
463 */
464
465 strcpy(name, "Any");
466 strncpy(name + 3, p->name, len);
467 name[len + 3] = '\0';
eef5ad1b 468 offset = 3;
782359ca 469 }
470
8b43895a 471 first = p;
472 }
473 }
474 }
fd8b1cf8 475}
476
477
d6de4648 478/*
479 * 'SendBrowseList()' - Send new browsing information.
480 */
481
fd8b1cf8 482void
483SendBrowseList(void)
484{
d6de4648 485 int i; /* Looping var */
486 printer_t *p, /* Current printer */
487 *np; /* Next printer */
f9d6449d 488 time_t ut, /* Minimum update time */
489 to; /* Timeout time */
d6de4648 490 int bytes; /* Length of packet */
491 char packet[1540];
492 /* Browse data packet */
493
494
495 /*
496 * Compute the update time...
497 */
498
f9d6449d 499 ut = time(NULL) - BrowseInterval;
500 to = time(NULL) - BrowseTimeout;
d6de4648 501
502 /*
503 * Loop through all of the printers and send local updates as needed...
504 */
505
506 for (p = Printers; p != NULL; p = np)
507 {
508 np = p->next;
509
510 if (p->type & CUPS_PRINTER_REMOTE)
511 {
512 /*
513 * See if this printer needs to be timed out...
514 */
515
f9d6449d 516 if (p->browse_time < to)
e63d9801 517 {
518 DEBUG_printf(("Printer \"%s\" has timed out (%d < %d...)\n",
519 p->name, p->browse_time, to));
d6de4648 520 DeletePrinter(p);
e63d9801 521 }
d6de4648 522 }
18d7d592 523 else if (p->browse_time < ut && !(p->type & CUPS_PRINTER_IMPLICIT))
d6de4648 524 {
525 /*
526 * Need to send an update...
527 */
528
529 p->browse_time = time(NULL);
530
ae5f9b38 531 sprintf(packet, "%x %x %s\n", p->type | CUPS_PRINTER_REMOTE, p->state,
532 p->uri);
d6de4648 533 bytes = strlen(packet);
8828fd5f 534 DEBUG_printf(("SendBrowseList: (%d bytes) %s", bytes, packet));
d6de4648 535
536 /*
537 * Send a packet to each browse address...
538 */
539
540 for (i = 0; i < NumBrowsers; i ++)
16b0a852 541 if (sendto(BrowseSocket, packet, bytes, 0,
542 (struct sockaddr *)Browsers + i, sizeof(Browsers[0])) <= 0)
8828fd5f 543 LogMessage(LOG_ERROR, "SendBrowseList: sendto failed for browser %d - %s.",
fd3ece61 544 i + 1, strerror(errno));
d6de4648 545 }
546 }
fd8b1cf8 547}
a129ddbd 548
549
550/*
1a5606a3 551 * End of "$Id: dirsvc.c,v 1.41 1999/09/17 19:11:46 mike Exp $".
a129ddbd 552 */