Bug Summary

File:update/server.c
Location:line 296, column 5
Description:Access to field 'maxProcs' results in a dereference of a null pointer (loaded from variable 'service')

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#include <afsconfig.h>
11#include <afs/param.h>
12#include <afs/stds.h>
13
14#include <afs/procmgmt.h>
15#include <roken.h>
16
17#ifdef AFS_NT40_ENV
18#include <WINNT/afsevent.h>
19#endif
20
21#ifdef AFS_AIX_ENV
22#include <sys/statfs.h>
23#endif
24
25#include <rx/xdr.h>
26#include <rx/rx.h>
27#include <rx/rxkad.h>
28#include <afs/cellconfig.h>
29#include <afs/afsutil.h>
30#include <afs/fileutil.h>
31#include <afs/com_err.h>
32
33#include "update.h"
34#include "global.h"
35
36static int AddObject(char **expPath, char *dir);
37static int PathInDirectory(char *dir, char *path);
38int update_SendFile(int, struct rx_call *, struct stat *);
39int update_SendDirInfo(char *, struct rx_call *, struct stat *,
40 char *origDir);
41
42struct afsconf_dir *cdir;
43int nDirs;
44char *dirName[MAXENTRIES20];
45int dirLevel[MAXENTRIES20];
46char *whoami;
47
48static int Quit(char *);
49
50int rxBind = 0;
51
52#define ADDRSPERSITE16 16 /* Same global is in rx/rx_user.c */
53afs_uint32 SHostAddrs[ADDRSPERSITE16];
54
55/* check whether caller is authorized to manage RX statistics */
56int
57update_rxstat_userok(struct rx_call *call)
58{
59 return afsconf_SuperUser(cdir, call, NULL((void *)0));
60}
61
62/*
63 * PathInDirectory() -- determine if path is in directory (or is directory)
64 */
65static int
66PathInDirectory(char *dir, char *path)
67{
68 int inDir = 0;
69 size_t dirLen;
70 char dirNorm[AFSDIR_PATH_MAX256], pathNorm[AFSDIR_PATH_MAX256];
71
72#ifdef AFS_NT40_ENV
73 /* case-insensitive comparison of normalized, same-flavor (short) paths */
74 DWORD status;
75
76 status = GetShortPathName(dir, dirNorm, AFSDIR_PATH_MAX256);
77 if (status == 0 || status > AFSDIR_PATH_MAX256) {
78 /* can't convert path to short version; just use long version */
79 strcpy(dirNorm, dir);
80 }
81 FilepathNormalize(dirNorm);
82
83 status = GetShortPathName(path, pathNorm, AFSDIR_PATH_MAX256);
84 if (status == 0 || status > AFSDIR_PATH_MAX256) {
85 /* can't convert path to short version; just use long version */
86 strcpy(pathNorm, path);
87 }
88 FilepathNormalize(pathNorm);
89
90 dirLen = strlen(dirNorm);
91
92 if (_strnicmp(dirNorm, pathNorm, dirLen) == 0) {
93 /* substrings match; path must match dir or be subdirectory */
94 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
95 inDir = 1;
96 }
97 }
98#else
99 /* case-sensitive comparison of normalized paths */
100 strcpy(dirNorm, dir);
101 FilepathNormalize(dirNorm);
102
103 strcpy(pathNorm, path);
104 FilepathNormalize(pathNorm);
105
106 dirLen = strlen(dirNorm);
107
108 if (strncmp(dirNorm, pathNorm, dirLen) == 0) {
109 /* substrings match; path must match dir or be subdirectory */
110 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
111 inDir = 1;
112 }
113 }
114#endif /* AFS_NT40_ENV */
115 return inDir;
116}
117
118int
119AuthOkay(struct rx_call *call, char *name)
120{
121 int i;
122 rxkad_level level;
123 afs_int32 code;
124 int matches;
125
126 /* Must be in 'UserList' to use */
127 if (!afsconf_SuperUser(cdir, call, NULL((void *)0)))
128 return 0;
129
130 if (rx_SecurityClassOf(rx_ConnectionOf(call))((((call)->conn))->securityIndex) == 2) {
131 code = rxkad_GetServerInfo(call->conn, &level, 0, 0, 0, 0, 0);
132 if (code)
133 return 0;
134 } else
135 level = 0;
136
137 matches = 0;
138 for (i = 0; i < nDirs; i++) {
139 if (PathInDirectory(dirName[i], name)) {
140 if (dirLevel[i] > level)
141 return 0;
142 matches++;
143 /* keep searching in case there's a more restrictive subtree
144 * specified later. */
145 }
146 }
147 if (nDirs && !matches)
148 return 0; /* if dirs spec., name must match */
149 return 1; /* okay or no dirs */
150}
151
152int
153osi_audit(void)
154{
155/* this sucks but it works for now.
156*/
157 return 0;
158}
159
160#ifndef AFS_NT40_ENV
161#include "AFS_component_version_number.c"
162#endif
163
164int
165main(int argc, char *argv[])
166{
167 struct rx_securityClass **securityClasses;
168 afs_int32 numClasses;
169 struct rx_service *service;
170 afs_uint32 host = htonl(INADDR_ANY)(__builtin_constant_p((u_int32_t)0x00000000) ? ((((__uint32_t
)((u_int32_t)0x00000000)) >> 24) | ((((__uint32_t)((u_int32_t
)0x00000000)) & (0xff << 16)) >> 8) | ((((__uint32_t
)((u_int32_t)0x00000000)) & (0xff << 8)) << 8
) | (((__uint32_t)((u_int32_t)0x00000000)) << 24)) : __bswap32_var
((u_int32_t)0x00000000))
;
171
172 int a = 0;
173 rxkad_level level;
174 rxkad_level newLevel;
175
176#ifdef AFS_AIX32_ENV
177 /*
178 * The following signal action for AIX is necessary so that in case of a
179 * crash (i.e. core is generated) we can include the user's data section
180 * in the core dump. Unfortunately, by default, only a partial core is
181 * generated which, in many cases, isn't too useful.
182 */
183 struct sigaction nsa;
184
185 sigemptyset(&nsa.sa_mask);
186 nsa.sa_handler__sigaction_u.__sa_handler = SIG_DFL((__sighandler_t *)0);
187 nsa.sa_flags = SA_FULLDUMP;
188 sigaction(SIGABRT6, &nsa, NULL((void *)0));
189 sigaction(SIGSEGV11, &nsa, NULL((void *)0));
190#endif
191
192 whoami = argv[0];
193
194#ifdef AFS_NT40_ENV
195 /* dummy signal call to force afsprocmgmt.dll to load on NT */
196 signal(SIGUSR130, SIG_DFL((__sighandler_t *)0));
197#endif
198
199 /* Initialize dirpaths */
200 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK0x2)) {
1
Taking false branch
201#ifdef AFS_NT40_ENV
202 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
203#endif
204 fprintf(stderr__stderrp, "%s: Unable to obtain AFS server directory.\n",
205 argv[0]);
206 exit(2);
207 }
208 nDirs = 0;
209 level = rxkad_clear0;
210
211 if (argc == 1) /* no arguments */
2
Taking true branch
212 goto usage;
3
Control jumps to line 235
213
214 /* support help flag */
215 if (strcmp("-help", argv[1]) == 0)
216 goto usage;
217 if (strcmp("help", argv[1]) == 0)
218 goto usage;
219
220 for (a = 1; a < argc; a++) {
4
Loop condition is false. Execution continues on line 249
221 if (argv[a][0] == '-') { /* parse options */
222 if (strcmp(argv[a], "-rxbind") == 0) {
223 rxBind = 1;
224 continue;
225 } else {
226 char arg[256];
227 lcstring(arg, argv[a], sizeof(arg));
228 newLevel = rxkad_StringToLevel(&argv[a][1]);
229 if (newLevel != -1) {
230 level = newLevel; /* set new level */
231 continue;
232 }
233 }
234 usage:
235 Quit("Usage: upserver [<directory>+] [-crypt <directory>+] [-clear <directory>+] [-auth <directory>+] [-rxbind] [-help]\n");
236 } else {
237 if (nDirs >= sizeof(dirName) / sizeof(dirName[0]))
238 Quit("Too many dirs");
239 if (AddObject(&dirName[nDirs], argv[a])) {
240 printf("%s: Unable to export dir %s. Skipping\n", whoami,
241 argv[a]);
242 continue;
243 }
244 dirLevel[nDirs] = level; /* remember current level */
245 nDirs++;
246 }
247 }
248
249 if (nDirs == 0) { /* Didn't find any directories to export */
5
Taking false branch
250 printf("%s: No directories to export. Quitting\n", whoami);
251 exit(1);
252 }
253
254 cdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATHgetDirPath(AFSDIR_SERVER_ETC_DIRPATH_ID));
255 if (cdir == 0) {
6
Taking false branch
256 fprintf(stderr__stderrp, "Can't get server configuration info (%s)\n",
257 AFSDIR_SERVER_ETC_DIRPATHgetDirPath(AFSDIR_SERVER_ETC_DIRPATH_ID));
258 exit(1);
259 }
260
261 if (rxBind) {
7
Taking false branch
262 afs_int32 ccode;
263 if (AFSDIR_SERVER_NETRESTRICT_FILEPATHgetDirPath(AFSDIR_SERVER_NETRESTRICT_FILEPATH_ID) ||
264 AFSDIR_SERVER_NETINFO_FILEPATHgetDirPath(AFSDIR_SERVER_NETINFO_FILEPATH_ID)) {
265 char reason[1024];
266 ccode = parseNetFiles(SHostAddrs, NULL((void *)0), NULL((void *)0),
267 ADDRSPERSITE16, reason,
268 AFSDIR_SERVER_NETINFO_FILEPATHgetDirPath(AFSDIR_SERVER_NETINFO_FILEPATH_ID),
269 AFSDIR_SERVER_NETRESTRICT_FILEPATHgetDirPath(AFSDIR_SERVER_NETRESTRICT_FILEPATH_ID));
270 } else
271 {
272 ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE16);
273 }
274 if (ccode == 1)
275 host = SHostAddrs[0];
276 }
277
278 /* Initialize Rx, telling it port number this server will use for its
279 * single service */
280 if (rx_InitHost(host, htons(AFSCONF_UPDATEPORT)(__builtin_constant_p(7008) ? (__uint16_t)(((__uint16_t)(7008
)) << 8 | ((__uint16_t)(7008)) >> 8) : __bswap16_var
(7008))
) < 0)
8
Taking false branch
281 Quit("rx_init");
282
283 afsconf_BuildServerSecurityObjects(cdir, &securityClasses, &numClasses);
284
285 if (securityClasses[2] == NULL((void *)0))
9
Taking false branch
286 Quit("rxkad_NewServerSecurityObject");
287
288 /* Instantiate a single UPDATE service. The rxgen-generated procedure
289 * which is called to decode requests is passed in here
290 * (UPDATE_ExecuteRequest). */
291 service =
292 rx_NewServiceHost(host, 0, UPDATE_SERVICEID4, "UPDATE", securityClasses,
293 numClasses, UPDATE_ExecuteRequest);
294 if (service == (struct rx_service *)0)
10
Taking true branch
295 Quit("rx_NewService");
296 rx_SetMaxProcs(service, 2)((service)->maxProcs = (2));
11
Within the expansion of the macro 'rx_SetMaxProcs':
a
Access to field 'maxProcs' results in a dereference of a null pointer (loaded from variable 'service')
297
298 /* allow super users to manage RX statistics */
299 rx_SetRxStatUserOk(update_rxstat_userok);
300
301 rx_StartServer(1); /* Donate this process to the server process pool */
302 Quit("StartServer returned?");
303 return 0;
304}
305
306/* fetch the file name and send it to the remote requester specified by call */
307
308int
309UPDATE_FetchFile(struct rx_call *call, char *name)
310{
311 int fd = -1;
312 int error = 0;
313 struct stat status;
314 char *reqObject;
315
316 /* construct a local path from a canonical (wire-format) path */
317 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
318 afs_com_err(whoami, error, "Unable to construct local path");
319 return UPDATE_ERROR1;
320 }
321
322 if (!AuthOkay(call, reqObject)) {
323 error = UPDATE_ERROR1;
324 } else {
325 fd = open(reqObject, O_RDONLY0x0000, 0);
326 if (fd < 0 || fstat(fd, &status) < 0) {
327 printf("Failed to open %s\n", reqObject);
328 error = UPDATE_ERROR1;
329 }
330 if (!error)
331 error = update_SendFile(fd, call, &status);
332 if (fd >= 0)
333 close(fd);
334 }
335 free(reqObject);
336 return error;
337}
338
339/* fetch dir info about directory name and send it to remote host associated
340 with call. */
341int
342UPDATE_FetchInfo(struct rx_call *call, char *name)
343{
344 int error = 0;
345 struct stat status;
346 char *reqObject;
347
348 /* construct a local path from a canonical (wire-format) path */
349 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
350 afs_com_err(whoami, error, "Unable to construct local path");
351 return UPDATE_ERROR1;
352 }
353
354 if (!AuthOkay(call, reqObject)) {
355 error = UPDATE_ERROR1;
356 } else {
357 /* we only need to stat the obj, not open it. */
358 if (stat(reqObject, &status) < 0) {
359 printf("Failed to open %s\n", reqObject);
360 error = UPDATE_ERROR1;
361 }
362 if ((status.st_mode & S_IFMT0170000) != S_IFDIR0040000) {
363 printf(" file %s is not a directory \n", reqObject);
364 error = -1;
365 }
366
367 if (!error)
368 error = update_SendDirInfo(reqObject, call, &status, name);
369 }
370 free(reqObject);
371 return error;
372}
373
374static int
375Quit(char *msg)
376{
377 fprintf(stderr__stderrp, "%s", msg);
378 exit(1);
379}
380
381int
382update_SendFile(int fd, struct rx_call *call, struct stat *status)
383{
384 char *buffer = (char *)0;
385 int blockSize;
386 afs_int32 length, tlen;
387#ifdef AFS_AIX_ENV
388 struct statfs tstatfs;
389#endif
390
391 afs_int32 error = 0;
392#ifdef AFS_AIX_ENV
393 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
394 fstatfs(fd, &tstatfs);
395 blockSize = tstatfs.f_bsize;
396#elif AFS_NT40_ENV
397 blockSize = 4096;
398#else
399 blockSize = status->st_blksize;
400#endif
401 length = status->st_size;
402 buffer = (char *)malloc(blockSize);
403 if (!buffer) {
404 printf("malloc failed\n");
405 return UPDATE_ERROR1;
406 }
407 tlen = htonl(length)(__builtin_constant_p(length) ? ((((__uint32_t)(length)) >>
24) | ((((__uint32_t)(length)) & (0xff << 16)) >>
8) | ((((__uint32_t)(length)) & (0xff << 8)) <<
8) | (((__uint32_t)(length)) << 24)) : __bswap32_var(length
))
;
408 rx_Write(call, (char *)&tlen, sizeof(afs_int32))rx_WriteProc(call, (char *)&tlen, sizeof(afs_int32)); /* send length on fetch */
409 while (!error && length) {
410 int nbytes = (length > blockSize ? blockSize : length);
411 nbytes = read(fd, buffer, nbytes);
412 if (nbytes <= 0) {
413 fprintf(stderr__stderrp, "File system read failed\n");
414 break;
415 }
416 if (rx_Write(call, buffer, nbytes)rx_WriteProc(call, buffer, nbytes) != nbytes)
417 break;
418 length -= nbytes;
419 }
420 if (buffer)
421 free(buffer);
422 if (length)
423 error = UPDATE_ERROR1;
424 return error;
425}
426
427/* Enumerate dir (name) and write dir entry info into temp file.
428 */
429int
430update_SendDirInfo(char *name, /* Name of dir to enumerate */
431 struct rx_call *call, /* rx call */
432 struct stat *status, /* stat struct for dir */
433 char *origDir) /* orig name of dir before being localized */
434{
435 DIR *dirp;
436 struct dirent *dp;
437 FILE *stream;
438 struct stat tstatus;
439 char filename[MAXFNSIZE1024], dirInfoFile[MAXFNSIZE1024];
440 int fd, tfd, errcode, error, err;
441
442 error = 0;
443 dirp = opendir(name);
444 sprintf(dirInfoFile, "%s/upserver.tmp", gettmpdir());
445 stream = fopen(dirInfoFile, "w");
446 if (!stream) {
447 error = EIO5;
448 } else {
449 while ((dp = readdir(dirp))) {
450 strcpy(filename, name);
451 strcat(filename, "/");
452 strcat(filename, dp->d_name);
453
454 tfd = open(filename, O_RDONLY0x0000, 0);
455 if (tfd < 0 || fstat(tfd, &tstatus) < 0) {
456 printf("Failed to open %s\n", name);
457 error = UPDATE_ERROR1;
458 goto fail;
459 }
460 if ((tstatus.st_mode & S_IFMT0170000) != S_IFDIR0040000) { /* not a directory */
461 char dirEntry[MAXFNSIZE1024];
462
463 strcpy(dirEntry, origDir);
464 strcat(dirEntry, "/");
465 strcat(dirEntry, dp->d_name);
466 err =
467 fprintf(stream, "\"%s\" %u %u %u %u %u %u\n", dirEntry,
468 (unsigned int)tstatus.st_mtimest_mtim.tv_sec,
469 (unsigned int)tstatus.st_size, tstatus.st_mode,
470 tstatus.st_uid, tstatus.st_gid,
471 (unsigned int)tstatus.st_atimest_atim.tv_sec);
472 if (err < 0)
473 error = EIO5;
474 }
475 err = close(tfd);
476 if (err) {
477 printf("could not close file %s \n", filename);
478 error = UPDATE_ERROR1;
479 goto fail;
480 }
481 }
482 }
483 fail:
484 if (dirp)
485 closedir(dirp);
486 if (stream) {
487 if (ferror(stream)(!__isthreaded ? (((stream)->_flags & 0x0040) != 0) : (
ferror)(stream))
)
488 if (!error)
489 error = UPDATE_ERROR1;
490 fclose(stream);
491 }
492 if (error == 0) {
493 fd = open(dirInfoFile, O_RDONLY0x0000, 0);
494 if (fd >= 0) {
495 fstat(fd, &tstatus);
496 errcode = update_SendFile(fd, call, &tstatus);
497 if (errcode)
498 if (!error)
499 error = UPDATE_ERROR1;
500 close(fd);
501 }
502 }
503 unlink(dirInfoFile);
504 return error;
505}
506
507
508/* AddObject() - Adds the object to the list of exported objects after
509 * converting to a local path.
510 *
511 * expPath : points to allocated storage in which the exportable path is
512 * passed back.
513 * dir : dir name passed in for export
514 *
515 */
516static int
517AddObject(char **expPath, char *dir)
518{
519 int error;
520 struct stat statbuf;
521
522 /* construct a local path from a canonical (wire-format) path */
523 if ((error = ConstructLocalPath(dir, "/", expPath))) {
524 afs_com_err(whoami, error, "Unable to construct local path");
525 return error;
526 }
527
528 /* stat the object */
529 error = stat(*expPath, &statbuf);
530 if (error) {
531 afs_com_err(whoami, error, ";Can't stat object.");
532 return error;
533 }
534 /* now check if the object has an exportable (file/dir) type */
535 if (!(statbuf.st_mode & S_IFDIR0040000)) {
536 fprintf(stderr__stderrp, "%s: Unacceptable object type for %s\n", whoami,
537 *expPath);
538 return -1;
539 }
540
541 return 0;
542}