prototyping-20040623
[openafs.git] / src / ptserver / ptuser.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 #if defined(UKERNEL)
12 #include "afs/param.h"
13 #else
14 #include <afs/param.h>
15 #endif
16
17 RCSID
18     ("$Header$");
19
20 #if defined(UKERNEL)
21 #include "afs/sysincludes.h"
22 #include "afs_usrops.h"
23 #include "afsincludes.h"
24 #include "afs/stds.h"
25 #include "rx/rx.h"
26 #include "rx/xdr.h"
27 #include "rx/rxkad.h"
28 #include "afs/auth.h"
29 #include "afs/cellconfig.h"
30 #include "afs/afsutil.h"
31 #include "afs/ptclient.h"
32 #include "afs/pterror.h"
33 #else /* defined(UKERNEL) */
34 #include <afs/stds.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #ifdef AFS_NT40_ENV
38 #include <winsock2.h>
39 #else
40 #include <netinet/in.h>
41 #endif
42 #include <stdio.h>
43 #ifdef HAVE_STRING_H
44 #include <string.h>
45 #else
46 #ifdef HAVE_STRINGS_H
47 #include <strings.h>
48 #endif
49 #endif
50 #include <rx/rx.h>
51 #include <rx/xdr.h>
52 #include <rx/rxkad.h>
53 #include <afs/auth.h>
54 #include <afs/cellconfig.h>
55 #include <afs/afsutil.h>
56 #include "ptclient.h"
57 #include "pterror.h"
58 #endif /* defined(UKERNEL) */
59
60
61 struct ubik_client *pruclient = 0;
62 static afs_int32 lastLevel;     /* security level pruclient, if any */
63
64 static char *whoami = "libprot";
65
66 afs_int32
67 pr_Initialize(IN afs_int32 secLevel, IN char *confDir, IN char *cell)
68 {
69     afs_int32 code;
70     struct rx_connection *serverconns[MAXSERVERS];
71     struct rx_securityClass *sc[3];
72     static struct afsconf_dir *tdir = 0;        /* only do this once */
73     static char tconfDir[100];
74     struct ktc_token ttoken;
75     afs_int32 scIndex;
76     static struct afsconf_cell info;
77     afs_int32 i;
78     char cellstr[64];
79
80     initialize_PT_error_table();
81     initialize_RXK_error_table();
82     initialize_ACFG_error_table();
83     initialize_KTC_error_table();
84
85     if (strcmp(confDir, tconfDir)) {
86         /*
87          * Different conf dir; force re-evaluation.
88          */
89         tdir = (struct afsconf_dir *)0;
90         pruclient = (struct ubik_client *)0;
91     }
92     if (tdir == 0) {
93         strncpy(tconfDir, confDir, sizeof(tconfDir));
94 #if defined(UKERNEL)
95         tdir = afs_cdir;
96         if (!cell) {
97             cell = afs_LclCellName;
98         }
99 #else /* defined(UKERNEL) */
100         tdir = afsconf_Open(confDir);
101         if (!tdir) {
102             if (confDir && strcmp(confDir, ""))
103                 fprintf(stderr,
104                         "libprot: Could not open configuration directory: %s.\n",
105                         confDir);
106             return -1;
107         }
108
109         if (!cell) {
110             code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr));
111             if (code) {
112                 fprintf(stderr,
113                         "vos: can't get local cell name - check %s/%s\n",
114                         confDir, AFSDIR_THISCELL_FILE);
115                 exit(1);
116             }
117             cell = cellstr;
118         }
119 #endif /* defined(UKERNEL) */
120
121         code = afsconf_GetCellInfo(tdir, cell, "afsprot", &info);
122         if (code) {
123             fprintf(stderr, "libprot: Could not locate cell %s in %s/%s\n",
124                     cell, confDir, AFSDIR_CELLSERVDB_FILE);
125             return code;
126         }
127     }
128
129     /* If we already have a client and it is at the security level we
130      * want, don't get a new one. Unless the security level is 2 in
131      * which case we will get one (and re-read the key file).
132      */
133     if (pruclient && (lastLevel == secLevel) && (secLevel != 2))
134         return 0;
135
136     code = rx_Init(0);
137     if (code) {
138         fprintf(stderr, "libprot:  Could not initialize rx.\n");
139         return code;
140     }
141
142     scIndex = secLevel;
143     sc[0] = 0;
144     sc[1] = 0;
145     sc[2] = 0;
146     /* Most callers use secLevel==1, however, the fileserver uses secLevel==2
147      * to force use of the KeyFile.  secLevel == 0 implies -noauth was
148      * specified. */
149     if ((secLevel == 2) && (afsconf_GetLatestKey(tdir, 0, 0) == 0)) {
150         /* If secLevel is two assume we're on a file server and use
151          * ClientAuthSecure if possible. */
152         code = afsconf_ClientAuthSecure(tdir, &sc[2], &scIndex);
153         if (code)
154             fprintf(stderr,
155                     "libprot: clientauthsecure returns %d %s"
156                     " (so trying noauth)\n", code, error_message(code));
157         if (code)
158             scIndex = 0;        /* use noauth */
159         if (scIndex != 2)
160             /* if there was a problem, an unauthenticated conn is returned */
161             sc[scIndex] = sc[2];
162     } else if (secLevel > 0) {
163         struct ktc_principal sname;
164         strcpy(sname.cell, info.name);
165         sname.instance[0] = 0;
166         strcpy(sname.name, "afs");
167         code = ktc_GetToken(&sname, &ttoken, sizeof(ttoken), NULL);
168         if (code)
169             scIndex = 0;
170         else {
171             if (ttoken.kvno >= 0 && ttoken.kvno <= 255)
172                 /* this is a kerberos ticket, set scIndex accordingly */
173                 scIndex = 2;
174             else {
175                 fprintf(stderr,
176                         "libprot: funny kvno (%d) in ticket, proceeding\n",
177                         ttoken.kvno);
178                 scIndex = 2;
179             }
180             sc[2] =
181                 rxkad_NewClientSecurityObject(secLevel, &ttoken.sessionKey,
182                                               ttoken.kvno, ttoken.ticketLen,
183                                               ttoken.ticket);
184         }
185     }
186     if (scIndex == 1)
187         return PRBADARG;
188     if ((scIndex == 0) && (sc[0] == 0))
189         sc[0] = rxnull_NewClientSecurityObject();
190     if ((scIndex == 0) && (secLevel != 0))
191         com_err(whoami, code,
192                 "Could not get afs tokens, running unauthenticated.");
193
194     memset(serverconns, 0, sizeof(serverconns));        /* terminate list!!! */
195     for (i = 0; i < info.numServers; i++)
196         serverconns[i] =
197             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
198                              info.hostAddr[i].sin_port, PRSRV, sc[scIndex],
199                              scIndex);
200
201     code = ubik_ClientInit(serverconns, &pruclient);
202     if (code) {
203         com_err(whoami, code, "ubik client init failed.");
204         return code;
205     }
206     lastLevel = scIndex;
207
208     code = rxs_Release(sc[scIndex]);
209     return code;
210 }
211
212 int
213 pr_End()
214 {
215     int code = 0;
216
217     if (pruclient) {
218         code = ubik_ClientDestroy(pruclient);
219         pruclient = 0;
220     }
221     return code;
222 }
223
224
225
226 int
227 pr_CreateUser(char name[PR_MAXNAMELEN], afs_int32 *id)
228 {
229     register afs_int32 code;
230
231     stolower(name);
232     if (*id) {
233         code = ubik_Call(PR_INewEntry, pruclient, 0, name, *id, 0);
234         return code;
235     } else {
236         code = ubik_Call(PR_NewEntry, pruclient, 0, name, 0, 0, id);
237         return code;
238     }
239
240 }
241
242 int 
243 pr_CreateGroup(char name[PR_MAXNAMELEN], char owner[PR_MAXNAMELEN], afs_int32 *id)
244 {
245     register afs_int32 code;
246     afs_int32 oid = 0;
247     afs_int32 flags = 0;
248
249     stolower(name);
250     if (owner) {
251         code = pr_SNameToId(owner, &oid);
252         if (code)
253             return code;
254         if (oid == ANONYMOUSID)
255             return PRNOENT;
256     }
257     flags |= PRGRP;
258     if (*id) {
259         code = ubik_Call(PR_INewEntry, pruclient, 0, name, *id, oid);
260         return code;
261     } else {
262         code = ubik_Call(PR_NewEntry, pruclient, 0, name, flags, oid, id);
263         return code;
264     }
265 }
266
267 int
268 pr_Delete(char *name)
269 {
270     register afs_int32 code;
271     afs_int32 id;
272
273     stolower(name);
274     code = pr_SNameToId(name, &id);
275     if (code)
276         return code;
277     if (id == ANONYMOUSID)
278         return PRNOENT;
279     code = ubik_Call(PR_Delete, pruclient, 0, id);
280     return code;
281 }
282
283 int
284 pr_DeleteByID(afs_int32 id)
285 {
286     register afs_int32 code;
287
288     code = ubik_Call(PR_Delete, pruclient, 0, id);
289     return code;
290 }
291
292 int
293 pr_AddToGroup(char *user, char *group)
294 {
295     register afs_int32 code;
296     namelist lnames;
297     idlist lids;
298
299     lnames.namelist_len = 2;
300     lnames.namelist_val = (prname *) malloc(2 * PR_MAXNAMELEN);
301     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
302     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
303     lids.idlist_val = 0;
304     lids.idlist_len = 0;
305     code = pr_NameToId(&lnames, &lids);
306     if (code)
307         goto done;
308     /* if here, still could be missing an entry */
309     if (lids.idlist_val[0] == ANONYMOUSID
310         || lids.idlist_val[1] == ANONYMOUSID) {
311         code = PRNOENT;
312         goto done;
313     }
314     code =
315         ubik_Call(PR_AddToGroup, pruclient, 0, lids.idlist_val[0],
316                   lids.idlist_val[1]);
317   done:
318     if (lnames.namelist_val)
319         free(lnames.namelist_val);
320     if (lids.idlist_val)
321         free(lids.idlist_val);
322     return code;
323 }
324
325 int
326 pr_RemoveUserFromGroup(char *user, char *group)
327 {
328     register afs_int32 code;
329     namelist lnames;
330     idlist lids;
331
332     lnames.namelist_len = 2;
333     lnames.namelist_val = (prname *) malloc(2 * PR_MAXNAMELEN);
334     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
335     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
336     lids.idlist_val = 0;
337     lids.idlist_len = 0;
338     code = pr_NameToId(&lnames, &lids);
339     if (code)
340         goto done;
341
342     if (lids.idlist_val[0] == ANONYMOUSID
343         || lids.idlist_val[1] == ANONYMOUSID) {
344         code = PRNOENT;
345         goto done;
346     }
347     code =
348         ubik_Call(PR_RemoveFromGroup, pruclient, 0, lids.idlist_val[0],
349                   lids.idlist_val[1]);
350   done:
351     if (lnames.namelist_val)
352         free(lnames.namelist_val);
353     if (lids.idlist_val)
354         free(lids.idlist_val);
355     return code;
356
357 }
358
359 int
360 pr_NameToId(namelist *names, idlist *ids)
361 {
362     register afs_int32 code;
363     register afs_int32 i;
364
365     for (i = 0; i < names->namelist_len; i++)
366         stolower(names->namelist_val[i]);
367     code = ubik_Call(PR_NameToID, pruclient, 0, names, ids);
368     return code;
369 }
370
371 int
372 pr_SNameToId(char name[PR_MAXNAMELEN], afs_int32 *id)
373 {
374     namelist lnames;
375     idlist lids;
376     register afs_int32 code;
377
378     lids.idlist_len = 0;
379     lids.idlist_val = 0;
380     lnames.namelist_len = 1;
381     lnames.namelist_val = (prname *) malloc(PR_MAXNAMELEN);
382     stolower(name);
383     strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN);
384     code = ubik_Call(PR_NameToID, pruclient, 0, &lnames, &lids);
385     if (lids.idlist_val) {
386         *id = *lids.idlist_val;
387         free(lids.idlist_val);
388     }
389     if (lnames.namelist_val)
390         free(lnames.namelist_val);
391     return code;
392 }
393
394 int
395 pr_IdToName(idlist *ids, namelist *names)
396 {
397     register afs_int32 code;
398
399     code = ubik_Call(PR_IDToName, pruclient, 0, ids, names);
400     return code;
401 }
402
403 int
404 pr_SIdToName(afs_int32 id, char name[PR_MAXNAMELEN])
405 {
406     namelist lnames;
407     idlist lids;
408     register afs_int32 code;
409
410     lids.idlist_len = 1;
411     lids.idlist_val = (afs_int32 *) malloc(sizeof(afs_int32));
412     *lids.idlist_val = id;
413     lnames.namelist_len = 0;
414     lnames.namelist_val = 0;
415     code = ubik_Call(PR_IDToName, pruclient, 0, &lids, &lnames);
416     if (lnames.namelist_val) {
417         strncpy(name, lnames.namelist_val[0], PR_MAXNAMELEN);
418         free(lnames.namelist_val);
419     }
420     if (lids.idlist_val)
421         free(lids.idlist_val);
422     return code;
423 }
424
425 int
426 pr_GetCPS(afs_int32 id, prlist *CPS)
427 {
428     register afs_int32 code;
429     afs_int32 over;
430
431     over = 0;
432     code = ubik_Call(PR_GetCPS, pruclient, 0, id, CPS, &over);
433     if (code != PRSUCCESS)
434         return code;
435     if (over) {
436         /* do something about this, probably make a new call */
437         /* don't forget there's a hard limit in the interface */
438         fprintf(stderr, "membership list for id %d exceeds display limit\n",
439                 id);
440     }
441     return 0;
442 }
443
444 int
445 pr_GetCPS2(afs_int32 id, afs_int32 host, prlist *CPS)
446 {
447     register afs_int32 code;
448     afs_int32 over;
449
450     over = 0;
451     code = ubik_Call(PR_GetCPS2, pruclient, 0, id, host, CPS, &over);
452     if (code != PRSUCCESS)
453         return code;
454     if (over) {
455         /* do something about this, probably make a new call */
456         /* don't forget there's a hard limit in the interface */
457         fprintf(stderr, "membership list for id %d exceeds display limit\n",
458                 id);
459     }
460     return 0;
461 }
462
463 int
464 pr_GetHostCPS(afs_int32 host, prlist *CPS)
465 {
466     register afs_int32 code;
467     afs_int32 over;
468
469     over = 0;
470     code = ubik_Call(PR_GetHostCPS, pruclient, 0, host, CPS, &over);
471     if (code != PRSUCCESS)
472         return code;
473     if (over) {
474         /* do something about this, probably make a new call */
475         /* don't forget there's a hard limit in the interface */
476         fprintf(stderr,
477                 "membership list for host id %d exceeds display limit\n",
478                 host);
479     }
480     return 0;
481 }
482
483 int
484 pr_ListMembers(char *group, namelist *lnames)
485 {
486     register afs_int32 code;
487     afs_int32 gid;
488
489     code = pr_SNameToId(group, &gid);
490     if (code)
491         return code;
492     if (gid == ANONYMOUSID)
493         return PRNOENT;
494     code = pr_IDListMembers(gid, lnames);
495     return code;
496 }
497
498 int
499 pr_ListOwned(afs_int32 oid, namelist *lnames, afs_int32 *moreP)
500 {
501     register afs_int32 code;
502     prlist alist;
503     idlist *lids;
504
505     alist.prlist_len = 0;
506     alist.prlist_val = 0;
507     code = ubik_Call(PR_ListOwned, pruclient, 0, oid, &alist, moreP);
508     if (code)
509         return code;
510     if (*moreP == 1) {
511         /* Remain backwards compatible when moreP was a T/F bit */
512         fprintf(stderr, "membership list for id %d exceeds display limit\n",
513                 oid);
514         *moreP = 0;
515     }
516     lids = (idlist *) & alist;
517     code = pr_IdToName(lids, lnames);
518     if (code)
519         return code;
520     if (alist.prlist_val)
521         free(alist.prlist_val);
522     return PRSUCCESS;
523 }
524
525 int
526 pr_IDListMembers(afs_int32 gid, namelist *lnames)
527 {
528     register afs_int32 code;
529     prlist alist;
530     idlist *lids;
531     afs_int32 over;
532
533     alist.prlist_len = 0;
534     alist.prlist_val = 0;
535     code = ubik_Call(PR_ListElements, pruclient, 0, gid, &alist, &over);
536     if (code)
537         return code;
538     if (over) {
539         fprintf(stderr, "membership list for id %d exceeds display limit\n",
540                 gid);
541     }
542     lids = (idlist *) & alist;
543     code = pr_IdToName(lids, lnames);
544     if (code)
545         return code;
546     if (alist.prlist_val)
547         free(alist.prlist_val);
548     return PRSUCCESS;
549 }
550
551 int
552 pr_ListEntry(afs_int32 id, struct prcheckentry *aentry)
553 {
554     register afs_int32 code;
555
556     code = ubik_Call(PR_ListEntry, pruclient, 0, id, aentry);
557     return code;
558 }
559
560 afs_int32
561 pr_ListEntries(int flag, afs_int32 startindex, afs_int32 *nentries, struct prlistentries **entries, afs_int32 *nextstartindex)
562 {
563     afs_int32 code;
564     prentries bulkentries;
565
566     *nentries = 0;
567     *entries = NULL;
568     *nextstartindex = -1;
569     bulkentries.prentries_val = 0;
570     bulkentries.prentries_len = 0;
571
572     code =
573         ubik_Call(PR_ListEntries, pruclient, 0, flag, startindex,
574                   &bulkentries, nextstartindex);
575     *nentries = bulkentries.prentries_len;
576     *entries = bulkentries.prentries_val;
577     return code;
578 }
579
580 int
581 pr_CheckEntryByName(char *name, afs_int32 *id, char *owner, char *creator)
582 {
583     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
584     register afs_int32 code;
585     struct prcheckentry aentry;
586
587     code = pr_SNameToId(name, id);
588     if (code)
589         return code;
590     if (*id == ANONYMOUSID)
591         return PRNOENT;
592     code = ubik_Call(PR_ListEntry, pruclient, 0, *id, &aentry);
593     if (code)
594         return code;
595     /* this should be done in one RPC, but I'm lazy. */
596     code = pr_SIdToName(aentry.owner, owner);
597     if (code)
598         return code;
599     code = pr_SIdToName(aentry.creator, creator);
600     if (code)
601         return code;
602     return PRSUCCESS;
603 }
604
605 int
606 pr_CheckEntryById(char *name, afs_int32 id, char *owner, char *creator)
607 {
608     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
609     register afs_int32 code;
610     struct prcheckentry aentry;
611
612     code = pr_SIdToName(id, name);
613     if (code)
614         return code;
615     if (id == ANONYMOUSID)
616         return PRNOENT;
617     code = ubik_Call(PR_ListEntry, pruclient, 0, id, &aentry);
618     if (code)
619         return code;
620     /* this should be done in one RPC, but I'm lazy. */
621     code = pr_SIdToName(aentry.owner, owner);
622     if (code)
623         return code;
624     code = pr_SIdToName(aentry.creator, creator);
625     if (code)
626         return code;
627     return PRSUCCESS;
628 }
629
630 int
631 pr_ChangeEntry(char *oldname, char *newname, afs_int32 *newid, char *newowner)
632 {
633     register afs_int32 code;
634     afs_int32 id;
635     afs_int32 oid = 0;
636
637     code = pr_SNameToId(oldname, &id);
638     if (code)
639         return code;
640     if (id == ANONYMOUSID)
641         return PRNOENT;
642     if (newowner && *newowner) {
643         code = pr_SNameToId(newowner, &oid);
644         if (code)
645             return code;
646         if (oid == ANONYMOUSID)
647             return PRNOENT;
648     }
649     code = ubik_Call(PR_ChangeEntry, pruclient, 0, id, newname, oid, newid);
650     return code;
651 }
652
653 int
654 pr_IsAMemberOf(char *uname, char *gname, afs_int32 *flag)
655 {
656     register afs_int32 code;
657     namelist lnames;
658     idlist lids;
659
660     stolower(uname);
661     stolower(gname);
662     lnames.namelist_len = 2;
663     lnames.namelist_val = (prname *) malloc(2 * PR_MAXNAMELEN);
664     strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
665     strncpy(lnames.namelist_val[1], gname, PR_MAXNAMELEN);
666     lids.idlist_val = 0;
667     lids.idlist_len = 0;
668     code = pr_NameToId(&lnames, &lids);
669     if (code) {
670         if (lnames.namelist_val)
671             free(lnames.namelist_val);
672         if (lids.idlist_val)
673             free(lids.idlist_val);
674         return code;
675     }
676     code =
677         ubik_Call(PR_IsAMemberOf, pruclient, 0, lids.idlist_val[0],
678                   lids.idlist_val[1], flag);
679     if (lnames.namelist_val)
680         free(lnames.namelist_val);
681     if (lids.idlist_val)
682         free(lids.idlist_val);
683     return code;
684 }
685
686 int
687 pr_ListMaxUserId(afs_int32 *mid)
688 {
689     register afs_int32 code;
690     afs_int32 gid;
691     code = ubik_Call(PR_ListMax, pruclient, 0, mid, &gid);
692     return code;
693 }
694
695 int
696 pr_SetMaxUserId(afs_int32 mid)
697 {
698     register afs_int32 code;
699     afs_int32 flag = 0;
700     code = ubik_Call(PR_SetMax, pruclient, 0, mid, flag);
701     return code;
702 }
703
704 int
705 pr_ListMaxGroupId(afs_int32 *mid)
706 {
707     register afs_int32 code;
708     afs_int32 id;
709     code = ubik_Call(PR_ListMax, pruclient, 0, &id, mid);
710     return code;
711 }
712
713 int
714 pr_SetMaxGroupId(afs_int32 mid)
715 {
716     register afs_int32 code;
717     afs_int32 flag = 0;
718
719     flag |= PRGRP;
720     code = ubik_Call(PR_SetMax, pruclient, 0, mid, flag);
721     return code;
722 }
723
724 afs_int32
725 pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers)
726 {
727     register afs_int32 code;
728
729     code =
730         ubik_Call(PR_SetFieldsEntry, pruclient, 0, id, mask, flags, ngroups,
731                   nusers, 0, 0);
732     return code;
733 }
734
735 int
736 stolower(char *s)
737 {
738     while (*s) {
739         if (isupper(*s))
740             *s = tolower(*s);
741         s++;
742     }
743     return 0;
744 }