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