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/procmgmt.h>
27 #include <netinet/in.h>
41 #include <afs/cellconfig.h>
42 #include <afs/afsutil.h>
43 #include <afs/fileutil.h>
44 #include <afs/com_err.h>
46 #include <sys/statfs.h>
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
*,
57 struct afsconf_dir
*cdir
;
59 char *dirName
[MAXENTRIES
];
60 int dirLevel
[MAXENTRIES
];
63 static int Quit(char *);
67 #define ADDRSPERSITE 16 /* Same global is in rx/rx_user.c */
68 afs_uint32 SHostAddrs
[ADDRSPERSITE
];
70 /* check whether caller is authorized to manage RX statistics */
72 update_rxstat_userok(struct rx_call
*call
)
74 return afsconf_SuperUser(cdir
, call
, NULL
);
78 * PathInDirectory() -- determine if path is in directory (or is directory)
81 PathInDirectory(char *dir
, char *path
)
85 char dirNorm
[AFSDIR_PATH_MAX
], pathNorm
[AFSDIR_PATH_MAX
];
88 /* case-insensitive comparison of normalized, same-flavor (short) paths */
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 */
96 FilepathNormalize(dirNorm
);
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
);
103 FilepathNormalize(pathNorm
);
105 dirLen
= strlen(dirNorm
);
107 if (_strnicmp(dirNorm
, pathNorm
, dirLen
) == 0) {
108 /* substrings match; path must match dir or be subdirectory */
109 if (pathNorm
[dirLen
] == '\0' || pathNorm
[dirLen
] == '/') {
114 /* case-sensitive comparison of normalized paths */
115 strcpy(dirNorm
, dir
);
116 FilepathNormalize(dirNorm
);
118 strcpy(pathNorm
, path
);
119 FilepathNormalize(pathNorm
);
121 dirLen
= strlen(dirNorm
);
123 if (strncmp(dirNorm
, pathNorm
, dirLen
) == 0) {
124 /* substrings match; path must match dir or be subdirectory */
125 if (pathNorm
[dirLen
] == '\0' || pathNorm
[dirLen
] == '/') {
129 #endif /* AFS_NT40_ENV */
134 AuthOkay(struct rx_call
*call
, char *name
)
141 /* Must be in 'UserList' to use */
142 if (!afsconf_SuperUser(cdir
, call
, NULL
))
145 if (rx_SecurityClassOf(rx_ConnectionOf(call
)) == 2) {
146 code
= rxkad_GetServerInfo(call
->conn
, &level
, 0, 0, 0, 0, 0);
153 for (i
= 0; i
< nDirs
; i
++) {
154 if (PathInDirectory(dirName
[i
], name
)) {
155 if (dirLevel
[i
] > level
)
158 /* keep searching in case there's a more restrictive subtree
159 * specified later. */
162 if (nDirs
&& !matches
)
163 return 0; /* if dirs spec., name must match */
164 return 1; /* okay or no dirs */
170 /* this sucks but it works for now.
176 #include "AFS_component_version_number.c"
180 main(int argc
, char *argv
[])
182 struct rx_securityClass
**securityClasses
;
183 afs_int32 numClasses
;
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");
252 if (nDirs
>= sizeof(dirName
) / sizeof(dirName
[0]))
253 Quit("Too many dirs");
254 if (AddObject(&dirName
[nDirs
], argv
[a
])) {
255 printf("%s: Unable to export dir %s. Skipping\n", whoami
,
259 dirLevel
[nDirs
] = level
; /* remember current level */
264 if (nDirs
== 0) { /* Didn't find any directories to export */
265 printf("%s: No directories to export. Quitting\n", whoami
);
269 cdir
= afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH
);
271 fprintf(stderr
, "Can't get server configuration info (%s)\n",
272 AFSDIR_SERVER_ETC_DIRPATH
);
278 if (AFSDIR_SERVER_NETRESTRICT_FILEPATH
||
279 AFSDIR_SERVER_NETINFO_FILEPATH
) {
281 ccode
= parseNetFiles(SHostAddrs
, NULL
, NULL
,
282 ADDRSPERSITE
, reason
,
283 AFSDIR_SERVER_NETINFO_FILEPATH
,
284 AFSDIR_SERVER_NETRESTRICT_FILEPATH
);
287 ccode
= rx_getAllAddr(SHostAddrs
, ADDRSPERSITE
);
290 host
= SHostAddrs
[0];
293 /* Initialize Rx, telling it port number this server will use for its
295 if (rx_InitHost(host
, htons(AFSCONF_UPDATEPORT
)) < 0)
298 afsconf_BuildServerSecurityObjects(cdir
, 0, &securityClasses
, &numClasses
);
300 if (securityClasses
[2] == NULL
)
301 Quit("rxkad_NewServerSecurityObject");
303 /* Instantiate a single UPDATE service. The rxgen-generated procedure
304 * which is called to decode requests is passed in here
305 * (UPDATE_ExecuteRequest). */
307 rx_NewServiceHost(host
, 0, UPDATE_SERVICEID
, "UPDATE", securityClasses
,
308 numClasses
, UPDATE_ExecuteRequest
);
309 if (service
== (struct rx_service
*)0)
310 Quit("rx_NewService");
311 rx_SetMaxProcs(service
, 2);
313 /* allow super users to manage RX statistics */
314 rx_SetRxStatUserOk(update_rxstat_userok
);
316 rx_StartServer(1); /* Donate this process to the server process pool */
317 Quit("StartServer returned?");
321 /* fetch the file name and send it to the remote requester specified by call */
324 UPDATE_FetchFile(struct rx_call
*call
, char *name
)
331 /* construct a local path from a canonical (wire-format) path */
332 if ((error
= ConstructLocalPath(name
, "/", &reqObject
))) {
333 afs_com_err(whoami
, error
, "Unable to construct local path");
337 if (!AuthOkay(call
, reqObject
)) {
338 error
= UPDATE_ERROR
;
340 fd
= open(reqObject
, O_RDONLY
, 0);
341 if (fd
< 0 || fstat(fd
, &status
) < 0) {
342 printf("Failed to open %s\n", reqObject
);
343 error
= UPDATE_ERROR
;
346 error
= update_SendFile(fd
, call
, &status
);
354 /* fetch dir info about directory name and send it to remote host associated
357 UPDATE_FetchInfo(struct rx_call
*call
, char *name
)
363 /* construct a local path from a canonical (wire-format) path */
364 if ((error
= ConstructLocalPath(name
, "/", &reqObject
))) {
365 afs_com_err(whoami
, error
, "Unable to construct local path");
369 if (!AuthOkay(call
, reqObject
)) {
370 error
= UPDATE_ERROR
;
372 /* we only need to stat the obj, not open it. */
373 if (stat(reqObject
, &status
) < 0) {
374 printf("Failed to open %s\n", reqObject
);
375 error
= UPDATE_ERROR
;
377 if ((status
.st_mode
& S_IFMT
) != S_IFDIR
) {
378 printf(" file %s is not a directory \n", reqObject
);
383 error
= update_SendDirInfo(reqObject
, call
, &status
, name
);
392 fprintf(stderr
, "%s", msg
);
397 update_SendFile(int fd
, struct rx_call
*call
, struct stat
*status
)
399 char *buffer
= (char *)0;
401 afs_int32 length
, tlen
;
403 struct statfs tstatfs
;
408 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
409 fstatfs(fd
, &tstatfs
);
410 blockSize
= tstatfs
.f_bsize
;
414 blockSize
= status
->st_blksize
;
416 length
= status
->st_size
;
417 buffer
= (char *)malloc(blockSize
);
419 printf("malloc failed\n");
422 tlen
= htonl(length
);
423 rx_Write(call
, (char *)&tlen
, sizeof(afs_int32
)); /* send length on fetch */
424 while (!error
&& length
) {
425 int nbytes
= (length
> blockSize
? blockSize
: length
);
426 nbytes
= read(fd
, buffer
, nbytes
);
428 fprintf(stderr
, "File system read failed\n");
431 if (rx_Write(call
, buffer
, nbytes
) != nbytes
)
438 error
= UPDATE_ERROR
;
442 /* Enumerate dir (name) and write dir entry info into temp file.
445 update_SendDirInfo(char *name
, /* Name of dir to enumerate */
446 struct rx_call
*call
, /* rx call */
447 struct stat
*status
, /* stat struct for dir */
448 char *origDir
) /* orig name of dir before being localized */
454 char filename
[MAXFNSIZE
], dirInfoFile
[MAXFNSIZE
];
455 int fd
, tfd
, errcode
, error
, err
;
458 dirp
= opendir(name
);
459 sprintf(dirInfoFile
, "%s/upserver.tmp", gettmpdir());
460 stream
= fopen(dirInfoFile
, "w");
464 while ((dp
= readdir(dirp
))) {
465 strcpy(filename
, name
);
466 strcat(filename
, "/");
467 strcat(filename
, dp
->d_name
);
469 tfd
= open(filename
, O_RDONLY
, 0);
470 if (tfd
< 0 || fstat(tfd
, &tstatus
) < 0) {
471 printf("Failed to open %s\n", name
);
472 error
= UPDATE_ERROR
;
475 if ((tstatus
.st_mode
& S_IFMT
) != S_IFDIR
) { /* not a directory */
476 char dirEntry
[MAXFNSIZE
];
478 strcpy(dirEntry
, origDir
);
479 strcat(dirEntry
, "/");
480 strcat(dirEntry
, dp
->d_name
);
482 fprintf(stream
, "\"%s\" %u %u %u %u %u %u\n", dirEntry
,
483 (unsigned int)tstatus
.st_mtime
,
484 (unsigned int)tstatus
.st_size
, tstatus
.st_mode
,
485 tstatus
.st_uid
, tstatus
.st_gid
,
486 (unsigned int)tstatus
.st_atime
);
492 printf("could not close file %s \n", filename
);
493 error
= UPDATE_ERROR
;
504 error
= UPDATE_ERROR
;
508 fd
= open(dirInfoFile
, O_RDONLY
, 0);
511 errcode
= update_SendFile(fd
, call
, &tstatus
);
514 error
= UPDATE_ERROR
;
523 /* AddObject() - Adds the object to the list of exported objects after
524 * converting to a local path.
526 * expPath : points to allocated storage in which the exportable path is
528 * dir : dir name passed in for export
532 AddObject(char **expPath
, char *dir
)
537 /* construct a local path from a canonical (wire-format) path */
538 if ((error
= ConstructLocalPath(dir
, "/", expPath
))) {
539 afs_com_err(whoami
, error
, "Unable to construct local path");
543 /* stat the object */
544 error
= stat(*expPath
, &statbuf
);
546 afs_com_err(whoami
, error
, ";Can't stat object.");
549 /* now check if the object has an exportable (file/dir) type */
550 if (!(statbuf
.st_mode
& S_IFDIR
)) {
551 fprintf(stderr
, "%s: Unacceptable object type for %s\n", whoami
,