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>
14 #include <afs/procmgmt.h>
19 #include <WINNT/afsevent.h>
23 #include <sys/statfs.h>
29 #include <afs/authcon.h>
30 #include <afs/cellconfig.h>
31 #include <afs/afsutil.h>
32 #include <afs/fileutil.h>
33 #include <afs/com_err.h>
38 static int AddObject(char **expPath, char *dir);
39 static int PathInDirectory(char *dir, char *path);
40 int update_SendFile(int, struct rx_call *, struct stat *);
41 int update_SendDirInfo(char *, struct rx_call *, struct stat *,
44 struct afsconf_dir *cdir;
46 char *dirName[MAXENTRIES];
47 int dirLevel[MAXENTRIES];
50 static int Quit(char *);
54 #define ADDRSPERSITE 16 /* Same global is in rx/rx_user.c */
55 afs_uint32 SHostAddrs[ADDRSPERSITE];
57 /* check whether caller is authorized to manage RX statistics */
59 update_rxstat_userok(struct rx_call *call)
61 return afsconf_SuperUser(cdir, call, NULL);
65 * PathInDirectory() -- determine if path is in directory (or is directory)
66 * Returns 1 if yes, 0 if no, -1 on error.
69 PathInDirectory(char *dir, char *path)
73 char *dirNorm, *pathNorm;
76 /* case-insensitive comparison of normalized, same-flavor (short) paths */
79 dirNorm = malloc(AFSDIR_PATH_MAX);
82 status = GetShortPathName(dir, dirNorm, AFSDIR_PATH_MAX);
83 if (status == 0 || status > AFSDIR_PATH_MAX) {
84 /* can't convert path to short version; just use long version */
86 dirNorm = strdup(dir);
90 FilepathNormalize(dirNorm);
92 pathNorm = malloc(AFSDIR_PATH_MAX);
93 if (pathNorm == NULL) {
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 */
101 pathNorm = strdup(path);
102 if (pathNorm == NULL) {
107 FilepathNormalize(pathNorm);
109 dirLen = strlen(dirNorm);
111 if (_strnicmp(dirNorm, pathNorm, dirLen) == 0) {
112 /* substrings match; path must match dir or be subdirectory */
113 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
118 /* case-sensitive comparison of normalized paths */
119 dirNorm = strdup(dir);
122 FilepathNormalize(dirNorm);
124 pathNorm = strdup(path);
125 if (pathNorm == NULL) {
129 FilepathNormalize(pathNorm);
131 dirLen = strlen(dirNorm);
133 if (strncmp(dirNorm, pathNorm, dirLen) == 0) {
134 /* substrings match; path must match dir or be subdirectory */
135 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
139 #endif /* AFS_NT40_ENV */
144 return (code != 0) ? code : inDir;
148 AuthOkay(struct rx_call *call, char *name)
155 /* Must be in 'UserList' to use */
156 if (!afsconf_SuperUser(cdir, call, NULL))
159 if (rx_SecurityClassOf(rx_ConnectionOf(call)) == RX_SECIDX_KAD) {
160 code = rxkad_GetServerInfo(rx_ConnectionOf(call), &level, 0, 0, 0, 0, 0);
167 for (i = 0; i < nDirs; i++) {
168 r = PathInDirectory(dirName[i], name);
172 if (dirLevel[i] > level)
175 /* keep searching in case there's a more restrictive subtree
176 * specified later. */
179 if (nDirs && !matches)
180 return 0; /* if dirs spec., name must match */
181 return 1; /* okay or no dirs */
187 /* this sucks but it works for now.
193 #include "AFS_component_version_number.c"
197 main(int argc, char *argv[])
199 struct rx_securityClass **securityClasses;
200 afs_int32 numClasses;
201 struct rx_service *service;
203 afs_uint32 host = htonl(INADDR_ANY);
207 rxkad_level newLevel;
208 struct afsconf_bsso_info bsso;
212 * The following signal action for AIX is necessary so that in case of a
213 * crash (i.e. core is generated) we can include the user's data section
214 * in the core dump. Unfortunately, by default, only a partial core is
215 * generated which, in many cases, isn't too useful.
217 struct sigaction nsa;
219 sigemptyset(&nsa.sa_mask);
220 nsa.sa_handler = SIG_DFL;
221 nsa.sa_flags = SA_FULLDUMP;
222 sigaction(SIGABRT, &nsa, NULL);
223 sigaction(SIGSEGV, &nsa, NULL);
226 memset(&bsso, 0, sizeof(bsso));
231 /* dummy signal call to force afsprocmgmt.dll to load on NT */
232 signal(SIGUSR1, SIG_DFL);
235 /* Initialize dirpaths */
236 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
238 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
240 fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
247 if (argc == 1) /* no arguments */
250 /* support help flag */
251 if (strcmp("-help", argv[1]) == 0)
253 if (strcmp("help", argv[1]) == 0)
256 for (a = 1; a < argc; a++) {
257 if (argv[a][0] == '-') { /* parse options */
258 if (strcmp(argv[a], "-rxbind") == 0) {
263 lcstring(arg, argv[a], sizeof(arg));
264 newLevel = rxkad_StringToLevel(&argv[a][1]);
265 if (newLevel != -1) {
266 level = newLevel; /* set new level */
271 Quit("Usage: upserver [<directory>+] [-crypt <directory>+] [-clear <directory>+] [-auth <directory>+] [-rxbind] [-help]\n");
273 if (nDirs >= sizeof(dirName) / sizeof(dirName[0]))
274 Quit("Too many dirs");
275 if (AddObject(&dirName[nDirs], argv[a])) {
276 printf("%s: Unable to export dir %s. Skipping\n", whoami,
280 dirLevel[nDirs] = level; /* remember current level */
285 if (nDirs == 0) { /* Didn't find any directories to export */
286 printf("%s: No directories to export. Quitting\n", whoami);
290 cdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
292 fprintf(stderr, "Can't get server configuration info (%s)\n",
293 AFSDIR_SERVER_ETC_DIRPATH);
299 if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
300 AFSDIR_SERVER_NETINFO_FILEPATH) {
302 ccode = afsconf_ParseNetFiles(SHostAddrs, NULL, NULL,
303 ADDRSPERSITE, reason,
304 AFSDIR_SERVER_NETINFO_FILEPATH,
305 AFSDIR_SERVER_NETRESTRICT_FILEPATH);
308 ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
311 host = SHostAddrs[0];
314 /* Initialize Rx, telling it port number this server will use for its
316 fprintf(stderr, "upserver binding rx to %s:%d\n",
317 afs_inet_ntoa_r(host, hoststr), AFSCONF_UPDATEPORT);
318 if (rx_InitHost(host, htons(AFSCONF_UPDATEPORT)) < 0)
322 afsconf_BuildServerSecurityObjects_int(&bsso, &securityClasses, &numClasses);
324 if (securityClasses[2] == NULL)
325 Quit("rxkad_NewServerSecurityObject");
327 /* Instantiate a single UPDATE service. The rxgen-generated procedure
328 * which is called to decode requests is passed in here
329 * (UPDATE_ExecuteRequest). */
331 rx_NewServiceHost(host, 0, UPDATE_SERVICEID, "UPDATE", securityClasses,
332 numClasses, UPDATE_ExecuteRequest);
333 if (service == (struct rx_service *)0)
334 Quit("rx_NewService");
335 rx_SetMaxProcs(service, 2);
337 /* allow super users to manage RX statistics */
338 rx_SetRxStatUserOk(update_rxstat_userok);
340 rx_StartServer(1); /* Donate this process to the server process pool */
341 Quit("StartServer returned?");
345 /* fetch the file name and send it to the remote requester specified by call */
348 UPDATE_FetchFile(struct rx_call *call, char *name)
355 /* construct a local path from a canonical (wire-format) path */
356 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
357 afs_com_err(whoami, error, "Unable to construct local path");
361 if (!AuthOkay(call, reqObject)) {
362 error = UPDATE_ERROR;
364 fd = open(reqObject, O_RDONLY, 0);
365 if (fd < 0 || fstat(fd, &status) < 0) {
366 printf("Failed to open %s\n", reqObject);
367 error = UPDATE_ERROR;
370 error = update_SendFile(fd, call, &status);
378 /* fetch dir info about directory name and send it to remote host associated
381 UPDATE_FetchInfo(struct rx_call *call, char *name)
387 /* construct a local path from a canonical (wire-format) path */
388 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
389 afs_com_err(whoami, error, "Unable to construct local path");
393 if (!AuthOkay(call, reqObject)) {
394 error = UPDATE_ERROR;
396 /* we only need to stat the obj, not open it. */
397 if (stat(reqObject, &status) < 0) {
398 printf("Failed to open %s\n", reqObject);
399 error = UPDATE_ERROR;
401 if ((status.st_mode & S_IFMT) != S_IFDIR) {
402 printf(" file %s is not a directory \n", reqObject);
407 error = update_SendDirInfo(reqObject, call, &status, name);
416 fprintf(stderr, "%s", msg);
421 update_SendFile(int fd, struct rx_call *call, struct stat *status)
423 char *buffer = (char *)0;
425 afs_int32 length, tlen;
427 struct statfs tstatfs;
432 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
433 fstatfs(fd, &tstatfs);
434 blockSize = tstatfs.f_bsize;
438 blockSize = status->st_blksize;
440 length = status->st_size;
441 buffer = malloc(blockSize);
443 printf("malloc failed\n");
446 tlen = htonl(length);
447 rx_Write(call, (char *)&tlen, sizeof(afs_int32)); /* send length on fetch */
448 while (!error && length) {
449 int nbytes = (length > blockSize ? blockSize : length);
450 nbytes = read(fd, buffer, nbytes);
452 fprintf(stderr, "File system read failed\n");
455 if (rx_Write(call, buffer, nbytes) != nbytes)
462 error = UPDATE_ERROR;
466 /* Enumerate dir (name) and write dir entry info into temp file.
469 update_SendDirInfo(char *name, /* Name of dir to enumerate */
470 struct rx_call *call, /* rx call */
471 struct stat *status, /* stat struct for dir */
472 char *origDir) /* orig name of dir before being localized */
478 char filename[MAXFNSIZE], dirInfoFile[MAXFNSIZE];
479 int fd, tfd, errcode, error, err;
482 dirp = opendir(name);
483 sprintf(dirInfoFile, "%s/upserver.tmp", gettmpdir());
484 stream = fopen(dirInfoFile, "w");
488 while ((dp = readdir(dirp))) {
489 strcpy(filename, name);
490 strcat(filename, "/");
491 strcat(filename, dp->d_name);
493 tfd = open(filename, O_RDONLY, 0);
494 if (tfd < 0 || fstat(tfd, &tstatus) < 0) {
495 printf("Failed to open %s\n", name);
496 error = UPDATE_ERROR;
499 if ((tstatus.st_mode & S_IFMT) != S_IFDIR) { /* not a directory */
500 char dirEntry[MAXFNSIZE];
502 strcpy(dirEntry, origDir);
503 strcat(dirEntry, "/");
504 strcat(dirEntry, dp->d_name);
506 fprintf(stream, "\"%s\" %u %u %u %u %u %u\n", dirEntry,
507 (unsigned int)tstatus.st_mtime,
508 (unsigned int)tstatus.st_size, tstatus.st_mode,
509 tstatus.st_uid, tstatus.st_gid,
510 (unsigned int)tstatus.st_atime);
516 printf("could not close file %s \n", filename);
517 error = UPDATE_ERROR;
528 error = UPDATE_ERROR;
532 fd = open(dirInfoFile, O_RDONLY, 0);
535 errcode = update_SendFile(fd, call, &tstatus);
538 error = UPDATE_ERROR;
547 /* AddObject() - Adds the object to the list of exported objects after
548 * converting to a local path.
550 * expPath : points to allocated storage in which the exportable path is
552 * dir : dir name passed in for export
556 AddObject(char **expPath, char *dir)
561 /* construct a local path from a canonical (wire-format) path */
562 if ((error = ConstructLocalPath(dir, "/", expPath))) {
563 afs_com_err(whoami, error, "Unable to construct local path");
567 /* stat the object */
568 error = stat(*expPath, &statbuf);
570 afs_com_err(whoami, error, ";Can't stat object.");
573 /* now check if the object has an exportable (file/dir) type */
574 if (!(statbuf.st_mode & S_IFDIR)) {
575 fprintf(stderr, "%s: Unacceptable object type for %s\n", whoami,