Bug Summary

File:bucoord/dsvs.c
Location:line 590, column 6
Description:Dereference of null pointer (loaded from variable 'curptr')

Annotated Source Code

1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10/*
11 * ALL RIGHTS RESERVED
12 *
13 * (C) COPYRIGHT IBM CORPORATION 1987, 1998
14 * LICENSED MATERIALS - PROPERTY OF IBM
15 */
16
17
18#include <afsconfig.h>
19#include <afs/param.h>
20
21#include <roken.h>
22
23#include <afs/cmd.h>
24#include <afs/com_err.h>
25#include <afs/bubasics.h>
26
27#include "bc.h"
28#include "bucoord_internal.h"
29
30struct ubik_client *cstructp; /*Ptr to Ubik client structure */
31
32static int FreeVolumeEntryList(struct bc_volumeEntry *aentry);
33static int FreeVolumeEntry(struct bc_volumeEntry *aentry);
34
35/* Code to maintain dump schedule and volume set abstractions.
36 * A volume set looks like this:
37 * vsname: servername partition-name <volume list>*
38 * A dump schedule looks like this:
39 * dsname: vsname period parent-ds
40 */
41
42/* get partition id from a name */
43afs_int32
44bc_GetPartitionID(char *aname, afs_int32 *aval)
45{
46
47 /*bc_GetPartitionID */
48
49 char tc;
50 char ascii[3];
51
52 /* special-case "anything" */
53 if (strcmp(aname, ".*") == 0) {
54 *aval = -1;
55 return 0;
56 }
57 tc = *aname;
58 if (tc == 0)
59 return -1; /* unknown */
60 /* numbers go straight through */
61 if (tc >= '0' && tc <= '9') {
62 *aval = bc_SafeATOI(aname);
63 return 0;
64 }
65 /* otherwise check for vicepa or /vicepa, or just plain "a" */
66 ascii[2] = 0;
67 if (strlen(aname) <= 2) {
68 strcpy(ascii, aname);
69 } else if (!strncmp(aname, "/vicep", 6)) {
70 strncpy(ascii, aname + 6, 2);
71 } else if (!strncmp(aname, "vicep", 5)) {
72 strncpy(ascii, aname + 5, 2);
73 } else
74 return (BC_NOPARTITION(156288011L)); /* bad partition name */
75 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
76 * from 0. Do the appropriate conversion */
77 if (ascii[1] == 0) {
78 /* one char name, 0..25 */
79 if (ascii[0] < 'a' || ascii[0] > 'z')
80 return -1; /* wrongo */
81 *aval = ascii[0] - 'a';
82 return 0;
83 } else {
84 /* two char name, 26 .. <whatever> */
85 if (ascii[0] < 'a' || ascii[0] > 'z')
86 return -1; /* wrongo */
87 if (ascii[1] < 'a' || ascii[1] > 'z')
88 return -1; /* just as bad */
89 *aval = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
90 return 0;
91 }
92} /*bc_GetPartitionID */
93
94/*----------------------------------------------------------------------------
95 * bc_ParseHost
96 *
97 * Description:
98 * Given a string containing a host name or its IP address in dot notation, fill in
99 * the given sockaddr with all the corresponding info.
100 *
101 * Arguments:
102 * aname : Host name or dotted IP address.
103 * asockaddr: Ptr to sockaddr to fill in for the above host.
104 *
105 * Returns:
106 * 0 if everything went well,
107 * -1 if it couldn't be translated.
108 *
109 * Environment:
110 * Nothing interesting.
111 *
112 * Side Effects:
113 * None.
114 *----------------------------------------------------------------------------
115 */
116
117int
118bc_ParseHost(char *aname, struct sockaddr_in *asockaddr)
119
120{ /*bc_ParseHost */
121
122 struct hostent *th; /*Host entry */
123 afs_uint32 addr; /*Converted address */
124 afs_int32 b1, b2, b3, b4; /*Byte-sized address chunks */
125 afs_int32 code; /*Return code from sscanf() */
126 afs_int32 tmp1, tmp2;
127
128 /*
129 * Try to parse the given name as a dot-notation IP address first.
130 */
131 code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
132 if (code == 4) {
133 /*
134 * Four chunks were read, so we assume success. Construct the socket.
135 */
136#ifdef STRUCT_SOCKADDR_HAS_SA_LEN1
137 asockaddr->sin_len = sizeof(struct sockaddr_in);
138#endif
139 asockaddr->sin_family = AF_INET2;
140 asockaddr->sin_port = 0;
141 addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
142 memcpy(&tmp1, &addr, sizeof(afs_int32));
143 tmp2 = htonl(tmp1)(__builtin_constant_p(tmp1) ? ((((__uint32_t)(tmp1)) >>
24) | ((((__uint32_t)(tmp1)) & (0xff << 16)) >>
8) | ((((__uint32_t)(tmp1)) & (0xff << 8)) <<
8) | (((__uint32_t)(tmp1)) << 24)) : __bswap32_var(tmp1
))
;
144 memcpy(&asockaddr->sin_addr.s_addr, &tmp2, sizeof(afs_int32));
145 return (0);
146 }
147
148 /*
149 * The given string isn't a dotted IP address. Try to map it as a host
150 * name, or leave it as a wild-card.
151 */
152
153 if (strcmp(aname, ".*") == 0) {
154 memset(asockaddr, 0, sizeof(struct sockaddr_in));
155 return 0;
156 }
157
158 th = gethostbyname(aname);
159 if (!th)
160 /*
161 * No such luck, return failure.
162 */
163 return (BC_NOHOST(156288010L));
164
165 /*
166 * We found a mapping; construct the socket.
167 */
168#ifdef STRUCT_SOCKADDR_HAS_SA_LEN1
169 asockaddr->sin_len = sizeof(struct sockaddr_in);
170#endif
171 asockaddr->sin_family = AF_INET2;
172 asockaddr->sin_port = 0;
173 memcpy(&tmp1, th->h_addrh_addr_list[0], sizeof(afs_int32));
174 tmp2 = htonl(tmp1)(__builtin_constant_p(tmp1) ? ((((__uint32_t)(tmp1)) >>
24) | ((((__uint32_t)(tmp1)) & (0xff << 16)) >>
8) | ((((__uint32_t)(tmp1)) & (0xff << 8)) <<
8) | (((__uint32_t)(tmp1)) << 24)) : __bswap32_var(tmp1
))
;
175 memcpy(&(asockaddr->sin_addr.s_addr), &tmp2,
176 sizeof(asockaddr->sin_addr.s_addr));
177 return (0);
178
179} /*bc_ParseHost */
180
181
182/* create an empty volume set, new items are added via bc_AddVolumeItem */
183int
184bc_CreateVolumeSet(struct bc_config *aconfig, char *avolName,
185 afs_int32 aflags)
186{
187 struct bc_volumeSet **tlast, *tset, *nset;
188
189 if (bc_FindVolumeSet(aconfig, avolName))
190 return -1; /* already exists */
191 /* move to end of the list */
192
193 nset = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
194 memset(nset, 0, sizeof(*nset));
195 nset->flags = aflags;
196 nset->name = (char *)malloc(strlen(avolName) + 1);
197 strcpy(nset->name, avolName);
198 if (aflags & VSFLAG_TEMPORARY1) {
199 /* Add to beginning of list */
200 nset->next = aconfig->vset;
201 aconfig->vset = nset;
202 } else {
203 /* Add to end of list */
204 for (tlast = &aconfig->vset, tset = *tlast; tset;
205 tlast = &tset->next, tset = *tlast);
206 *tlast = nset;
207 }
208 return 0;
209}
210
211static int
212FreeVolumeEntry(struct bc_volumeEntry *aentry)
213{
214 free(aentry->name);
215 free(aentry->serverName);
216 free(aentry->partname);
217 free(aentry);
218 return 0;
219}
220
221static int
222FreeVolumeEntryList(struct bc_volumeEntry *aentry)
223{
224 struct bc_volumeEntry *tnext;
225
226 while (aentry) {
227 tnext = aentry->next;
228 FreeVolumeEntry(aentry);
229 aentry = tnext;
230 }
231 return 0;
232}
233
234
235
236void
237FreeVolumeSet(struct bc_volumeSet *avset)
238{
239 FreeVolumeEntryList(avset->ventries);
240 free(avset->name);
241 free(avset);
242}
243
244int
245bc_DeleteVolumeSet(struct bc_config *aconfig, char *avolName,
246 afs_int32 *flags)
247{
248 struct bc_volumeSet **tlast, *tset;
249
250 *flags = 0;
251 tlast = &aconfig->vset;
252 for (tset = *tlast; tset; tlast = &tset->next, tset = *tlast) {
253 if (strcmp(avolName, tset->name) == 0) {
254 *flags = tset->flags; /* Remember flags */
255 *tlast = tset->next; /* Remove from chain */
256 FreeVolumeSet(tset); /* Free the volume set */
257 return 0;
258 }
259 }
260
261 /* if we get here, we didn't find the item */
262 return -1;
263}
264
265int
266bc_DeleteVolumeItem(struct bc_config *aconfig, char *avolName,
267 afs_int32 anumber)
268{
269 afs_int32 i;
270 struct bc_volumeSet *tset;
271 struct bc_volumeEntry *tentry, **tlast;
272
273 tset = bc_FindVolumeSet(aconfig, avolName);
274 if (!tset)
275 return -1;
276
277 tlast = &tset->ventries;
278 for (i = 1, tentry = *tlast; tentry;
279 tlast = &tentry->next, tentry = *tlast, i++) {
280 if (anumber == i) {
281 /* found entry we want */
282 *tlast = tentry->next;
283 FreeVolumeEntry(tentry);
284 return 0;
285 }
286 }
287 return -2; /* not found */
288}
289
290int
291bc_AddVolumeItem(struct bc_config *aconfig, char *avolName, char *ahost,
292 char *apart, char *avol)
293{
294 struct bc_volumeSet *tset;
295 struct bc_volumeEntry **tlast, *tentry;
296 afs_int32 code;
297
298 tset = bc_FindVolumeSet(aconfig, avolName);
299 if (!tset)
300 return (BC_NOVOLSET(156288007L));
301
302 /* otherwise append this item to the end of the real list */
303 tlast = &tset->ventries;
304
305 /* move to end of the list */
306 for (tentry = *tlast; tentry; tlast = &tentry->next, tentry = *tlast);
307 tentry = (struct bc_volumeEntry *)malloc(sizeof(struct bc_volumeEntry));
308 memset(tentry, 0, sizeof(*tentry));
309 tentry->serverName = (char *)malloc(strlen(ahost) + 1);
310 strcpy(tentry->serverName, ahost);
311 tentry->partname = (char *)malloc(strlen(apart) + 1);
312 strcpy(tentry->partname, apart);
313 tentry->name = (char *)malloc(strlen(avol) + 1);
314 strcpy(tentry->name, avol);
315
316 code = bc_ParseHost(tentry->serverName, &tentry->server);
317 if (code)
318 return (code);
319
320 code = bc_GetPartitionID(tentry->partname, &tentry->partition);
321 if (code)
322 return (code);
323
324 *tlast = tentry; /* thread on the list */
325 return 0;
326}
327
328struct bc_volumeSet *
329bc_FindVolumeSet(struct bc_config *aconfig, char *aname)
330{ /*bc_FindVolumeSet */
331
332 struct bc_volumeSet *tvs;
333
334 for (tvs = aconfig->vset; tvs; tvs = tvs->next) {
335 if (!strcmp(tvs->name, aname))
336 return (tvs);
337 }
338 return (struct bc_volumeSet *)0;
339
340} /*bc_FindVolumeSet */
341
342/* ------------------------------------
343 * dumpschedule management code
344 * ------------------------------------
345 */
346
347/* bc_CreateDumpSchedule
348 * Add another node to the dump schedule.
349 * entry:
350 * aconfig - in core configuration structures
351 * adumpName - name of new dump node
352 * expDate - expiration date
353 * expType - absolute or relative
354 */
355
356int
357bc_CreateDumpSchedule(struct bc_config *aconfig, char *adumpName,
358 afs_int32 expDate, afs_int32 expType)
359{
360 struct bc_dumpSchedule *tdump;
361 struct bc_dumpSchedule *parent, *node;
362 afs_int32 code;
363
364 if (strcmp(adumpName, "none") == 0)
365 return -2; /* invalid name */
366
367 code = FindDump(aconfig, adumpName, &parent, &node);
368 if (code == 0)
369 return -1; /* node already exists */
370 else if (code != -1)
371 return -2; /* name specification error */
372
373 tdump = (struct bc_dumpSchedule *)malloc(sizeof(struct bc_dumpSchedule));
374 memset(tdump, 0, sizeof(*tdump));
375
376 /* prepend this node to the dump schedule list */
377 tdump->next = aconfig->dsched;
378 aconfig->dsched = tdump;
379
380 /* save the name of this dump node */
381 tdump->name = (char *)malloc(strlen(adumpName) + 1);
382 strcpy(tdump->name, adumpName);
383
384 /* expiration information */
385 tdump->expDate = expDate;
386 tdump->expType = expType;
387
388 bc_ProcessDumpSchedule(aconfig); /* redo tree */
389 return 0;
390}
391
392
393/* Recursively remove this node and all of its children from aconfig's
394 * list of dumps. Note that this leaves the sibling pointers damaged (pointing
395 * to strange places), so we must call bc_ProcessDumpSchedule when we're done.
396 */
397int
398bc_DeleteDumpScheduleAddr(struct bc_config *aconfig,
399 struct bc_dumpSchedule *adumpAddr)
400{
401 struct bc_dumpSchedule **tlast, *tdump;
402 struct bc_dumpSchedule *tnext;
403
404 /* knock off all children first */
405 for (tdump = adumpAddr->firstChild; tdump; tdump = tnext) {
406 /* extract next ptr now, since will be freed by recursive call below */
407 tnext = tdump->nextSibling;
408 bc_DeleteDumpScheduleAddr(aconfig, tdump);
409 }
410
411 /* finally, remove us from the list of good dudes */
412 for (tlast = &aconfig->dsched, tdump = *tlast; tdump;
413 tlast = &tdump->next, tdump = *tlast) {
414 if (tdump == adumpAddr) {
415 /* found the one we're looking for */
416 *tlast = tdump->next; /* remove us from basic list */
417 free(tdump->name);
418 free(tdump);
419 return 0;
420 }
421 }
422 return 0;
423}
424
425/* bc_FindDumpSchedule
426 * Finds dump schedule aname by doing a linear search
427 * entry:
428 * aconfig - handle for incore configuration tables
429 * aname - (path)name to match on
430 * exit:
431 * 0 for failure, ptr to dumpschedule for success
432 */
433
434struct bc_dumpSchedule *
435bc_FindDumpSchedule(struct bc_config *aconfig, char *aname)
436{
437 struct bc_dumpSchedule *tds;
438 for (tds = aconfig->dsched; tds; tds = tds->next) {
439 if (!strcmp(tds->name, aname))
440 return tds;
441 }
442 return (struct bc_dumpSchedule *)0;
443}
444
445/* bc_DeleteDumpSchedule
446 * Delete dump node adumpName from the dump schedule
447 */
448
449int
450bc_DeleteDumpSchedule(struct bc_config *aconfig, char *adumpName)
451{
452 struct bc_dumpSchedule *tdump;
453
454 /* does a linear search of the dump schedules in order to find
455 * the one to delete
456 */
457 for (tdump = aconfig->dsched; tdump; tdump = tdump->next) {
458 if (strcmp(tdump->name, adumpName) == 0) {
459 /* found it, we can zap recursively */
460 bc_DeleteDumpScheduleAddr(aconfig, tdump);
461 /* tree's been pruned, but we have to recompute the internal pointers
462 * from first principles, since we didn't bother to maintain
463 * the sibling and children pointers during the call to delete
464 * the nodes */
465 bc_ProcessDumpSchedule(aconfig);
466 return 0;
467 }
468 }
469 /* if we make it here, there's no such dump schedule entry */
470 return -1;
471}
472
473
474/* bc_ProcessDumpSchedule
475 * Walk over the dump schedule list, building it into a tree. This
476 * algorithm is simple, but takes O(N*2) operations to run, with N=number
477 * of dump schedule nodes. It probably will never matter
478 */
479
480int
481bc_ProcessDumpSchedule(struct bc_config *aconfig)
482{
483 struct bc_dumpSchedule *tds;
484 struct bc_dumpSchedule *parentptr, *nodeptr;
485 int retval;
486
487 /* first, clear all the links on all entries so that this function
488 * may be called any number of times with no ill effects
489 */
490 for (tds = aconfig->dsched; tds; tds = tds->next) {
491 tds->parent = (struct bc_dumpSchedule *)0;
492 tds->nextSibling = (struct bc_dumpSchedule *)0;
493 tds->firstChild = (struct bc_dumpSchedule *)0;
494 }
495
496 for (tds = aconfig->dsched; tds; tds = tds->next) {
497 retval = FindDump(aconfig, tds->name, &parentptr, &nodeptr);
498 if (retval != 0) {
499 printf("bc_processdumpschedule: finddump returns %d\n", retval);
500 exit(1);
501 }
502
503 /* only need to do work if it is not a root node */
504 if (parentptr != 0) {
505 nodeptr->parent = parentptr;
506 nodeptr->nextSibling = parentptr->firstChild;
507 parentptr->firstChild = nodeptr;
508 }
509 }
510 return 0;
511}
512
513
514/* FindDump
515 * entry:
516 * exit:
517 * parentptr - set to parent node, if one exists
518 * nodeptr - set to node requested
519 *
520 * return values are:
521 * 0 - success, parentptr and nodeptr set appropriately
522 * -1 - node not found, parent exists if reqd. Will be 0 for root nodes.
523 * -2 - path search error. Some node on the path does not exist.
524 * -3 - name specification error
525 * notes:
526 * pathname checking should be done externally. In particular, trailing
527 * / symbols may return confusing error codes. (e.g on missing last
528 * node returns -2 rather than -1)
529 */
530
531int
532FindDump(struct bc_config *aconfig, char *nodeString,
533 struct bc_dumpSchedule **parentptr,
534 struct bc_dumpSchedule **nodeptr)
535{
536 struct bc_dumpSchedule *dsptr;
537 char *separator;
538 int matchLength;
539 char *curptr;
540
541 *parentptr = 0;
542 *nodeptr = 0;
543
544 /* ensure first char is correct separator */
545 if ((nodeString[0] != '/')
1
Taking false branch
546 || (strlen(&nodeString[0]) <= 1)
547 ) {
548 printf("FindDump: %s, error in dump name specification\n",
549 nodeString);
550 return (-3);
551 }
552
553 matchLength = 0;
554 curptr = &nodeString[1]; /* past first / */
555 separator = strchr(curptr, '/');
556 if (separator == 0)
2
Taking true branch
557 matchLength = strlen(curptr) + 1; /* +1 for leading / */
558 else
559 matchLength = (separator - &nodeString[0]);
560
561 /* printf("matchLength = %d\n", matchLength); */
562 while (1) {
3
Loop condition is true. Entering loop body
563 /* now search all the nodes for this name */
564 for (dsptr = aconfig->dsched; dsptr != 0; dsptr = dsptr->next) {
4
Loop condition is true. Entering loop body
565 /* printf("compare %s with %s for %d\n",
566 * dsptr->name, nodeString, matchLength); */
567 if (strlen(dsptr->name) != matchLength)
5
Taking false branch
568 continue;
569
570 if (strncmp(dsptr->name, nodeString, matchLength) == 0) {
6
Taking true branch
571 *nodeptr = dsptr;
572 break;
7
Execution continues on line 576
573 }
574 }
575
576 if (nodeString[matchLength] == 0) {
8
Taking false branch
577 /* last node in the path */
578 if (*nodeptr)
579 return (0); /* all ok */
580 else
581 /* node not found; parent exists for non root nodes */
582 return (-1);
583 }
584
585 if (*nodeptr == 0)
9
Taking false branch
586 /* failed to find a node in the path */
587 return (-2);
588
589 curptr = separator + 1;
590 if (*curptr == 0) {
10
Dereference of null pointer (loaded from variable 'curptr')
591 printf("FindDump: trailing / in %s\n", nodeString);
592 return (-3);
593 }
594
595 separator = strchr(curptr, '/');
596 if (separator == 0)
597 matchLength = strlen(&nodeString[0]);
598 else
599 matchLength = separator - &nodeString[0];
600
601 *parentptr = *nodeptr;
602 *nodeptr = 0;
603 }
604}