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 <afs/param.h>
15 #include <sys/types.h>
18 #include <WINNT/afsevent.h>
21 #include <afs/dirent.h>
22 #include <afs/procmgmt.h>
25 #include <netinet/in.h>
35 #include <afs/cellconfig.h>
36 #include <afs/afsutil.h>
37 #include <afs/fileutil.h>
43 extern UPDATE_ExecuteRequest();
44 static int AddObject(char **expPath, char *dir);
45 static int PathInDirectory(char *dir, char *path);
47 struct afsconf_dir *cdir;
49 char *dirName[MAXENTRIES];
50 int dirLevel[MAXENTRIES];
55 /* check whether caller is authorized to manage RX statistics */
56 int update_rxstat_userok(call)
59 return afsconf_SuperUser(cdir, call, (char *)0);
63 * PathInDirectory() -- determine if path is in directory (or is directory)
66 PathInDirectory(char *dir, char *path)
70 char dirNorm[AFSDIR_PATH_MAX], pathNorm[AFSDIR_PATH_MAX];
73 /* case-insensitive comparison of normalized, same-flavor (short) paths */
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 */
81 FilepathNormalize(dirNorm);
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);
88 FilepathNormalize(pathNorm);
90 dirLen = strlen(dirNorm);
92 if (_strnicmp(dirNorm, pathNorm, dirLen) == 0) {
93 /* substrings match; path must match dir or be subdirectory */
94 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
99 /* case-sensitive comparison of normalized paths */
100 strcpy(dirNorm, dir);
101 FilepathNormalize(dirNorm);
103 strcpy(pathNorm, path);
104 FilepathNormalize(pathNorm);
106 dirLen = strlen(dirNorm);
108 if (strncmp(dirNorm, pathNorm, dirLen) == 0) {
109 /* substrings match; path must match dir or be subdirectory */
110 if (pathNorm[dirLen] == '\0' || pathNorm[dirLen] == '/') {
114 #endif /* AFS_NT40_ENV */
119 int AuthOkay (call, name)
120 struct rx_call *call;
128 /* Must be in 'UserList' to use */
129 if (!afsconf_SuperUser (cdir, call, (char *)0)) return 0;
131 if (rx_SecurityClassOf (rx_ConnectionOf(call)) == 2) {
132 code = rxkad_GetServerInfo (call->conn, &level, 0,0,0,0,0);
137 for (i=0; i<nDirs; i++) {
138 if (PathInDirectory(dirName[i], name)) {
139 if (dirLevel[i] > level) return 0;
141 /* keep searching in case there's a more restrictive subtree
142 * specified later. */
145 if (nDirs && !matches) return 0; /* if dirs spec., name must match */
146 return 1; /* okay or no dirs */
151 /* this sucks but it works for now.
157 #include "AFS_component_version_number.c"
160 int main (argc, argv)
164 struct rx_securityClass *securityObjects[3];
165 struct rx_service *service;
166 extern struct rx_securityClass *rxnull_NewServerSecurityObject();
167 extern afs_int32 afsconf_GetKey();
171 rxkad_level newLevel;
175 * The following signal action for AIX is necessary so that in case of a
176 * crash (i.e. core is generated) we can include the user's data section
177 * in the core dump. Unfortunately, by default, only a partial core is
178 * generated which, in many cases, isn't too useful.
180 struct sigaction nsa;
182 sigemptyset(&nsa.sa_mask);
183 nsa.sa_handler = SIG_DFL;
184 nsa.sa_flags = SA_FULLDUMP;
185 sigaction(SIGABRT, &nsa, NULL);
186 sigaction(SIGSEGV, &nsa, NULL);
192 /* dummy signal call to force afsprocmgmt.dll to load on NT */
193 signal(SIGUSR1, SIG_DFL);
196 /* Initialize dirpaths */
197 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
199 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0],0);
201 fprintf(stderr, "%s: Unable to obtain AFS server directory.\n", argv[0]);
207 if (argc == 1) /* no arguments */
210 /* support help flag */
211 if(strcmp("-help",argv[1])==0)
213 if(strcmp("help",argv[1])==0)
216 for (a=1; a<argc; a++) {
217 if (argv[a][0] == '-') { /* parse options */
218 int arglen = strlen(argv[a]);
220 lcstring (arg, argv[a], sizeof(arg));
221 #define IsArg(a) (strncmp (arg,a, arglen) == 0)
222 newLevel = StringToLevel (&argv[a][1]);
223 if (newLevel != -1) {
224 level = newLevel; /* set new level */
228 Quit ("Usage: upserver [<directory>+] [-crypt <directory>+] [-clear <directory>+] [-auth <directory>+] [-help]\n");
231 if (nDirs >= sizeof(dirName)/sizeof(dirName[0]))
232 Quit("Too many dirs");
233 dirlen = strlen (argv[a]);
234 if (AddObject(&dirName[nDirs], argv[a])) {
235 printf("%s: Unable to export dir %s. Skipping\n", whoami, argv[a]);
238 dirLevel[nDirs] = level; /* remember current level */
243 if (nDirs == 0) { /* Didn't find any directories to export */
244 printf("%s: No directories to export. Quitting\n", whoami);
248 cdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
250 fprintf (stderr, "Can't get server configuration info (%s)\n",
251 AFSDIR_SERVER_ETC_DIRPATH);
255 /* Initialize Rx, telling it port number this server will use for its
257 if (rx_Init(htons(AFSCONF_UPDATEPORT)) < 0) Quit("rx_init");
259 /* Create a single security object, in this case the null security object,
260 * for unauthenticated connections, which will be used to control security
261 * on connections made to this server. */
263 /* WHAT A JOKE! Let's use rxkad at least so we know who we're talking to,
264 * then sometimes require full encryption. */
266 /* rxnull and rxvab are no longer supported */
267 securityObjects[0] = rxnull_NewServerSecurityObject();
269 securityObjects[1] = (struct rx_securityClass *) 0;
271 securityObjects[2] = rxkad_NewServerSecurityObject
272 (rxkad_clear, cdir, afsconf_GetKey, 0);
273 if (securityObjects[2] == (struct rx_securityClass *) 0)
274 Quit("rxkad_NewServerSecurityObject");
276 /* Instantiate a single UPDATE service. The rxgen-generated procedure
277 * which is called to decode requests is passed in here
278 * (UPDATE_ExecuteRequest). */
279 service = rx_NewService (0, UPDATE_SERVICEID, "UPDATE",
280 securityObjects, 3, UPDATE_ExecuteRequest);
281 if (service == (struct rx_service *) 0) Quit("rx_NewService");
282 rx_SetMaxProcs(service, 2);
284 /* allow super users to manage RX statistics */
285 rx_SetRxStatUserOk(update_rxstat_userok);
287 rx_StartServer(1); /* Donate this process to the server process pool */
288 Quit("StartServer returned?");
291 /* fetch the file name and send it to the remote requester specified by call */
293 int UPDATE_FetchFile(call, name)
294 struct rx_call *call;
302 /* construct a local path from a canonical (wire-format) path */
303 if ( error = ConstructLocalPath(name, "/", &reqObject) ) {
304 com_err(whoami, error, "Unable to construct local path");
308 if (!AuthOkay (call, reqObject)) {
309 error = UPDATE_ERROR;
311 fd = open(reqObject, O_RDONLY, 0);
312 if (fd < 0 || fstat(fd, &status) < 0) {
313 printf("Failed to open %s\n", reqObject);
314 error = UPDATE_ERROR;
316 if (!error) error = update_SendFile(fd, call, &status);
317 if (fd >= 0) close(fd);
323 /* fetch dir info about directory name and send it to remote host associated
325 int UPDATE_FetchInfo(call, name)
326 struct rx_call *call;
334 /* construct a local path from a canonical (wire-format) path */
335 if ( error = ConstructLocalPath(name, "/", &reqObject) ) {
336 com_err(whoami, error, "Unable to construct local path");
340 if (!AuthOkay (call, reqObject)) {
341 error = UPDATE_ERROR;
343 /* we only need to stat the obj, not open it. */
344 if (stat(reqObject, &status) < 0) {
345 printf("Failed to open %s\n", reqObject);
346 error = UPDATE_ERROR;
348 if((status.st_mode & S_IFMT) != S_IFDIR){
349 printf(" file %s is not a directory \n", reqObject);
350 if (fd >= 0) close(fd);
354 if (fd >= 0) close(fd);
355 if (!error) error = update_SendDirInfo(reqObject, call, &status, name);
361 static Quit(msg, a, b)
364 fprintf(stderr, msg, a, b);
368 int update_SendFile(fd, call, status)
370 register struct rx_call *call;
371 register struct stat *status;
373 char *buffer = (char*) 0;
375 afs_int32 length, tlen;
378 #include <sys/statfs.h>
379 struct statfs tstatfs;
384 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
385 fstatfs(fd, &tstatfs);
386 blockSize = tstatfs.f_bsize;
390 blockSize = status->st_blksize;
392 length = status->st_size;
393 buffer = (char *)malloc(blockSize);
395 printf("malloc failed\n");
399 xdrrx_create(&xdr, call, XDR_ENCODE);
400 if (!xdr_afs_int32(&xdr, &length)) error = UPDATE_ERROR;
402 tlen = htonl(length);
403 rx_Write(call, &tlen, sizeof(afs_int32)); /* send length on fetch */
405 while (!error && length) {
406 register nbytes = (length>blockSize?blockSize:length);
407 nbytes = read(fd, buffer, nbytes);
409 fprintf(stderr, "File system read failed\n");
412 if (rx_Write(call, buffer, nbytes) != nbytes)
416 if (buffer) free(buffer);
417 if (length) error = UPDATE_ERROR;
421 /* Enumerate dir (name) and write dir entry info into temp file.
423 int update_SendDirInfo(name, call, status, origDir)
424 char *name; /* Name of dir to enumerate */
425 register struct rx_call *call; /* rx call */
426 register struct stat *status; /* stat struct for dir */
427 char *origDir; /* orig name of dir before being localized */
433 char filename[MAXSIZE], dirInfoFile[MAXSIZE];
434 int fd, tfd, errcode, error, err;
437 dirp = opendir(name);
438 sprintf(dirInfoFile, "%s/upserver.tmp", gettmpdir());
439 stream = fopen(dirInfoFile, "w");
443 while(dp = readdir(dirp)){
444 strcpy(filename, name);
445 strcat(filename,"/");
446 strcat(filename,dp->d_name);
448 tfd = open(filename, O_RDONLY, 0);
449 if (tfd < 0 || fstat(tfd, &tstatus) < 0) {
450 printf("Failed to open %s\n", name);
451 error = UPDATE_ERROR;
454 if((tstatus.st_mode & S_IFMT) != S_IFDIR){/* not a directory */
455 char dirEntry[MAXSIZE];
457 strcpy(dirEntry, origDir); strcat(dirEntry, "/");
458 strcat(dirEntry, dp->d_name);
459 err = fprintf(stream, "\"%s\" %u %u %u %u %u %u\n", dirEntry, tstatus.st_mtime,tstatus.st_size,tstatus.st_mode,tstatus.st_uid,tstatus.st_gid, tstatus.st_atime);
460 if (err < 0) error = EIO;
464 printf("could not close file %s \n",filename);
465 error = UPDATE_ERROR;
471 if (dirp) closedir(dirp);
474 if (!error) error = UPDATE_ERROR;
478 fd = open(dirInfoFile, O_RDONLY, 0);
481 errcode = update_SendFile(fd, call, &tstatus);
482 if(errcode) if(!error) error = UPDATE_ERROR;
491 /* AddObject() - Adds the object to the list of exported objects after
492 * converting to a local path.
494 * expPath : points to allocated storage in which the exportable path is
496 * dir : dir name passed in for export
499 static int AddObject(char **expPath, char *dir)
504 /* construct a local path from a canonical (wire-format) path */
505 if ( error = ConstructLocalPath(dir, "/", expPath) ) {
506 com_err(whoami, error, "Unable to construct local path");
510 /* stat the object */
511 error = stat(*expPath, &statbuf);
513 com_err(whoami, error, ";Can't stat object.");
516 /* now check if the object has an exportable (file/dir) type */
517 if ( ! (statbuf.st_mode & S_IFDIR) ) {
518 fprintf(stderr, "%s: Unacceptable object type for %s\n", whoami, *expPath);