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