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