2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
20 #include <sys/types.h>
23 #include <WINNT/afsevent.h>
26 #include <afs/dirent.h>
27 #include <afs/procmgmt.h>
30 #include <netinet/in.h>
50 #include <afs/cellconfig.h>
51 #include <afs/afsutil.h>
52 #include <afs/fileutil.h>
56 extern int UPDATE_ExecuteRequest();
57 static int AddObject(char **expPath, char *dir);
58 static int PathInDirectory(char *dir, char *path);
60 struct afsconf_dir *cdir;
62 char *dirName[MAXENTRIES];
63 int dirLevel[MAXENTRIES];
68 /* check whether caller is authorized to manage RX statistics */
70 update_rxstat_userok(call)
73 return afsconf_SuperUser(cdir, call, NULL);
77 * PathInDirectory() -- determine if path is in directory (or is directory)
80 PathInDirectory(char *dir, char *path)
84 char dirNorm[AFSDIR_PATH_MAX], pathNorm[AFSDIR_PATH_MAX];
87 /* case-insensitive comparison of normalized, same-flavor (short) paths */
90 status = GetShortPathName(dir, dirNorm, AFSDIR_PATH_MAX);
91 if (status == 0 || status > AFSDIR_PATH_MAX) {
92 /* can't convert path to short version; just use long version */
95 FilepathNormalize(dirNorm);
97 status = GetShortPathName(path, pathNorm, AFSDIR_PATH_MAX);
98 if (status == 0 || status > AFSDIR_PATH_MAX) {
99 /* can't convert path to short version; just use long version */
100 strcpy(pathNorm, path);
102 FilepathNormalize(pathNorm);
104 dirLen = strlen(dirNorm);
106 if (_strnicmp(dirNorm, pathNorm, dirLen) == 0) {
107 /* substrings match; path must match dir or be subdirectory */
108 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
113 /* case-sensitive comparison of normalized paths */
114 strcpy(dirNorm, dir);
115 FilepathNormalize(dirNorm);
117 strcpy(pathNorm, path);
118 FilepathNormalize(pathNorm);
120 dirLen = strlen(dirNorm);
122 if (strncmp(dirNorm, pathNorm, dirLen) == 0) {
123 /* substrings match; path must match dir or be subdirectory */
124 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
128 #endif /* AFS_NT40_ENV */
135 struct rx_call *call;
143 /* Must be in 'UserList' to use */
144 if (!afsconf_SuperUser(cdir, call, NULL))
147 if (rx_SecurityClassOf(rx_ConnectionOf(call)) == 2) {
148 code = rxkad_GetServerInfo(call->conn, &level, 0, 0, 0, 0, 0);
155 for (i = 0; i < nDirs; i++) {
156 if (PathInDirectory(dirName[i], name)) {
157 if (dirLevel[i] > level)
160 /* keep searching in case there's a more restrictive subtree
161 * specified later. */
164 if (nDirs && !matches)
165 return 0; /* if dirs spec., name must match */
166 return 1; /* okay or no dirs */
172 /* this sucks but it works for now.
178 #include "AFS_component_version_number.c"
186 struct rx_securityClass *securityObjects[3];
187 struct rx_service *service;
191 rxkad_level newLevel;
195 * The following signal action for AIX is necessary so that in case of a
196 * crash (i.e. core is generated) we can include the user's data section
197 * in the core dump. Unfortunately, by default, only a partial core is
198 * generated which, in many cases, isn't too useful.
200 struct sigaction nsa;
202 sigemptyset(&nsa.sa_mask);
203 nsa.sa_handler = SIG_DFL;
204 nsa.sa_flags = SA_FULLDUMP;
205 sigaction(SIGABRT, &nsa, NULL);
206 sigaction(SIGSEGV, &nsa, NULL);
212 /* dummy signal call to force afsprocmgmt.dll to load on NT */
213 signal(SIGUSR1, SIG_DFL);
216 /* Initialize dirpaths */
217 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
219 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
221 fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
228 if (argc == 1) /* no arguments */
231 /* support help flag */
232 if (strcmp("-help", argv[1]) == 0)
234 if (strcmp("help", argv[1]) == 0)
237 for (a = 1; a < argc; a++) {
238 if (argv[a][0] == '-') { /* parse options */
240 lcstring(arg, argv[a], sizeof(arg));
241 newLevel = StringToLevel(&argv[a][1]);
242 if (newLevel != -1) {
243 level = newLevel; /* set new level */
247 Quit("Usage: upserver [<directory>+] [-crypt <directory>+] [-clear <directory>+] [-auth <directory>+] [-help]\n");
250 if (nDirs >= sizeof(dirName) / sizeof(dirName[0]))
251 Quit("Too many dirs");
252 dirlen = strlen(argv[a]);
253 if (AddObject(&dirName[nDirs], argv[a])) {
254 printf("%s: Unable to export dir %s. Skipping\n", whoami,
258 dirLevel[nDirs] = level; /* remember current level */
263 if (nDirs == 0) { /* Didn't find any directories to export */
264 printf("%s: No directories to export. Quitting\n", whoami);
268 cdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
270 fprintf(stderr, "Can't get server configuration info (%s)\n",
271 AFSDIR_SERVER_ETC_DIRPATH);
275 /* Initialize Rx, telling it port number this server will use for its
277 if (rx_Init(htons(AFSCONF_UPDATEPORT)) < 0)
280 /* Create a single security object, in this case the null security object,
281 * for unauthenticated connections, which will be used to control security
282 * on connections made to this server. */
284 /* WHAT A JOKE! Let's use rxkad at least so we know who we're talking to,
285 * then sometimes require full encryption. */
287 /* rxnull and rxvab are no longer supported */
288 securityObjects[0] = rxnull_NewServerSecurityObject();
290 securityObjects[1] = (struct rx_securityClass *)0;
293 rxkad_NewServerSecurityObject(rxkad_clear, cdir, afsconf_GetKey, 0);
294 if (securityObjects[2] == (struct rx_securityClass *)0)
295 Quit("rxkad_NewServerSecurityObject");
297 /* Instantiate a single UPDATE service. The rxgen-generated procedure
298 * which is called to decode requests is passed in here
299 * (UPDATE_ExecuteRequest). */
301 rx_NewService(0, UPDATE_SERVICEID, "UPDATE", securityObjects, 3,
302 UPDATE_ExecuteRequest);
303 if (service == (struct rx_service *)0)
304 Quit("rx_NewService");
305 rx_SetMaxProcs(service, 2);
307 /* allow super users to manage RX statistics */
308 rx_SetRxStatUserOk(update_rxstat_userok);
310 rx_StartServer(1); /* Donate this process to the server process pool */
311 Quit("StartServer returned?");
315 /* fetch the file name and send it to the remote requester specified by call */
318 UPDATE_FetchFile(call, name)
319 struct rx_call *call;
327 /* construct a local path from a canonical (wire-format) path */
328 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
329 com_err(whoami, error, "Unable to construct local path");
333 if (!AuthOkay(call, reqObject)) {
334 error = UPDATE_ERROR;
336 fd = open(reqObject, O_RDONLY, 0);
337 if (fd < 0 || fstat(fd, &status) < 0) {
338 printf("Failed to open %s\n", reqObject);
339 error = UPDATE_ERROR;
342 error = update_SendFile(fd, call, &status);
350 /* fetch dir info about directory name and send it to remote host associated
353 UPDATE_FetchInfo(call, name)
354 struct rx_call *call;
362 /* construct a local path from a canonical (wire-format) path */
363 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
364 com_err(whoami, error, "Unable to construct local path");
368 if (!AuthOkay(call, reqObject)) {
369 error = UPDATE_ERROR;
371 /* we only need to stat the obj, not open it. */
372 if (stat(reqObject, &status) < 0) {
373 printf("Failed to open %s\n", reqObject);
374 error = UPDATE_ERROR;
376 if ((status.st_mode & S_IFMT) != S_IFDIR) {
377 printf(" file %s is not a directory \n", reqObject);
386 error = update_SendDirInfo(reqObject, call, &status, name);
396 fprintf(stderr, msg, a, b);
401 update_SendFile(fd, call, status)
403 register struct rx_call *call;
404 register struct stat *status;
406 char *buffer = (char *)0;
408 afs_int32 length, tlen;
413 #include <sys/statfs.h>
414 struct statfs tstatfs;
419 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
420 fstatfs(fd, &tstatfs);
421 blockSize = tstatfs.f_bsize;
425 blockSize = status->st_blksize;
427 length = status->st_size;
428 buffer = (char *)malloc(blockSize);
430 printf("malloc failed\n");
434 xdrrx_create(&xdr, call, XDR_ENCODE);
435 if (!xdr_afs_int32(&xdr, &length))
436 error = UPDATE_ERROR;
438 tlen = htonl(length);
439 rx_Write(call, &tlen, sizeof(afs_int32)); /* send length on fetch */
441 while (!error && length) {
442 register int nbytes = (length > blockSize ? blockSize : length);
443 nbytes = read(fd, buffer, nbytes);
445 fprintf(stderr, "File system read failed\n");
448 if (rx_Write(call, buffer, nbytes) != nbytes)
455 error = UPDATE_ERROR;
459 /* Enumerate dir (name) and write dir entry info into temp file.
462 update_SendDirInfo(name, call, status, origDir)
463 char *name; /* Name of dir to enumerate */
464 register struct rx_call *call; /* rx call */
465 register struct stat *status; /* stat struct for dir */
466 char *origDir; /* orig name of dir before being localized */
472 char filename[MAXSIZE], dirInfoFile[MAXSIZE];
473 int fd, tfd, errcode, error, err;
476 dirp = opendir(name);
477 sprintf(dirInfoFile, "%s/upserver.tmp", gettmpdir());
478 stream = fopen(dirInfoFile, "w");
482 while ((dp = readdir(dirp))) {
483 strcpy(filename, name);
484 strcat(filename, "/");
485 strcat(filename, dp->d_name);
487 tfd = open(filename, O_RDONLY, 0);
488 if (tfd < 0 || fstat(tfd, &tstatus) < 0) {
489 printf("Failed to open %s\n", name);
490 error = UPDATE_ERROR;
493 if ((tstatus.st_mode & S_IFMT) != S_IFDIR) { /* not a directory */
494 char dirEntry[MAXSIZE];
496 strcpy(dirEntry, origDir);
497 strcat(dirEntry, "/");
498 strcat(dirEntry, dp->d_name);
500 fprintf(stream, "\"%s\" %u %u %u %u %u %u\n", dirEntry,
501 (unsigned int)tstatus.st_mtime,
502 (unsigned int)tstatus.st_size, tstatus.st_mode,
503 tstatus.st_uid, tstatus.st_gid,
504 (unsigned int)tstatus.st_atime);
510 printf("could not close file %s \n", filename);
511 error = UPDATE_ERROR;
522 error = UPDATE_ERROR;
526 fd = open(dirInfoFile, O_RDONLY, 0);
529 errcode = update_SendFile(fd, call, &tstatus);
532 error = UPDATE_ERROR;
541 /* AddObject() - Adds the object to the list of exported objects after
542 * converting to a local path.
544 * expPath : points to allocated storage in which the exportable path is
546 * dir : dir name passed in for export
550 AddObject(char **expPath, char *dir)
555 /* construct a local path from a canonical (wire-format) path */
556 if ((error = ConstructLocalPath(dir, "/", expPath))) {
557 com_err(whoami, error, "Unable to construct local path");
561 /* stat the object */
562 error = stat(*expPath, &statbuf);
564 com_err(whoami, error, ";Can't stat object.");
567 /* now check if the object has an exportable (file/dir) type */
568 if (!(statbuf.st_mode & S_IFDIR)) {
569 fprintf(stderr, "%s: Unacceptable object type for %s\n", whoami,