Unused variable warning fixes
[openafs.git] / src / update / server.c
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
36 static int AddObject(char **expPath, char *dir);
37 static int PathInDirectory(char *dir, char *path);
38 int update_SendFile(int, struct rx_call *, struct stat *);
39 int update_SendDirInfo(char *, struct rx_call *, struct stat *,
40                        char *origDir);
41
42 struct afsconf_dir *cdir;
43 int nDirs;
44 char *dirName[MAXENTRIES];
45 int dirLevel[MAXENTRIES];
46 char *whoami;
47
48 static int Quit(char *);
49
50 int rxBind = 0;
51
52 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
53 afs_uint32 SHostAddrs[ADDRSPERSITE];
54
55 /* check whether caller is authorized to manage RX statistics */
56 int
57 update_rxstat_userok(struct rx_call *call)
58 {
59     return afsconf_SuperUser(cdir, call, NULL);
60 }
61
62 /*
63  * PathInDirectory() -- determine if path is in directory (or is directory)
64  */
65 static int
66 PathInDirectory(char *dir, char *path)
67 {
68     int inDir = 0;
69     size_t dirLen;
70     char dirNorm[AFSDIR_PATH_MAX], pathNorm[AFSDIR_PATH_MAX];
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_MAX);
77     if (status == 0 || status > AFSDIR_PATH_MAX) {
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_MAX);
84     if (status == 0 || status > AFSDIR_PATH_MAX) {
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
118 int
119 AuthOkay(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))
128         return 0;
129
130     if (rx_SecurityClassOf(rx_ConnectionOf(call)) == 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
152 int
153 osi_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
164 int
165 main(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);
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 = SIG_DFL;
187     nsa.sa_flags = SA_FULLDUMP;
188     sigaction(SIGABRT, &nsa, NULL);
189     sigaction(SIGSEGV, &nsa, NULL);
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(SIGUSR1, SIG_DFL);
197 #endif
198
199     /* Initialize dirpaths */
200     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
201 #ifdef AFS_NT40_ENV
202         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
203 #endif
204         fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
205                 argv[0]);
206         exit(2);
207     }
208     nDirs = 0;
209     level = rxkad_clear;
210
211     if (argc == 1)              /* no arguments */
212         goto usage;
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++) {
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 */
250         printf("%s: No directories to export. Quitting\n", whoami);
251         exit(1);
252     }
253
254     cdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
255     if (cdir == 0) {
256         fprintf(stderr, "Can't get server configuration info (%s)\n",
257                 AFSDIR_SERVER_ETC_DIRPATH);
258         exit(1);
259     }
260
261     if (rxBind) {
262         afs_int32 ccode;
263         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
264             AFSDIR_SERVER_NETINFO_FILEPATH) {
265             char reason[1024];
266             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
267                                            ADDRSPERSITE, reason,
268                                            AFSDIR_SERVER_NETINFO_FILEPATH,
269                                            AFSDIR_SERVER_NETRESTRICT_FILEPATH);
270         } else
271         {
272             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
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)) < 0)
281         Quit("rx_init");
282
283     afsconf_BuildServerSecurityObjects(cdir, &securityClasses, &numClasses);
284
285     if (securityClasses[2] == NULL)
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_SERVICEID, "UPDATE", securityClasses,
293                           numClasses, UPDATE_ExecuteRequest);
294     if (service == (struct rx_service *)0)
295         Quit("rx_NewService");
296     rx_SetMaxProcs(service, 2);
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
308 int
309 UPDATE_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_ERROR;
320     }
321
322     if (!AuthOkay(call, reqObject)) {
323         error = UPDATE_ERROR;
324     } else {
325         fd = open(reqObject, O_RDONLY, 0);
326         if (fd < 0 || fstat(fd, &status) < 0) {
327             printf("Failed to open %s\n", reqObject);
328             error = UPDATE_ERROR;
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. */
341 int
342 UPDATE_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_ERROR;
352     }
353
354     if (!AuthOkay(call, reqObject)) {
355         error = UPDATE_ERROR;
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_ERROR;
361         }
362         if ((status.st_mode & S_IFMT) != S_IFDIR) {
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
374 static int
375 Quit(char *msg)
376 {
377     fprintf(stderr, "%s", msg);
378     exit(1);
379 }
380
381 int
382 update_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_ERROR;
406     }
407     tlen = htonl(length);
408     rx_Write(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, "File system read failed\n");
414             break;
415         }
416         if (rx_Write(call, buffer, nbytes) != nbytes)
417             break;
418         length -= nbytes;
419     }
420     if (buffer)
421         free(buffer);
422     if (length)
423         error = UPDATE_ERROR;
424     return error;
425 }
426
427 /* Enumerate dir (name) and write dir entry info into temp file.
428  */
429 int
430 update_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[MAXFNSIZE], dirInfoFile[MAXFNSIZE];
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 = EIO;
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_RDONLY, 0);
455             if (tfd < 0 || fstat(tfd, &tstatus) < 0) {
456                 printf("Failed to open %s\n", name);
457                 error = UPDATE_ERROR;
458                 goto fail;
459             }
460             if ((tstatus.st_mode & S_IFMT) != S_IFDIR) {        /* not a directory */
461                 char dirEntry[MAXFNSIZE];
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_mtime,
469                             (unsigned int)tstatus.st_size, tstatus.st_mode,
470                             tstatus.st_uid, tstatus.st_gid,
471                             (unsigned int)tstatus.st_atime);
472                 if (err < 0)
473                     error = EIO;
474             }
475             err = close(tfd);
476             if (err) {
477                 printf("could not close file %s \n", filename);
478                 error = UPDATE_ERROR;
479                 goto fail;
480             }
481         }
482     }
483   fail:
484     if (dirp)
485         closedir(dirp);
486     if (stream) {
487         if (ferror(stream))
488             if (!error)
489                 error = UPDATE_ERROR;
490         fclose(stream);
491     }
492     if (error == 0) {
493         fd = open(dirInfoFile, O_RDONLY, 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_ERROR;
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  */
516 static int
517 AddObject(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_IFDIR)) {
536         fprintf(stderr, "%s: Unacceptable object type for %s\n", whoami,
537                 *expPath);
538         return -1;
539     }
540
541     return 0;
542 }