2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Implementation of basic procedures for the AFS user account
16 * --------------------- Required definitions ---------------------
18 #include <afsconfig.h>
19 #include <afs/param.h>
24 #include "uss_procs.h" /*Module interface */
25 #include "uss_common.h" /*Common defs & operations */
26 #include "uss_acl.h" /*ACL-related operations */
27 #include <errno.h> /*Unix error codes */
28 #include <pwd.h> /*Password info */
29 #include <sys/stat.h> /*Stat defs */
30 #include <dirent.h> /*Directory package */
31 #include <sys/file.h> /*O_EXCL, O_CREAT, etc */
44 #include <afs/kautils.h> /*MAXKTCREALMLEN*/
46 #undef USS_PROCS_DB_INSTANCE
47 #undef USS_PROCS_DB_BUILDDIR
48 #define uss_procs_MAX_SIZE 2048
55 /*-----------------------------------------------------------------------
56 * EXPORTED uss_procs_BuildDir
59 * Called from the code generated by the uss grammar.
63 *------------------------------------------------------------------------*/
66 uss_procs_BuildDir(a_path, a_mode, a_owner, a_access)
72 { /*uss_procs_BuildDir */
76 struct uss_subdir *new_dir;
80 * Don't do anything if there's already a problem.
86 printf("Building directory '%s'; owner: '%s', ACL: '%s'\n", a_path,
90 * If we've not been given permission to overwrite things, make sure
91 * the target doesn't exist before doing anything.
93 if (!uss_OverwriteThisOne) {
95 if (!stat(temp, &stbuf)) {
97 printf("\t[Directory exists, NOT overwriting it]\n");
102 sscanf(a_mode, "%o", &m);
103 o = uss_procs_GetOwner(a_owner);
104 #ifdef USS_PROCS_DB_BUILDDIR
105 printf("DEBUGGING: Owner '%s' is uid %d\n", a_owner, o);
106 #endif /* USS_PROCS_DB_BUILDDIR */
109 if (mkdir(a_path, m)) {
111 * Can't make the directory. Complain if the directory doesn't
114 if (errno != EEXIST) {
115 uss_procs_PrintErr(line,
116 "Failed to create directory '%s': %s\n",
117 a_path, strerror(errno));
119 } /*Directory didn't exist */
120 } /*Create the directory */
123 if (uss_OverwriteThisOne)
124 fprintf(stderr, "\t[Dry run: mkdir %s, mode %o]\n", a_path, m);
128 if (chmod(a_path, m)) {
129 uss_procs_PrintErr(line,
130 "Can't chmod() directory '%s' to be '%s' : %s\n",
131 a_path, a_mode, strerror(errno));
133 } /* chmod the directory */
134 if (chown(a_path, o, -1)) {
135 uss_procs_PrintErr(line,
136 "Can't chown() directory '%s' to be owned by '%s' (uid %d): %s\n",
137 a_path, a_owner, o, strerror(errno));
139 } /*Couldn't chown */
143 "\t[Dry run: chown() directory '%s' to be owned by user]\n",
148 * Set the ACL for this new directory so that the uss_AccountCreator
149 * is the only party that has rights. This will be corrected as the
150 * final action performed on the account.
152 sprintf(buf, "%s %s all", a_path, uss_AccountCreator);
155 fprintf(stderr, "Setting ACL: '%s'\n", buf);
156 if (uss_acl_SetAccess(buf, 1, 0))
160 fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n", buf,
165 * Use our linked list to remember this directory's true ACL setting so
166 * we may set it correctly at the tail end of the account creation.
168 new_dir = (struct uss_subdir *)malloc(sizeof(struct uss_subdir));
169 new_dir->previous = uss_currentDir;
170 new_dir->path = (char *)malloc(strlen(a_path) + 1);
171 strcpy(new_dir->path, a_path);
172 new_dir->finalACL = (char *)malloc(strlen(a_access) + 1);
173 strcpy(new_dir->finalACL, a_access);
174 uss_currentDir = new_dir;
177 * Return the happy news.
181 } /*uss_procs_BuildDir */
184 /*-----------------------------------------------------------------------
185 * EXPORTED uss_procs_CpFile
188 * Called from the code generated by the uss grammar.
192 *------------------------------------------------------------------------*/
195 uss_procs_CpFile(a_path, a_mode, a_owner, a_proto)
201 { /*uss_procs_CpFile */
208 * Don't do anything if something has already gone wrong.
214 printf("Installing '%s'\n", a_path);
217 * If we've not been given permission to overwrite things, make sure
218 * the target doesn't exist before doing anything.
220 if (!uss_OverwriteThisOne) {
221 strcpy(temp, a_path);
222 if (!stat(temp, &stbuf)) {
224 printf("\t[Entry exists, NOT overwriting it]\n");
229 sscanf(a_mode, "%o", &m);
230 o = uss_procs_GetOwner(a_owner);
232 strcpy(temp, a_proto);
234 if (stat(temp, &stbuf)) {
235 uss_procs_PrintErr(line, "Failed to stat '%s': %s\n", a_proto,
240 if (stbuf.st_mode & S_IFDIR) {
241 if ((cp = strrchr(a_path, '/')) == NULL) {
242 strcat(a_proto, "/");
243 strcat(a_proto, a_path);
246 * Append the last part (file name).
251 /*Target is a directory */
253 if (Copy(a_proto, a_path, m)) {
254 uss_procs_PrintErr(line, "Failed to copy '%s' to '%s'\n", a_proto,
260 fprintf(stderr, "\t[Dry run: Copying '%s' to '%s', mode %o]\n",
265 if (chown(a_path, o, -1)) {
266 uss_procs_PrintErr(line,
267 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
268 a_path, a_owner, o, strerror(errno));
274 "\t[Dry run: chown() file '%s' to be owned by user]\n",
279 * Return the happy news.
283 } /*uss_procs_CpFile */
286 /*-----------------------------------------------------------------------
287 * EXPORTED uss_procs_EchoToFile
290 * Called from the code generated by the uss grammar.
294 *------------------------------------------------------------------------*/
297 uss_procs_EchoToFile(a_path, a_mode, a_owner, a_content)
303 { /*uss_procs_EchoToFile */
309 * Don't do anything if something has already gone wrong.
315 printf("Echoing to '%s'\n", a_path);
318 * If we've not been given permission to overwrite things, make sure
319 * the target doesn't exist before doing anything.
321 if (!uss_OverwriteThisOne) {
322 strcpy(temp, a_path);
323 if (!stat(temp, &stbuf)) {
325 printf("\t[Entry exists, NOT overwriting it]\n");
330 sscanf(a_mode, "%o", &m);
331 o = uss_procs_GetOwner(a_owner);
334 if (Echo(a_content, a_path, m)) {
335 uss_procs_PrintErr(line,
336 "Failed to echo string '%s' to file '%s'\n",
342 fprintf(stderr, "\t[Dry run: Echoing '%s' into file '%s']\n",
347 if (chown(a_path, o, -1)) {
348 uss_procs_PrintErr(line,
349 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
350 a_path, a_owner, o, strerror(errno));
356 "\t[Dry run: chown() file '%s' to be owned by user]\n",
361 * Return the happy news.
365 } /*uss_procs_EchoToFile */
368 /*-----------------------------------------------------------------------
369 * EXPORTED uss_procs_Exec
372 * Called from the code generated by the uss grammar, as well as
377 *------------------------------------------------------------------------*/
380 uss_procs_Exec(a_command)
383 { /*uss_procs_Exec */
386 printf("Running '%s'\n", a_command);
389 if (system(a_command)) {
390 uss_procs_PrintErr(line, "Failed to run the '%s' command: %s\n",
391 a_command, strerror(errno));
396 fprintf(stderr, "\t[Dry run: executing '%s']\n", a_command);
400 * Return the happy news.
404 } /*uss_procs_Exec */
407 /*-----------------------------------------------------------------------
408 * EXPORTED uss_procs_SetLink
411 * Called from the code generated by the uss grammar.
415 *------------------------------------------------------------------------*/
418 uss_procs_SetLink(a_path1, a_path2, a_type)
423 { /*uss_procs_SetLink */
428 printf("Setting link '%s' to '%s'\n", a_path1, a_path2);
431 * If we've not been given permission to overwrite things, make sure
432 * the target doesn't exist before doing anything.
434 if (!uss_OverwriteThisOne) {
435 strcpy(temp, a_path2);
436 if (!stat(temp, &stbuf)) {
438 printf("\t[Entry exists, NOT overwriting it]\n");
448 if (symlink(a_path1, a_path2)) {
449 uss_procs_PrintErr(line,
450 "Failed to make symlink '%s' to '%s': %s\n",
451 a_path1, a_path2, strerror(errno));
456 fprintf(stderr, "\t[Dry run: Making symlink '%s' to '%s']\n",
465 if (link(a_path1, a_path2)) {
466 uss_procs_PrintErr(line,
467 "Failed to make hard link '%s' to '%s': %s\n",
468 a_path1, a_path2, strerror(errno));
473 fprintf(stderr, "\t[Dry run: Making hard link '%s' to '%s']\n",
479 * Return the happy news.
483 } /*uss_procs_SetLink */
486 /*-----------------------------------------------------------------------
487 * EXPORTED uss_procs_GetOwner
490 * Nothing interesting.
494 *------------------------------------------------------------------------*/
497 uss_procs_GetOwner(a_ownerStr)
500 { /*uss_procs_GetOwner */
502 struct passwd *pw; /*Ptr to password file entry */
503 int ownerID; /*Numerical owner */
505 ownerID = atoi(a_ownerStr);
506 if ((ownerID == 0) && (a_ownerStr[0] != '0')) {
508 * The owner is not in numerical format
510 if ((pw = getpwnam(a_ownerStr)) == NULL) {
511 uss_procs_PrintErr(line, "Owner '%s' is an unknown user\n",
519 } /*uss_procs_GetOwner */
521 /*-----------------------------------------------------------------------
525 * Copies the "from" file to the "to" file and sets the mode.
528 * a_from : File to copy from.
529 * a_to : File to copy to.
530 * a_mode : New Unix mode to set.
533 * 0 if everything went well,
534 * if there was a problem.
537 * Nothing interesting.
541 *------------------------------------------------------------------------*/
544 Copy(a_from, a_to, a_mode)
551 register int fd1, fd2;
556 fd1 = open(a_to, O_EXCL | O_CREAT | O_WRONLY, a_mode);
558 if (errno == EEXIST) {
560 * The file exists. Since we can only be called when overwriting
561 * has been enabled, we back off and open the file normally (not
562 * supplying O_EXCL), then continue normally.
564 fd1 = open(a_to, O_CREAT | O_WRONLY, a_mode);
566 uss_procs_PrintErr(line,
567 "%s: Failed to open '%s' for overwrite: %s.\n",
568 uss_whoami, a_to, strerror(errno));
572 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s.\n",
573 uss_whoami, a_to, strerror(errno));
578 if ((fd2 = open(a_from, O_RDONLY, 0)) < 0) {
579 uss_procs_PrintErr(line, "%s: Error reading '%s': %s\n", uss_whoami,
580 a_from, strerror(errno));
584 while ((cnt = read(fd2, buf, BUFSIZ)) == BUFSIZ)
585 write(fd1, buf, cnt);
587 write(fd1, buf, cnt);
590 uss_procs_PrintErr(line, "Failed to close '%s' %s\n", a_to,
595 uss_procs_PrintErr(line, "Warning: Failed to close '%s': %s\n",
596 a_from, strerror(errno));
601 /*-----------------------------------------------------------------------
605 * Writes a string into a file and sets its mode.
608 * a_s : String to write.
609 * a_f : Filename to write to.
610 * a_mode : New Unix mode to set.
613 * 0 if everything went well,
614 * if there was a problem.
617 * Nothing interesting.
621 *------------------------------------------------------------------------*/
624 Echo(a_s, a_f, a_mode)
634 fd = open(a_f, O_EXCL | O_CREAT | O_WRONLY, a_mode);
636 if (errno == EEXIST) {
638 * The file exists. Since we can only be called when
639 * overwriting has been enabled, we back off and open the
640 * file normally (not supplying the O_EXCL), then continue
641 * normally. Notice that we must truncate the file, since
642 * if the original file is longer than the stuff we're about
643 * to put in, all the old data past the current write will
646 fd = open(a_f, O_TRUNC | O_WRONLY, a_mode);
648 uss_procs_PrintErr(line,
649 "%s: Failed to open '%s' for overwrite: %s.\n",
650 uss_whoami, a_f, strerror(errno));
654 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s. \n",
655 uss_whoami, a_f, strerror(errno));
659 write(fd, a_s, strlen(a_s));
662 uss_procs_PrintErr(line, "Failed to close '%s': %s\n", a_f,
670 /*-----------------------------------------------------------------------
671 * static uss_procs_PickADir
674 * Tries to replace $AUTO by a subdir. Subdirs are given by means
675 * of "G" in the configuration file. Each of the directories is
676 * examined, and the one with the inimum number of entries is
684 * 0 if everything went well,
685 * -1 if there was a problem.
688 * Called with THREE parameters from lex.c!
692 *------------------------------------------------------------------------*/
695 uss_procs_PickADir(path, cp)
699 { /*uss_procs_PickADir */
701 char cd[300]; /*Current directory for search */
703 int i, count, MinIndex, mina = 10000;
708 if (uss_NumGroups == 0) {
709 fprintf(stderr, "%s: No choice yet given to replace $AUTO\n",
711 fprintf(stderr, "%s: Use the G command before $AUTO in config file\n",
716 if (uss_Auto[0] != '\0')
717 return (0); /* we have already done this for this user */
719 if (*(cp - 1) == '/') { /*it's ..../$AUTO */
720 for (i = 0; &path[i] != cp; i++)
726 "%s: $AUTO must be used to replace the whole path or the whole name of a subdirectory. Found: %s$AUTO\n",
735 * We now have the current dir (cd). Search all of the given
736 * subdirs (by G in template), count the number of entries in
737 * each and pick the minimum.
739 for (i = 0; i < uss_NumGroups; i++) {
740 sprintf(dirname, "%s/%s", cd, uss_DirPool[i]);
741 if ((dirp = opendir(dirname)) == NULL) {
742 if (errno != ENOTDIR)
744 "%s: Warning: Can't open dir '%s' (errno=%d). Skipped.\n",
745 uss_whoami, dirname, errno);
746 continue; /*Skip and continue anyway */
749 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
750 if (dp->d_name[0] != '.')
751 count++; /* forget about files starting with . */
753 printf("debug: Dir '%s' has %d entries\n", dirname, count);
754 #endif /* USS_PROCS_DB */
761 if (mina == 10000) { /* We found nothing */
762 fprintf(stderr, "%s: Warning: No valid choice to replace $AUTO\n",
766 strcpy(uss_Auto, uss_DirPool[MinIndex]);
768 printf("Picking dir w/minimum number of entries: '%s'\n",
773 } /*uss_procs_PickADir */
775 /*-----------------------------------------------------------------------
776 * EXPORTED uss_procs_AddToDirPool
779 * Called from the code generated by the uss grammar.
783 *------------------------------------------------------------------------*/
786 uss_procs_AddToDirPool(a_dirToAdd)
789 if (uss_NumGroups > 99) {
792 strcpy(uss_DirPool[uss_NumGroups++], a_dirToAdd);
796 /*-----------------------------------------------------------------------
797 * EXPORTED uss_procs_FindAndOpen
800 * Nothing interesting.
804 *------------------------------------------------------------------------*/
807 uss_procs_FindAndOpen(a_fileToOpen)
810 { /*uss_procs_FindAndOpen */
812 #define NUM_TPL_PATHS 3
814 FILE *rv; /*Template file descriptor */
815 int i; /*Loop counter */
816 char tmp_str[uss_MAX_SIZE]; /*Tmp string */
818 TemplatePath[NUM_TPL_PATHS][1024]; /*Template directories */
819 int cant_read; /*Can't read the file? */
822 * If a full pathname was given, just take it as is.
824 if (strchr(a_fileToOpen, '/')) {
825 strcpy(tmp_str, a_fileToOpen);
826 rv = fopen(a_fileToOpen, "r");
829 * A relative pathname was given. Try to find the file in each of
830 * the default template directories.
834 sprintf(TemplatePath[0], "%s", ".");
835 sprintf(TemplatePath[1], "/afs/%s/common/uss", uss_Cell);
836 sprintf(TemplatePath[2], "%s", "/etc");
838 for (i = 0; i < NUM_TPL_PATHS; i++) {
839 sprintf(tmp_str, "%s/%s", TemplatePath[i], a_fileToOpen);
840 if ((rv = fopen(tmp_str, "r")) != NULL)
844 * If the file was there but couldn't be opened, we have
847 if (errno != ENOENT) {
851 } /*Look in template directories */
854 * If we found and opened the file, we're happy. Otherwise,
855 * print out what went wrong.
859 fprintf(stderr, "Using template '%s'\n", tmp_str);
863 * Check to see if we specifically found the file but
867 fprintf(stderr, "%s: Can't open template '%s': %s\n",
868 uss_whoami, tmp_str, strerror(errno));
870 fprintf(stderr, "%s: Can't find template '%s' in searchlist",
871 uss_whoami, a_fileToOpen);
872 for (i = 0; i < NUM_TPL_PATHS; i++)
873 fprintf(stderr, " '%s'", TemplatePath[i]);
874 fprintf(stderr, "\n");
875 } /*Can't find template */
877 } /*Relative pathname given */
880 * Whatever happened, return what we got.
884 } /*uss_procs_FindAndOpen */
887 /*-----------------------------------------------------------------------
888 * EXPORTED uss_procs_PrintErr
891 * Nothing interesting.
895 *------------------------------------------------------------------------*/
898 uss_procs_PrintErr(a_lineNum, a_fmt, a_1, a_2, a_3, a_4, a_5)
907 { /*uss_procs_PrintErr */
910 fprintf(stderr, "%s: Template file, line %d: ", uss_whoami, a_lineNum);
911 fprintf(stderr, a_fmt, a_1, a_2, a_3, a_4, a_5);
913 } /*uss_procs_PrintErr */