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*/
43 #include <afs/kautils.h> /*MAXKTCREALMLEN*/
47 #undef USS_PROCS_DB_INSTANCE
48 #undef USS_PROCS_DB_BUILDDIR
50 #define uss_procs_MAX_SIZE 2048
58 /*-----------------------------------------------------------------------
59 * EXPORTED uss_procs_BuildDir
62 * Called from the code generated by the uss grammar.
66 *------------------------------------------------------------------------*/
68 afs_int32 uss_procs_BuildDir(a_path, a_mode, a_owner, a_access)
74 { /*uss_procs_BuildDir*/
78 struct uss_subdir *new_dir;
82 * Don't do anything if there's already a problem.
88 printf("Building directory '%s'; owner: '%s', ACL: '%s'\n",
89 a_path, a_owner, a_access);
92 * If we've not been given permission to overwrite things, make sure
93 * the target doesn't exist before doing anything.
95 if (!uss_OverwriteThisOne) {
97 if (!stat(temp, &stbuf)) {
99 printf("\t[Directory exists, NOT overwriting it]\n");
104 sscanf(a_mode, "%o", &m);
105 o = uss_procs_GetOwner(a_owner);
106 #ifdef USS_PROCS_DB_BUILDDIR
107 printf("DEBUGGING: Owner '%s' is uid %d\n", a_owner, o);
108 #endif /* USS_PROCS_DB_BUILDDIR */
111 if (mkdir(a_path, m)) {
113 * Can't make the directory. Complain if the directory doesn't
116 if (errno != EEXIST) {
117 uss_procs_PrintErr(line,
118 "Failed to create directory '%s': %s\n",
119 a_path, strerror(errno));
121 } /*Directory didn't exist*/
122 } /*Create the directory*/
125 if (uss_OverwriteThisOne)
126 fprintf(stderr, "\t[Dry run: mkdir %s, mode %o]\n",
131 if (chmod(a_path, m)) {
132 uss_procs_PrintErr(line,
133 "Can't chmod() directory '%s' to be '%s' : %s\n",
134 a_path, a_mode, strerror(errno));
136 } /* chmod the directory */
137 if (chown(a_path, o, -1)) {
138 uss_procs_PrintErr(line,
139 "Can't chown() directory '%s' to be owned by '%s' (uid %d): %s\n",
140 a_path, a_owner, o, strerror(errno));
146 "\t[Dry run: chown() directory '%s' to be owned by user]\n",
151 * Set the ACL for this new directory so that the uss_AccountCreator
152 * is the only party that has rights. This will be corrected as the
153 * final action performed on the account.
155 sprintf(buf, "%s %s all", a_path, uss_AccountCreator);
159 "Setting ACL: '%s'\n", buf);
160 if (uss_acl_SetAccess(buf, 1, 0))
164 fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n",
169 * Use our linked list to remember this directory's true ACL setting so
170 * we may set it correctly at the tail end of the account creation.
172 new_dir = (struct uss_subdir *) malloc(sizeof(struct uss_subdir));
173 new_dir->previous = uss_currentDir;
174 new_dir->path = (char *) malloc(strlen(a_path)+1);
175 strcpy(new_dir->path, a_path);
176 new_dir->finalACL = (char *) malloc(strlen(a_access)+1);
177 strcpy(new_dir->finalACL, a_access);
178 uss_currentDir = new_dir;
181 * Return the happy news.
185 } /*uss_procs_BuildDir*/
188 /*-----------------------------------------------------------------------
189 * EXPORTED uss_procs_CpFile
192 * Called from the code generated by the uss grammar.
196 *------------------------------------------------------------------------*/
198 afs_int32 uss_procs_CpFile(a_path, a_mode, a_owner, a_proto)
204 { /*uss_procs_CpFile*/
211 * Don't do anything if something has already gone wrong.
217 printf("Installing '%s'\n", a_path);
220 * If we've not been given permission to overwrite things, make sure
221 * the target doesn't exist before doing anything.
223 if (!uss_OverwriteThisOne) {
224 strcpy(temp, a_path);
225 if (!stat(temp, &stbuf)) {
227 printf("\t[Entry exists, NOT overwriting it]\n");
232 sscanf(a_mode, "%o", &m);
233 o = uss_procs_GetOwner(a_owner);
235 strcpy(temp, a_proto);
237 if (stat(temp, &stbuf)) {
238 uss_procs_PrintErr(line, "Failed to stat '%s': %s\n",
239 a_proto, strerror(errno));
243 if (stbuf.st_mode & S_IFDIR) {
244 if ((cp = strrchr(a_path, '/')) == NULL) {
245 strcat(a_proto, "/");
246 strcat(a_proto, a_path);
250 * Append the last part (file name).
254 } /*Target is a directory*/
257 if (Copy(a_proto, a_path, m)) {
258 uss_procs_PrintErr(line,
259 "Failed to copy '%s' to '%s'\n",
265 fprintf(stderr, "\t[Dry run: Copying '%s' to '%s', mode %o]\n",
270 if (chown(a_path, o, -1)) {
271 uss_procs_PrintErr(line,
272 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
273 a_path, a_owner, o, strerror(errno));
278 fprintf(stderr, "\t[Dry run: chown() file '%s' to be owned by user]\n",
283 * Return the happy news.
287 } /*uss_procs_CpFile*/
290 /*-----------------------------------------------------------------------
291 * EXPORTED uss_procs_EchoToFile
294 * Called from the code generated by the uss grammar.
298 *------------------------------------------------------------------------*/
300 afs_int32 uss_procs_EchoToFile(a_path, a_mode, a_owner, a_content)
306 { /*uss_procs_EchoToFile*/
312 * Don't do anything if something has already gone wrong.
318 printf("Echoing to '%s'\n", a_path);
321 * If we've not been given permission to overwrite things, make sure
322 * the target doesn't exist before doing anything.
324 if (!uss_OverwriteThisOne) {
325 strcpy(temp, a_path);
326 if (!stat(temp, &stbuf)) {
328 printf("\t[Entry exists, NOT overwriting it]\n");
333 sscanf(a_mode, "%o", &m);
334 o = uss_procs_GetOwner(a_owner);
337 if (Echo(a_content, a_path, m)){
338 uss_procs_PrintErr(line,
339 "Failed to echo string '%s' to file '%s'\n",
345 fprintf(stderr, "\t[Dry run: Echoing '%s' into file '%s']\n",
350 if (chown(a_path, o, -1)){
351 uss_procs_PrintErr(line,
352 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
353 a_path, a_owner, o, strerror(errno));
359 "\t[Dry run: chown() file '%s' to be owned by user]\n",
364 * Return the happy news.
368 } /*uss_procs_EchoToFile*/
371 /*-----------------------------------------------------------------------
372 * EXPORTED uss_procs_Exec
375 * Called from the code generated by the uss grammar, as well as
380 *------------------------------------------------------------------------*/
382 afs_int32 uss_procs_Exec(a_command)
388 printf("Running '%s'\n", a_command);
391 if (system(a_command)) {
392 uss_procs_PrintErr(line,
393 "Failed to run the '%s' command: %s\n",
394 a_command, strerror(errno));
399 fprintf(stderr, "\t[Dry run: executing '%s']\n", a_command);
403 * Return the happy news.
410 /*-----------------------------------------------------------------------
411 * EXPORTED uss_procs_SetLink
414 * Called from the code generated by the uss grammar.
418 *------------------------------------------------------------------------*/
420 afs_int32 uss_procs_SetLink(a_path1, a_path2, a_type)
425 { /*uss_procs_SetLink*/
430 printf("Setting link '%s' to '%s'\n", a_path1, a_path2);
433 * If we've not been given permission to overwrite things, make sure
434 * the target doesn't exist before doing anything.
436 if (!uss_OverwriteThisOne) {
437 strcpy(temp, a_path2);
438 if (!stat(temp, &stbuf)) {
440 printf("\t[Entry exists, NOT overwriting it]\n");
450 if (symlink(a_path1, a_path2)) {
451 uss_procs_PrintErr(line,
452 "Failed to make symlink '%s' to '%s': %s\n",
453 a_path1, a_path2, strerror(errno));
458 fprintf(stderr, "\t[Dry run: Making symlink '%s' to '%s']\n",
467 if (link(a_path1, a_path2)) {
468 uss_procs_PrintErr(line,
469 "Failed to make hard link '%s' to '%s': %s\n",
470 a_path1, a_path2, strerror(errno));
475 fprintf(stderr, "\t[Dry run: Making hard link '%s' to '%s']\n",
481 * Return the happy news.
485 } /*uss_procs_SetLink*/
488 /*-----------------------------------------------------------------------
489 * EXPORTED uss_procs_GetOwner
492 * Nothing interesting.
496 *------------------------------------------------------------------------*/
498 int uss_procs_GetOwner(a_ownerStr)
501 { /*uss_procs_GetOwner*/
503 struct passwd *pw; /*Ptr to password file entry*/
504 int ownerID; /*Numerical owner*/
506 ownerID = atoi(a_ownerStr);
507 if ((ownerID == 0) && (a_ownerStr[0] != '0')) {
509 * The owner is not in numerical format
511 if ((pw = getpwnam(a_ownerStr)) == NULL) {
512 uss_procs_PrintErr(line,
513 "Owner '%s' is an unknown user\n",
522 } /*uss_procs_GetOwner*/
524 /*-----------------------------------------------------------------------
528 * Copies the "from" file to the "to" file and sets the mode.
531 * a_from : File to copy from.
532 * a_to : File to copy to.
533 * a_mode : New Unix mode to set.
536 * 0 if everything went well,
537 * if there was a problem.
540 * Nothing interesting.
544 *------------------------------------------------------------------------*/
546 static int Copy(a_from, a_to, a_mode)
553 register int fd1, fd2;
558 fd1 = open(a_to, O_EXCL | O_CREAT | O_WRONLY, a_mode);
560 if (errno == EEXIST) {
562 * The file exists. Since we can only be called when overwriting
563 * has been enabled, we back off and open the file normally (not
564 * supplying O_EXCL), then continue normally.
566 fd1 = open(a_to, O_CREAT | O_WRONLY, a_mode);
568 uss_procs_PrintErr(line,
569 "%s: Failed to open '%s' for overwrite: %s.\n",
570 uss_whoami, a_to, strerror(errno));
574 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s.\n",
575 uss_whoami, a_to, strerror(errno));
580 if ((fd2 = open(a_from, O_RDONLY, 0)) < 0) {
581 uss_procs_PrintErr(line, "%s: Error reading '%s': %s\n",
582 uss_whoami, a_from, strerror(errno));
586 while ((cnt = read(fd2, buf, BUFSIZ)) == BUFSIZ)
587 write(fd1, buf, cnt);
589 write(fd1, buf, cnt);
592 uss_procs_PrintErr(line,
593 "Failed to close '%s' %s\n",
594 a_to, strerror(errno));
598 uss_procs_PrintErr(line, "Warning: Failed to close '%s': %s\n",
599 a_from, strerror(errno));
604 /*-----------------------------------------------------------------------
608 * Writes a string into a file and sets its mode.
611 * a_s : String to write.
612 * a_f : Filename to write to.
613 * a_mode : New Unix mode to set.
616 * 0 if everything went well,
617 * if there was a problem.
620 * Nothing interesting.
624 *------------------------------------------------------------------------*/
626 static int Echo(a_s, a_f, a_mode)
636 fd = open(a_f, O_EXCL | O_CREAT | O_WRONLY, a_mode);
638 if (errno == EEXIST) {
640 * The file exists. Since we can only be called when
641 * overwriting has been enabled, we back off and open the
642 * file normally (not supplying the O_EXCL), then continue
643 * normally. Notice that we must truncate the file, since
644 * if the original file is longer than the stuff we're about
645 * to put in, all the old data past the current write will
648 fd = open(a_f, O_TRUNC | O_WRONLY, a_mode);
650 uss_procs_PrintErr(line,
651 "%s: Failed to open '%s' for overwrite: %s.\n",
652 uss_whoami, a_f, strerror(errno));
656 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s. \n",
657 uss_whoami, a_f, strerror(errno));
661 write(fd, a_s, strlen(a_s));
664 uss_procs_PrintErr(line, "Failed to close '%s': %s\n",
665 a_f, strerror(errno));
672 /*-----------------------------------------------------------------------
673 * static uss_procs_PickADir
676 * Tries to replace $AUTO by a subdir. Subdirs are given by means
677 * of "G" in the configuration file. Each of the directories is
678 * examined, and the one with the inimum number of entries is
686 * 0 if everything went well,
687 * -1 if there was a problem.
690 * Called with THREE parameters from lex.c!
694 *------------------------------------------------------------------------*/
696 afs_int32 uss_procs_PickADir(path, cp)
700 { /*uss_procs_PickADir*/
702 char cd[300]; /*Current directory for search*/
704 int i, count, MinIndex, mina = 10000;
709 if (uss_NumGroups == 0){
710 fprintf(stderr,"%s: No choice yet given to replace $AUTO\n",
712 fprintf(stderr,"%s: Use the G command before $AUTO in config file\n",
717 if (uss_Auto[0] != '\0')
718 return(0); /* we have already done this for this user */
720 if (*(cp-1) == '/') { /*it's ..../$AUTO*/
721 for (i = 0; &path[i] != cp; i++)
727 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);
730 cd[0] = '/'; cd[1] = '\0';
734 * We now have the current dir (cd). Search all of the given
735 * subdirs (by G in template), count the number of entries in
736 * each and pick the minimum.
738 for (i=0; i < uss_NumGroups; i++) {
739 sprintf(dirname, "%s/%s", cd, uss_DirPool[i]);
740 if ((dirp = opendir(dirname)) == NULL) {
741 if (errno != ENOTDIR)
743 "%s: Warning: Can't open dir '%s' (errno=%d). Skipped.\n",
744 uss_whoami, dirname, errno);
745 continue; /*Skip and continue anyway*/
748 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
749 if (dp->d_name[0] != '.')
750 count++; /* forget about files starting with .*/
752 printf("debug: Dir '%s' has %d entries\n", dirname, count);
753 #endif /* USS_PROCS_DB */
760 if (mina == 10000) { /* We found nothing */
761 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 *------------------------------------------------------------------------*/
785 int uss_procs_AddToDirPool(a_dirToAdd)
788 if (uss_NumGroups > 99) {
791 strcpy(uss_DirPool[uss_NumGroups++], a_dirToAdd);
795 /*-----------------------------------------------------------------------
796 * EXPORTED uss_procs_FindAndOpen
799 * Nothing interesting.
803 *------------------------------------------------------------------------*/
805 FILE *uss_procs_FindAndOpen(a_fileToOpen)
808 { /*uss_procs_FindAndOpen*/
810 #define NUM_TPL_PATHS 3
812 FILE *rv; /*Template file descriptor*/
813 int i; /*Loop counter*/
814 char tmp_str[uss_MAX_SIZE]; /*Tmp string*/
816 TemplatePath[NUM_TPL_PATHS][1024]; /*Template directories*/
817 int cant_read; /*Can't read the file?*/
820 * If a full pathname was given, just take it as is.
822 if (strchr(a_fileToOpen, '/')) {
823 strcpy(tmp_str, a_fileToOpen);
824 rv = fopen(a_fileToOpen, "r");
828 * A relative pathname was given. Try to find the file in each of
829 * the default template directories.
833 sprintf(TemplatePath[0], "%s", ".");
834 sprintf(TemplatePath[1], "/afs/%s/common/uss", uss_Cell);
835 sprintf(TemplatePath[2], "%s", "/etc");
837 for (i = 0; i < NUM_TPL_PATHS; i++) {
838 sprintf(tmp_str, "%s/%s", TemplatePath[i], a_fileToOpen);
839 if ((rv = fopen(tmp_str, "r")) != NULL)
843 * If the file was there but couldn't be opened, we have
846 if (errno != ENOENT) {
850 } /*Look in template directories*/
853 * If we found and opened the file, we're happy. Otherwise,
854 * print out what went wrong.
858 fprintf(stderr, "Using template '%s'\n", tmp_str);
862 * Check to see if we specifically found the file but
867 "%s: Can't open template '%s': %s\n",
868 uss_whoami, tmp_str, strerror(errno));
871 "%s: Can't find template '%s' in searchlist",
872 uss_whoami, a_fileToOpen);
873 for (i = 0; i < NUM_TPL_PATHS; i++)
874 fprintf(stderr, " '%s'", TemplatePath[i]);
875 fprintf(stderr, "\n");
876 } /*Can't find template*/
878 } /*Relative pathname given*/
881 * Whatever happened, return what we got.
885 } /*uss_procs_FindAndOpen*/
888 /*-----------------------------------------------------------------------
889 * EXPORTED uss_procs_PrintErr
892 * Nothing interesting.
896 *------------------------------------------------------------------------*/
898 void 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*/