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