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