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>
18 #include <sys/types.h>
21 #include <WINNT/afsevent.h>
24 #include <afs/dirent.h>
25 #include <afs/procmgmt.h>
28 #include <netinet/in.h>
42 #include <afs/cellconfig.h>
43 #include <afs/afsutil.h>
44 #include <afs/fileutil.h>
45 #include <afs/com_err.h>
47 #include <sys/statfs.h>
52 static int AddObject(char **expPath, char *dir);
53 static int PathInDirectory(char *dir, char *path);
54 int update_SendFile(int, struct rx_call *, struct stat *);
55 int update_SendDirInfo(char *, struct rx_call *, struct stat *,
58 struct afsconf_dir *cdir;
60 char *dirName[MAXENTRIES];
61 int dirLevel[MAXENTRIES];
64 static int Quit(char *);
68 #define ADDRSPERSITE 16 /* Same global is in rx/rx_user.c */
69 afs_uint32 SHostAddrs[ADDRSPERSITE];
71 /* check whether caller is authorized to manage RX statistics */
73 update_rxstat_userok(struct rx_call *call)
75 return afsconf_SuperUser(cdir, call, NULL);
79 * PathInDirectory() -- determine if path is in directory (or is directory)
82 PathInDirectory(char *dir, char *path)
86 char dirNorm[AFSDIR_PATH_MAX], pathNorm[AFSDIR_PATH_MAX];
89 /* case-insensitive comparison of normalized, same-flavor (short) paths */
92 status = GetShortPathName(dir, dirNorm, AFSDIR_PATH_MAX);
93 if (status == 0 || status > AFSDIR_PATH_MAX) {
94 /* can't convert path to short version; just use long version */
97 FilepathNormalize(dirNorm);
99 status = GetShortPathName(path, pathNorm, AFSDIR_PATH_MAX);
100 if (status == 0 || status > AFSDIR_PATH_MAX) {
101 /* can't convert path to short version; just use long version */
102 strcpy(pathNorm, path);
104 FilepathNormalize(pathNorm);
106 dirLen = strlen(dirNorm);
108 if (_strnicmp(dirNorm, pathNorm, dirLen) == 0) {
109 /* substrings match; path must match dir or be subdirectory */
110 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
115 /* case-sensitive comparison of normalized paths */
116 strcpy(dirNorm, dir);
117 FilepathNormalize(dirNorm);
119 strcpy(pathNorm, path);
120 FilepathNormalize(pathNorm);
122 dirLen = strlen(dirNorm);
124 if (strncmp(dirNorm, pathNorm, dirLen) == 0) {
125 /* substrings match; path must match dir or be subdirectory */
126 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
130 #endif /* AFS_NT40_ENV */
135 AuthOkay(struct rx_call *call, char *name)
142 /* Must be in 'UserList' to use */
143 if (!afsconf_SuperUser(cdir, call, NULL))
146 if (rx_SecurityClassOf(rx_ConnectionOf(call)) == 2) {
147 code = rxkad_GetServerInfo(call->conn, &level, 0, 0, 0, 0, 0);
154 for (i = 0; i < nDirs; i++) {
155 if (PathInDirectory(dirName[i], name)) {
156 if (dirLevel[i] > level)
159 /* keep searching in case there's a more restrictive subtree
160 * specified later. */
163 if (nDirs && !matches)
164 return 0; /* if dirs spec., name must match */
165 return 1; /* okay or no dirs */
171 /* this sucks but it works for now.
177 #include "AFS_component_version_number.c"
181 main(int argc, char *argv[])
183 struct rx_securityClass *securityObjects[3];
184 struct rx_service *service;
185 afs_uint32 host = htonl(INADDR_ANY);
189 rxkad_level newLevel;
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.
198 struct sigaction nsa;
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);
210 /* dummy signal call to force afsprocmgmt.dll to load on NT */
211 signal(SIGUSR1, SIG_DFL);
214 /* Initialize dirpaths */
215 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
217 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
219 fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
226 if (argc == 1) /* no arguments */
229 /* support help flag */
230 if (strcmp("-help", argv[1]) == 0)
232 if (strcmp("help", argv[1]) == 0)
235 for (a = 1; a < argc; a++) {
236 if (argv[a][0] == '-') { /* parse options */
237 if (strcmp(argv[a], "-rxbind") == 0) {
242 lcstring(arg, argv[a], sizeof(arg));
243 newLevel = rxkad_StringToLevel(&argv[a][1]);
244 if (newLevel != -1) {
245 level = newLevel; /* set new level */
250 Quit("Usage: upserver [<directory>+] [-crypt <directory>+] [-clear <directory>+] [-auth <directory>+] [-rxbind] [-help]\n");
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,
261 dirLevel[nDirs] = level; /* remember current level */
266 if (nDirs == 0) { /* Didn't find any directories to export */
267 printf("%s: No directories to export. Quitting\n", whoami);
271 cdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
273 fprintf(stderr, "Can't get server configuration info (%s)\n",
274 AFSDIR_SERVER_ETC_DIRPATH);
280 if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
281 AFSDIR_SERVER_NETINFO_FILEPATH) {
283 ccode = parseNetFiles(SHostAddrs, NULL, NULL,
284 ADDRSPERSITE, reason,
285 AFSDIR_SERVER_NETINFO_FILEPATH,
286 AFSDIR_SERVER_NETRESTRICT_FILEPATH);
289 ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
292 host = SHostAddrs[0];
295 /* Initialize Rx, telling it port number this server will use for its
297 if (rx_InitHost(host, htons(AFSCONF_UPDATEPORT)) < 0)
300 /* Create a single security object, in this case the null security object,
301 * for unauthenticated connections, which will be used to control security
302 * on connections made to this server. */
304 /* WHAT A JOKE! Let's use rxkad at least so we know who we're talking to,
305 * then sometimes require full encryption. */
307 /* rxnull and rxvab are no longer supported */
308 securityObjects[0] = rxnull_NewServerSecurityObject();
310 securityObjects[1] = (struct rx_securityClass *)0;
313 rxkad_NewServerSecurityObject(rxkad_clear, cdir, afsconf_GetKey, 0);
314 if (securityObjects[2] == (struct rx_securityClass *)0)
315 Quit("rxkad_NewServerSecurityObject");
317 /* Instantiate a single UPDATE service. The rxgen-generated procedure
318 * which is called to decode requests is passed in here
319 * (UPDATE_ExecuteRequest). */
321 rx_NewServiceHost(host, 0, UPDATE_SERVICEID, "UPDATE", securityObjects,
322 3, UPDATE_ExecuteRequest);
323 if (service == (struct rx_service *)0)
324 Quit("rx_NewService");
325 rx_SetMaxProcs(service, 2);
327 /* allow super users to manage RX statistics */
328 rx_SetRxStatUserOk(update_rxstat_userok);
330 rx_StartServer(1); /* Donate this process to the server process pool */
331 Quit("StartServer returned?");
335 /* fetch the file name and send it to the remote requester specified by call */
338 UPDATE_FetchFile(struct rx_call *call, char *name)
345 /* construct a local path from a canonical (wire-format) path */
346 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
347 afs_com_err(whoami, error, "Unable to construct local path");
351 if (!AuthOkay(call, reqObject)) {
352 error = UPDATE_ERROR;
354 fd = open(reqObject, O_RDONLY, 0);
355 if (fd < 0 || fstat(fd, &status) < 0) {
356 printf("Failed to open %s\n", reqObject);
357 error = UPDATE_ERROR;
360 error = update_SendFile(fd, call, &status);
368 /* fetch dir info about directory name and send it to remote host associated
371 UPDATE_FetchInfo(struct rx_call *call, char *name)
377 /* construct a local path from a canonical (wire-format) path */
378 if ((error = ConstructLocalPath(name, "/", &reqObject))) {
379 afs_com_err(whoami, error, "Unable to construct local path");
383 if (!AuthOkay(call, reqObject)) {
384 error = UPDATE_ERROR;
386 /* we only need to stat the obj, not open it. */
387 if (stat(reqObject, &status) < 0) {
388 printf("Failed to open %s\n", reqObject);
389 error = UPDATE_ERROR;
391 if ((status.st_mode & S_IFMT) != S_IFDIR) {
392 printf(" file %s is not a directory \n", reqObject);
397 error = update_SendDirInfo(reqObject, call, &status, name);
406 fprintf(stderr, msg);
411 update_SendFile(register int fd, register struct rx_call *call, register struct stat *status)
413 char *buffer = (char *)0;
415 afs_int32 length, tlen;
417 struct statfs tstatfs;
422 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
423 fstatfs(fd, &tstatfs);
424 blockSize = tstatfs.f_bsize;
428 blockSize = status->st_blksize;
430 length = status->st_size;
431 buffer = (char *)malloc(blockSize);
433 printf("malloc failed\n");
436 tlen = htonl(length);
437 rx_Write(call, &tlen, sizeof(afs_int32)); /* send length on fetch */
438 while (!error && length) {
439 register int nbytes = (length > blockSize ? blockSize : length);
440 nbytes = read(fd, buffer, nbytes);
442 fprintf(stderr, "File system read failed\n");
445 if (rx_Write(call, buffer, nbytes) != nbytes)
452 error = UPDATE_ERROR;
456 /* Enumerate dir (name) and write dir entry info into temp file.
459 update_SendDirInfo(char *name, /* Name of dir to enumerate */
460 register struct rx_call *call, /* rx call */
461 register struct stat *status, /* stat struct for dir */
462 char *origDir) /* orig name of dir before being localized */
468 char filename[MAXSIZE], dirInfoFile[MAXSIZE];
469 int fd, tfd, errcode, error, err;
472 dirp = opendir(name);
473 sprintf(dirInfoFile, "%s/upserver.tmp", gettmpdir());
474 stream = fopen(dirInfoFile, "w");
478 while ((dp = readdir(dirp))) {
479 strcpy(filename, name);
480 strcat(filename, "/");
481 strcat(filename, dp->d_name);
483 tfd = open(filename, O_RDONLY, 0);
484 if (tfd < 0 || fstat(tfd, &tstatus) < 0) {
485 printf("Failed to open %s\n", name);
486 error = UPDATE_ERROR;
489 if ((tstatus.st_mode & S_IFMT) != S_IFDIR) { /* not a directory */
490 char dirEntry[MAXSIZE];
492 strcpy(dirEntry, origDir);
493 strcat(dirEntry, "/");
494 strcat(dirEntry, dp->d_name);
496 fprintf(stream, "\"%s\" %u %u %u %u %u %u\n", dirEntry,
497 (unsigned int)tstatus.st_mtime,
498 (unsigned int)tstatus.st_size, tstatus.st_mode,
499 tstatus.st_uid, tstatus.st_gid,
500 (unsigned int)tstatus.st_atime);
506 printf("could not close file %s \n", filename);
507 error = UPDATE_ERROR;
518 error = UPDATE_ERROR;
522 fd = open(dirInfoFile, O_RDONLY, 0);
525 errcode = update_SendFile(fd, call, &tstatus);
528 error = UPDATE_ERROR;
537 /* AddObject() - Adds the object to the list of exported objects after
538 * converting to a local path.
540 * expPath : points to allocated storage in which the exportable path is
542 * dir : dir name passed in for export
546 AddObject(char **expPath, char *dir)
551 /* construct a local path from a canonical (wire-format) path */
552 if ((error = ConstructLocalPath(dir, "/", expPath))) {
553 afs_com_err(whoami, error, "Unable to construct local path");
557 /* stat the object */
558 error = stat(*expPath, &statbuf);
560 afs_com_err(whoami, error, ";Can't stat object.");
563 /* now check if the object has an exportable (file/dir) type */
564 if (!(statbuf.st_mode & S_IFDIR)) {
565 fprintf(stderr, "%s: Unacceptable object type for %s\n", whoami,