death to register
[openafs.git] / src / uss / uss.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  *      Main module for the AFS user account management tool.
12  */
13
14 /*
15  * --------------------- Required definitions ---------------------
16  */
17 #include <stdlib.h>
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21
22 #ifdef  AFS_AIX32_ENV
23 #include <signal.h>
24 #endif
25
26 #include <string.h>
27
28 #include "uss_common.h"         /*Common uss definitions, globals */
29 #include "uss_procs.h"          /*Main uss operations */
30 #include "uss_kauth.h"          /*AuthServer routines */
31 #include "uss_fs.h"             /*CacheManager ops */
32 #include "uss_ptserver.h"
33 #include "uss_vol.h"
34 #include "uss_acl.h"
35 #include <afs/cmd.h>            /*Command line parsing */
36 #include <afs/cellconfig.h>     /*Cell config defs */
37 #include <afs/kautils.h>        /*MAXKTCREALMLEN & MAXKTCNAMELEN */
38 #include <afs/pterror.h>
39 #include <afs/vlserver.h>
40 #include <ubik.h>
41
42 extern int yylex(void);
43 extern int yyparse (void);
44 /*
45  * Label certain things which will be activated at a later time,
46  * as well as certain semi-implemented features/switches which need
47  * to be hidden for the general AFS 3.2 release.
48  */
49 #define USS_FUTURE_FEATURES             1
50 #define USS_DONT_HIDE_SOME_FEATURES     0
51
52 /*
53  * ---------------------- Exported variables ----------------------
54  */
55 char *uss_fs_InBuff = NULL;     /*Cache Manager input  buff */
56 char *uss_fs_OutBuff = NULL;    /*Cache Manager output buff */
57
58 /*
59  * Set up convenient tags for the command line parameter indicies.
60  */
61
62 /*Add*/
63 #define AUP_USER         0
64 #define AUP_REALNAME     1
65 #define AUP_PASSWD       2
66 #define AUP_PWEXPIRES    3
67 #define AUP_SERVER       4      /* was 3 */
68 #define AUP_PART         5      /* was 4 */
69 #define AUP_MNTPT        6      /* was 5 */
70 #define AUP_UID          7      /* was 6 */
71
72 /*Bulk*/
73 #define ABULK_FILE       0
74
75 extern int uss_perr;
76 /*Delete*/
77 #define DUP_USER         0
78 #define DUP_MNTPT        1
79 #define DUP_RESTOREDIR   2
80 #define DUP_SAVEVOLUME   3
81 #define DUP_PWDPATH      4
82 #define DUP_PWDFORMAT    5
83
84 /*PurgeVolumes*/
85 #define PVP_VOLNAME      0
86 #define PVP_VOLFILE      1
87
88 /*Common ones*/
89 #define AUSS_TEMPLATE   10      /* was 7 */
90 #define AUSS_VERBOSE    11      /* was 8 */
91 #define AUSS_VAR        12      /* was 9 */
92 #define AUSS_CELL       13      /* was 10 */
93 #define AUSS_ADMIN      14      /* was 11 */
94 #define AUSS_DRYRUN     15      /* was 12 */
95 #define AUSS_SKIPAUTH   16      /* was 13 */
96 #define AUSS_OVERWRITE  17      /* was 14 */
97 #define AUSS_PWEXPIRES  18      /* was 15 */
98 #define AUSS_PIPE       19      /*  was 16 */
99
100 #undef USS_DB
101
102 static char Template[300] = "uss.template";     /*Default name */
103
104 extern FILE *yyin, *yyout;      /*YACC input & output files */
105 extern int doUnlog;
106 int uss_BulkExpires = 0;
107 int local_Cell = 1;
108
109 static int DoAdd(void);
110
111 /*-----------------------------------------------------------------------
112  * static GetCommon
113  *
114  * Description:
115  *      Read in the command line arguments common to all uss operations.
116  *
117  * Arguments:
118  *      a_as : Ptr to the command line syntax descriptor.
119  *
120  * Returns:
121  *      0 (always)
122  *
123  * Environment:
124  *      May exit the program if trouble is encountered determining the
125  *      cell name.  Set up as the command line parser's BeforeProc().
126  *
127  * Side Effects:
128  *      As advertised.
129  *------------------------------------------------------------------------*/
130
131 static int
132 GetCommon(struct cmd_syndesc *a_as, void *arock)
133 {                               /*GetCommon */
134
135     int code;                   /*Result of ka_LocalCell */
136
137     if (strcmp(a_as->name, "help") == 0)
138         return 0;
139     if (a_as->parms[AUSS_TEMPLATE].items)
140         strcpy(Template, a_as->parms[AUSS_TEMPLATE].items->data);
141     if (a_as->parms[AUSS_VERBOSE].items)
142         uss_verbose = 1;
143     else
144         uss_verbose = 0;
145
146     code = ka_CellConfig(AFSDIR_CLIENT_ETC_DIRPATH);
147     if (code)
148         fprintf(stderr, "%s: ** Call to ka_CellConfig() failed (code=%d)\n",
149                 uss_whoami, code);
150
151     if (a_as->parms[AUSS_CELL].items) {
152         char local_cell[MAXKTCREALMLEN];
153         if (ka_ExpandCell
154             (a_as->parms[AUSS_CELL].items->data, uss_Cell, 0 /*local */ )) {
155             fprintf(stderr, "%s: ** Unknown or ambiguous cell name: %s\n",
156                     uss_whoami, a_as->parms[AUSS_CELL].items->data);
157             exit(-1);
158         }
159         /*
160          * Get the local cell name
161          */
162         if (ka_ExpandCell((char *)0, local_cell, 0 /*local */ )) {
163             fprintf(stderr, "Can't get local cellname\n");
164             exit(-1);
165         }
166         if (strcmp(uss_Cell, local_cell)) {
167             /*
168              * Not the same; not a local cell
169              */
170             local_Cell = 0;
171         }
172     } else {
173         /*
174          * Get the local cell name
175          */
176         if (ka_ExpandCell((char *)0, uss_Cell, 0 /*local */ )) {
177             fprintf(stderr, "Can't get local cellname\n");
178             exit(-1);
179         }
180         if (uss_verbose)
181             fprintf(stderr, "No cell specified; assuming '%s'.\n", uss_Cell);
182     }
183
184     return (0);
185
186 }                               /*GetCommon */
187
188
189 /*-----------------------------------------------------------------------
190  * static SaveRestoreInfo
191  *
192  * Description:
193  *      Save all the information required to restore the currently
194  *      parsed user account.
195  *
196  * Arguments:
197  *      None.
198  *
199  * Returns:
200  *      0 if everything went well,
201  *      1 if something went wrong in the function, or
202  *      Lower-level error code if something went wrong below us.
203  *
204  * Environment:
205  *      We need to determine and store the following new pieces of
206  *      information:
207  *              User's AFS ID
208  *              Name of user's volume
209  *              FileServer & partition hosting the volume
210  *
211  * Side Effects:
212  *      As advertised.
213  *------------------------------------------------------------------------*/
214
215 static int
216 SaveRestoreInfo(void)
217 {                               /*SaveRestoreInfo */
218 #ifdef USS_DB
219     static char rn[] = "uss:SaveRestoreInfo";   /*Routine name */
220 #endif
221     afs_int32 code;     /*Return code */
222     afs_int32 deletedUid;       /*Uid to be nuked */
223
224     /*
225      * Translate the user name to the user ID.
226      */
227     code = uss_ptserver_XlateUser(uss_User, &deletedUid);
228     if (code)
229         return (code);
230 #ifdef USS_DB
231     printf("%s: User '%s' translated to uid %d\n", rn, uss_User, deletedUid);
232 #endif /* USS_DB */
233     sprintf(uss_Uid, "%d", deletedUid);
234
235     /*
236      * Pull out the name of the volume at the given mountpoint, along
237      * with the name of the FileServer and partition hosting it.  This
238      * also sets up all the numerical info for the above.
239      */
240     code = uss_vol_GetVolInfoFromMountPoint(uss_MountPoint);
241     if (code)
242         return (code);
243
244     /*
245      * Report back that we did fine.
246      */
247     return (0);
248
249 }                               /*SaveRestoreInfo */
250
251
252 /*-----------------------------------------------------------------------
253  * static DoDelete
254  *
255  * Description:
256  *      With everything properly inserted into the common variables,
257  *      delete the specified user account.
258  *
259  * Arguments:
260  *      None.
261  *
262  * Returns:
263  *      0 if everything went well,
264  *      1 if something went wrong in the function, or
265  *      Lower-level error code if something went wrong below us.
266  *
267  * Environment:
268  *      Nothing interesting.
269  *
270  * Side Effects:
271  *      As advertised.
272  *------------------------------------------------------------------------*/
273
274 static int
275 DoDelete(void)
276 {                               /*DoDelete */
277
278     int code;                   /*Return code */
279
280     /*
281      * Make sure the user name is a lega one.
282      */
283     code = uss_kauth_CheckUserName();
284     if (code)
285         return (code);
286
287     /*
288      * Store all the info about the account before actually doing
289      * anything.
290      */
291     code = SaveRestoreInfo();
292     if (code)
293         return (code);
294
295     if ((uss_VolumeID != 0) && (uss_MountPoint[0] != '\0')) {
296         /*
297          * Unmount the user's volume from the file system.
298          */
299         if (uss_verbose) {
300             fprintf(stderr,
301                     "Unmounting volume '%s' (ID %u) mounted at '%s'\n",
302                     uss_Volume, uss_VolumeID, uss_MountPoint);
303         }
304
305         code = uss_fs_RmMountPoint(uss_MountPoint);
306         if (code) {
307             if (uss_verbose)
308                 fprintf(stderr, "%s: Can't remove mountpoint '%s'\n",
309                         uss_whoami, uss_MountPoint);
310             return (code);      /* Must return - we may have incorrect volume */
311         }
312     }
313
314     /*
315      * If our caller has elected to delete the user's volume now,
316      * then do so.
317      */
318     if (!uss_SaveVolume && (uss_VolumeID != 0)) {
319         if (uss_verbose) {
320             fprintf(stderr, "Deleting volume '%s' (ID %u)\n", uss_Volume,
321                     uss_VolumeID);
322         }
323
324         code =
325             uss_vol_DeleteVol(uss_Volume, uss_VolumeID, uss_Server,
326                               uss_ServerID, uss_Partition, uss_PartitionID);
327         if (code) {
328             if (uss_verbose)
329                 fprintf(stderr, "%s: Can't delete volume '%s' (ID %u)\n",
330                         uss_whoami, uss_Volume, uss_VolumeID);
331             return (code);
332         }
333     } else if (uss_verbose && (uss_MountPoint[0] != '\0'))
334         printf("%s: Warning: Not attempting to delete volume at '%s'\n",
335                uss_whoami, uss_MountPoint);
336
337     /*
338      * Get rid of the user's authentication entry.
339      */
340     code = uss_kauth_DelUser(uss_User);
341     if (code)
342         return (code);
343
344     /*
345      * Finally, remove the user's AFS ID from the Protection DB and
346      * return that result.
347      */
348     code = uss_ptserver_DelUser(uss_User);
349     return (code);
350
351 }                               /*DoDelete */
352
353
354 /*-----------------------------------------------------------------------
355  * static DelUser
356  *
357  * Description:
358  *      Process the given (non-bulk) delete command.
359  *
360  * Arguments:
361  *      a_as   : Ptr to the command line syntax descriptor.
362  *      a_rock : Ptr to the rock passed in.
363  *
364  * Returns:
365  *      0 if everything went well,
366  *      1 if something went wrong in the function, or
367  *      Lower-level error code if something went wrong below us.
368  *
369  * Environment:
370  *      Nothing interesting.
371  *
372  * Side Effects:
373  *      As advertised.
374  *------------------------------------------------------------------------*/
375
376 static int
377 DelUser(struct cmd_syndesc *a_as, void *a_rock)
378 {                               /*DelUser */
379
380     int code;
381
382     /*
383      * Before we do anything else, make sure we initialize the
384      * global field settings.
385      */
386     uss_common_Reset();
387
388     /*
389      * Pull out the fields as passed in by the caller on the command
390      * line.
391      */
392     strcpy(uss_User, a_as->parms[DUP_USER].items->data);
393     if (a_as->parms[DUP_MNTPT].items)
394         strcpy(uss_MountPoint, a_as->parms[DUP_MNTPT].items->data);
395 #if USS_FUTURE_FEATURES
396 #if USS_DONT_HIDE_SOME_FEATURES
397     strcpy(uss_RestoreDir, a_as->parms[DUP_RESTOREDIR].items->data);
398 #endif /* USS_DONT_HIDE_SOME_FEATURES */
399 #endif /* USS_FUTURE_FEATURES */
400
401 /*
402     if (a_as->parms[DUP_SAVEVOLUME].items)
403         uss_SaveVolume = 1;
404 */
405
406     if (a_as->parms[2].items) {
407         uss_SaveVolume = 1;
408     }
409 #if USS_FUTURE_FEATURES
410 #if USS_DONT_HIDE_SOME_FEATURES
411     if (a_as->parms[DUP_PWDPATH].items)
412         strcpy(uss_PwdPath, a_as->parms[DUP_PWDPATH].items->data);
413     if (a_as->parms[DUP_PWDFORMAT].items)
414         strcpy(uss_PwdFormat, a_as->parms[DUP_PWDFORMAT].items->data);
415 #endif /* USS_DONT_HIDE_SOME_FEATURES */
416 #endif /* USS_FUTURE_FEATURES */
417
418     if (a_as->parms[AUSS_DRYRUN].items)
419         uss_DryRun = 1;
420     if (a_as->parms[AUSS_SKIPAUTH].items)
421         uss_SkipKaserver = 1;
422     if (a_as->parms[AUSS_ADMIN].items) {
423         strcpy(uss_Administrator, a_as->parms[AUSS_ADMIN].items->data);
424         /*      fprintf(stderr, "debugging: uss_Administrator set to '%s'\n",
425          * uss_Administrator); */
426     } else {
427         /*      fprintf(stderr, "debugging: No administrator value given\n"); */
428         uss_Administrator[0] = '\0';
429     }
430
431     /*
432      * Initialize uss_AccountCreator().
433      */
434     code = uss_kauth_InitAccountCreator();
435     if (code)
436         return (code);
437
438     /*
439      * Now that the command line arguments are parsed and properly stored,
440      * go for it!
441      */
442
443     return (DoDelete());
444
445 }                               /*DelUser */
446
447 #if USS_FUTURE_FEATURES
448 #if USS_DONT_HIDE_SOME_FEATURES
449 /*-----------------------------------------------------------------------
450  * static PurgeVolumes
451  *
452  * Description:
453  *      Purge the given volume(s).
454  *
455  * Arguments:
456  *      a_as   : Ptr to the command line syntax descriptor.
457  *      a_rock : Ptr to the rock passed in.
458  *
459  * Returns:
460  *      0 if everything went well,
461  *      1 if something went wrong in the function, or
462  *      Lower-level error code if something went wrong below us.
463  *
464  * Environment:
465  *      Nothing interesting.
466  *
467  * Side Effects:
468  *      As advertised.
469  *------------------------------------------------------------------------*/
470
471 static int
472 PurgeVolumes(struct cmd_syndesc *a_as, void *a_rock)
473 {                               /*PurgeVolumes */
474
475     fprintf(stderr, "Sorry, purgevolumes has not yet been implemented.\n");
476     return (0);
477
478 }                               /*PurgeVolumes */
479
480
481 /*-----------------------------------------------------------------------
482  * static RestoreUser
483  *
484  * Description:
485  *      Process the given delete command.
486  *
487  * Arguments:
488  *      a_as   : Ptr to the command line syntax descriptor.
489  *      a_rock : Ptr to the rock passed in.
490  *
491  * Returns:
492  *      0 if everything went well,
493  *      1 if something went wrong in the function, or
494  *      Lower-level error code if something went wrong below us.
495  *
496  * Environment:
497  *      Nothing interesting.
498  *
499  * Side Effects:
500  *      As advertised.
501  *------------------------------------------------------------------------*/
502
503 static int
504 RestoreUser(struct cmd_syndesc *a_as, void *a_rock)
505 {                               /*RestoreUser */
506
507     fprintf(stderr, "Sorry, restoreuser has not yet been implemented.\n");
508     return (0);
509
510 }                               /*RestoreUser */
511
512 #endif
513 #endif
514
515 /*-----------------------------------------------------------------------
516  * static DoBulkAddLine
517  *
518  * Description:
519  *      Process the given bulk add command.
520  *
521  * Arguments:
522  *      a_buf : Ptr to the buffer holding the bulk add command.
523  *      a_tp  : Ptr to the first char past the opcode.
524  *
525  * Returns:
526  *      0  if everything went well,
527  *      -1 if something went wrong in the function, or
528  *      Lower-level error code if something went wrong below us.
529  *
530  * Environment:
531  *      The required fields are:
532  *              -user
533  *
534  * Side Effects:
535  *      As advertised.
536  *------------------------------------------------------------------------*/
537
538 static int
539 DoBulkAddLine(char *a_buf,  char *a_tp)
540 {                               /*DoBulkAddLine */
541
542     int i;              /*Loop variable */
543 #ifdef USS_DB
544     static char rn[] = "DoBulkAddLine"; /*Routine name */
545 #endif
546     int overflow;               /*Overflow in field copy? */
547
548 #ifdef USS_DB
549     printf("%s: Command buffer left to parse: '%s'\n", rn, a_tp);
550 #endif /* USS_DB */
551     uss_Expires = uss_BulkExpires;
552
553     /*
554      * Pull out all the fields.
555      */
556     a_tp = uss_common_FieldCp(uss_User, a_tp, ':', uss_UserLen, &overflow);
557     if (overflow) {
558         fprintf(stderr,
559                 "%s: * User field in add cmd too long (max is %d chars; truncated value is '%s')\n",
560                 uss_whoami, uss_UserLen, uss_User);
561         return (-1);
562     }
563     if ((*a_tp == '\0') || (*a_tp == '\n')) {
564         fprintf(stderr,
565                 "%s: * The user field must appear in a bulk add command.\n",
566                 uss_whoami);
567         return (-1);
568     }
569
570     a_tp =
571         uss_common_FieldCp(uss_RealName, a_tp, ':', uss_RealNameLen,
572                            &overflow);
573     if (overflow) {
574         fprintf(stderr,
575                 "%s: * Real name field in add cmd too long (max is %d chars; truncated value is '%s')\n",
576                 uss_whoami, uss_RealNameLen, uss_RealName);
577         return (-1);
578     }
579     if (uss_RealName[0] == '\0') {
580         /*
581          * The user's real name has not been supplied.  As a
582          * default, we use the account name.
583          */
584         sprintf(uss_RealName, "%s", uss_User);
585         if (uss_verbose)
586             fprintf(stderr, "%s: Using default real name, '%s'\n", uss_whoami,
587                     uss_User);
588     }
589     /*Use default full name */
590     a_tp = uss_common_FieldCp(uss_Pwd, a_tp, ':', uss_PwdLen, &overflow);
591     if (overflow) {
592         fprintf(stderr,
593                 "%s: * Password field in add cmd too long (max is %d chars; truncated value is '%s')\n",
594                 uss_whoami, uss_PwdLen, uss_Pwd);
595         return (-1);
596     }
597     if (uss_Pwd[0] == '\0') {
598         /*
599          * The user's password has not been provided.  Use
600          * the default.
601          */
602         sprintf(uss_Pwd, "%s", uss_DEFAULT_PASSWORD);
603         if (uss_verbose)
604             fprintf(stderr, "%s: Using default password, '%s'\n", uss_whoami,
605                     uss_Pwd);
606     }                           /*Use default password */
607     if ((*a_tp == '\0') || (*a_tp == '\n'))
608         goto DoBulkAddLine_ParsingDone;
609
610
611     {
612         char temp[10];
613         a_tp = uss_common_FieldCp(temp, a_tp, ':', 9, &overflow);
614         if (overflow) {
615             fprintf(stderr,
616                     "%s: * Password expiration time is longer than %d characters, ignoring...\n",
617                     uss_whoami, 9);
618         }
619         if (temp[0] == '\0') {
620             /* Expiration time not specified.  Use default */
621             if (uss_verbose)
622                 fprintf(stderr, "%s: Using default expiration time, '%d'\n",
623                         uss_whoami, uss_Expires);
624         } else {
625             int te;
626             te = atoi(temp);
627             if (te < 0 || te > 254) {
628                 fprintf(stderr,
629                         "%s: * Password Expiration must be in [0..254] days, using default %d\n",
630                         uss_whoami, uss_Expires);
631             } else
632                 uss_Expires = te;
633         }
634
635         if ((*a_tp == '\0') || (*a_tp == '\n'))
636             goto DoBulkAddLine_ParsingDone;
637     }
638
639
640     a_tp =
641         uss_common_FieldCp(uss_Server, a_tp, ':', uss_ServerLen, &overflow);
642     if (overflow) {
643         fprintf(stderr,
644                 "%s: * Server field in add cmd too long (max is %d chars; truncated value is '%s')\n",
645                 uss_whoami, uss_ServerLen, uss_Server);
646         return (-1);
647     }
648     if ((*a_tp == '\0') || (*a_tp == '\n'))
649         goto DoBulkAddLine_ParsingDone;
650
651     a_tp =
652         uss_common_FieldCp(uss_Partition, a_tp, ':', uss_PartitionLen,
653                            &overflow);
654     if (overflow) {
655         fprintf(stderr,
656                 "%s: * Partition field in add cmd too long (max is %d chars; truncated value is '%s')\n",
657                 uss_whoami, uss_PartitionLen, uss_Partition);
658         return (-1);
659     }
660     if ((*a_tp == '\0') || (*a_tp == '\n'))
661         goto DoBulkAddLine_ParsingDone;
662
663     a_tp =
664         uss_common_FieldCp(uss_MountPoint, a_tp, ':', uss_MountPointLen,
665                            &overflow);
666     if (overflow) {
667         fprintf(stderr,
668                 "%s: * Mountpoint field in add cmd too long (max is %d chars; truncated value is '%s')\n",
669                 uss_whoami, uss_MountPointLen, uss_MountPoint);
670         return (-1);
671     }
672     if ((*a_tp == '\0') || (*a_tp == '\n'))
673         goto DoBulkAddLine_ParsingDone;
674
675     a_tp = uss_common_FieldCp(uss_Uid, a_tp, ':', uss_UidLen, &overflow);
676     if (overflow) {
677         fprintf(stderr,
678                 "%s: * UID field in add cmd too long (max is %d chars; truncated value is '%s')\n",
679                 uss_whoami, uss_UidLen, uss_Uid);
680         return (-1);
681     }
682     uss_DesiredUID = atoi(uss_Uid);
683     if ((*a_tp == '\0') || (*a_tp == '\n'))
684         goto DoBulkAddLine_ParsingDone;
685
686     for (uss_VarMax = 1; uss_VarMax < 10; uss_VarMax++) {
687         a_tp =
688             uss_common_FieldCp(uss_Var[uss_VarMax], a_tp, ':',
689                                uss_MAX_ARG_SIZE, &overflow);
690         if (overflow) {
691             fprintf(stderr,
692                     "%s: * Variable %d field in add cmd too long (max is %d chars; truncated value is '%s')\n",
693                     uss_whoami, uss_VarMax, uss_MAX_ARG_SIZE,
694                     uss_Var[uss_VarMax]);
695             return (-1);
696         }
697         if ((*a_tp == '\0') || (*a_tp == '\n'))
698             goto DoBulkAddLine_ParsingDone;
699     }
700
701   DoBulkAddLine_ParsingDone:
702     /*
703      * If there's anything left on the line, we ignore it.  Announce
704      * the bulk add parameters we've parsed or filled in if we're
705      * being verbose, then go for it.
706      */
707     if (uss_verbose) {
708         fprintf(stderr,
709                 "\nAdding user '%s' ('%s'), password='%s' on server '%s', partition '%s', home directory='%s'",
710                 uss_User, uss_RealName, uss_Pwd,
711                 (uss_Server[0] != '\0' ? uss_Server : "<default>"),
712                 (uss_Partition[0] != '\0' ? uss_Partition : "<default>"),
713                 (uss_MountPoint[0] != '\0' ? uss_MountPoint : "<default>"));
714         if (uss_DesiredUID)
715             fprintf(stderr, ", uid preset to %d\n", uss_DesiredUID);
716         else
717             fprintf(stderr, ", no preset uid\n");
718         for (i = 1; i <= uss_VarMax; i++) {
719             if (uss_Var[i][0] != '\0')
720                 fprintf(stderr, "$%1d='%s' ", i, uss_Var[i]);
721         }
722         if (uss_VarMax > 0)
723             fprintf(stderr, "\n");
724     }
725
726     /*Verbose status of add command */
727     /*
728      * Now do the real work.
729      */
730     return (DoAdd());
731
732 }                               /*DoBulkAddLine */
733
734
735 /*-----------------------------------------------------------------------
736  * static DoBulkDeleteLine
737  *
738  * Description:
739  *      Process the given bulk delete command.
740  *
741  * Arguments:
742  *      a_buf : Ptr to the buffer holding the bulk delete command.
743  *      a_tp  : Ptr to the first char past the opcode.
744  *
745  * Returns:
746  *      0  if everything went well,
747  *      -1 if something went wrong in the function, or
748  *      Lower-level error code if something went wrong below us.
749  *
750  * Environment:
751  *      The required fields are:
752  *              -user, -mountpoint, -restoredir
753  *
754  * Side Effects:
755  *      As advertised.
756  *------------------------------------------------------------------------*/
757
758 static int
759 DoBulkDeleteLine(char *a_buf, char *a_tp)
760 {                               /*DoBulkDeleteLine */
761
762     char volField[32];          /*Value of optional vol disposition field */
763     int overflow;               /*Was there an overflow in field copying? */
764
765     /*
766      * Pull out all the fields.
767      */
768     a_tp = uss_common_FieldCp(uss_User, a_tp, ':', uss_UserLen, &overflow);
769     if (overflow) {
770         fprintf(stderr,
771                 "%s: * User field in delete cmd too long (max is %d chars; truncated value is '%s')\n",
772                 uss_whoami, uss_UserLen, uss_User);
773         return (-1);
774     }
775     if ((uss_User[0] == '\0') || (*a_tp == '\0') || (*a_tp == '\n'))
776         goto Delete_MissingRequiredParam;
777
778     a_tp =
779         uss_common_FieldCp(uss_MountPoint, a_tp, ':', uss_MountPointLen,
780                            &overflow);
781     if (overflow) {
782         fprintf(stderr,
783                 "%s: * Mountpoint field in delete cmd too long (max is %d chars; truncated value is '%s')\n",
784                 uss_whoami, uss_MountPointLen, uss_MountPoint);
785         return (-1);
786     }
787 #if USS_FUTURE_FEATURES
788 #if USS_DONT_HIDE_SOME_FEATURES
789     if ((uss_MountPoint[0] == '\0') || (*a_tp == '\0') || (*a_tp == '\n'))
790         goto Delete_MissingRequiredParam;
791 #endif /* USS_DONT_HIDE_SOME_FEATURES */
792 #else
793     if ((*a_tp == '\0') || (*a_tp == '\n'))
794         goto Delete_ParsingDone;
795 #endif /* USS_FUTURE_FEATURES */
796
797 #if USS_FUTURE_FEATURES
798 #if USS_DONT_HIDE_SOME_FEATURES
799     a_tp =
800         uss_common_FieldCp(uss_RestoreDir, a_tp, ':', uss_RestoreDirLen,
801                            &overflow);
802     if (overflow) {
803         fprintf(stderr,
804                 "%s: * RestoreDir field in delete cmd too long (max is %d chars; truncated value is '%s')\n",
805                 uss_whoami, uss_RestoreDirLen, uss_RestoreDir);
806         return (-1);
807     }
808     if (uss_RestoreDir[0] == '\0')
809         goto Delete_MissingRequiredParam;
810     if ((*a_tp == '\0') || (*a_tp == '\n'))
811         goto Delete_ParsingDone;
812
813     a_tp =
814         uss_common_FieldCp(uss_PwdPath, a_tp, ':', uss_PwdPathLen, &overflow);
815     if (overflow) {
816         fprintf(stderr,
817                 "%s: * Password path field in delete cmd too long (max is %d chars; truncated value is '%s')\n",
818                 uss_whoami, uss_PwdPathLen, uss_PwdPath);
819         return (-1);
820     }
821     if ((*a_tp == '\0') || (*a_tp == '\n'))
822         goto Delete_ParsingDone;
823
824     a_tp =
825         uss_common_FieldCp(uss_PwdFormat, a_tp, ':', uss_PwdFormatLen,
826                            &overflow);
827     if (overflow) {
828         fprintf(stderr,
829                 "%s: * Password format field in delete cmd too long (max is %d chars; truncated value is '%s')\n",
830                 uss_whoami, uss_PwdFormatLen, uss_PwdFormat);
831         return (-1);
832     }
833     if ((*a_tp == '\0') || (*a_tp == '\n'))
834         goto Delete_ParsingDone;
835 #endif /* USS_DONT_HIDE_SOME_FEATURES */
836 #endif /* USS_FUTURE_FEATURES */
837
838     a_tp = uss_common_FieldCp(volField, a_tp, ':', 32, &overflow);
839     if (overflow) {
840         fprintf(stderr,
841                 "%s: * Volume save/del field in delete cmd too long (max is 32 chars; truncated value is '%s')\n",
842                 uss_whoami, volField);
843         return (-1);
844     }
845     if ((*a_tp == '\0') || (*a_tp == '\n'))
846         goto Delete_ParsingDone;
847
848     if (strcmp(volField, "delvolume") == 0)
849         uss_SaveVolume = 0;
850     else
851         uss_SaveVolume = 1;
852
853   Delete_ParsingDone:
854     /*
855      * If there's anything left on the line, we ignore it.  Announce
856      * the bulk delete parameters we've parsed if we're being verbose,
857      * then go for it.
858      */
859     if (uss_verbose) {
860 #if USS_FUTURE_FEATURES
861 #if USS_DONT_HIDE_SOME_FEATURES
862         fprintf(stderr,
863                 "\nDeleting user '%s' mounted at '%s', restoredir='%s', pwd path='%s', pwd format='%s'",
864                 uss_User, uss_MountPoint, uss_RestoreDir, uss_PwdPath,
865                 uss_PwdFormat);
866 #endif /* USS_DONT_HIDE_SOME_FEATURES */
867 #else
868         fprintf(stderr, "\nDeleting user '%s' mounted at '%s'", uss_User,
869                 uss_MountPoint);
870 #endif /* USS_FUTURE_FEATURES */
871         if (uss_SaveVolume)
872             fprintf(stderr, ", saving user's volume\n");
873         else
874             fprintf(stderr, ", deleting user's volume\n");
875     }
876
877     /*Verbose status of delete command */
878     /*
879      * Now do the real work.
880      */
881     return (DoDelete());
882
883   Delete_MissingRequiredParam:
884     fprintf(stderr,
885             "%s: * All of the user, mountpoint, and restoredir fields must appear in a bulk delete command line.\n",
886             uss_whoami);
887     return (-1);
888
889 }                               /*DoBulkDeleteLine */
890
891 #if USS_FUTURE_FEATURES
892 #if USS_DONT_HIDE_SOME_FEATURES
893 /*-----------------------------------------------------------------------
894  * static DoBulkPurgeVolumeLine
895  *
896  * Description:
897  *      Process the given bulk add command.
898  *
899  * Arguments:
900  *      a_buf : Ptr to the buffer holding the bulk add command.
901  *      a_tp  : Ptr to the first char past the opcode.
902  *
903  * Returns:
904  *      0  if everything went well,
905  *      -1 if something went wrong in the function, or
906  *      Lower-level error code if something went wrong below us.
907  *
908  * Environment:
909  *      Nothing interesting.
910  *
911  * Side Effects:
912  *      As advertised.
913  *------------------------------------------------------------------------*/
914
915 static int
916 DoBulkPurgeVolumeLine(char *a_buf, char *a_tp)
917 {                               /*DoBulkPurgeVolumeLine */
918
919     int i;              /*Loop variable */
920     int overflow;               /*Did a field copy overflow happen? */
921
922     /*
923      * Pull out all the fields.
924      */
925     a_tp = uss_common_FieldCp(uss_User, a_tp, ':', uss_UserLen, &overflow);
926     if (overflow) {
927         fprintf(stderr,
928                 "%s: * User field in purgevolume cmd too long (max is %d chars; truncated value is '%s')\n",
929                 uss_whoami, uss_UserLen, uss_User);
930         return (-1);
931     }
932     if ((*a_tp == '\0') || (*a_tp == '\n')) {
933         fprintf(stderr,
934                 "%s: * The user field must appear in a bulk add command.\n",
935                 uss_whoami);
936         return (-1);
937     }
938
939     a_tp =
940         uss_common_FieldCp(uss_RealName, a_tp, ':', uss_RealNameLen,
941                            &overflow);
942     if (overflow) {
943         fprintf(stderr,
944                 "%s: * Real name field in purgevolume cmd too long (max is %d chars; truncated value is '%s')\n",
945                 uss_whoami, uss_RealNameLen, uss_RealName);
946         return (-1);
947     }
948     if (uss_RealName[0] == '\0') {
949         /*
950          * The user's real name has not been supplied.  As a
951          * default, we use the account name.
952          */
953         sprintf(uss_RealName, "%s", uss_User);
954         if (uss_verbose)
955             fprintf(stderr, "%s: Using default real name, '%s'\n", uss_whoami,
956                     uss_User);
957     }
958     /*Use default full name */
959     a_tp = uss_common_FieldCp(uss_Pwd, a_tp, ':', uss_PwdLen, &overflow);
960     if (overflow) {
961         fprintf(stderr,
962                 "%s: * Password field in purgevolume cmd too long (max is %d chars; truncated value is '%s')\n",
963                 uss_whoami, uss_PwdLen, uss_Pwd);
964         return (-1);
965     }
966     if (uss_Pwd[0] == '\0') {
967         /*
968          * The user's password has not been provided.  Use
969          * the default.
970          */
971         sprintf(uss_Pwd, "%s", uss_DEFAULT_PASSWORD);
972         if (uss_verbose)
973             fprintf(stderr, "%s: Using default password, '%s'\n", uss_whoami,
974                     uss_Pwd);
975     }                           /*Use default password */
976     if ((*a_tp == '\0') || (*a_tp == '\n'))
977         return (0);
978
979     a_tp =
980         uss_common_FieldCp(uss_Server, a_tp, ':', uss_ServerLen, &overflow);
981     if (overflow) {
982         fprintf(stderr, "%s: * Server field too long (max is %d chars)\n",
983                 uss_whoami, uss_ServerLen);
984         return (-1);
985     }
986     if ((*a_tp == '\0') || (*a_tp == '\n'))
987         return (0);
988
989     a_tp =
990         uss_common_FieldCp(uss_Partition, a_tp, ':', uss_PartitionLen,
991                            &overflow);
992     if (overflow) {
993         fprintf(stderr, "%s: * Partition field too long (max is %d chars)\n",
994                 uss_whoami, uss_PartitionLen);
995         return (-1);
996     }
997     if ((*a_tp == '\0') || (*a_tp == '\n'))
998         return (0);
999
1000     a_tp =
1001         uss_common_FieldCp(uss_MountPoint, a_tp, ':', uss_MountPointLen,
1002                            &overflow);
1003     if (overflow) {
1004         fprintf(stderr, "%s: * Mountpoint field too long (max is %d chars)\n",
1005                 uss_whoami, uss_MountPointLen);
1006         return (-1);
1007     }
1008     if ((*a_tp == '\0') || (*a_tp == '\n'))
1009         return (0);
1010
1011     a_tp = uss_common_FieldCp(uss_Uid, a_tp, ':', uss_UidLen, &overflow);
1012     if (overflow) {
1013         fprintf(stderr, "%s: * UID field too long (max is %d chars)\n",
1014                 uss_whoami, uss_UidLen);
1015         return (-1);
1016     }
1017     uss_DesiredUID = atoi(uss_Uid);
1018     if ((*a_tp == '\0') || (*a_tp == '\n'))
1019         return (0);
1020
1021     for (uss_VarMax = 1; uss_VarMax < 10; uss_VarMax++) {
1022         a_tp =
1023             uss_common_FieldCp(uss_Var[uss_VarMax], a_tp, ':',
1024                                uss_MAX_ARG_SIZE, &overflow);
1025         if (overflow) {
1026             fprintf(stderr,
1027                     "%s: * Variable %d field too long (max is %d chars)\n",
1028                     uss_whoami, uss_VarMax, uss_MAX_ARG_SIZE);
1029             return (-1);
1030         }
1031         if ((*a_tp == '\0') || (*a_tp == '\n'))
1032             return (0);
1033     }
1034
1035     /*
1036      * If there's anything left on the line, we ignore it.  Announce
1037      * the bulk add parameters we've parsed or filled in if we're
1038      * being verbose, then go for it.
1039      */
1040     if (uss_verbose) {
1041         fprintf(stderr,
1042                 "\nAdding user '%s' ('%s'), password='%s' on server '%s', partition '%s', home directory='%s'",
1043                 uss_User, uss_RealName, uss_Pwd,
1044                 (uss_Server[0] != '\0' ? uss_Server : "<default>"),
1045                 (uss_Partition[0] != '\0' ? uss_Partition : "<default>"),
1046                 (uss_MountPoint[0] != '\0' ? uss_MountPoint : "<default>"));
1047         if (uss_DesiredUID)
1048             fprintf(stderr, ", uid preset to %d\n", uss_DesiredUID);
1049         else
1050             fprintf(stderr, ", no preset uid\n");
1051         for (i = 1; i <= uss_VarMax; i++) {
1052             if (uss_Var[i][0] != '\0')
1053                 fprintf(stderr, "$%1d='%s' ", i, uss_Var[i]);
1054         }
1055         if (uss_VarMax > 0)
1056             fprintf(stderr, "\n");
1057     }
1058
1059     /*Verbose status of add command */
1060     /*
1061      * Now do the real work.
1062      */
1063     return (DoAdd());
1064
1065 }                               /*DoBulkPurgeVolumeLine */
1066 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1067 #endif /* USS_FUTURE_FEATURES */
1068
1069 #if USS_FUTURE_FEATURES
1070 #if USS_DONT_HIDE_SOME_FEATURES
1071 /*-----------------------------------------------------------------------
1072  * static DoBulkRestoreLine
1073  *
1074  * Description:
1075  *      Process the given bulk add command.
1076  *
1077  * Arguments:
1078  *      a_buf : Ptr to the buffer holding the bulk add command.
1079  *      a_tp  : Ptr to the first char past the opcode.
1080  *
1081  * Returns:
1082  *      0  if everything went well,
1083  *      -1 if something went wrong in the function, or
1084  *      Lower-level error code if something went wrong below us.
1085  *
1086  * Environment:
1087  *      Nothing interesting.
1088  *
1089  * Side Effects:
1090  *      As advertised.
1091  *------------------------------------------------------------------------*/
1092
1093 static int
1094 DoBulkRestoreLine(char *a_buf, char *a_tp)
1095 {                               /*DoBulkRestoreLine */
1096
1097     int i;              /*Loop variable */
1098     int overflow;               /*Overflow occur on field copy? */
1099
1100     /*
1101      * Pull out all the fields.
1102      */
1103     a_tp = uss_common_FieldCp(uss_User, a_tp, ':', uss_UserLen, &overflow);
1104     if (overflow) {
1105         fprintf(stderr, "%s: * User field too long (max is %d chars)\n",
1106                 uss_whoami, uss_UserLen);
1107         return (-1);
1108     }
1109     if ((*a_tp == '\0') || (*a_tp == '\n')) {
1110         fprintf(stderr,
1111                 "%s: * The user field must appear in a bulk add command.\n",
1112                 uss_whoami);
1113         return (-1);
1114     }
1115
1116     a_tp =
1117         uss_common_FieldCp(uss_RealName, a_tp, ':', uss_RealNameLen,
1118                            &overflow);
1119     if (overflow) {
1120         fprintf(stderr, "%s: * Real name field too long (max is %d chars)\n",
1121                 uss_whoami, uss_RealNameLen);
1122         return (-1);
1123     }
1124     if (uss_RealName[0] == '\0') {
1125         /*
1126          * The user's real name has not been supplied.  As a
1127          * default, we use the account name.
1128          */
1129         sprintf(uss_RealName, "%s", uss_User);
1130         if (uss_verbose)
1131             fprintf(stderr, "%s: Using default real name, '%s'\n", uss_whoami,
1132                     uss_User);
1133     }
1134     /*Use default full name */
1135     a_tp = uss_common_FieldCp(uss_Pwd, a_tp, ':', uss_PwdLen, &overflow);
1136     if (overflow) {
1137         fprintf(stderr, "%s: * Password field too long (max is %d chars)\n",
1138                 uss_whoami, uss_PwdLen);
1139         return (-1);
1140     }
1141     if (uss_Pwd[0] == '\0') {
1142         /*
1143          * The user's password has not been provided.  Use
1144          * the default.
1145          */
1146         sprintf(uss_Pwd, "%s", uss_DEFAULT_PASSWORD);
1147         if (uss_verbose)
1148             fprintf(stderr, "%s: Using default password, '%s'\n", uss_whoami,
1149                     uss_Pwd);
1150     }                           /*Use default password */
1151     if ((*a_tp == '\0') || (*a_tp == '\n'))
1152         return (0);
1153
1154     a_tp =
1155         uss_common_FieldCp(uss_Server, a_tp, ':', uss_ServerLen, &overflow);
1156     if (overflow) {
1157         fprintf(stderr, "%s: * Server field too long (max is %d chars)\n",
1158                 uss_whoami, uss_ServerLen);
1159         return (-1);
1160     }
1161     if ((*a_tp == '\0') || (*a_tp == '\n'))
1162         return (0);
1163
1164     a_tp =
1165         uss_common_FieldCp(uss_Partition, a_tp, ':', uss_PartitionLen,
1166                            &overflow);
1167     if (overflow) {
1168         fprintf(stderr, "%s: * Partition field too long (max is %d chars)\n",
1169                 uss_whoami, uss_PartitionLen);
1170         return (-1);
1171     }
1172     if ((*a_tp == '\0') || (*a_tp == '\n'))
1173         return (0);
1174
1175     a_tp =
1176         uss_common_FieldCp(uss_MountPoint, a_tp, ':', uss_MountPointLen,
1177                            &overflow);
1178     if (overflow) {
1179         fprintf(stderr, "%s: * mountpoint field too long (max is %d chars)\n",
1180                 uss_whoami, uss_MountPointLen);
1181         return (-1);
1182     }
1183     if ((*a_tp == '\0') || (*a_tp == '\n'))
1184         return (0);
1185
1186     a_tp = uss_common_FieldCp(uss_Uid, a_tp, ':', uss_UidLen, &overflow);
1187     if (overflow) {
1188         fprintf(stderr, "%s: * UID field too long (max is %d chars)\n",
1189                 uss_whoami, uss_UidLen);
1190         return (-1);
1191     }
1192     uss_DesiredUID = atoi(uss_Uid);
1193     if ((*a_tp == '\0') || (*a_tp == '\n'))
1194         return (0);
1195
1196     for (uss_VarMax = 1; uss_VarMax < 10; uss_VarMax++) {
1197         a_tp =
1198             uss_common_FieldCp(uss_Var[uss_VarMax], a_tp, ':',
1199                                uss_MAX_ARG_SIZE, &overflow);
1200         if (overflow) {
1201             fprintf(stderr,
1202                     "%s: * Variable %d field too long (max is %d chars)\n",
1203                     uss_whoami, uss_VarMax, uss_MAX_ARG_SIZE);
1204             return (-1);
1205         }
1206         if ((*a_tp == '\0') || (*a_tp == '\n'))
1207             return (0);
1208     }
1209
1210     /*
1211      * If there's anything left on the line, we ignore it.  Announce
1212      * the bulk add parameters we've parsed or filled in if we're
1213      * being verbose, then go for it.
1214      */
1215     if (uss_verbose) {
1216         fprintf(stderr,
1217                 "\nAdding user '%s' ('%s'), password='%s' on server '%s', partition '%s', home directory='%s'",
1218                 uss_User, uss_RealName, uss_Pwd,
1219                 (uss_Server[0] != '\0' ? uss_Server : "<default>"),
1220                 (uss_Partition[0] != '\0' ? uss_Partition : "<default>"),
1221                 (uss_MountPoint[0] != '\0' ? uss_MountPoint : "<default>"));
1222         if (uss_DesiredUID)
1223             fprintf(stderr, ", uid preset to %d\n", uss_DesiredUID);
1224         else
1225             fprintf(stderr, ", no preset uid\n");
1226         for (i = 1; i <= uss_VarMax; i++) {
1227             if (uss_Var[i][0] != '\0')
1228                 fprintf(stderr, "$%1d='%s' ", i, uss_Var[i]);
1229         }
1230         if (uss_VarMax > 0)
1231             fprintf(stderr, "\n");
1232     }
1233
1234     /*Verbose status of add command */
1235     /*
1236      * Now do the real work.
1237      */
1238     return (DoRestore());
1239
1240 }                               /*DoBulkRestoreLine */
1241 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1242 #endif /* USS_FUTURE_FEATURES */
1243
1244
1245 /*-----------------------------------------------------------------------
1246  * static DoBulkExecLine
1247  *
1248  * Description:
1249  *      Process the given bulk exec command.
1250  *
1251  * Arguments:
1252  *      a_buf : Ptr to the buffer holding the bulk exec command.
1253  *      a_tp  : Ptr to the first char past the opcode.
1254  *
1255  * Returns:
1256  *      0  if everything went well,
1257  *      -1 if something went wrong in the function, or
1258  *      Lower-level error code if something went wrong below us.
1259  *
1260  * Environment:
1261  *      Nothing interesting.
1262  *
1263  * Side Effects:
1264  *      As advertised.
1265  *------------------------------------------------------------------------*/
1266
1267 static int
1268 DoBulkExecLine(char *a_buf, char *a_tp)
1269 {                               /*DoBulkExecLine */
1270
1271     afs_int32 code;     /*Return code */
1272
1273     /*
1274      * Really, uss_procs_Exec does all the work for us!
1275      */
1276     code = uss_procs_Exec(a_tp);
1277     return (code);
1278
1279 }                               /*DoBulkExecLine */
1280
1281
1282 /*-----------------------------------------------------------------------
1283  * static HandleBulk
1284  *
1285  * Description:
1286  *      Process the given bulk command.
1287  *
1288  * Arguments:
1289  *      a_as   : Ptr to the command line syntax descriptor.
1290  *      a_rock : Ptr to the rock passed in.
1291  *
1292  * Returns:
1293  *      0 if everything went well,
1294  *      1 if something went wrong in the function, or
1295  *      Lower-level error code if something went wrong below us.
1296  *
1297  * Environment:
1298  *      Nothing interesting.
1299  *
1300  * Side Effects:
1301  *      As advertised.
1302  *------------------------------------------------------------------------*/
1303 extern int Pipe;
1304 static int
1305 HandleBulk(struct cmd_syndesc *a_as, void *a_rock)
1306 {                               /*HandleBulk */
1307
1308 #define USS_BULK_CMD_CHARS       128
1309 #define USS_BULK_BUF_CHARS      1024
1310
1311     char cmd[USS_BULK_CMD_CHARS], buf[USS_BULK_BUF_CHARS];
1312     FILE *infile;
1313     char *tp;
1314     int overflow;
1315     int code;
1316
1317     int line_no = 0;
1318     int error = 0;
1319     char tbuf[USS_BULK_BUF_CHARS];
1320
1321     /*
1322      * Open up the bulk file, croak if we can't.
1323      */
1324     if ((infile = fopen(a_as->parms[ABULK_FILE].items->data, "r")) == NULL) {
1325         fprintf(stderr, "%s: * Failed to open input file %s\n", uss_whoami,
1326                 a_as->parms[ABULK_FILE].items->data);
1327         return (-1);
1328     }
1329
1330     /*
1331      * Pull out the other fields as passed in by the caller on the
1332      * command line.
1333      */
1334     if (a_as->parms[AUSS_DRYRUN].items)
1335         uss_DryRun = 1;
1336     if (a_as->parms[AUSS_SKIPAUTH].items)
1337         uss_SkipKaserver = 1;
1338     if (a_as->parms[AUSS_OVERWRITE].items)
1339         uss_Overwrite = 1;
1340     if (a_as->parms[AUSS_PIPE].items)
1341         Pipe = 1;
1342     if (a_as->parms[AUSS_ADMIN].items)
1343         strcpy(uss_Administrator, a_as->parms[AUSS_ADMIN].items->data);
1344     else
1345         uss_Administrator[0] = '\0';
1346
1347     if (a_as->parms[AUSS_PWEXPIRES].items) {
1348         uss_BulkExpires = atoi(a_as->parms[AUSS_PWEXPIRES].items->data);
1349         if (uss_BulkExpires < 0 || uss_BulkExpires > 254) {
1350             fprintf(stderr,
1351                     "%s: Password Expiration must be in [0..255] days\n",
1352                     uss_whoami);
1353             return (-1);
1354         }
1355     } else
1356         uss_BulkExpires = 0;
1357
1358     /*
1359      * Initialize uss_AccountCreator().
1360      */
1361     code = uss_kauth_InitAccountCreator();
1362     if (code)
1363         return (code);
1364
1365     /*
1366      * Process all the lines in the bulk command file.
1367      */
1368     uss_VarMax = 0;             /*No uss vars picked up yet */
1369     while (fgets(buf, sizeof(buf), infile) != NULL) {
1370
1371         /* skip blank line */
1372
1373         if (buf[0] == '\n')
1374             continue;
1375
1376         /* After executing the line, print the line and the result */
1377         if (line_no) {
1378             if (error == UNOQUORUM) {
1379                 IOMGR_Sleep(1);
1380             }
1381
1382             if (!error)
1383                 error = uss_perr;
1384             printf("LINE %d %s %s", line_no, (error ? "FAIL" : "SUCCESS"),
1385                    tbuf);
1386             fflush(stdout);
1387         }
1388
1389         /*
1390          * Reset the common variables for each command line
1391          * processed.
1392          */
1393         uss_common_Reset();
1394
1395         strncpy(tbuf, buf, USS_BULK_BUF_CHARS-1);
1396
1397         /*
1398          * First line of file = line 1.
1399          */
1400
1401         ++line_no;
1402
1403         /*
1404          * Get the opcode and act upon it.
1405          */
1406         tp = uss_common_FieldCp(cmd, buf, ' ', USS_BULK_CMD_CHARS, &overflow);
1407         if (overflow) {
1408             fprintf(stderr,
1409                     "%s: * Bulk opcode field too long (max is %d chars)\n",
1410                     uss_whoami, USS_BULK_CMD_CHARS);
1411
1412             error = -1;
1413             continue;
1414 /*
1415             return(-1);
1416 */
1417         }
1418         if (strcmp(cmd, "add") == 0) {
1419             error = DoBulkAddLine(buf, tp);
1420             continue;
1421         }
1422         if (strcmp(cmd, "delete") == 0) {
1423             error = DoBulkDeleteLine(buf, tp);
1424             continue;
1425         }
1426         if (strcmp(cmd, "delvolume") == 0) {
1427             uss_SaveVolume = 0;
1428             error = 0;
1429             continue;
1430         }
1431 #if USS_FUTURE_FEATURES
1432 #if USS_DONT_HIDE_SOME_FEATURES
1433         if (strcmp(cmd, "purgevolume") == 0) {
1434             error = DoBulkPurgeVolumeLine(buf, tp);
1435             continue;
1436         }
1437         if (strcmp(cmd, "pwdformat") == 0) {
1438             /*Set the password format here */
1439             continue;
1440         }
1441         if (strcmp(cmd, "pwdpath") == 0) {
1442             /*Set the password path here */
1443             continue;
1444         }
1445         if (strcmp(cmd, "restore") == 0) {
1446             error = DoBulkRestoreLine(buf, tp);
1447             continue;
1448         }
1449 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1450 #endif /* USS_FUTURE_FEATURES */
1451         if (strcmp(cmd, "savevolume") == 0) {
1452             /*Set the savevolume flag here */
1453             continue;
1454         }
1455         if (strcmp(cmd, "exec") == 0) {
1456             error = DoBulkExecLine(buf, tp);
1457             continue;
1458         }
1459
1460         /*
1461          * If none of the valid opcodes match, see if the line is either
1462          * a comment of a blank.  If so, just ignore it.  Otherwise, we
1463          * have a problem.
1464          */
1465         if ((cmd[0] != '#') && (cmd[0] != '\0')) {
1466             fprintf(stderr,
1467                     "%s: ** Unrecognized command ('%s') in bulk file\n",
1468                     uss_whoami, cmd);
1469
1470             error = -1;
1471             continue;
1472
1473 /*
1474             return(-1);
1475 */
1476         }                       /*Bad bulk line */
1477     }                           /*Process a line in the bulk file */
1478
1479     /* Last line. */
1480     if (line_no) {
1481         if (!error)
1482             error = uss_perr;
1483         printf("LINE %d %s %s", line_no, (error ? "FAIL" : "SUCCESS"), tbuf);
1484         fflush(stdout);
1485     }
1486
1487     return (0);
1488 }                               /*HandleBulk */
1489
1490
1491 /*-----------------------------------------------------------------------
1492  * static AddUser
1493  *
1494  * Description:
1495  *      Process the given (non-bulk) add command.
1496  *
1497  * Arguments:
1498  *      a_as   : Ptr to the command line syntax descriptor.
1499  *      a_rock : Ptr to the rock passed in.
1500  *
1501  * Returns:
1502  *      0 if everything went well,
1503  *      1 if something went wrong in the function, or
1504  *      Lower-level error code if something went wrong below us.
1505  *
1506  * Environment:
1507  *      Nothing interesting.
1508  *
1509  * Side Effects:
1510  *      As advertised.
1511  *------------------------------------------------------------------------*/
1512
1513 static int
1514 AddUser(struct cmd_syndesc *a_as, void *a_rock)
1515 {                               /*AddUser */
1516
1517     int i;
1518     struct cmd_item *ti;
1519     int code;
1520
1521     /*
1522      * Before we do anything else, make sure we initialize the
1523      * global field settings.
1524      */
1525     uss_common_Reset();
1526
1527     /*
1528      * Pull out the fields as passed in by the caller on the command
1529      * line.
1530      */
1531     strcpy(uss_User, a_as->parms[AUP_USER].items->data);
1532     if (a_as->parms[AUP_REALNAME].items)
1533         strcpy(uss_RealName, a_as->parms[AUP_REALNAME].items->data);
1534     else
1535         strcpy(uss_RealName, uss_User);
1536     if (a_as->parms[AUP_PASSWD].items)
1537         strcpy(uss_Pwd, a_as->parms[AUP_PASSWD].items->data);
1538     else
1539         strcpy(uss_Pwd, uss_DEFAULT_PASSWORD);
1540     if (a_as->parms[AUP_SERVER].items)
1541         strcpy(uss_Server, a_as->parms[AUP_SERVER].items->data);
1542     if (a_as->parms[AUP_PART].items)
1543         strcpy(uss_Partition, a_as->parms[AUP_PART].items->data);
1544     if (a_as->parms[AUP_MNTPT].items)
1545         strcpy(uss_MountPoint, a_as->parms[AUP_MNTPT].items->data);
1546     if (a_as->parms[AUP_UID].items)
1547         uss_DesiredUID = atoi(a_as->parms[AUP_UID].items->data);
1548     else
1549         uss_DesiredUID = 0;
1550     if (a_as->parms[AUP_PWEXPIRES].items) {
1551         uss_Expires = atoi(a_as->parms[AUP_PWEXPIRES].items->data);
1552         if (uss_Expires < 0 || uss_Expires > 254) {
1553             fprintf(stderr,
1554                     "%s: Password Expiration must be in [0..255] days\n",
1555                     uss_whoami);
1556             return (-1);
1557         }
1558     } else
1559         uss_Expires = 0;
1560
1561     if (a_as->parms[AUSS_DRYRUN].items)
1562         uss_DryRun = 1;
1563     if (a_as->parms[AUSS_SKIPAUTH].items)
1564         uss_SkipKaserver = 1;
1565     if (a_as->parms[AUSS_OVERWRITE].items)
1566         uss_Overwrite = 1;
1567     if (a_as->parms[AUSS_ADMIN].items) {
1568         strcpy(uss_Administrator, a_as->parms[AUSS_ADMIN].items->data);
1569         /*      fprintf(stderr, "debugging: uss_Administrator set to '%s'\n",
1570          * uss_Administrator); */
1571     } else {
1572         /*      fprintf(stderr, "debugging: No administrator value given\n"); */
1573         uss_Administrator[0] = '\0';
1574     }
1575
1576     if (a_as->parms[AUSS_VAR].items) {
1577         for (ti = a_as->parms[AUSS_VAR].items; ti; ti = ti->next) {
1578             i = atoi(ti->data);
1579             if (i < 0 || i > 9 || (i == 0 && *ti->data != '0')) {
1580                 fprintf(stderr,
1581                         "%s: Bad -var format: must be '0 val0 1 val1 ... 9 val9'\n",
1582                         uss_whoami);
1583                 return (-1);
1584             }
1585             ti = ti->next;
1586             if (!ti) {
1587                 fprintf(stderr,
1588                         "%s: -var values must appear in pairs: 'Num val'\n",
1589                         uss_whoami);
1590                 return (-1);
1591             }
1592             strcpy(uss_Var[i], ti->data);
1593             if (i > uss_VarMax)
1594                 uss_VarMax = i;
1595         }                       /*Remember each VAR item */
1596     }
1597
1598     /*VAR items exist */
1599     /*
1600      * Initialize uss_AccountCreator().
1601      */
1602     code = uss_kauth_InitAccountCreator();
1603     if (code)
1604         return (code);
1605
1606     /*
1607      * Now that the command line arguments are parsed and properly stored,
1608      * go for it!
1609      */
1610     return (DoAdd());
1611
1612 }                               /*AddUser */
1613
1614
1615 /*-----------------------------------------------------------------------
1616  * static DoAdd
1617  *
1618  * Description:
1619  *      Create the desired user account, having parsed the add command
1620  *      from either the command line or a bulk file.
1621  *
1622  * Arguments:
1623  *      None.
1624  *
1625  * Returns:
1626  *      0 if everything went well,
1627  *      1 if something went wrong in the function, or
1628  *      Lower-level error code if something went wrong below us.
1629  *
1630  * Environment:
1631  *      All values needed have been put in the common variables.
1632  *
1633  * Side Effects:
1634  *      As advertised.
1635  *------------------------------------------------------------------------*/
1636
1637 static int
1638 DoAdd(void)
1639 {                               /*DoAdd */
1640
1641     int code;                   /*Return code */
1642
1643     /*
1644      * Make sure the user name is legal.
1645      */
1646     code = uss_kauth_CheckUserName();
1647     if (code)
1648         return (code);
1649
1650     /*
1651      * This time around, we start off assuming the global value of the
1652      * -overwrite flag.
1653      */
1654     uss_OverwriteThisOne = uss_Overwrite;
1655
1656     /*
1657      * Open up the template file before doing any real processing,
1658      * so we can quit early should it not be found.
1659      */
1660     if (yyin == NULL) {
1661         if ((yyin = uss_procs_FindAndOpen(Template)) == NULL) {
1662             fprintf(stderr, "%s: ** Can't open template file '%s'\n",
1663                     uss_whoami, Template);
1664             return (-1);
1665         }
1666         yyout = fopen("/dev/null", "w");
1667     } else
1668         rewind(yyin);
1669
1670     /*
1671      * Add the new user to the Protection DB.
1672      */
1673     code = uss_ptserver_AddUser(uss_User, uss_Uid);
1674     if (code) {
1675         fprintf(stderr, "%s: Failed to add user '%s' to the Protection DB\n",
1676                 uss_whoami, uss_User);
1677         return (code);
1678     }
1679
1680     /*
1681      * Add the new user to the Authentication DB.
1682      */
1683     code = uss_kauth_AddUser(uss_User, uss_Pwd);
1684     if (code) {
1685         fprintf(stderr, "%s: Can't add user '%s' to the Authentication DB\n",
1686                 uss_whoami, uss_User);
1687         return (code);
1688     }
1689
1690     /*
1691      * Process the items covered by the template file.
1692      */
1693     if (yyparse() && (!uss_ignoreFlag))
1694         exit(-1);
1695
1696     /*
1697      * Finally, clean up after ourselves, removing the uss_AccountCreator
1698      * from various of the new user's ACLs.
1699      */
1700     return (uss_acl_CleanUp());
1701
1702 }                               /*DoAdd */
1703
1704
1705 #if USS_FUTURE_FEATURES
1706 #if USS_DONT_HIDE_SOME_FEATURES
1707 /*-----------------------------------------------------------------------
1708  * static DoRestore
1709  *
1710  * Description:
1711  *      Perform the parsed restore command.
1712  *
1713  * Arguments:
1714  *      None.
1715  *
1716  * Returns:
1717  *      0 if everything went well,
1718  *      1 if something went wrong in the function, or
1719  *      Lower-level error code if something went wrong below us.
1720  *
1721  * Environment:
1722  *      All values needed have been put in the common variables.
1723  *
1724  * Side Effects:
1725  *      As advertised.
1726  *------------------------------------------------------------------------*/
1727
1728 static int
1729 DoRestore(void)
1730 {                               /*DoRestore */
1731
1732     return (0);
1733
1734 }                               /*DoRestore */
1735 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1736 #endif /* USS_FUTURE_FEATURES */
1737
1738
1739 /*-----------------------------------------------------------------------
1740  * static InitETTables
1741  *
1742  * Description:
1743  *      Set up the error code tables for the various modules we use.
1744  *
1745  * Arguments:
1746  *      None.
1747  *
1748  * Returns:
1749  *      Nothing.
1750  *
1751  * Environment:
1752  *      Nothing interesting.
1753  *
1754  * Side Effects:
1755  *      As advertised.
1756  *------------------------------------------------------------------------*/
1757
1758 void
1759 InitETTables(void)
1760 {                               /*InitETTables */
1761
1762
1763     /*
1764      * In order to get error code -> error message translations to work,
1765      * we have to initialize all error tables.
1766      */
1767     initialize_CMD_error_table();
1768     initialize_RXK_error_table();
1769     initialize_KTC_error_table();
1770     initialize_KA_error_table();
1771     initialize_ACFG_error_table();
1772     initialize_VL_error_table();
1773     initialize_PT_error_table();
1774     initialize_U_error_table();
1775
1776 }                               /*InitETTables */
1777
1778
1779 int
1780 osi_audit(void)
1781 {
1782 /* this sucks but it works for now.
1783 */
1784     return 0;
1785 }
1786
1787 #include "AFS_component_version_number.c"
1788
1789 int
1790 main(int argc, char *argv[])
1791 {                               /*Main routine */
1792
1793     struct cmd_syndesc *cs;     /*Command line syntax descriptor */
1794     afs_int32 code;     /*Return code */
1795
1796 #ifdef  AFS_AIX32_ENV
1797     /*
1798      * The following signal action for AIX is necessary so that in case of a 
1799      * crash (i.e. core is generated) we can include the user's data section 
1800      * in the core dump. Unfortunately, by default, only a partial core is
1801      * generated which, in many cases, isn't too useful.
1802      */
1803     struct sigaction nsa;
1804
1805     sigemptyset(&nsa.sa_mask);
1806     nsa.sa_handler = SIG_DFL;
1807     nsa.sa_flags = SA_FULLDUMP;
1808     sigaction(SIGABRT, &nsa, NULL);
1809     sigaction(SIGSEGV, &nsa, NULL);
1810 #endif
1811     strcpy(uss_whoami, argv[0]);
1812     yyin = (FILE *) NULL;
1813
1814     uss_fs_InBuff = (char *)malloc(USS_FS_MAX_SIZE);    /*Cache Manager input buff */
1815     uss_fs_OutBuff = (char *)malloc(USS_FS_MAX_SIZE);   /*Cache Manager output buff */
1816     if (!uss_fs_InBuff || !uss_fs_OutBuff) {
1817         fprintf(stderr, "%s: Can't malloc in/out buffers\n", uss_whoami);
1818         exit(-1);
1819     }
1820
1821     /* ----------------------------- add ----------------------------- */
1822
1823     cs = cmd_CreateSyntax("add", AddUser, NULL, "create a new user account");
1824     cmd_AddParm(cs, "-user", CMD_SINGLE, 0, "login name");
1825     cmd_AddParm(cs, "-realname", CMD_SINGLE, CMD_OPTIONAL,
1826                 "full name in quotes");
1827     cmd_AddParm(cs, "-pass", CMD_SINGLE, CMD_OPTIONAL, "initial password");
1828     /* new parm */
1829     cmd_AddParm(cs, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1830                 "password expires in [0..254] days (0 => never)");
1831     cmd_AddParm(cs, "-server", CMD_SINGLE, CMD_OPTIONAL,
1832                 "FileServer for home volume");
1833     cmd_AddParm(cs, "-partition", CMD_SINGLE, CMD_OPTIONAL,
1834                 "FileServer's disk partition for home volume");
1835     cmd_AddParm(cs, "-mount", CMD_SINGLE, CMD_OPTIONAL,
1836                 "home directory mount point");
1837     cmd_AddParm(cs, "-uid", CMD_SINGLE, CMD_OPTIONAL,
1838                 "uid to assign the user");
1839     cmd_Seek(cs, AUSS_TEMPLATE);
1840     cmd_AddParm(cs, "-template", CMD_SINGLE, CMD_OPTIONAL,
1841                 "pathname of template file");
1842     cmd_AddParm(cs, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose operation");
1843     cmd_AddParm(cs, "-var", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
1844                 "auxiliary argument pairs (Num val)");
1845     cmd_AddParm(cs, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1846     cmd_AddParm(cs, "-admin", CMD_SINGLE, CMD_OPTIONAL,
1847                 "administrator to authenticate");
1848     cmd_AddParm(cs, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
1849                 "only list what would be done, don't do it");
1850     cmd_AddParm(cs, "-skipauth", CMD_FLAG, CMD_OPTIONAL,
1851                 "ignore all contact with the authentication server (kaserver)");
1852     cmd_AddParm(cs, "-overwrite", CMD_FLAG, CMD_OPTIONAL,
1853                 "Overwrite pre-existing files in user home directory tree");
1854
1855
1856     /* ---------------------------- bulk ----------------------------- */
1857
1858     cs = cmd_CreateSyntax("bulk", HandleBulk, NULL, "bulk input mode");
1859     cmd_AddParm(cs, "-file", CMD_SINGLE, 0, "bulk input file");
1860     cmd_Seek(cs, AUSS_TEMPLATE);
1861     cmd_AddParm(cs, "-template", CMD_SINGLE, CMD_OPTIONAL,
1862                 "pathname of template file");
1863     cmd_AddParm(cs, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose operation");
1864     cmd_Seek(cs, AUSS_CELL);
1865     cmd_AddParm(cs, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1866     cmd_AddParm(cs, "-admin", CMD_SINGLE, CMD_OPTIONAL,
1867                 "administrator to authenticate");
1868     cmd_AddParm(cs, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
1869                 "only list what would be done, don't do it");
1870     cmd_AddParm(cs, "-skipauth", CMD_FLAG, CMD_OPTIONAL,
1871                 "ignore all contact with the authentication server (kaserver)");
1872     cmd_AddParm(cs, "-overwrite", CMD_FLAG, CMD_OPTIONAL,
1873                 "Overwrite pre-existing files in user home directory tree");
1874     cmd_Seek(cs, AUSS_PWEXPIRES);
1875     cmd_AddParm(cs, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1876                 "password expires in [0..254] days (0 => never)");
1877     cmd_Seek(cs, AUSS_PIPE);
1878     cmd_AddParm(cs, "-pipe", CMD_FLAG, CMD_OPTIONAL,
1879                 "don't prompt for passwd; get it from standard input");
1880
1881     /* ---------------------------- delete --------------------------- */
1882
1883     cs = cmd_CreateSyntax("delete", DelUser, NULL, "delete a user account");
1884     cmd_AddParm(cs, "-user", CMD_SINGLE, 0, "login name");
1885     cmd_AddParm(cs, "-mountpoint", CMD_SINGLE, CMD_OPTIONAL,
1886                 "mountpoint for user's volume");
1887 #if USS_FUTURE_FEATURES
1888 #if USS_DONT_HIDE_SOME_FEATURES
1889     cmd_AddParm(cs, "-restoredir", CMD_SINGLE, 0,
1890                 "directory where restore info is to be placed");
1891 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1892 #endif /* USS_FUTURE_FEATURES */
1893     cmd_AddParm(cs, "-savevolume", CMD_FLAG, CMD_OPTIONAL,
1894                 "don't destroy the user's volume");
1895 #if USS_FUTURE_FEATURES
1896 #if USS_DONT_HIDE_SOME_FEATURES
1897     cmd_AddParm(cs, "-pwdpath", CMD_SINGLE, CMD_OPTIONAL,
1898                 "pathname to the password file");
1899     cmd_AddParm(cs, "-pwdformat", CMD_SINGLE, CMD_OPTIONAL,
1900                 "password entry format");
1901 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1902 #endif /* USS_FUTURE_FEATURES */
1903     cmd_Seek(cs, AUSS_VERBOSE);
1904     cmd_AddParm(cs, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose operation");
1905     cmd_Seek(cs, AUSS_CELL);
1906     cmd_AddParm(cs, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1907     cmd_AddParm(cs, "-admin", CMD_SINGLE, CMD_OPTIONAL,
1908                 "administrator to authenticate");
1909     cmd_AddParm(cs, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
1910                 "only list what would be done, don't do it");
1911     cmd_AddParm(cs, "-skipauth", CMD_FLAG, CMD_OPTIONAL,
1912                 "ignore all contact with the authentication server (kaserver)");
1913 #if USS_FUTURE_FEATURES
1914 #if USS_DONT_HIDE_SOME_FEATURES
1915     /* ------------------------- purgevolumes ------------------------ */
1916
1917     cs = cmd_CreateSyntax("purgevolumes", PurgeVolumes, NULL,
1918                           "destroy a deleted user's volume");
1919     cmd_AddParm(cs, "-volname", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
1920                 "Name(s) of volume(s) to destroy");
1921     cmd_AddParm(cs, "-volfile", CMD_SINGLE, CMD_OPTIONAL,
1922                 "pathname to volume purge file");
1923     cmd_Seek(cs, AUSS_VERBOSE);
1924     cmd_AddParm(cs, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose operation");
1925     cmd_Seek(cs, AUSS_CELL);
1926     cmd_AddParm(cs, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1927     cmd_AddParm(cs, "-admin", CMD_SINGLE, CMD_OPTIONAL,
1928                 "administrator to authenticate");
1929     cmd_AddParm(cs, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
1930                 "only list what would be done, don't do it");
1931     cmd_AddParm(cs, "-skipauth", CMD_FLAG, CMD_OPTIONAL,
1932                 "ignore all contact with the authentication server (kaserver)");
1933 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1934 #endif /* USS_FUTURE_FEATURES */
1935
1936 #if USS_FUTURE_FEATURES
1937 #if USS_DONT_HIDE_SOME_FEATURES
1938     /* ---------------------------- restore -------------------------- */
1939
1940     cs = cmd_CreateSyntax("restore", RestoreUser, NULL,
1941                           "restore a deleted user account");
1942     cmd_AddParm(cs, "-user", CMD_SINGLE, 0, "login name to restore");
1943     cmd_AddParm(cs, "-uid", CMD_SINGLE, 0, "user id number");
1944     cmd_AddParm(cs, "-mount", CMD_SINGLE, 0, "mountpoint for user's volume");
1945     cmd_AddParm(cs, "-volname", CMD_SINGLE, 0, "name of user's volume");
1946     cmd_AddParm(cs, "-realname", CMD_SINGLE, CMD_OPTIONAL,
1947                 "user's full name");
1948     cmd_AddParm(cs, "-server", CMD_SINGLE, CMD_OPTIONAL,
1949                 "FileServer to host user's volume");
1950     cmd_AddParm(cs, "-partition", CMD_SINGLE, CMD_OPTIONAL,
1951                 "FileServer partition to host user's volume");
1952     cmd_AddParm(cs, "-pwdpath", CMD_SINGLE, CMD_OPTIONAL,
1953                 "pathname to the password file");
1954     cmd_AddParm(cs, "-pwdformat", CMD_SINGLE, CMD_OPTIONAL,
1955                 "password entry format");
1956     cmd_Seek(cs, AUSS_VERBOSE);
1957     cmd_AddParm(cs, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose operation");
1958     cmd_Seek(cs, AUSS_CELL);
1959     cmd_AddParm(cs, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1960     cmd_AddParm(cs, "-admin", CMD_SINGLE, CMD_OPTIONAL,
1961                 "administrator to authenticate");
1962     cmd_AddParm(cs, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
1963                 "only list what would be done, don't do it");
1964     cmd_AddParm(cs, "-skipauth", CMD_FLAG, CMD_OPTIONAL,
1965                 "ignore all contact with the authentication server (kaserver)");
1966 #endif /* USS_DONT_HIDE_SOME_FEATURES */
1967 #endif /* USS_FUTURE_FEATURES */
1968
1969     /*
1970      * Set up all the error code translation tables, initialize the
1971      * command variables, and set up to parse the common command line
1972      * parameters.
1973      */
1974     InitETTables();
1975     uss_common_Init();
1976     cmd_SetBeforeProc(GetCommon, NULL);
1977
1978     /*
1979      * Execute the parsed command.
1980      */
1981     code = cmd_Dispatch(argc, argv);
1982 #if 0
1983     if (code) {
1984         fprintf(stderr, "%s: Call to cmd_Dispatch() failed; code is %d\n",
1985                 uss_whoami, code);
1986         exit(-1);
1987     }
1988 #endif /* 0 */
1989     if (doUnlog) {
1990         code = uss_fs_UnlogToken(uss_Cell);
1991     }
1992     return 0;
1993 }                               /*Main routine */