]> andersk Git - moira.git/blob - clients/stella/stella.c
Check the sanity of KERBEROS machine owners, just like we do for list
[moira.git] / clients / stella / stella.c
1 /*
2  * Command line oriented Moira host tool.
3  *
4  * kolya@MIT.EDU, January 2000
5  *
6  * Somewhat based on blanche
7  *
8  * Copyright (C) 2000 by the Massachusetts Institute of Technology.
9  * For copying and distribution information, please see the file
10  * <mit-copyright.h>.
11  */
12
13 #include <mit-copyright.h>
14 #include <moira.h>
15 #include <moira_site.h>
16 #include <mrclient.h>
17
18 #include <ctype.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 RCSID("$Header$");
25
26 struct owner_type {
27   int type;
28   char *name;
29 };
30
31 struct mqelem {
32   struct mqelem *q_forw;
33   struct mqelem *q_back;
34   void *q_data;
35 };
36
37 struct string_list {
38   char *string;
39   struct string_list *next;
40 };
41
42 #define M_ANY           0
43 #define M_USER          1
44 #define M_LIST          2
45 #define M_KERBEROS      3
46 #define M_NONE          4
47
48 /* argument parsing macro */
49 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
50
51 /* flags from command line */
52 int info_flag, update_flag, create_flag, delete_flag, list_map_flag;
53 int update_alias_flag, update_map_flag, verbose, noauth;
54
55 struct string_list *alias_add_queue, *alias_remove_queue;
56 struct string_list *map_add_queue, *map_remove_queue;
57
58 char *hostname, *whoami;
59
60 char *newname, *address, *network, *h_status, *vendor, *model;
61 char *os, *location, *contact, *billing_contact, *adm_cmt, *op_cmt;
62
63 struct owner_type *owner;
64
65 void usage(char **argv);
66 int store_host_info(int argc, char **argv, void *hint);
67 void show_host_info(char **argv);
68 int show_machine_in_cluster(int argc, char **argv, void *hint);
69 struct owner_type *parse_member(char *s);
70 struct string_list *add_to_string_list(struct string_list *old_list, char *s);
71 int wrap_mr_query(char *handle, int argc, char **argv,
72                   int (*callback)(int, char **, void *), void *callarg);
73 void print_query(char *query_name, int argc, char **argv);
74
75 int main(int argc, char **argv)
76 {
77   int status, success;
78   char **arg = argv;
79   char *server = NULL;
80
81   /* clear all flags & lists */
82   info_flag = update_flag = create_flag = list_map_flag = update_map_flag = 0;
83   update_alias_flag = verbose = noauth = 0;
84   newname = address = network = h_status = vendor = model = NULL;
85   os = location = contact = billing_contact = adm_cmt = op_cmt = NULL;
86   owner = NULL;
87   alias_add_queue = alias_remove_queue = NULL;
88   map_add_queue = map_remove_queue = NULL;
89   whoami = argv[0];
90
91   success = 1;
92
93   /* parse args, building addlist, dellist, & synclist */
94   while (++arg - argv < argc)
95     {
96       if (**arg == '-')
97         {
98           if (argis("i", "info"))
99             info_flag++;
100           else if (argis("C", "create"))
101             create_flag++;
102           else if (argis("D", "delete"))
103             delete_flag++;
104           else if (argis("R", "rename")) {
105             if (arg - argv < argc - 1) {
106               arg++;
107               update_flag++;
108               newname = *arg;
109             } else
110               usage(argv);
111           }
112           else if (argis("A", "address")) {
113             if (arg - argv < argc - 1) {
114               arg++;
115               update_flag++;
116               address = *arg;
117             } else
118               usage(argv);
119           }
120           else if (argis("O", "owner")) {
121             if (arg - argv < argc - 1) {
122               arg++;
123               update_flag++;
124               owner = parse_member(*arg);
125             } else
126               usage(argv);
127           }
128           else if (argis("N", "network")) {
129             if (arg - argv < argc - 1) {
130               arg++;
131               update_flag++;
132               network = *arg;
133             } else
134               usage(argv);
135           }
136           else if (argis("S", "status")) {
137             if (arg - argv < argc - 1) {
138               int i;
139               int len;
140
141               arg++;
142               update_flag++;
143               h_status = *arg;
144
145               len = strlen(h_status);
146               for(i = 0; i < len; i++) {
147                 if(!isdigit(h_status[i])) {
148                   printf("Error: status code %s is not numeric.\n", h_status);
149                   exit(1);
150                 }
151               }
152             } else
153               usage(argv);
154           }
155           else if (argis("V", "vendor")) {
156             if (arg - argv < argc - 1) {
157               arg++;
158               update_flag++;
159               vendor = *arg;
160             } else
161               usage(argv);
162           }
163           else if (argis("M", "model")) {
164             if (arg - argv < argc - 1) {
165               arg++;
166               update_flag++;
167               model = *arg;
168             } else
169               usage(argv);
170           }
171           else if (argis("o", "os")) {
172             if (arg - argv < argc - 1) {
173               arg++;
174               update_flag++;
175               os = *arg;
176             } else
177               usage(argv);
178           }
179           else if (argis("L", "location")) {
180             if (arg - argv < argc - 1) {
181               arg++;
182               update_flag++;
183               location = *arg;
184             } else
185               usage(argv);
186           }
187           else if (argis("c", "contact")) {
188             if (arg - argv < argc - 1) {
189               arg++;
190               update_flag++;
191               contact = *arg;
192             } else
193               usage(argv);
194           }
195           else if (argis("bc", "billingcontact")) {
196             if (arg - argv < argc - 1) {
197               arg++;
198               update_flag++;
199               billing_contact = *arg;
200             } else
201               usage(argv);
202           }
203           else if (argis("ac", "admcmt")) {
204             if (arg - argv < argc - 1) {
205               arg++;
206               update_flag++;
207               adm_cmt = *arg;
208             } else
209               usage(argv);
210           }
211           else if (argis("oc", "opcmt")) {
212             if (arg - argv < argc - 1) {
213               arg++;
214               update_flag++;
215               op_cmt = *arg;
216             } else
217               usage(argv);
218           }
219           else if (argis("a", "aliasadd")) {
220             if (arg - argv < argc - 1) {
221               arg++;
222               alias_add_queue=add_to_string_list(alias_add_queue, *arg);
223             } else
224               usage(argv);
225             update_alias_flag++;
226           }
227           else if (argis("d", "aliasdelete")) {
228             if (arg - argv < argc - 1) {
229               arg++;
230               alias_remove_queue=add_to_string_list(alias_remove_queue, *arg);
231             } else
232               usage(argv);
233             update_alias_flag++;
234           }
235           else if (argis("am", "addmap")) {
236             if (arg - argv < argc - 1) {
237               arg++;
238               map_add_queue=add_to_string_list(map_add_queue, *arg);
239             } else
240               usage(argv);
241             update_map_flag++;
242           }
243           else if (argis("dm", "deletemap")) {
244             if (arg - argv < argc - 1) {
245               arg++;
246               map_remove_queue=add_to_string_list(map_remove_queue, *arg);
247             } else
248               usage(argv);
249             update_map_flag++;
250           }
251           else if (argis("lm", "listmap"))
252             list_map_flag++;
253           else if (argis("n", "noauth"))
254             noauth++;
255           else if (argis("v", "verbose"))
256             verbose++;
257           else if (argis("db", "database"))
258             {
259               if (arg - argv < argc - 1)
260                 {
261                   ++arg;
262                   server = *arg;
263                 }
264               else
265                 usage(argv);
266             }
267           else
268             usage(argv);
269         }
270       else if (hostname == NULL)
271         hostname = *arg;
272       else
273         usage(argv);
274     }
275   if (hostname == NULL)
276     usage(argv);
277
278   /* default to info_flag if nothing else was specified */
279   if(!(info_flag   || update_flag   || create_flag     || \
280        delete_flag || list_map_flag || update_map_flag || \
281        update_alias_flag)) {
282     info_flag++;
283   }
284
285   /* fire up Moira */
286   status = mrcl_connect(server, "stella", 6, !noauth);
287   if (status == MRCL_AUTH_ERROR)
288     {
289       com_err(whoami, 0, "Try the -noauth flag if you don't "
290               "need authentication.");
291     }
292   if (status)
293     exit(2);
294
295   /* create if needed */
296   if (create_flag)
297     {
298       char *argv[30];
299       int cnt;
300
301       for (cnt = 0; cnt < 16; cnt++) {
302         argv[cnt] = "";
303       }
304
305       argv[0] = canonicalize_hostname(strdup(hostname));
306
307       if (vendor)
308         argv[1] = vendor;
309       if (model)
310         argv[2] = model;
311       if (os)
312         argv[3] = os;
313       if (location)
314         argv[4] = location;
315       if (contact)
316         argv[5] = contact;
317       if (billing_contact)
318         argv[6] = billing_contact;
319       /* The use field always gets set to "0" */
320       argv[7] = "0";
321       if (h_status)
322         argv[8] = h_status;
323       else
324         argv[8] = "1";
325       if (network)
326         argv[9] = network;
327       if (address)
328         argv[10] = address;
329       else
330         argv[10] = "unique";
331       if (adm_cmt)
332         argv[13] = adm_cmt;
333       if (op_cmt)
334         argv[14] = op_cmt;
335
336       if (owner)
337         {
338           argv[12] = owner->name;
339           switch (owner->type)
340             {
341             case M_ANY:
342             case M_USER:
343               argv[11] = "USER";
344               status = wrap_mr_query("add_host", 15, argv, NULL, NULL);
345               if (owner->type != M_ANY || status != MR_USER)
346                 break;
347
348             case M_LIST:
349               argv[11] = "LIST";
350               status = wrap_mr_query("add_host", 15, argv, NULL, NULL);
351               break;
352
353             case M_KERBEROS:
354               argv[11] = "KERBEROS";
355               status = mrcl_validate_kerberos_member(argv[12], &argv[12]);
356               if (mrcl_get_message())
357                 mrcl_com_err(whoami);
358               status = wrap_mr_query("add_host", 15, argv, NULL, NULL);
359               break;
360
361             case M_NONE:
362               argv[11] = "NONE";
363               status = wrap_mr_query("add_host", 15, argv, NULL, NULL);
364               break;
365             }
366         }
367       else
368         {
369           argv[11] = "NONE";
370           argv[12] = "NONE";
371
372           status = wrap_mr_query("add_host", 15, argv, NULL, NULL);
373         }
374
375       if (status)
376         {
377           com_err(whoami, status, "while creating host.");
378           exit(1);
379         }
380
381     }
382   else if (update_flag)
383     {
384       char *old_argv[30];
385       char *argv[16];
386       char *args[5];
387
388       args[0] = canonicalize_hostname(strdup(hostname));
389       args[1] = args[2] = args[3] = "*";
390
391       status = wrap_mr_query("get_host", 4, args, store_host_info, old_argv);
392       if (status)
393         {
394           com_err(whoami, status, "while getting list information");
395           exit(1);
396         }
397
398       argv[1] = old_argv[0];
399       argv[2] = old_argv[1];
400       argv[3] = old_argv[2];
401       argv[4] = old_argv[3];
402       argv[5] = old_argv[4];
403       argv[6] = old_argv[5];
404       argv[7] = old_argv[6];
405       argv[8] = old_argv[7];
406       argv[9] = old_argv[8];
407       argv[10] = old_argv[10];
408       argv[11] = old_argv[11];
409       argv[12] = old_argv[12];
410       argv[13] = old_argv[13];
411       argv[14] = old_argv[14];
412       argv[15] = old_argv[15];
413
414       argv[0] = canonicalize_hostname(strdup(hostname));
415       if (newname)
416         argv[1] = canonicalize_hostname(strdup(newname));
417       if (vendor)
418         argv[2] = vendor;
419       if (model)
420         argv[3] = model;
421       if (os)
422         argv[4] = os;
423       if (location)
424         argv[5] = location;
425       if (contact)
426         argv[6] = contact;
427       if (billing_contact)
428         argv[7] = billing_contact;
429       if (h_status)
430         argv[9] = h_status;
431       if (network)
432         argv[10] = network;
433       if (address)
434         argv[11] = address;
435       if (adm_cmt)
436         argv[14] = adm_cmt;
437       if (op_cmt)
438         argv[15] = op_cmt;
439
440       if (owner)
441         {
442           argv[13] = owner->name;
443           switch (owner->type)
444             {
445             case M_ANY:
446             case M_USER:
447               argv[12] = "USER";
448               status = wrap_mr_query("update_host", 16, argv, NULL, NULL);
449               if (owner->type != M_ANY || status != MR_USER)
450                 break;
451
452             case M_LIST:
453               argv[12] = "LIST";
454               status = wrap_mr_query("update_host", 16, argv, NULL, NULL);
455               break;
456
457             case M_KERBEROS:
458               argv[12] = "KERBEROS";
459               status = mrcl_validate_kerberos_member(argv[13], &argv[13]);
460               if (mrcl_get_message())
461                 mrcl_com_err(whoami);
462               status = wrap_mr_query("update_host", 16, argv, NULL, NULL);
463               break;
464
465             case M_NONE:
466               argv[12] = "NONE";
467               status = wrap_mr_query("update_host", 16, argv, NULL, NULL);
468               break;
469             }
470         }
471       else
472         status = wrap_mr_query("update_host", 16, argv, NULL, NULL);
473
474       if (status)
475         com_err(whoami, status, "while updating host.");
476       else if (newname)
477         hostname = newname;
478     }
479
480   /* create aliases if necessary */
481   if (alias_add_queue) {
482     struct string_list *q = alias_add_queue;
483
484     while(q) {
485       char *alias = q->string;
486       char *args[2];
487
488       args[0] = partial_canonicalize_hostname(strdup(alias));
489       args[1] = canonicalize_hostname(strdup(hostname));
490       status = wrap_mr_query("add_hostalias", 2, args, NULL, NULL);
491       if (status) {
492         com_err(whoami, status, "while adding host alias");
493         exit(1);
494       }
495
496       q = q->next;
497     }
498   }
499
500   /* delete aliases if necessary */
501   if (alias_remove_queue) {
502     struct string_list *q = alias_remove_queue;
503
504     while(q) {
505       char *alias = q->string;
506       char *args[2];
507
508       args[0] = partial_canonicalize_hostname(strdup(alias));
509       args[1] = canonicalize_hostname(strdup(hostname));
510       status = wrap_mr_query("delete_hostalias", 2, args, NULL, NULL);
511       if (status) {
512         com_err(whoami, status, "while deleting host alias");
513         exit(1);
514       }
515
516       q = q->next;
517     }
518   }
519
520   /* create cluster mappings */
521   if (map_add_queue) {
522     struct string_list *q = map_add_queue;
523
524     while(q) {
525       char *clustername = q->string;
526       char *args[2];
527
528       args[0] = canonicalize_hostname(strdup(hostname));
529       args[1] = clustername;
530       status = wrap_mr_query("add_machine_to_cluster", 2, args, NULL, NULL);
531       if (status) {
532         com_err(whoami, status, "while adding cluster mapping");
533         exit(1);
534       }
535
536       q = q->next;
537     }
538   }
539
540   /* delete cluster mappings */
541   if (map_remove_queue) {
542     struct string_list *q = map_remove_queue;
543
544     while(q) {
545       char *clustername = q->string;
546       char *args[2];
547
548       args[0] = canonicalize_hostname(strdup(hostname));
549       args[1] = clustername;
550       status = wrap_mr_query("delete_machine_from_cluster", 2, args,
551                              NULL, NULL);
552       if (status) {
553         com_err(whoami, status, "while deleting cluster mapping");
554         exit(1);
555       }
556
557       q = q->next;
558     }
559   }
560
561   /* display list info if requested to */
562   if (info_flag) {
563     struct mqelem *elem = NULL;
564     char *args[5];
565     char *argv[30];
566
567     args[0] = canonicalize_hostname(strdup(hostname));
568     args[1] = args[2] = args[3] = "*";
569     status = wrap_mr_query("get_host", 4, args, store_host_info, argv);
570     if (status) {
571       com_err(whoami, status, "while getting host information");
572       exit(1);
573     }
574     show_host_info(argv);
575   }
576
577   /* list cluster mappings if needed */
578   if (list_map_flag) {
579     char *args[3];
580
581     args[0] = canonicalize_hostname(strdup(hostname));
582     args[1] = "*";
583     status = wrap_mr_query("get_machine_to_cluster_map", 2, args,
584                       show_machine_in_cluster, NULL);
585     if (status)
586       if (status != MR_NO_MATCH) {
587         com_err(whoami, status, "while getting cluster mappings");
588         exit(1);
589       }
590   }
591
592   if (delete_flag) {
593     char *argv[1];
594
595     argv[0] = canonicalize_hostname(strdup(hostname));
596     status = wrap_mr_query("delete_host", 1, argv, NULL, NULL);
597     if (status) {
598       com_err(whoami, status, "while deleting host");
599       exit(1);
600     }
601   }
602
603   /* We're done! */
604   mr_disconnect();
605   exit(success ? 0 : 1);
606 }
607
608 void usage(char **argv)
609 {
610 #define USAGE_OPTIONS_FORMAT "  %-39s%s\n"
611   fprintf(stderr, "Usage: %s hostname [options]\n", argv[0]);
612   fprintf(stderr, "Options are\n");
613   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-C   | -create",
614           "-O   | -owner owner");
615   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D   | -delete",
616           "-S   | -status status");
617   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-R   | -rename newname",
618           "-V   | -vendor vendor");
619   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a   | -addalias alias",
620           "-M   | -model model");
621   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d   | -deletealias alias",
622           "-L   | -location location");
623   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i   | -info",
624           "-o   | -os os");
625   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-oc  | -opcmt op_cmt",
626           "-c   | -contact contact");
627   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ac  | -admcmt adm_cmt",
628           "-bc  | -billingcontact billing_contact");
629   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-A   | -address address",
630           "-N   | -network network");
631   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-am  | -addmap cluster",
632           "-dm  | deletemap cluster");
633   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-lm  | -listmap",
634           "-db  | -database host[:port]");
635   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v   | -verbose",
636           "-n   | -noauth");
637   exit(1);
638 }
639
640 /* Show alias information */
641
642 static int show_has_aliases;
643
644 int show_alias_info(int argc, char **argv, void *hint)
645 {
646   if(!show_has_aliases++)
647     printf("Aliases:  %s", argv[0]);
648   else
649     printf(", %s", argv[0]);
650
651   return MR_CONT;
652 }
653
654 static char *states[] = {
655   "Reserved (0)",
656   "Active (1)",
657   "None (2)",
658   "Deleted (3)"
659 };
660
661 static char *MacState(int state)
662 {
663   static char buf[BUFSIZ];
664
665   if (state < 0 || state > 3)
666     {
667       sprintf(buf, "Unknown (%d)", state);
668       return buf;
669     }
670   return states[state];
671 }
672
673 /* Retrieve information about a host */
674
675 int store_host_info(int argc, char **argv, void *hint)
676 {
677   int i;
678   char **nargv = hint;
679
680   for(i=0; i<argc; i++)
681     nargv[i] = strdup(argv[i]);
682
683   return MR_CONT;
684 }
685
686 void show_host_info(char **argv)
687 {
688   char tbuf[256];
689   char *args[3];
690   struct mqelem *elem = NULL;
691   int stat;
692
693   printf("Machine:  %s\n", argv[M_NAME]);
694   args[0] = "*";
695   args[1] = argv[M_NAME];
696   show_has_aliases = 0;
697   stat = wrap_mr_query("get_hostalias", 2, args, show_alias_info, &elem);
698   printf("\n");
699   if (stat) {
700     if (stat != MR_NO_MATCH)
701       com_err(whoami, stat, "while getting aliases");
702   } else {
703     printf("\n");
704   }
705   sprintf(tbuf, "%s %s", argv[M_OWNER_TYPE],
706           strcmp(argv[M_OWNER_TYPE], "NONE") ? argv[M_OWNER_NAME] : "");
707   printf("Address:  %-16s    Network:    %-16s\n",
708           argv[M_ADDR], argv[M_SUBNET]);
709   printf("Owner:    %-16s    Use data:   %s\n", tbuf, argv[M_INUSE]);
710   printf("Status:   %-16s    Changed:    %s\n",
711           MacState(atoi(argv[M_STAT])), argv[M_STAT_CHNG]);
712   printf("\n");
713   printf("Vendor:   %-16s    Location:        %s\n", argv[M_VENDOR], 
714          argv[M_LOC]);
715   printf("Model:    %-16s    Contact:         %s\n", argv[M_MODEL], 
716          argv[M_CONTACT]);
717   printf("OS:       %-16s    Billing Contact: %s\n", argv[M_OS], 
718          argv[M_BILL_CONTACT]);
719   printf("\nOpt: %s\n", argv[M_USE]);
720   printf("\nAdm cmt: %s\n", argv[M_ACOMMENT]);
721   printf("Op cmt:  %s\n", argv[M_OCOMMENT]);
722   printf("\n");
723   printf("Created  by %s on %s\n", argv[M_CREATOR], argv[M_CREATED]);
724   printf("Last mod by %s at %s with %s.\n", argv[M_MODBY], argv[M_MODTIME], argv[M_MODWITH]);
725 }
726
727 int show_machine_in_cluster(int argc, char **argv, void *hint)
728 {
729   printf("Machine: %-30s Cluster: %-30s\n", argv[0], argv[1]);
730
731   return MR_CONT;
732 }
733
734 /* Parse a line of input, fetching a member.  NULL is returned if a member
735  * is not found.  ';' is a comment character.
736  */
737
738 struct owner_type *parse_member(char *s)
739 {
740   struct owner_type *m;
741   char *p, *lastchar;
742
743   while (*s && isspace(*s))
744     s++;
745   lastchar = p = s;
746   while (*p && *p != '\n' && *p != ';')
747     {
748       if (isprint(*p) && !isspace(*p))
749         lastchar = p++;
750       else
751         p++;
752     }
753   lastchar++;
754   *lastchar = '\0';
755   if (p == s || strlen(s) == 0)
756     return NULL;
757
758   if (!(m = malloc(sizeof(struct owner_type))))
759     return NULL;
760
761   if ((p = strchr(s, ':')))
762     {
763       *p = '\0';
764       m->name = ++p;
765       if (!strcasecmp("user", s))
766         m->type = M_USER;
767       else if (!strcasecmp("list", s))
768         m->type = M_LIST;
769       else if (!strcasecmp("kerberos", s))
770         m->type = M_KERBEROS;
771       else if (!strcasecmp("none", s))
772         m->type = M_NONE;
773       else
774         {
775           m->type = M_ANY;
776           *(--p) = ':';
777           m->name = s;
778         }
779       m->name = strdup(m->name);
780     }
781   else
782     {
783       m->name = strdup(s);
784       m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
785     }
786   return m;
787 }
788
789 struct string_list *add_to_string_list(struct string_list *old_list, char *s) {
790   struct string_list *new_list;
791
792   new_list = (struct string_list *)malloc(sizeof(struct string_list *));
793   new_list->next = old_list;
794   new_list->string = s;
795
796   return new_list;
797 }
798
799 int wrap_mr_query(char *handle, int argc, char **argv,
800                   int (*callback)(int, char **, void *), void *callarg) {
801   if (verbose)
802     print_query(handle, argc, argv);
803
804   return mr_query(handle, argc, argv, callback, callarg);
805 }
806
807 void print_query(char *query_name, int argc, char **argv) {
808   int cnt;
809
810   printf("qy %s", query_name);
811   for(cnt=0; cnt<argc; cnt++)
812     printf(" <%s>", argv[cnt]);
813   printf("\n");
814 }
This page took 0.103098 seconds and 5 git commands to generate.