Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / update / server.c
blob7c44ab9e96d8733e872b978a01e741ca7e5c8e53
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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
8 */
10 #include <afsconfig.h>
11 #include <afs/param.h>
14 #include <afs/stds.h>
15 #ifdef AFS_AIX32_ENV
16 #include <signal.h>
17 #endif
18 #include <sys/types.h>
19 #ifdef AFS_NT40_ENV
20 #include <winsock2.h>
21 #include <WINNT/afsevent.h>
22 #include <fcntl.h>
23 #include <io.h>
24 #include <afs/procmgmt.h>
25 #else
26 #include <netdb.h>
27 #include <netinet/in.h>
28 #include <sys/file.h>
29 #endif
30 #include <dirent.h>
31 #include <string.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <rx/xdr.h>
39 #include <rx/rx.h>
40 #include <rx/rxkad.h>
41 #include <afs/cellconfig.h>
42 #include <afs/afsutil.h>
43 #include <afs/fileutil.h>
44 #include <afs/com_err.h>
45 #ifdef AFS_AIX_ENV
46 #include <sys/statfs.h>
47 #endif
48 #include "update.h"
49 #include "global.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 *,
55 char *origDir);
57 struct afsconf_dir *cdir;
58 int nDirs;
59 char *dirName[MAXENTRIES];
60 int dirLevel[MAXENTRIES];
61 char *whoami;
63 static int Quit(char *);
65 int rxBind = 0;
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 */
71 int
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)
80 static int
81 PathInDirectory(char *dir, char *path)
83 int inDir = 0;
84 size_t dirLen;
85 char dirNorm[AFSDIR_PATH_MAX], pathNorm[AFSDIR_PATH_MAX];
87 #ifdef AFS_NT40_ENV
88 /* case-insensitive comparison of normalized, same-flavor (short) paths */
89 DWORD status;
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 */
94 strcpy(dirNorm, dir);
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] == '/') {
110 inDir = 1;
113 #else
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] == '/') {
126 inDir = 1;
129 #endif /* AFS_NT40_ENV */
130 return inDir;
134 AuthOkay(struct rx_call *call, char *name)
136 int i;
137 rxkad_level level;
138 afs_int32 code;
139 int matches;
141 /* Must be in 'UserList' to use */
142 if (!afsconf_SuperUser(cdir, call, NULL))
143 return 0;
145 if (rx_SecurityClassOf(rx_ConnectionOf(call)) == 2) {
146 code = rxkad_GetServerInfo(call->conn, &level, 0, 0, 0, 0, 0);
147 if (code)
148 return 0;
149 } else
150 level = 0;
152 matches = 0;
153 for (i = 0; i < nDirs; i++) {
154 if (PathInDirectory(dirName[i], name)) {
155 if (dirLevel[i] > level)
156 return 0;
157 matches++;
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 */
168 osi_audit(void)
170 /* this sucks but it works for now.
172 return 0;
175 #ifndef AFS_NT40_ENV
176 #include "AFS_component_version_number.c"
177 #endif
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);
187 int a = 0;
188 rxkad_level level;
189 rxkad_level newLevel;
191 #ifdef AFS_AIX32_ENV
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);
205 #endif
207 whoami = argv[0];
209 #ifdef AFS_NT40_ENV
210 /* dummy signal call to force afsprocmgmt.dll to load on NT */
211 signal(SIGUSR1, SIG_DFL);
212 #endif
214 /* Initialize dirpaths */
215 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
216 #ifdef AFS_NT40_ENV
217 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
218 #endif
219 fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
220 argv[0]);
221 exit(2);
223 nDirs = 0;
224 level = rxkad_clear;
226 if (argc == 1) /* no arguments */
227 goto usage;
229 /* support help flag */
230 if (strcmp("-help", argv[1]) == 0)
231 goto usage;
232 if (strcmp("help", argv[1]) == 0)
233 goto usage;
235 for (a = 1; a < argc; a++) {
236 if (argv[a][0] == '-') { /* parse options */
237 if (strcmp(argv[a], "-rxbind") == 0) {
238 rxBind = 1;
239 continue;
240 } else {
241 char arg[256];
242 lcstring(arg, argv[a], sizeof(arg));
243 newLevel = rxkad_StringToLevel(&argv[a][1]);
244 if (newLevel != -1) {
245 level = newLevel; /* set new level */
246 continue;
249 usage:
250 Quit("Usage: upserver [<directory>+] [-crypt <directory>+] [-clear <directory>+] [-auth <directory>+] [-rxbind] [-help]\n");
251 } else {
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,
256 argv[a]);
257 continue;
259 dirLevel[nDirs] = level; /* remember current level */
260 nDirs++;
264 if (nDirs == 0) { /* Didn't find any directories to export */
265 printf("%s: No directories to export. Quitting\n", whoami);
266 exit(1);
269 cdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
270 if (cdir == 0) {
271 fprintf(stderr, "Can't get server configuration info (%s)\n",
272 AFSDIR_SERVER_ETC_DIRPATH);
273 exit(1);
276 if (rxBind) {
277 afs_int32 ccode;
278 if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
279 AFSDIR_SERVER_NETINFO_FILEPATH) {
280 char reason[1024];
281 ccode = parseNetFiles(SHostAddrs, NULL, NULL,
282 ADDRSPERSITE, reason,
283 AFSDIR_SERVER_NETINFO_FILEPATH,
284 AFSDIR_SERVER_NETRESTRICT_FILEPATH);
285 } else
287 ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
289 if (ccode == 1)
290 host = SHostAddrs[0];
293 /* Initialize Rx, telling it port number this server will use for its
294 * single service */
295 if (rx_InitHost(host, htons(AFSCONF_UPDATEPORT)) < 0)
296 Quit("rx_init");
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). */
306 service =
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?");
318 return 0;
321 /* fetch the file name and send it to the remote requester specified by call */
324 UPDATE_FetchFile(struct rx_call *call, char *name)
326 int fd = -1;
327 int error = 0;
328 struct stat status;
329 char *reqObject;
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");
334 return UPDATE_ERROR;
337 if (!AuthOkay(call, reqObject)) {
338 error = UPDATE_ERROR;
339 } else {
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;
345 if (!error)
346 error = update_SendFile(fd, call, &status);
347 if (fd >= 0)
348 close(fd);
350 free(reqObject);
351 return error;
354 /* fetch dir info about directory name and send it to remote host associated
355 with call. */
357 UPDATE_FetchInfo(struct rx_call *call, char *name)
359 int error = 0;
360 struct stat status;
361 char *reqObject;
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");
366 return UPDATE_ERROR;
369 if (!AuthOkay(call, reqObject)) {
370 error = UPDATE_ERROR;
371 } else {
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);
379 error = -1;
382 if (!error)
383 error = update_SendDirInfo(reqObject, call, &status, name);
385 free(reqObject);
386 return error;
389 static int
390 Quit(char *msg)
392 fprintf(stderr, "%s", msg);
393 exit(1);
397 update_SendFile(int fd, struct rx_call *call, struct stat *status)
399 char *buffer = (char *)0;
400 int blockSize;
401 afs_int32 length, tlen;
402 #ifdef AFS_AIX_ENV
403 struct statfs tstatfs;
404 #endif
406 afs_int32 error = 0;
407 #ifdef AFS_AIX_ENV
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;
411 #elif AFS_NT40_ENV
412 blockSize = 4096;
413 #else
414 blockSize = status->st_blksize;
415 #endif
416 length = status->st_size;
417 buffer = (char *)malloc(blockSize);
418 if (!buffer) {
419 printf("malloc failed\n");
420 return UPDATE_ERROR;
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);
427 if (nbytes <= 0) {
428 fprintf(stderr, "File system read failed\n");
429 break;
431 if (rx_Write(call, buffer, nbytes) != nbytes)
432 break;
433 length -= nbytes;
435 if (buffer)
436 free(buffer);
437 if (length)
438 error = UPDATE_ERROR;
439 return 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 */
450 DIR *dirp;
451 struct dirent *dp;
452 FILE *stream;
453 struct stat tstatus;
454 char filename[MAXFNSIZE], dirInfoFile[MAXFNSIZE];
455 int fd, tfd, errcode, error, err;
457 error = 0;
458 dirp = opendir(name);
459 sprintf(dirInfoFile, "%s/upserver.tmp", gettmpdir());
460 stream = fopen(dirInfoFile, "w");
461 if (!stream) {
462 error = EIO;
463 } else {
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;
473 goto fail;
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);
481 err =
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);
487 if (err < 0)
488 error = EIO;
490 err = close(tfd);
491 if (err) {
492 printf("could not close file %s \n", filename);
493 error = UPDATE_ERROR;
494 goto fail;
498 fail:
499 if (dirp)
500 closedir(dirp);
501 if (stream) {
502 if (ferror(stream))
503 if (!error)
504 error = UPDATE_ERROR;
505 fclose(stream);
507 if (error == 0) {
508 fd = open(dirInfoFile, O_RDONLY, 0);
509 if (fd >= 0) {
510 fstat(fd, &tstatus);
511 errcode = update_SendFile(fd, call, &tstatus);
512 if (errcode)
513 if (!error)
514 error = UPDATE_ERROR;
515 close(fd);
518 unlink(dirInfoFile);
519 return 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
527 * passed back.
528 * dir : dir name passed in for export
531 static int
532 AddObject(char **expPath, char *dir)
534 int error;
535 struct stat statbuf;
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");
540 return error;
543 /* stat the object */
544 error = stat(*expPath, &statbuf);
545 if (error) {
546 afs_com_err(whoami, error, ";Can't stat object.");
547 return error;
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,
552 *expPath);
553 return -1;
556 return 0;