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>
23 #include "uss_procs.h" /*Module interface*/
24 #include "uss_common.h" /*Common defs & operations*/
25 #include "uss_acl.h" /*ACL-related operations*/
26 #include <errno.h> /*Unix error codes*/
27 #include <pwd.h> /*Password info*/
28 #include <sys/stat.h> /*Stat defs*/
29 #include <dirent.h> /*Directory package*/
30 #include <sys/file.h> /*O_EXCL, O_CREAT, etc*/
34 #include <afs/kautils.h> /*MAXKTCREALMLEN*/
39 #undef USS_PROCS_DB_INSTANCE
40 #undef USS_PROCS_DB_BUILDDIR
42 #define uss_procs_MAX_SIZE 2048
46 extern char *rindex();
51 /*-----------------------------------------------------------------------
52 * EXPORTED uss_procs_BuildDir
55 * Called from the code generated by the uss grammar.
59 *------------------------------------------------------------------------*/
61 afs_int32 uss_procs_BuildDir(a_path, a_mode, a_owner, a_access)
67 { /*uss_procs_BuildDir*/
71 struct uss_subdir *new_dir;
75 * Don't do anything if there's already a problem.
81 printf("Building directory '%s'; owner: '%s', ACL: '%s'\n",
82 a_path, a_owner, a_access);
85 * If we've not been given permission to overwrite things, make sure
86 * the target doesn't exist before doing anything.
88 if (!uss_OverwriteThisOne) {
90 if (!stat(temp, &stbuf)) {
92 printf("\t[Directory exists, NOT overwriting it]\n");
97 sscanf(a_mode, "%o", &m);
98 o = uss_procs_GetOwner(a_owner);
99 #ifdef USS_PROCS_DB_BUILDDIR
100 printf("DEBUGGING: Owner '%s' is uid %d\n", a_owner, o);
101 #endif /* USS_PROCS_DB_BUILDDIR */
104 if (mkdir(a_path, m)) {
106 * Can't make the directory. Complain if the directory doesn't
109 if (errno != EEXIST) {
110 uss_procs_PrintErr(line,
111 "Failed to create directory '%s': %s\n",
112 a_path, sys_errlist[errno]);
114 } /*Directory didn't exist*/
115 } /*Create the directory*/
118 if (uss_OverwriteThisOne)
119 fprintf(stderr, "\t[Dry run: mkdir %s, mode %o]\n",
124 if (chmod(a_path, m)) {
125 uss_procs_PrintErr(line,
126 "Can't chmod() directory '%s' to be '%s' : %s\n",
127 a_path, a_mode, sys_errlist[errno]);
129 } /* chmod the directory */
130 if (chown(a_path, o, -1)) {
131 uss_procs_PrintErr(line,
132 "Can't chown() directory '%s' to be owned by '%s' (uid %d): %s\n",
133 a_path, a_owner, o, sys_errlist[errno]);
139 "\t[Dry run: chown() directory '%s' to be owned by user]\n",
144 * Set the ACL for this new directory so that the uss_AccountCreator
145 * is the only party that has rights. This will be corrected as the
146 * final action performed on the account.
148 sprintf(buf, "%s %s all", a_path, uss_AccountCreator);
152 "Setting ACL: '%s'\n", buf);
153 if (uss_acl_SetAccess(buf, 1, 0))
157 fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n",
162 * Use our linked list to remember this directory's true ACL setting so
163 * we may set it correctly at the tail end of the account creation.
165 new_dir = (struct uss_subdir *) malloc(sizeof(struct uss_subdir));
166 new_dir->previous = uss_currentDir;
167 new_dir->path = (char *) malloc(strlen(a_path)+1);
168 strcpy(new_dir->path, a_path);
169 new_dir->finalACL = (char *) malloc(strlen(a_access)+1);
170 strcpy(new_dir->finalACL, a_access);
171 uss_currentDir = new_dir;
174 * Return the happy news.
178 } /*uss_procs_BuildDir*/
181 /*-----------------------------------------------------------------------
182 * EXPORTED uss_procs_CpFile
185 * Called from the code generated by the uss grammar.
189 *------------------------------------------------------------------------*/
191 afs_int32 uss_procs_CpFile(a_path, a_mode, a_owner, a_proto)
197 { /*uss_procs_CpFile*/
204 * Don't do anything if something has already gone wrong.
210 printf("Installing '%s'\n", a_path);
213 * If we've not been given permission to overwrite things, make sure
214 * the target doesn't exist before doing anything.
216 if (!uss_OverwriteThisOne) {
217 strcpy(temp, a_path);
218 if (!stat(temp, &stbuf)) {
220 printf("\t[Entry exists, NOT overwriting it]\n");
225 sscanf(a_mode, "%o", &m);
226 o = uss_procs_GetOwner(a_owner);
228 strcpy(temp, a_proto);
230 if (stat(temp, &stbuf)) {
231 uss_procs_PrintErr(line, "Failed to stat '%s': %s\n",
232 a_proto, sys_errlist[errno]);
236 if (stbuf.st_mode & S_IFDIR) {
237 if ((cp = rindex(a_path, '/')) == NULL) {
238 strcat(a_proto, "/");
239 strcat(a_proto, a_path);
243 * Append the last part (file name).
247 } /*Target is a directory*/
250 if (Copy(a_proto, a_path, m)) {
251 uss_procs_PrintErr(line,
252 "Failed to copy '%s' to '%s'\n",
258 fprintf(stderr, "\t[Dry run: Copying '%s' to '%s', mode %o]\n",
263 if (chown(a_path, o, -1)) {
264 uss_procs_PrintErr(line,
265 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
266 a_path, a_owner, o, sys_errlist[errno]);
271 fprintf(stderr, "\t[Dry run: chown() file '%s' to be owned by user]\n",
276 * Return the happy news.
280 } /*uss_procs_CpFile*/
283 /*-----------------------------------------------------------------------
284 * EXPORTED uss_procs_EchoToFile
287 * Called from the code generated by the uss grammar.
291 *------------------------------------------------------------------------*/
293 afs_int32 uss_procs_EchoToFile(a_path, a_mode, a_owner, a_content)
299 { /*uss_procs_EchoToFile*/
305 * Don't do anything if something has already gone wrong.
311 printf("Echoing to '%s'\n", a_path);
314 * If we've not been given permission to overwrite things, make sure
315 * the target doesn't exist before doing anything.
317 if (!uss_OverwriteThisOne) {
318 strcpy(temp, a_path);
319 if (!stat(temp, &stbuf)) {
321 printf("\t[Entry exists, NOT overwriting it]\n");
326 sscanf(a_mode, "%o", &m);
327 o = uss_procs_GetOwner(a_owner);
330 if (Echo(a_content, a_path, m)){
331 uss_procs_PrintErr(line,
332 "Failed to echo string '%s' to file '%s'\n",
338 fprintf(stderr, "\t[Dry run: Echoing '%s' into file '%s']\n",
343 if (chown(a_path, o, -1)){
344 uss_procs_PrintErr(line,
345 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
346 a_path, a_owner, o, sys_errlist[errno]);
352 "\t[Dry run: chown() file '%s' to be owned by user]\n",
357 * Return the happy news.
361 } /*uss_procs_EchoToFile*/
364 /*-----------------------------------------------------------------------
365 * EXPORTED uss_procs_Exec
368 * Called from the code generated by the uss grammar, as well as
373 *------------------------------------------------------------------------*/
375 afs_int32 uss_procs_Exec(a_command)
381 printf("Running '%s'\n", a_command);
384 if (system(a_command)) {
385 uss_procs_PrintErr(line,
386 "Failed to run the '%s' command: %s\n",
387 a_command, sys_errlist[errno]);
392 fprintf(stderr, "\t[Dry run: executing '%s']\n", a_command);
396 * Return the happy news.
403 /*-----------------------------------------------------------------------
404 * EXPORTED uss_procs_SetLink
407 * Called from the code generated by the uss grammar.
411 *------------------------------------------------------------------------*/
413 afs_int32 uss_procs_SetLink(a_path1, a_path2, a_type)
418 { /*uss_procs_SetLink*/
423 printf("Setting link '%s' to '%s'\n", a_path1, a_path2);
426 * If we've not been given permission to overwrite things, make sure
427 * the target doesn't exist before doing anything.
429 if (!uss_OverwriteThisOne) {
430 strcpy(temp, a_path2);
431 if (!stat(temp, &stbuf)) {
433 printf("\t[Entry exists, NOT overwriting it]\n");
443 if (symlink(a_path1, a_path2)) {
444 uss_procs_PrintErr(line,
445 "Failed to make symlink '%s' to '%s': %s\n",
446 a_path1, a_path2, sys_errlist[errno]);
451 fprintf(stderr, "\t[Dry run: Making symlink '%s' to '%s']\n",
460 if (link(a_path1, a_path2)) {
461 uss_procs_PrintErr(line,
462 "Failed to make hard link '%s' to '%s': %s\n",
463 a_path1, a_path2, sys_errlist[errno]);
468 fprintf(stderr, "\t[Dry run: Making hard link '%s' to '%s']\n",
474 * Return the happy news.
478 } /*uss_procs_SetLink*/
481 /*-----------------------------------------------------------------------
482 * EXPORTED uss_procs_GetOwner
485 * Nothing interesting.
489 *------------------------------------------------------------------------*/
491 int uss_procs_GetOwner(a_ownerStr)
494 { /*uss_procs_GetOwner*/
496 struct passwd *pw; /*Ptr to password file entry*/
497 int ownerID; /*Numerical owner*/
499 ownerID = atoi(a_ownerStr);
500 if ((ownerID == 0) && (a_ownerStr[0] != '0')) {
502 * The owner is not in numerical format
504 if ((pw = getpwnam(a_ownerStr)) == NULL) {
505 uss_procs_PrintErr(line,
506 "Owner '%s' is an unknown user\n",
515 } /*uss_procs_GetOwner*/
517 /*-----------------------------------------------------------------------
521 * Copies the "from" file to the "to" file and sets the mode.
524 * a_from : File to copy from.
525 * a_to : File to copy to.
526 * a_mode : New Unix mode to set.
529 * 0 if everything went well,
530 * if there was a problem.
533 * Nothing interesting.
537 *------------------------------------------------------------------------*/
539 static int Copy(a_from, a_to, a_mode)
546 register int fd1, fd2;
551 fd1 = open(a_to, O_EXCL | O_CREAT | O_WRONLY, a_mode);
553 if (errno == EEXIST) {
555 * The file exists. Since we can only be called when overwriting
556 * has been enabled, we back off and open the file normally (not
557 * supplying O_EXCL), then continue normally.
559 fd1 = open(a_to, O_CREAT | O_WRONLY, a_mode);
561 uss_procs_PrintErr(line,
562 "%s: Failed to open '%s' for overwrite: %s.\n",
563 uss_whoami, a_to, sys_errlist[errno]);
567 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s.\n",
568 uss_whoami, a_to, sys_errlist[errno]);
573 if ((fd2 = open(a_from, O_RDONLY, 0)) < 0) {
574 uss_procs_PrintErr(line, "%s: Error reading '%s': %s\n",
575 uss_whoami, a_from, sys_errlist[errno]);
579 while ((cnt = read(fd2, buf, BUFSIZ)) == BUFSIZ)
580 write(fd1, buf, cnt);
582 write(fd1, buf, cnt);
585 uss_procs_PrintErr(line,
586 "Failed to close '%s' %s\n",
587 a_to, sys_errlist[errno]);
591 uss_procs_PrintErr(line, "Warning: Failed to close '%s': %s\n",
592 a_from, sys_errlist[errno]);
597 /*-----------------------------------------------------------------------
601 * Writes a string into a file and sets its mode.
604 * a_s : String to write.
605 * a_f : Filename to write to.
606 * a_mode : New Unix mode to set.
609 * 0 if everything went well,
610 * if there was a problem.
613 * Nothing interesting.
617 *------------------------------------------------------------------------*/
619 static int Echo(a_s, a_f, a_mode)
629 fd = open(a_f, O_EXCL | O_CREAT | O_WRONLY, a_mode);
631 if (errno == EEXIST) {
633 * The file exists. Since we can only be called when
634 * overwriting has been enabled, we back off and open the
635 * file normally (not supplying the O_EXCL), then continue
636 * normally. Notice that we must truncate the file, since
637 * if the original file is longer than the stuff we're about
638 * to put in, all the old data past the current write will
641 fd = open(a_f, O_TRUNC | O_WRONLY, a_mode);
643 uss_procs_PrintErr(line,
644 "%s: Failed to open '%s' for overwrite: %s.\n",
645 uss_whoami, a_f, sys_errlist[errno]);
649 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s. \n",
650 uss_whoami, a_f, sys_errlist[errno]);
654 write(fd, a_s, strlen(a_s));
657 uss_procs_PrintErr(line, "Failed to close '%s': %s\n",
658 a_f, sys_errlist[errno]);
665 /*-----------------------------------------------------------------------
666 * static uss_procs_PickADir
669 * Tries to replace $AUTO by a subdir. Subdirs are given by means
670 * of "G" in the configuration file. Each of the directories is
671 * examined, and the one with the inimum number of entries is
679 * 0 if everything went well,
680 * -1 if there was a problem.
683 * Called with THREE parameters from lex.c!
687 *------------------------------------------------------------------------*/
689 afs_int32 uss_procs_PickADir(path, cp)
693 { /*uss_procs_PickADir*/
695 char cd[300]; /*Current directory for search*/
697 int i, count, MinIndex, mina = 10000;
702 if (uss_NumGroups == 0){
703 fprintf(stderr,"%s: No choice yet given to replace $AUTO\n",
705 fprintf(stderr,"%s: Use the G command before $AUTO in config file\n",
710 if (uss_Auto[0] != '\0')
711 return(0); /* we have already done this for this user */
713 if (*(cp-1) == '/') { /*it's ..../$AUTO*/
714 for (i = 0; &path[i] != cp; i++)
720 fprintf(stderr,"%s: $AUTO must be used to replace the whole path or the whole name of a subdirectory. Found: %s$AUTO\n", uss_whoami, path);
723 cd[0] = '/'; cd[1] = '\0';
727 * We now have the current dir (cd). Search all of the given
728 * subdirs (by G in template), count the number of entries in
729 * each and pick the minimum.
731 for (i=0; i < uss_NumGroups; i++) {
732 sprintf(dirname, "%s/%s", cd, uss_DirPool[i]);
733 if ((dirp = opendir(dirname)) == NULL) {
734 if (errno != ENOTDIR)
736 "%s: Warning: Can't open dir '%s' (errno=%d). Skipped.\n",
737 uss_whoami, dirname, errno);
738 continue; /*Skip and continue anyway*/
741 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
742 if (dp->d_name[0] != '.')
743 count++; /* forget about files starting with .*/
745 printf("debug: Dir '%s' has %d entries\n", dirname, count);
746 #endif /* USS_PROCS_DB */
753 if (mina == 10000) { /* We found nothing */
754 fprintf(stderr,"%s: Warning: No valid choice to replace $AUTO\n",
759 strcpy(uss_Auto, uss_DirPool[MinIndex]);
761 printf("Picking dir w/minimum number of entries: '%s'\n",
766 } /*uss_procs_PickADir*/
768 /*-----------------------------------------------------------------------
769 * EXPORTED uss_procs_AddToDirPool
772 * Called from the code generated by the uss grammar.
776 *------------------------------------------------------------------------*/
778 int uss_procs_AddToDirPool(a_dirToAdd)
781 if (uss_NumGroups > 99) {
784 strcpy(uss_DirPool[uss_NumGroups++], a_dirToAdd);
788 /*-----------------------------------------------------------------------
789 * EXPORTED uss_procs_FindAndOpen
792 * Nothing interesting.
796 *------------------------------------------------------------------------*/
798 FILE *uss_procs_FindAndOpen(a_fileToOpen)
801 { /*uss_procs_FindAndOpen*/
803 #define NUM_TPL_PATHS 3
805 FILE *rv; /*Template file descriptor*/
806 int i; /*Loop counter*/
807 char tmp_str[uss_MAX_SIZE]; /*Tmp string*/
809 TemplatePath[NUM_TPL_PATHS][1024]; /*Template directories*/
810 int cant_read; /*Can't read the file?*/
813 * If a full pathname was given, just take it as is.
815 if (index(a_fileToOpen, '/')) {
816 strcpy(tmp_str, a_fileToOpen);
817 rv = fopen(a_fileToOpen, "r");
821 * A relative pathname was given. Try to find the file in each of
822 * the default template directories.
826 sprintf(TemplatePath[0], "%s", ".");
827 sprintf(TemplatePath[1], "/afs/%s/common/uss", uss_Cell);
828 sprintf(TemplatePath[2], "%s", "/etc");
830 for (i = 0; i < NUM_TPL_PATHS; i++) {
831 sprintf(tmp_str, "%s/%s", TemplatePath[i], a_fileToOpen);
832 if ((rv = fopen(tmp_str, "r")) != NULL)
836 * If the file was there but couldn't be opened, we have
839 if (errno != ENOENT) {
843 } /*Look in template directories*/
846 * If we found and opened the file, we're happy. Otherwise,
847 * print out what went wrong.
851 fprintf(stderr, "Using template '%s'\n", tmp_str);
855 * Check to see if we specifically found the file but
860 "%s: Can't open template '%s': %s\n",
861 uss_whoami, tmp_str, sys_errlist[errno]);
864 "%s: Can't find template '%s' in searchlist",
865 uss_whoami, a_fileToOpen);
866 for (i = 0; i < NUM_TPL_PATHS; i++)
867 fprintf(stderr, " '%s'", TemplatePath[i]);
868 fprintf(stderr, "\n");
869 } /*Can't find template*/
871 } /*Relative pathname given*/
874 * Whatever happened, return what we got.
878 } /*uss_procs_FindAndOpen*/
881 /*-----------------------------------------------------------------------
882 * EXPORTED uss_procs_PrintErr
885 * Nothing interesting.
889 *------------------------------------------------------------------------*/
891 void uss_procs_PrintErr(a_lineNum, a_fmt, a_1, a_2, a_3, a_4, a_5)
900 { /*uss_procs_PrintErr*/
903 fprintf(stderr,"%s: Template file, line %d: ", uss_whoami, a_lineNum);
904 fprintf(stderr, a_fmt, a_1, a_2, a_3, a_4, a_5);
906 } /*uss_procs_PrintErr*/