Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / kauth / knfs.c
1 /* Copyright (C) 1998 Transarc Corporation - All rights reserved */
2 /*
3  * (C) COPYRIGHT TRANSARC CORPORATION 1989
4  * LICENSED MATERIALS - PROPERTY OF TRANSARC
5  * ALL RIGHTS RESERVED
6  */
7
8 #include <afs/param.h>
9 #include <stdio.h>
10 #include <afs/stds.h>
11 #include <sys/types.h>
12 #include <ctype.h>
13 #include <sys/stat.h>
14 #include <signal.h>
15 #include <time.h>
16 #include <netdb.h>
17 #include <errno.h>
18 #include <sys/ioctl.h>
19 #include <afs/vice.h>
20 #include <afs/cmd.h>
21 #include <afs/auth.h>
22 #include <afs/afsutil.h>
23
24
25 extern struct cmd_syndesc *cmd_CreateSyntax();
26
27 /*
28 Modifications:
29
30 29 Oct 1992 Patch GetTokens to print something reasonable when there are no tokens.
31
32 */
33
34 /* this is a structure used to communicate with the afs cache mgr, but is
35  * otherwise irrelevant, or worse.
36  */
37 struct ClearToken {
38         afs_int32 AuthHandle;
39         char HandShakeKey[8];
40         afs_int32 ViceId;
41         afs_int32 BeginTimestamp;
42         afs_int32 EndTimestamp;
43 };
44
45
46 static SetSysname(ahost, auid, sysname)
47 afs_int32 ahost;
48 afs_int32 auid;
49 char *sysname;
50 {
51     afs_int32 code;
52     afs_int32 pheader[6];
53     char space[1200], *tp;
54     struct ViceIoctl blob;
55     afs_int32 setp = 1;
56
57     /* otherwise we've got the token, now prepare to build the pioctl args */
58     pheader[0] = ahost;
59     pheader[1] = auid;
60     pheader[2] = 0;                     /* group low */
61     pheader[3] = 0;                     /* group high */
62     pheader[4] = 38/*VIOC_AFS_SYSNAME*/;/* sysname pioctl index */
63     pheader[5] = 1;                     /* NFS protocol exporter # */
64         
65     /* copy stuff in */
66     bcopy(pheader, space, sizeof(pheader));
67     tp = space + sizeof(pheader);
68
69     /* finally setup the pioctl call's parameters */
70     blob.in_size = sizeof(pheader);
71     blob.in = space;
72     blob.out_size = 0;
73     blob.out = (char *) 0;
74     bcopy(&setp, tp, sizeof(afs_int32));
75     tp += sizeof(afs_int32);
76     strcpy(tp, sysname);
77     blob.in_size += sizeof(afs_int32) + strlen(sysname) + 1;
78     tp += strlen(sysname);
79     *(tp++) = '\0';
80     code = pioctl((char *) 0, _VICEIOCTL(99), &blob, 0);
81     if (code) {
82         code = errno;
83     }
84     return code;
85 }
86
87
88 static GetTokens(ahost, auid)
89     afs_int32 ahost;
90     afs_int32 auid;
91 {
92     struct ViceIoctl iob;
93     afs_int32 pheader[6];
94     char tbuffer[1024];
95     register afs_int32 code;
96     int index, newIndex;
97     char *stp;      /* secret token ptr */
98     struct ClearToken ct;
99     register char *tp;
100     afs_int32 temp, gotit = 0;
101     int maxLen; /* biggest ticket we can copy */
102     int tktLen; /* server ticket length */
103     time_t tokenExpireTime;
104     char UserName[16];
105     struct ktc_token token;
106     struct ktc_principal clientName;
107     time_t current_time;
108     char *expireString;
109
110     current_time = time(0);
111
112     /* otherwise we've got the token, now prepare to build the pioctl args */
113     pheader[0] = ahost;
114     pheader[1] = auid;
115     pheader[2] = 0;                     /* group low */
116     pheader[3] = 0;                     /* group high */
117     pheader[4] = 8;                     /* gettoken pioctl index */
118     pheader[5] = 1;                     /* NFS protocol exporter # */
119
120     for (index=0; index<200; index++) { /* sanity check in case pioctl fails */
121         code = ktc_ListTokens(index, &newIndex, &clientName);
122         if (code) {
123             if (code == KTC_NOENT) {
124                 /* all done */
125                 if (!gotit)
126                     printf("knfs: there are no tokens here.\n");
127                 code = 0;
128             }
129             break;      /* done, but failed */
130         }
131         if (strcmp(clientName.name, "afs") != 0) continue;      /* wrong ticket service */
132
133         /* copy stuff in */
134         bcopy(pheader, tbuffer, sizeof(pheader));
135         tp = tbuffer + sizeof(pheader);
136         bcopy(&index, tp, sizeof(afs_int32));
137         tp += sizeof(afs_int32);
138         iob.in = tbuffer;
139         iob.in_size = sizeof(afs_int32) + sizeof(pheader);
140         iob.out = tbuffer;
141         iob.out_size = sizeof(tbuffer);
142         code = pioctl((char *)0, _VICEIOCTL(99), &iob, 0);
143         if (code < 0 && errno == EDOM) return KTC_NOENT;
144         else if (code == 0) {
145             /* check to see if this is the right cell/realm */
146             tp = tbuffer;
147             bcopy(tp, &temp, sizeof(afs_int32)); /* get size of secret token */
148             tktLen = temp;  /* remember size of ticket */
149             tp += sizeof(afs_int32);
150             stp = tp;       /* remember where ticket is, for later */
151             tp += temp; /* skip ticket for now */
152             bcopy(tp, &temp, sizeof(afs_int32)); /* get size of clear token */
153             if (temp != sizeof(struct ClearToken)) return KTC_ERROR;
154             tp += sizeof(afs_int32);        /* skip length */
155             bcopy(tp, &ct, temp);   /* copy token for later use */
156             tp += temp;             /* skip clear token itself */
157             tp += sizeof(afs_int32);        /* skip primary flag */
158             /* tp now points to the cell name */
159             if (strcmp(tp, clientName.cell) == 0) {
160                 /* closing in now, we've got the right cell */
161                 gotit = 1;
162                 maxLen = sizeof(token) - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
163                 if (maxLen < tktLen) return KTC_TOOBIG;
164                 bcopy(stp, token.ticket, tktLen);
165                 token.startTime = ct.BeginTimestamp;
166                 token.endTime = ct.EndTimestamp;
167                 if (ct.AuthHandle == -1) ct.AuthHandle = 999;
168                 token.kvno = ct.AuthHandle;
169                 bcopy(ct.HandShakeKey, &token.sessionKey, sizeof(struct ktc_encryptionKey));
170                 token.ticketLen = tktLen;
171                 if ((token.kvno == 999) || /* old style bcrypt ticket */
172                     (ct.BeginTimestamp &&    /* new w/ prserver lookup */
173                      (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1))) {
174                     sprintf(clientName.name, "AFS ID %d", ct.ViceId);
175                     clientName.instance[0] = 0;
176                 } else {
177                     sprintf(clientName.name, "Unix UID %d", ct.ViceId);
178                     clientName.instance[0] = 0;
179                 }
180                 strcpy(clientName.cell, tp);
181
182                 tokenExpireTime = token.endTime;
183                 strcpy(UserName, clientName.name);
184                 if (clientName.instance[0] != 0) {
185                     strcat(UserName, ".");
186                     strcat(UserName, clientName.instance);
187                 }
188                 if (UserName[0] == 0)
189                     printf("Tokens");
190                 else if (strncmp(UserName, "AFS ID", 6) == 0) {
191                     printf("User's (%s) tokens", UserName);
192                 }
193                 else if (strncmp(UserName, "Unix UID", 8) == 0) {
194                     printf("Tokens");
195                 } else
196                     printf("User %s's tokens", UserName);
197                 printf(" for %s%s%s@%s ",
198                        clientName.name,
199                        clientName.instance[0] ? "." : "",
200                        clientName.instance,
201                        clientName.cell);
202                 if (tokenExpireTime <= current_time)
203                     printf("[>> Expired <<]\n");
204                 else {
205                     expireString = ctime(&tokenExpireTime);
206                     expireString += 4; /*Move past the day of week*/
207                     expireString[12] = '\0';
208                     printf("[Expires %s]\n", expireString);
209                 }
210
211             }
212         }
213     }
214     return code;
215 }
216
217
218 static NFSUnlog(ahost, auid)
219 afs_int32 ahost;
220 afs_int32 auid; {
221     afs_int32 code;
222     afs_int32 pheader[6];
223     char space[1200];
224     struct ViceIoctl blob;
225
226     /* otherwise we've got the token, now prepare to build the pioctl args */
227     pheader[0] = ahost;
228     pheader[1] = auid;
229     pheader[2] = 0;             /* group low */
230     pheader[3] = 0;             /* group high */
231     pheader[4] = 9;             /* unlog pioctl index */
232     pheader[5] = 1;             /* NFS protocol exporter # */
233         
234     /* copy stuff in */
235     bcopy(pheader, space, sizeof(pheader));
236
237     /* finally setup the pioctl call's parameters */
238     blob.in_size = sizeof(pheader);
239     blob.in = space;
240     blob.out_size = 0;
241     blob.out = (char *) 0;
242     code = pioctl((char *) 0, _VICEIOCTL(99), &blob, 0);
243     if (code) {
244         code = errno;
245     }
246     return code;
247 }
248
249 /* Copy the AFS service token into the kernel for a particular host and user */
250 static NFSCopyToken(ahost, auid)
251 afs_int32 ahost;
252 afs_int32 auid; {
253     struct ktc_principal client, server;
254     struct ktc_token theTicket;
255     afs_int32 code;
256     afs_int32 pheader[6];
257     char space[1200];
258     struct ClearToken ct;
259     afs_int32 index, newIndex;
260     afs_int32 temp;     /* for bcopy */
261     char *tp;
262     struct ViceIoctl blob;
263
264     for(index = 0;; index = newIndex) {
265         code = ktc_ListTokens(index, &newIndex, &server);
266         if (code) {
267             if (code == KTC_NOENT) {
268                 /* all done */
269                 code = 0;
270             }
271             break;      /* done, but failed */
272         }
273         if (strcmp(server.name, "afs") != 0) continue;  /* wrong ticket service */
274         code = ktc_GetToken(&server, &theTicket, sizeof(theTicket), &client);
275         if (code) return code;
276         
277         /* otherwise we've got the token, now prepare to build the pioctl args */
278         pheader[0] = ahost;
279         pheader[1] = auid;
280         pheader[2] = 0;         /* group low */
281         pheader[3] = 0;         /* group high */
282         pheader[4] = 3;         /* set token pioctl index */
283         pheader[5] = 1;         /* NFS protocol exporter # */
284         
285         /* copy in the header */
286         bcopy(pheader, space, sizeof(pheader));
287         tp = space + sizeof(pheader);
288         /* copy in the size of the encrypted part */
289         bcopy(&theTicket.ticketLen, tp, sizeof(afs_int32));
290         tp += sizeof(afs_int32);
291         /* copy in the ticket itself */
292         bcopy(theTicket.ticket, tp, theTicket.ticketLen);
293         tp += theTicket.ticketLen;
294         /* copy in "clear token"'s size */
295         temp = sizeof(struct ClearToken);
296         bcopy(&temp, tp, sizeof(afs_int32));
297         tp += sizeof(afs_int32);
298         /* create the clear token and copy *it* in */
299         ct.AuthHandle = theTicket.kvno; /* where we hide the key version # */
300         bcopy(&theTicket.sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
301
302         ct.ViceId = auid;
303         ct.BeginTimestamp = theTicket.startTime;
304         ct.EndTimestamp = theTicket.endTime;
305         bcopy(&ct, tp, sizeof(ct));
306         tp += sizeof(ct);
307         /* copy in obsolete primary flag */
308         temp = 0;
309         bcopy(&temp, tp, sizeof(afs_int32));
310         tp += sizeof(afs_int32);
311         /* copy in cell name, null terminated */
312         strcpy(tp, server.cell);
313         tp += strlen(server.cell)+1;
314
315         /* finally setup the pioctl call's parameters */
316         blob.in_size = tp-space;
317         blob.in = space;
318         blob.out_size = 0;
319         blob.out = (char *) 0;
320         code = pioctl((char *) 0, _VICEIOCTL(99), &blob, 0);
321         if (code) {
322             code = errno;
323             break;
324         }
325     }
326     return code;
327 }
328
329 static cmdproc(as, arock)
330 register struct cmd_syndesc *as;
331 afs_int32 arock; {
332     register struct hostent *the;
333     char *tp, *sysname = 0;
334     afs_int32 uid, addr;
335     register afs_int32 code;
336
337     the = (struct hostent *)
338         hostutil_GetHostByName(tp = as->parms[0].items->data);
339     if (!the) {
340         printf("knfs: unknown host '%s'.\n", tp);
341         return -1;
342     }
343     bcopy(the->h_addr, &addr, sizeof(afs_int32));
344     uid = -1;
345     if (as->parms[1].items) {
346         code = util_GetInt32(tp = as->parms[1].items->data, &uid);
347         if (code) {
348             printf("knfs: can't parse '%s' as a number (UID)\n", tp);
349             return code;
350         }
351     }
352     else uid = -1;      /* means wildcard: match any user on this host */
353
354     /*
355      * If not "-id" is passed then we use the getuid() id, unless it's root
356      * that is doing it in which case we only authenticate as "system:anyuser"
357      * as it's appropriate for root. (The cm handles conversions from 0 to
358      * "afs_nobody"!)
359      */
360     if (uid == -1) {
361         uid = getuid();
362     }
363
364     if (as->parms[2].items) {
365         sysname = as->parms[2].items->data;
366     }
367
368     if (as->parms[4].items) {
369         /* tokens specified */
370         code = GetTokens(addr, uid);
371         if (code) {
372             if (code == ENOEXEC)
373                 printf("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
374             else
375                 printf("knfs: failed to get tokens for uid %d (code %d)\n", uid, code);
376         }
377         return code;
378     }
379
380     /* finally, parsing is done, make the call */
381     if (as->parms[3].items) {
382         /* unlog specified */
383         code = NFSUnlog(addr, uid);
384         if (code) {
385             if (code == ENOEXEC)
386                 printf("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
387             else
388                 printf("knfs: failed to unlog (code %d)\n", code);
389         }
390     }
391     else {
392         code = NFSCopyToken(addr, uid);
393         if (code) {
394             if (code == ENOEXEC)
395                 printf("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
396             else
397                 printf("knfs: failed to copy tokens (code %d)\n", code);
398         }
399         if (sysname) {
400             code = SetSysname(addr, uid, sysname);
401             if (code) {
402                 printf("knfs: failed to set client's @sys to %s (code %d)\n", sysname, code);
403             }
404         }
405     }
406     return code;
407 }
408
409 #include "AFS_component_version_number.c"
410
411 main(argc, argv)
412 int argc;
413 char **argv; {
414     register struct cmd_syndesc *ts;
415     register afs_int32 code;
416
417 #ifdef  AFS_AIX32_ENV
418     /*
419      * The following signal action for AIX is necessary so that in case of a 
420      * crash (i.e. core is generated) we can include the user's data section 
421      * in the core dump. Unfortunately, by default, only a partial core is
422      * generated which, in many cases, isn't too useful.
423      */
424     struct sigaction nsa;
425     
426     sigemptyset(&nsa.sa_mask);
427     nsa.sa_handler = SIG_DFL;
428     nsa.sa_flags = SA_FULLDUMP;
429     sigaction(SIGABRT, &nsa, NULL);
430     sigaction(SIGSEGV, &nsa, NULL);
431 #endif
432
433     ts = cmd_CreateSyntax((char *) 0, cmdproc, 0, "copy tickets for NFS");
434     cmd_AddParm(ts, "-host", CMD_SINGLE, CMD_REQUIRED, "host name");
435     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "user ID (decimal)");
436     cmd_AddParm(ts, "-sysname", CMD_SINGLE, CMD_OPTIONAL, "host's '@sys' value");
437     cmd_AddParm(ts, "-unlog", CMD_FLAG, CMD_OPTIONAL, "unlog remote user");
438     cmd_AddParm(ts, "-tokens", CMD_FLAG, CMD_OPTIONAL, "display all tokens for remote [host,id]");
439
440     code = cmd_Dispatch(argc, argv);
441     return code;
442 }