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 */
39 #include <afs/kautils.h> /*MAXKTCREALMLEN*/
41 #undef USS_PROCS_DB_INSTANCE
42 #undef USS_PROCS_DB_BUILDDIR
43 #define uss_procs_MAX_SIZE 2048
47 static int Copy(char *a_from, char *a_to, int a_mode);
48 static int Echo(char *a_s, char *a_f, int a_mode);
50 /*-----------------------------------------------------------------------
51 * EXPORTED uss_procs_BuildDir
54 * Called from the code generated by the uss grammar.
58 *------------------------------------------------------------------------*/
61 uss_procs_BuildDir(char *a_path, char *a_mode, char *a_owner, char *a_access)
62 { /*uss_procs_BuildDir */
66 struct uss_subdir *new_dir;
70 * Don't do anything if there's already a problem.
76 printf("Building directory '%s'; owner: '%s', ACL: '%s'\n", a_path,
80 * If we've not been given permission to overwrite things, make sure
81 * the target doesn't exist before doing anything.
83 if (!uss_OverwriteThisOne) {
85 if (!stat(temp, &stbuf)) {
87 printf("\t[Directory exists, NOT overwriting it]\n");
92 sscanf(a_mode, "%o", &m);
93 o = uss_procs_GetOwner(a_owner);
94 #ifdef USS_PROCS_DB_BUILDDIR
95 printf("DEBUGGING: Owner '%s' is uid %d\n", a_owner, o);
96 #endif /* USS_PROCS_DB_BUILDDIR */
99 if (mkdir(a_path, m)) {
101 * Can't make the directory. Complain if the directory doesn't
104 if (errno != EEXIST) {
105 uss_procs_PrintErr(line,
106 "Failed to create directory '%s': %s\n",
107 a_path, strerror(errno));
109 } /*Directory didn't exist */
110 } /*Create the directory */
113 if (uss_OverwriteThisOne)
114 fprintf(stderr, "\t[Dry run: mkdir %s, mode %o]\n", a_path, m);
118 if (chmod(a_path, m)) {
119 uss_procs_PrintErr(line,
120 "Can't chmod() directory '%s' to be '%s' : %s\n",
121 a_path, a_mode, strerror(errno));
123 } /* chmod the directory */
124 if (chown(a_path, o, -1)) {
125 uss_procs_PrintErr(line,
126 "Can't chown() directory '%s' to be owned by '%s' (uid %d): %s\n",
127 a_path, a_owner, o, strerror(errno));
129 } /*Couldn't chown */
133 "\t[Dry run: chown() directory '%s' to be owned by user]\n",
138 * Set the ACL for this new directory so that the uss_AccountCreator
139 * is the only party that has rights. This will be corrected as the
140 * final action performed on the account.
142 sprintf(buf, "%s %s all", a_path, uss_AccountCreator);
145 fprintf(stderr, "Setting ACL: '%s'\n", buf);
146 if (uss_acl_SetAccess(buf, 1, 0))
150 fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n", buf,
155 * Use our linked list to remember this directory's true ACL setting so
156 * we may set it correctly at the tail end of the account creation.
158 new_dir = (struct uss_subdir *)malloc(sizeof(struct uss_subdir));
159 new_dir->previous = uss_currentDir;
160 new_dir->path = (char *)malloc(strlen(a_path) + 1);
161 strcpy(new_dir->path, a_path);
162 new_dir->finalACL = (char *)malloc(strlen(a_access) + 1);
163 strcpy(new_dir->finalACL, a_access);
164 uss_currentDir = new_dir;
167 * Return the happy news.
171 } /*uss_procs_BuildDir */
174 /*-----------------------------------------------------------------------
175 * EXPORTED uss_procs_CpFile
178 * Called from the code generated by the uss grammar.
182 *------------------------------------------------------------------------*/
185 uss_procs_CpFile(char *a_path, char *a_mode, char *a_owner, char *a_proto)
186 { /*uss_procs_CpFile */
193 * Don't do anything if something has already gone wrong.
199 printf("Installing '%s'\n", a_path);
202 * If we've not been given permission to overwrite things, make sure
203 * the target doesn't exist before doing anything.
205 if (!uss_OverwriteThisOne) {
206 strcpy(temp, a_path);
207 if (!stat(temp, &stbuf)) {
209 printf("\t[Entry exists, NOT overwriting it]\n");
214 sscanf(a_mode, "%o", &m);
215 o = uss_procs_GetOwner(a_owner);
217 strcpy(temp, a_proto);
219 if (stat(temp, &stbuf)) {
220 uss_procs_PrintErr(line, "Failed to stat '%s': %s\n", a_proto,
225 if (stbuf.st_mode & S_IFDIR) {
226 if ((cp = strrchr(a_path, '/')) == NULL) {
227 strcat(a_proto, "/");
228 strcat(a_proto, a_path);
231 * Append the last part (file name).
236 /*Target is a directory */
238 if (Copy(a_proto, a_path, m)) {
239 uss_procs_PrintErr(line, "Failed to copy '%s' to '%s'\n", a_proto,
245 fprintf(stderr, "\t[Dry run: Copying '%s' to '%s', mode %o]\n",
250 if (chown(a_path, o, -1)) {
251 uss_procs_PrintErr(line,
252 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
253 a_path, a_owner, o, strerror(errno));
259 "\t[Dry run: chown() file '%s' to be owned by user]\n",
264 * Return the happy news.
268 } /*uss_procs_CpFile */
271 /*-----------------------------------------------------------------------
272 * EXPORTED uss_procs_EchoToFile
275 * Called from the code generated by the uss grammar.
279 *------------------------------------------------------------------------*/
282 uss_procs_EchoToFile(char *a_path, char *a_mode, char *a_owner,
284 { /*uss_procs_EchoToFile */
290 * Don't do anything if something has already gone wrong.
296 printf("Echoing to '%s'\n", a_path);
299 * If we've not been given permission to overwrite things, make sure
300 * the target doesn't exist before doing anything.
302 if (!uss_OverwriteThisOne) {
303 strcpy(temp, a_path);
304 if (!stat(temp, &stbuf)) {
306 printf("\t[Entry exists, NOT overwriting it]\n");
311 sscanf(a_mode, "%o", &m);
312 o = uss_procs_GetOwner(a_owner);
315 if (Echo(a_content, a_path, m)) {
316 uss_procs_PrintErr(line,
317 "Failed to echo string '%s' to file '%s'\n",
323 fprintf(stderr, "\t[Dry run: Echoing '%s' into file '%s']\n",
328 if (chown(a_path, o, -1)) {
329 uss_procs_PrintErr(line,
330 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
331 a_path, a_owner, o, strerror(errno));
337 "\t[Dry run: chown() file '%s' to be owned by user]\n",
342 * Return the happy news.
346 } /*uss_procs_EchoToFile */
349 /*-----------------------------------------------------------------------
350 * EXPORTED uss_procs_Exec
353 * Called from the code generated by the uss grammar, as well as
358 *------------------------------------------------------------------------*/
361 uss_procs_Exec(char *a_command)
362 { /*uss_procs_Exec */
365 printf("Running '%s'\n", a_command);
368 if (system(a_command)) {
369 uss_procs_PrintErr(line, "Failed to run the '%s' command: %s\n",
370 a_command, strerror(errno));
375 fprintf(stderr, "\t[Dry run: executing '%s']\n", a_command);
379 * Return the happy news.
383 } /*uss_procs_Exec */
386 /*-----------------------------------------------------------------------
387 * EXPORTED uss_procs_SetLink
390 * Called from the code generated by the uss grammar.
394 *------------------------------------------------------------------------*/
397 uss_procs_SetLink(char *a_path1, char *a_path2, char a_type)
398 { /*uss_procs_SetLink */
403 printf("Setting link '%s' to '%s'\n", a_path1, a_path2);
406 * If we've not been given permission to overwrite things, make sure
407 * the target doesn't exist before doing anything.
409 if (!uss_OverwriteThisOne) {
410 strcpy(temp, a_path2);
411 if (!stat(temp, &stbuf)) {
413 printf("\t[Entry exists, NOT overwriting it]\n");
423 if (symlink(a_path1, a_path2)) {
424 uss_procs_PrintErr(line,
425 "Failed to make symlink '%s' to '%s': %s\n",
426 a_path1, a_path2, strerror(errno));
431 fprintf(stderr, "\t[Dry run: Making symlink '%s' to '%s']\n",
440 if (link(a_path1, a_path2)) {
441 uss_procs_PrintErr(line,
442 "Failed to make hard link '%s' to '%s': %s\n",
443 a_path1, a_path2, strerror(errno));
448 fprintf(stderr, "\t[Dry run: Making hard link '%s' to '%s']\n",
454 * Return the happy news.
458 } /*uss_procs_SetLink */
461 /*-----------------------------------------------------------------------
462 * EXPORTED uss_procs_GetOwner
465 * Nothing interesting.
469 *------------------------------------------------------------------------*/
472 uss_procs_GetOwner(char *a_ownerStr)
473 { /*uss_procs_GetOwner */
475 struct passwd *pw; /*Ptr to password file entry */
476 int ownerID; /*Numerical owner */
478 ownerID = atoi(a_ownerStr);
479 if ((ownerID == 0) && (a_ownerStr[0] != '0')) {
481 * The owner is not in numerical format
483 if ((pw = getpwnam(a_ownerStr)) == NULL) {
484 uss_procs_PrintErr(line, "Owner '%s' is an unknown user\n",
492 } /*uss_procs_GetOwner */
494 /*-----------------------------------------------------------------------
498 * Copies the "from" file to the "to" file and sets the mode.
501 * a_from : File to copy from.
502 * a_to : File to copy to.
503 * a_mode : New Unix mode to set.
506 * 0 if everything went well,
507 * if there was a problem.
510 * Nothing interesting.
514 *------------------------------------------------------------------------*/
517 Copy(char *a_from, char *a_to, int a_mode)
520 register int fd1, fd2;
525 fd1 = open(a_to, O_EXCL | O_CREAT | O_WRONLY, a_mode);
527 if (errno == EEXIST) {
529 * The file exists. Since we can only be called when overwriting
530 * has been enabled, we back off and open the file normally (not
531 * supplying O_EXCL), then continue normally.
533 fd1 = open(a_to, O_CREAT | O_WRONLY, a_mode);
535 uss_procs_PrintErr(line,
536 "%s: Failed to open '%s' for overwrite: %s.\n",
537 uss_whoami, a_to, strerror(errno));
541 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s.\n",
542 uss_whoami, a_to, strerror(errno));
547 if ((fd2 = open(a_from, O_RDONLY, 0)) < 0) {
548 uss_procs_PrintErr(line, "%s: Error reading '%s': %s\n", uss_whoami,
549 a_from, strerror(errno));
553 while ((cnt = read(fd2, buf, BUFSIZ)) == BUFSIZ)
554 write(fd1, buf, cnt);
556 write(fd1, buf, cnt);
559 uss_procs_PrintErr(line, "Failed to close '%s' %s\n", a_to,
563 if ((rc = close(fd2)))
564 uss_procs_PrintErr(line, "Warning: Failed to close '%s': %s\n",
565 a_from, strerror(errno));
570 /*-----------------------------------------------------------------------
574 * Writes a string into a file and sets its mode.
577 * a_s : String to write.
578 * a_f : Filename to write to.
579 * a_mode : New Unix mode to set.
582 * 0 if everything went well,
583 * if there was a problem.
586 * Nothing interesting.
590 *------------------------------------------------------------------------*/
593 Echo(char *a_s, char *a_f, int a_mode)
599 fd = open(a_f, O_EXCL | O_CREAT | O_WRONLY, a_mode);
601 if (errno == EEXIST) {
603 * The file exists. Since we can only be called when
604 * overwriting has been enabled, we back off and open the
605 * file normally (not supplying the O_EXCL), then continue
606 * normally. Notice that we must truncate the file, since
607 * if the original file is longer than the stuff we're about
608 * to put in, all the old data past the current write will
611 fd = open(a_f, O_TRUNC | O_WRONLY, a_mode);
613 uss_procs_PrintErr(line,
614 "%s: Failed to open '%s' for overwrite: %s.\n",
615 uss_whoami, a_f, strerror(errno));
619 uss_procs_PrintErr(line, "%s: Failed to open '%s': %s. \n",
620 uss_whoami, a_f, strerror(errno));
624 write(fd, a_s, strlen(a_s));
627 uss_procs_PrintErr(line, "Failed to close '%s': %s\n", a_f,
635 /*-----------------------------------------------------------------------
636 * static uss_procs_PickADir
639 * Tries to replace $AUTO by a subdir. Subdirs are given by means
640 * of "G" in the configuration file. Each of the directories is
641 * examined, and the one with the inimum number of entries is
649 * 0 if everything went well,
650 * -1 if there was a problem.
653 * Called with THREE parameters from lex.c!
657 *------------------------------------------------------------------------*/
660 uss_procs_PickADir(char *path, char *cp)
661 { /*uss_procs_PickADir */
663 char cd[300]; /*Current directory for search */
665 int i, count, MinIndex = 0, mina = 10000;
670 if (uss_NumGroups == 0) {
671 fprintf(stderr, "%s: No choice yet given to replace $AUTO\n",
673 fprintf(stderr, "%s: Use the G command before $AUTO in config file\n",
678 if (uss_Auto[0] != '\0')
679 return (0); /* we have already done this for this user */
681 if (*(cp - 1) == '/') { /*it's ..../$AUTO */
682 for (i = 0; &path[i] != cp; i++)
688 "%s: $AUTO must be used to replace the whole path or the whole name of a subdirectory. Found: %s$AUTO\n",
697 * We now have the current dir (cd). Search all of the given
698 * subdirs (by G in template), count the number of entries in
699 * each and pick the minimum.
701 for (i = 0; i < uss_NumGroups; i++) {
702 sprintf(dirname, "%s/%s", cd, uss_DirPool[i]);
703 if ((dirp = opendir(dirname)) == NULL) {
704 if (errno != ENOTDIR)
706 "%s: Warning: Can't open dir '%s' (errno=%d). Skipped.\n",
707 uss_whoami, dirname, errno);
708 continue; /*Skip and continue anyway */
711 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
712 if (dp->d_name[0] != '.')
713 count++; /* forget about files starting with . */
715 printf("debug: Dir '%s' has %d entries\n", dirname, count);
716 #endif /* USS_PROCS_DB */
723 if (mina == 10000) { /* We found nothing */
724 fprintf(stderr, "%s: Warning: No valid choice to replace $AUTO\n",
728 strcpy(uss_Auto, uss_DirPool[MinIndex]);
730 printf("Picking dir w/minimum number of entries: '%s'\n",
735 } /*uss_procs_PickADir */
737 /*-----------------------------------------------------------------------
738 * EXPORTED uss_procs_AddToDirPool
741 * Called from the code generated by the uss grammar.
745 *------------------------------------------------------------------------*/
748 uss_procs_AddToDirPool(char *a_dirToAdd)
750 if (uss_NumGroups > 99) {
753 strcpy(uss_DirPool[uss_NumGroups++], a_dirToAdd);
757 /*-----------------------------------------------------------------------
758 * EXPORTED uss_procs_FindAndOpen
761 * Nothing interesting.
765 *------------------------------------------------------------------------*/
768 uss_procs_FindAndOpen(char *a_fileToOpen)
769 { /*uss_procs_FindAndOpen */
771 #define NUM_TPL_PATHS 3
773 FILE *rv; /*Template file descriptor */
774 int i; /*Loop counter */
775 char tmp_str[uss_MAX_SIZE]; /*Tmp string */
777 TemplatePath[NUM_TPL_PATHS][1024]; /*Template directories */
778 int cant_read; /*Can't read the file? */
781 * If a full pathname was given, just take it as is.
783 if (strchr(a_fileToOpen, '/')) {
784 strcpy(tmp_str, a_fileToOpen);
785 rv = fopen(a_fileToOpen, "r");
788 * A relative pathname was given. Try to find the file in each of
789 * the default template directories.
793 sprintf(TemplatePath[0], "%s", ".");
794 sprintf(TemplatePath[1], "/afs/%s/common/uss", uss_Cell);
795 sprintf(TemplatePath[2], "%s", "/etc");
797 for (i = 0; i < NUM_TPL_PATHS; i++) {
798 sprintf(tmp_str, "%s/%s", TemplatePath[i], a_fileToOpen);
799 if ((rv = fopen(tmp_str, "r")) != NULL)
803 * If the file was there but couldn't be opened, we have
806 if (errno != ENOENT) {
810 } /*Look in template directories */
813 * If we found and opened the file, we're happy. Otherwise,
814 * print out what went wrong.
818 fprintf(stderr, "Using template '%s'\n", tmp_str);
822 * Check to see if we specifically found the file but
826 fprintf(stderr, "%s: Can't open template '%s': %s\n",
827 uss_whoami, tmp_str, strerror(errno));
829 fprintf(stderr, "%s: Can't find template '%s' in searchlist",
830 uss_whoami, a_fileToOpen);
831 for (i = 0; i < NUM_TPL_PATHS; i++)
832 fprintf(stderr, " '%s'", TemplatePath[i]);
833 fprintf(stderr, "\n");
834 } /*Can't find template */
836 } /*Relative pathname given */
839 * Whatever happened, return what we got.
843 } /*uss_procs_FindAndOpen */
846 /*-----------------------------------------------------------------------
847 * EXPORTED uss_procs_PrintErr
850 * Nothing interesting.
854 *------------------------------------------------------------------------*/
857 uss_procs_PrintErr(int a_lineNum, char *a_fmt, ... )
858 { /*uss_procs_PrintErr */
863 fprintf(stderr, "%s: Template file, line %d: ", uss_whoami, a_lineNum);
864 vfprintf(stderr, a_fmt, ap);
866 } /*uss_procs_PrintErr */