linux-nfstrans-updates-20080630
[openafs.git] / src / afs / afs_pag_call.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13 RCSID
14     ("$Header$");
15
16 #include "afs/sysincludes.h"    /* Standard vendor system headers */
17 #include "afsincludes.h"        /* Afs-based standard headers */
18 #include "afs/afs_stats.h"
19 #include "rx/rx_globals.h"
20 #if !defined(UKERNEL) && !defined(AFS_LINUX20_ENV)
21 #include "net/if.h"
22 #ifdef AFS_SGI62_ENV
23 #include "h/hashing.h"
24 #endif
25 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_DARWIN60_ENV)
26 #include "netinet/in_var.h"
27 #endif
28 #endif /* !defined(UKERNEL) */
29 #ifdef AFS_LINUX22_ENV
30 #include "h/smp_lock.h"
31 #endif
32 #include "rmtsys.h"
33 #include "pagcb.h"
34
35
36 afs_int32 afs_termState = 0;
37 afs_int32 afs_gcpags = AFS_GCPAGS;
38 int afs_shuttingdown = 0;
39 int afs_cold_shutdown = 0;
40 int afs_resourceinit_flag = 0;
41 afs_int32 afs_nfs_server_addr;
42 struct interfaceAddr afs_cb_interface;
43 struct afs_osi_WaitHandle AFS_WaitHandler;
44 static struct rx_securityClass *srv_secobj;
45 static struct rx_securityClass *clt_secobj;
46 static struct rx_service *stats_svc;
47 static struct rx_service *pagcb_svc;
48 static struct rx_connection *rmtsys_conn;
49 char *afs_sysname = 0;
50 char *afs_sysnamelist[MAXNUMSYSNAMES];
51 int afs_sysnamecount = 0;
52 int afs_sysnamegen = 0;
53 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
54
55
56 void afs_Daemon(void)
57 {
58     afs_int32 now, last10MinCheck, last60MinCheck;
59
60     last10MinCheck = 0;
61     last60MinCheck = 0;
62     while (1) {
63         rx_CheckPackets();
64         now = osi_Time();
65
66         if (last10MinCheck + 600 < now) {
67             afs_GCUserData(0);
68         }
69
70         if (last60MinCheck + 3600 < now) {
71             afs_int32 didany;
72             afs_GCPAGs(&didany);
73         }
74
75         now = 20000 - (osi_Time() - now);
76         afs_osi_Wait(now, &AFS_WaitHandler, 0);
77
78         if (afs_termState == AFSOP_STOP_AFS) {
79 #if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV)
80             afs_termState = AFSOP_STOP_RXEVENT;
81 #else
82             afs_termState = AFSOP_STOP_COMPLETE;
83 #endif
84             afs_osi_Wakeup(&afs_termState);
85             return;
86         }
87     }
88 }
89
90
91 void afspag_Init(afs_int32 nfs_server_addr)
92 {
93     struct clientcred ccred;
94     struct rmtbulk idata, odata;
95     afs_int32 code, err, addr, obuf;
96     int i;
97
98     afs_uuid_create(&afs_cb_interface.uuid);
99
100     AFS_GLOCK();
101
102     afs_InitStats();
103     rx_Init(htons(7001));
104
105     AFS_STATCNT(afs_ResourceInit);
106     RWLOCK_INIT(&afs_xuser, "afs_xuser");
107     RWLOCK_INIT(&afs_xpagcell, "afs_xpagcell");
108     RWLOCK_INIT(&afs_xpagsys, "afs_xpagsys");
109     RWLOCK_INIT(&afs_icl_lock, "afs_icl_lock");
110 #ifndef AFS_FBSD_ENV
111     LOCK_INIT(&osi_fsplock, "osi_fsplock");
112     LOCK_INIT(&osi_flplock, "osi_flplock");
113 #endif
114
115     afs_resourceinit_flag = 1;
116     afs_nfs_server_addr = nfs_server_addr;
117     for (i = 0; i < MAXNUMSYSNAMES; i++)
118         afs_sysnamelist[i] = afs_osi_Alloc(MAXSYSNAME);
119     afs_sysname = afs_sysnamelist[0];
120     strcpy(afs_sysname, SYS_NAME);
121     afs_sysnamecount = 1;
122     afs_sysnamegen++;
123
124     srv_secobj = rxnull_NewServerSecurityObject();
125     stats_svc = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", &srv_secobj,
126                               1, RXSTATS_ExecuteRequest);
127     pagcb_svc = rx_NewService(0, PAGCB_SERVICEID, "pagcb", &srv_secobj,
128                               1, PAGCB_ExecuteRequest);
129     rx_StartServer(0);
130
131     clt_secobj = rxnull_NewClientSecurityObject();
132     rmtsys_conn = rx_NewConnection(nfs_server_addr, htons(7009),
133                                    RMTSYS_SERVICEID, clt_secobj, 0);
134
135 #ifdef RXK_LISTENER_ENV
136     afs_start_thread(rxk_Listener,       "Rx Listener");
137 #endif
138     afs_start_thread(rx_ServerProc,      "Rx Server Thread");
139     afs_start_thread(afs_rxevent_daemon, "Rx Event Daemon");
140     afs_start_thread(afs_Daemon,         "AFS PAG Daemon");
141
142     afs_icl_InitLogs();
143
144     AFS_GUNLOCK();
145
146     /* If it's reachable, tell the translator to nuke our creds.
147      * We should be more agressive about making sure this gets done,
148      * even if the translator is unreachable when we boot.
149      */
150     addr = obuf = err = 0;
151     idata.rmtbulk_len = sizeof(addr);
152     idata.rmtbulk_val = (char *)&addr;
153     odata.rmtbulk_len = sizeof(obuf);
154     odata.rmtbulk_val = (char *)&obuf;
155     memset(&ccred, 0, sizeof(ccred));
156     code = RMTSYS_Pioctl(rmtsys_conn, &ccred, NIL_PATHP, 0x4F01, 0,
157                          &idata, &odata, &err);
158 }                               /*afs_ResourceInit */
159
160
161 /* called with the GLOCK held */
162 void afspag_Shutdown(void)
163 {
164     if (afs_shuttingdown)
165         return;
166     afs_shuttingdown = 1;
167     afs_termState = AFSOP_STOP_RXCALLBACK;
168     rx_WakeupServerProcs();
169     while (afs_termState == AFSOP_STOP_RXCALLBACK)
170         afs_osi_Sleep(&afs_termState);
171     /* rx_ServerProc sets AFS_STOP_AFS */
172
173     while (afs_termState == AFSOP_STOP_AFS) {
174         afs_osi_CancelWait(&AFS_WaitHandler);
175         afs_osi_Sleep(&afs_termState);
176     }
177     /* afs_Daemon sets AFS_STOP_RXEVENT */
178
179 #if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV)
180     while (afs_termState == AFSOP_STOP_RXEVENT)
181         afs_osi_Sleep(&afs_termState);
182     /* afs_rxevent_daemon sets AFSOP_STOP_RXK_LISTENER */
183
184 #if defined(RXK_LISTENER_ENV)
185     afs_osi_UnmaskRxkSignals();
186     osi_StopListener();
187     while (afs_termState == AFSOP_STOP_RXK_LISTENER)
188         afs_osi_Sleep(&afs_termState);
189     /* rxk_Listener sets AFSOP_STOP_COMPLETE */
190 #endif
191 #endif
192 }
193
194 static void token_conversion(char *buffer, int buf_size, int in)
195 {
196     struct ClearToken *ticket;
197     afs_int32 *lptr, n;
198
199     /* secret ticket */
200     if (buf_size < 4) return;
201     lptr = (afs_int32 *)buffer;
202     buffer += 4; buf_size -= 4;
203     if (in) {
204         *lptr = ntohl(*lptr);
205         n = *lptr;
206     } else {
207         n = *lptr;
208         *lptr = htonl(*lptr);
209     }
210     if (n < 0 || buf_size < n) return;
211     buffer += n; buf_size -= n;
212
213     /* clear token */
214     if (buf_size < 4) return;
215     lptr = (afs_int32 *)buffer;
216     buffer += 4; buf_size -= 4;
217     if (in) {
218         *lptr = ntohl(*lptr);
219         n = *lptr;
220     } else {
221         n = *lptr;
222         *lptr = htonl(*lptr);
223     }
224     if (n < 0 || buf_size < n) return;
225     if (n >= sizeof(struct ClearToken)) {
226         ticket = (struct ClearToken *)buffer;
227         if (in) {
228             ticket->AuthHandle     = ntohl(ticket->AuthHandle);
229             ticket->ViceId         = ntohl(ticket->ViceId);
230             ticket->BeginTimestamp = ntohl(ticket->BeginTimestamp);
231             ticket->EndTimestamp   = ntohl(ticket->EndTimestamp);
232         } else {
233             ticket->AuthHandle     = htonl(ticket->AuthHandle);
234             ticket->ViceId         = htonl(ticket->ViceId);
235             ticket->BeginTimestamp = htonl(ticket->BeginTimestamp);
236             ticket->EndTimestamp   = htonl(ticket->EndTimestamp);
237         }
238     }
239     buffer += n; buf_size -= n;
240
241     /* primary flag */
242     if (buf_size < 4) return;
243     lptr = (afs_int32 *)buffer;
244     if (in) {
245         *lptr = ntohl(*lptr);
246     } else {
247         *lptr = htonl((*lptr) & ~0x8000);
248     }
249     return;
250 }
251
252 static void FetchVolumeStatus_conversion(char *buffer, int buf_size, int in)
253 {
254     AFSFetchVolumeStatus *status = (AFSFetchVolumeStatus *)buffer;
255
256     if (buf_size < sizeof(AFSFetchVolumeStatus))
257         return;
258     if (in) {
259         status->Vid              = ntohl(status->Vid);
260         status->ParentId         = ntohl(status->ParentId);
261         status->Type             = ntohl(status->Type);
262         status->MinQuota         = ntohl(status->MinQuota);
263         status->MaxQuota         = ntohl(status->MaxQuota);
264         status->BlocksInUse      = ntohl(status->BlocksInUse);
265         status->PartBlocksAvail  = ntohl(status->PartBlocksAvail);
266         status->PartMaxBlocks    = ntohl(status->PartMaxBlocks);
267     } else {
268         status->Vid              = htonl(status->Vid);
269         status->ParentId         = htonl(status->ParentId);
270         status->Type             = htonl(status->Type);
271         status->MinQuota         = htonl(status->MinQuota);
272         status->MaxQuota         = htonl(status->MaxQuota);
273         status->BlocksInUse      = htonl(status->BlocksInUse);
274         status->PartBlocksAvail  = htonl(status->PartBlocksAvail);
275         status->PartMaxBlocks    = htonl(status->PartMaxBlocks);
276     }
277 }
278
279 static void inparam_conversion(int cmd, char *buffer, int buf_size, int in)
280 {
281     afs_int32 *lptr = (afs_int32 *)buffer;
282
283     switch (cmd & 0xffff) {
284         case (0x5600 |  3): /* VIOCSETTOK */
285             token_conversion(buffer, buf_size, in);
286             return;
287
288         case (0x5600 |  5): /* VIOCSETVOLSTAT */
289             FetchVolumeStatus_conversion(buffer, buf_size, in);
290             return;
291
292         case (0x5600 |  8): /* VIOCGETTOK */
293         case (0x5600 | 10): /* VIOCCKSERV */
294         case (0x5600 | 20): /* VIOCACCESS */
295         case (0x5600 | 24): /* VIOCSETCACHESIZE */
296         case (0x5600 | 27): /* VIOCGETCELL */
297         case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */
298         case (0x5600 | 34): /* VIOC_VENUSLOG */
299         case (0x5600 | 38): /* VIOC_AFS_SYSNAME */
300         case (0x5600 | 39): /* VIOC_EXPORTAFS */
301             /* one 32-bit integer */
302             if (buf_size >= 4) {
303                 if (in) lptr[0] = ntohl(lptr[0]);
304                 else    lptr[0] = htonl(lptr[0]);
305             }
306             return;
307
308         case (0x5600 | 36): /* VIOCSETCELLSTATUS */
309             /* two 32-bit integers */
310             if (buf_size >= 4) {
311                 if (in) lptr[0] = ntohl(lptr[0]);
312                 else    lptr[0] = htonl(lptr[0]);
313             }
314             if (buf_size >= 8) {
315                 if (in) lptr[1] = ntohl(lptr[1]);
316                 else    lptr[1] = htonl(lptr[1]);
317             }
318             return;
319     }
320 }
321
322 static void outparam_conversion(int cmd, char *buffer, int buf_size, int in)
323 {
324     afs_int32 *lptr = (afs_int32 *)buffer;
325     int i;
326
327     switch (cmd & 0xffff) {
328         case (0x5600 |  4): /* VIOCGETVOLSTAT */
329         case (0x5600 |  5): /* VIOCSETVOLSTAT */
330             FetchVolumeStatus_conversion(buffer, buf_size, in);
331             return;
332
333         case (0x5600 |  8): /* VIOCGETTOK */
334             token_conversion(buffer, buf_size, in);
335             return;
336
337         case (0x5600 | 12): /* VIOCCKCONN */
338         case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */
339         case (0x5600 | 34): /* VIOC_VENUSLOG */
340         case (0x5600 | 35): /* VIOC_GETCELLSTATUS */
341         case (0x5600 | 38): /* VIOC_AFS_SYSNAME */
342         case (0x5600 | 39): /* VIOC_EXPORTAFS */
343             /* one 32-bit integer */
344             if (buf_size >= 4) {
345                 if (in) lptr[0] = ntohl(lptr[0]);
346                 else    lptr[0] = htonl(lptr[0]);
347             }
348             return;
349
350         case (0x5600 | 40): /* VIOCGETCACHEPARMS */
351             /* sixteen 32-bit integers */
352             for (i = 0; i < 16 && buf_size >= 4; i++) {
353                 if (in) lptr[i] = ntohl(lptr[i]);
354                 else    lptr[i] = htonl(lptr[i]);
355                 buf_size -= 4;
356             }
357             return;
358     }
359 }
360
361
362 /* called with the GLOCK held */
363 int
364 #ifdef  AFS_SUN5_ENV
365 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
366      rval_t *rvp;
367      struct AFS_UCRED *credp;
368 #else
369 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
370 afs_syscall_pioctl(path, com, cmarg, follow, credp)
371      struct AFS_UCRED *credp;
372 #else
373 afs_syscall_pioctl(path, com, cmarg, follow)
374 #endif
375 #endif
376      char *path;
377      unsigned int com;
378      caddr_t cmarg;
379      int follow;
380 {
381 #ifdef  AFS_AIX41_ENV
382     struct ucred *credp = crref();      /* don't free until done! */
383 #endif
384 #ifdef AFS_LINUX22_ENV
385     cred_t *credp = crref();    /* don't free until done! */
386 #endif
387     struct afs_ioctl data;
388     struct clientcred ccred;
389     struct rmtbulk idata, odata;
390     short in_size, out_size;
391     afs_int32 code = 0, pag, err;
392     gid_t g0, g1;
393     char *abspath, *pathbuf = 0;
394
395     AFS_STATCNT(afs_syscall_pioctl);
396     if (follow)
397         follow = 1;             /* compat. with old venus */
398     code = copyin_afs_ioctl(cmarg, &data);
399     if (code) goto out;
400
401     if ((com & 0xff) == 90) {
402         /* PSetClientContext, in any space */
403         code = EINVAL;
404         goto out;
405     }
406
407     /* Special handling for a few pioctls */
408     switch (com & 0xffff) {
409         case (0x5600 |  3): /* VIOCSETTOK */
410             code = afspag_PSetTokens(data.in, data.in_size, &credp);
411             if (code) goto out;
412             break;
413
414         case (0x5600 |  9): /* VIOCUNLOG */
415         case (0x5600 | 21): /* VIOCUNPAG */
416             code = afspag_PUnlog(data.in, data.in_size, &credp);
417             if (code) goto out;
418             break;
419
420         case (0x5600 | 38): /* VIOC_AFS_SYSNAME */
421             code = afspag_PSetSysName(data.in, data.in_size, &credp);
422             if (code) goto out;
423             break;
424     }
425
426     /* Set up credentials */
427     memset(&ccred, 0, sizeof(ccred));
428     pag = PagInCred(credp);
429     ccred.uid = credp->cr_uid;
430     if (pag != NOPAG) {
431          afs_get_groups_from_pag(pag, &g0, &g1);
432          ccred.group0 = g0;
433          ccred.group1 = g1;
434     }
435
436     /*
437      * Copy the path and convert to absolute, if one was given.
438      * NB: We can only use osI_AllocLargeSpace here as long as
439      * RMTSYS_MAXPATHLEN is less than AFS_LRALLOCSIZ.
440      */
441     if (path) {
442         pathbuf = osi_AllocLargeSpace(RMTSYS_MAXPATHLEN);
443         if (!pathbuf) {
444             code = ENOMEM;
445             goto out;
446         }
447         code = osi_abspath(path, pathbuf, RMTSYS_MAXPATHLEN, 0, &abspath);
448         if (code)
449             goto out_path;
450     } else {
451         abspath = NIL_PATHP;
452     }
453
454     /* Allocate, copy, and convert incoming data */
455     idata.rmtbulk_len = in_size = data.in_size;
456     if (in_size  < 0 || in_size  > MAXBUFFERLEN) {
457         code = EINVAL;
458         goto out_path;
459     }
460     if (in_size > AFS_LRALLOCSIZ)
461          idata.rmtbulk_val = osi_Alloc(in_size);
462     else
463          idata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
464     if (!idata.rmtbulk_val) {
465         code = ENOMEM;
466         goto out_path;
467     }
468     if (in_size) {
469         AFS_COPYIN(data.in, idata.rmtbulk_val, in_size, code);
470         if (code)
471             goto out_idata;
472         inparam_conversion(com, idata.rmtbulk_val, in_size, 0);
473     }
474
475     /* Allocate space for outgoing data */
476     odata.rmtbulk_len = out_size = data.out_size;
477     if (out_size < 0 || out_size > MAXBUFFERLEN) {
478         code = EINVAL;
479         goto out_idata;
480     }
481     if (out_size > AFS_LRALLOCSIZ)
482          odata.rmtbulk_val = osi_Alloc(out_size);
483     else
484          odata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
485     if (!odata.rmtbulk_val) {
486         code = ENOMEM;
487         goto out_idata;
488     }
489
490     AFS_GUNLOCK();
491     code = RMTSYS_Pioctl(rmtsys_conn, &ccred, abspath, com, follow,
492                          &idata, &odata, &err);
493     AFS_GLOCK();
494     if (code)
495         goto out_odata;
496
497     /* Convert and copy out the result */
498     if (odata.rmtbulk_len > out_size) {
499         code = E2BIG;
500         goto out_odata;
501     }
502     if (odata.rmtbulk_len) {
503         outparam_conversion(com, odata.rmtbulk_val, odata.rmtbulk_len, 1);
504         AFS_COPYOUT(odata.rmtbulk_val, data.out, odata.rmtbulk_len, code);
505     }
506     if (!code)
507         code = err;
508
509 out_odata:
510     if (out_size > AFS_LRALLOCSIZ)
511         osi_Free(odata.rmtbulk_val, out_size);
512     else
513         osi_FreeLargeSpace(odata.rmtbulk_val);
514
515 out_idata:
516     if (in_size > AFS_LRALLOCSIZ)
517         osi_Free(idata.rmtbulk_val, in_size);
518     else
519         osi_FreeLargeSpace(idata.rmtbulk_val);
520
521 out_path:
522     if (path)
523         osi_FreeLargeSpace(pathbuf);
524
525 out:
526 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
527     crfree(credp);
528 #endif
529 #if defined(KERNEL_HAVE_UERROR)
530     if (!getuerror())
531         setuerror(code);
532     return (getuerror());
533 #else
534     return (code);
535 #endif
536 }
537
538
539 int
540 afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
541      long parm, parm2, parm3, parm4, parm5, parm6;
542 {
543     /* superusers may shut us down, as with afsd --shutdown */
544 #ifdef AFS_SUN5_ENV
545     if (parm == AFSOP_SHUTDOWN && afs_suser(CRED()))
546 #else
547     if (parm == AFSOP_SHUTDOWN && afs_suser(NULL))
548 #endif
549     {
550         AFS_GLOCK();
551         afspag_Shutdown();
552         AFS_GUNLOCK();
553         return 0;
554     }
555
556     /* otherwise, we don't support afs_syscall_call, period */
557 #if defined(KERNEL_HAVE_UERROR)
558     setuerror(EPERM);
559 #endif
560     return EPERM;
561 }