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 <afs/kautils.h> /*MAXKTCREALMLEN*/
25 #include "uss_procs.h" /*Module interface */
26 #include "uss_common.h" /*Common defs & operations */
27 #include "uss_acl.h" /*ACL-related operations */
30 #undef USS_PROCS_DB_INSTANCE
31 #undef USS_PROCS_DB_BUILDDIR
32 #define uss_procs_MAX_SIZE 2048
36 static int Copy(char *a_from
, char *a_to
, int a_mode
);
37 static int Echo(char *a_s
, char *a_f
, int a_mode
);
39 /*-----------------------------------------------------------------------
40 * EXPORTED uss_procs_BuildDir
43 * Called from the code generated by the uss grammar.
47 *------------------------------------------------------------------------*/
50 uss_procs_BuildDir(char *a_path
, char *a_mode
, char *a_owner
, char *a_access
)
51 { /*uss_procs_BuildDir */
55 struct uss_subdir
*new_dir
;
59 * Don't do anything if there's already a problem.
65 printf("Building directory '%s'; owner: '%s', ACL: '%s'\n", a_path
,
69 * If we've not been given permission to overwrite things, make sure
70 * the target doesn't exist before doing anything.
72 if (!uss_OverwriteThisOne
) {
74 if (!stat(temp
, &stbuf
)) {
76 printf("\t[Directory exists, NOT overwriting it]\n");
81 sscanf(a_mode
, "%o", &m
);
82 o
= uss_procs_GetOwner(a_owner
);
83 #ifdef USS_PROCS_DB_BUILDDIR
84 printf("DEBUGGING: Owner '%s' is uid %d\n", a_owner
, o
);
85 #endif /* USS_PROCS_DB_BUILDDIR */
88 if (mkdir(a_path
, m
)) {
90 * Can't make the directory. Complain if the directory doesn't
93 if (errno
!= EEXIST
) {
94 uss_procs_PrintErr(line
,
95 "Failed to create directory '%s': %s\n",
96 a_path
, strerror(errno
));
98 } /*Directory didn't exist */
99 } /*Create the directory */
102 if (uss_OverwriteThisOne
)
103 fprintf(stderr
, "\t[Dry run: mkdir %s, mode %o]\n", a_path
, m
);
107 if (chmod(a_path
, m
)) {
108 uss_procs_PrintErr(line
,
109 "Can't chmod() directory '%s' to be '%s' : %s\n",
110 a_path
, a_mode
, strerror(errno
));
112 } /* chmod the directory */
113 if (chown(a_path
, o
, -1)) {
114 uss_procs_PrintErr(line
,
115 "Can't chown() directory '%s' to be owned by '%s' (uid %d): %s\n",
116 a_path
, a_owner
, o
, strerror(errno
));
118 } /*Couldn't chown */
122 "\t[Dry run: chown() directory '%s' to be owned by user]\n",
127 * Set the ACL for this new directory so that the uss_AccountCreator
128 * is the only party that has rights. This will be corrected as the
129 * final action performed on the account.
131 sprintf(buf
, "%s %s all", a_path
, uss_AccountCreator
);
134 fprintf(stderr
, "Setting ACL: '%s'\n", buf
);
135 if (uss_acl_SetAccess(buf
, 1, 0))
139 fprintf(stderr
, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n", buf
,
144 * Use our linked list to remember this directory's true ACL setting so
145 * we may set it correctly at the tail end of the account creation.
147 new_dir
= malloc(sizeof(struct uss_subdir
));
148 new_dir
->previous
= uss_currentDir
;
149 new_dir
->path
= strdup(a_path
);
150 new_dir
->finalACL
= strdup(a_access
);
151 uss_currentDir
= new_dir
;
154 * Return the happy news.
158 } /*uss_procs_BuildDir */
161 /*-----------------------------------------------------------------------
162 * EXPORTED uss_procs_CpFile
165 * Called from the code generated by the uss grammar.
169 *------------------------------------------------------------------------*/
172 uss_procs_CpFile(char *a_path
, char *a_mode
, char *a_owner
, char *a_proto
)
173 { /*uss_procs_CpFile */
180 * Don't do anything if something has already gone wrong.
186 printf("Installing '%s'\n", a_path
);
189 * If we've not been given permission to overwrite things, make sure
190 * the target doesn't exist before doing anything.
192 if (!uss_OverwriteThisOne
) {
193 strcpy(temp
, a_path
);
194 if (!stat(temp
, &stbuf
)) {
196 printf("\t[Entry exists, NOT overwriting it]\n");
201 sscanf(a_mode
, "%o", &m
);
202 o
= uss_procs_GetOwner(a_owner
);
204 strcpy(temp
, a_proto
);
206 if (stat(temp
, &stbuf
)) {
207 uss_procs_PrintErr(line
, "Failed to stat '%s': %s\n", a_proto
,
212 if (stbuf
.st_mode
& S_IFDIR
) {
213 if ((cp
= strrchr(a_path
, '/')) == NULL
) {
214 strcat(a_proto
, "/");
215 strcat(a_proto
, a_path
);
218 * Append the last part (file name).
223 /*Target is a directory */
225 if (Copy(a_proto
, a_path
, m
)) {
226 uss_procs_PrintErr(line
, "Failed to copy '%s' to '%s'\n", a_proto
,
232 fprintf(stderr
, "\t[Dry run: Copying '%s' to '%s', mode %o]\n",
237 if (chown(a_path
, o
, -1)) {
238 uss_procs_PrintErr(line
,
239 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
240 a_path
, a_owner
, o
, strerror(errno
));
246 "\t[Dry run: chown() file '%s' to be owned by user]\n",
251 * Return the happy news.
255 } /*uss_procs_CpFile */
258 /*-----------------------------------------------------------------------
259 * EXPORTED uss_procs_EchoToFile
262 * Called from the code generated by the uss grammar.
266 *------------------------------------------------------------------------*/
269 uss_procs_EchoToFile(char *a_path
, char *a_mode
, char *a_owner
,
271 { /*uss_procs_EchoToFile */
277 * Don't do anything if something has already gone wrong.
283 printf("Echoing to '%s'\n", a_path
);
286 * If we've not been given permission to overwrite things, make sure
287 * the target doesn't exist before doing anything.
289 if (!uss_OverwriteThisOne
) {
290 strcpy(temp
, a_path
);
291 if (!stat(temp
, &stbuf
)) {
293 printf("\t[Entry exists, NOT overwriting it]\n");
298 sscanf(a_mode
, "%o", &m
);
299 o
= uss_procs_GetOwner(a_owner
);
302 if (Echo(a_content
, a_path
, m
)) {
303 uss_procs_PrintErr(line
,
304 "Failed to echo string '%s' to file '%s'\n",
310 fprintf(stderr
, "\t[Dry run: Echoing '%s' into file '%s']\n",
315 if (chown(a_path
, o
, -1)) {
316 uss_procs_PrintErr(line
,
317 "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
318 a_path
, a_owner
, o
, strerror(errno
));
324 "\t[Dry run: chown() file '%s' to be owned by user]\n",
329 * Return the happy news.
333 } /*uss_procs_EchoToFile */
336 /*-----------------------------------------------------------------------
337 * EXPORTED uss_procs_Exec
340 * Called from the code generated by the uss grammar, as well as
345 *------------------------------------------------------------------------*/
348 uss_procs_Exec(char *a_command
)
349 { /*uss_procs_Exec */
352 printf("Running '%s'\n", a_command
);
355 if (system(a_command
)) {
356 uss_procs_PrintErr(line
, "Failed to run the '%s' command: %s\n",
357 a_command
, strerror(errno
));
362 fprintf(stderr
, "\t[Dry run: executing '%s']\n", a_command
);
366 * Return the happy news.
370 } /*uss_procs_Exec */
373 /*-----------------------------------------------------------------------
374 * EXPORTED uss_procs_SetLink
377 * Called from the code generated by the uss grammar.
381 *------------------------------------------------------------------------*/
384 uss_procs_SetLink(char *a_path1
, char *a_path2
, char a_type
)
385 { /*uss_procs_SetLink */
390 printf("Setting link '%s' to '%s'\n", a_path1
, a_path2
);
393 * If we've not been given permission to overwrite things, make sure
394 * the target doesn't exist before doing anything.
396 if (!uss_OverwriteThisOne
) {
397 strcpy(temp
, a_path2
);
398 if (!stat(temp
, &stbuf
)) {
400 printf("\t[Entry exists, NOT overwriting it]\n");
410 if (symlink(a_path1
, a_path2
)) {
411 uss_procs_PrintErr(line
,
412 "Failed to make symlink '%s' to '%s': %s\n",
413 a_path1
, a_path2
, strerror(errno
));
418 fprintf(stderr
, "\t[Dry run: Making symlink '%s' to '%s']\n",
427 if (link(a_path1
, a_path2
)) {
428 uss_procs_PrintErr(line
,
429 "Failed to make hard link '%s' to '%s': %s\n",
430 a_path1
, a_path2
, strerror(errno
));
435 fprintf(stderr
, "\t[Dry run: Making hard link '%s' to '%s']\n",
441 * Return the happy news.
445 } /*uss_procs_SetLink */
448 /*-----------------------------------------------------------------------
449 * EXPORTED uss_procs_GetOwner
452 * Nothing interesting.
456 *------------------------------------------------------------------------*/
459 uss_procs_GetOwner(char *a_ownerStr
)
460 { /*uss_procs_GetOwner */
462 struct passwd
*pw
; /*Ptr to password file entry */
463 int ownerID
; /*Numerical owner */
465 ownerID
= atoi(a_ownerStr
);
466 if ((ownerID
== 0) && (a_ownerStr
[0] != '0')) {
468 * The owner is not in numerical format
470 if ((pw
= getpwnam(a_ownerStr
)) == NULL
) {
471 uss_procs_PrintErr(line
, "Owner '%s' is an unknown user\n",
479 } /*uss_procs_GetOwner */
481 /*-----------------------------------------------------------------------
485 * Copies the "from" file to the "to" file and sets the mode.
488 * a_from : File to copy from.
489 * a_to : File to copy to.
490 * a_mode : New Unix mode to set.
493 * 0 if everything went well,
494 * if there was a problem.
497 * Nothing interesting.
501 *------------------------------------------------------------------------*/
504 Copy(char *a_from
, char *a_to
, int a_mode
)
509 int rcnt
, wcnt
= -1, rc
;
512 fd1
= open(a_to
, O_EXCL
| O_CREAT
| O_WRONLY
, a_mode
);
514 if (errno
== EEXIST
) {
516 * The file exists. Since we can only be called when overwriting
517 * has been enabled, we back off and open the file normally (not
518 * supplying O_EXCL), then continue normally.
520 fd1
= open(a_to
, O_CREAT
| O_WRONLY
, a_mode
);
522 uss_procs_PrintErr(line
,
523 "%s: Failed to open '%s' for overwrite: %s.\n",
524 uss_whoami
, a_to
, strerror(errno
));
528 uss_procs_PrintErr(line
, "%s: Failed to open '%s': %s.\n",
529 uss_whoami
, a_to
, strerror(errno
));
534 if ((fd2
= open(a_from
, O_RDONLY
, 0)) < 0) {
535 uss_procs_PrintErr(line
, "%s: Error reading '%s': %s\n", uss_whoami
,
536 a_from
, strerror(errno
));
541 rcnt
= read(fd2
, buf
, BUFSIZ
);
544 wcnt
= write(fd1
, buf
, rcnt
);
545 } while (rcnt
== BUFSIZ
&& rcnt
== wcnt
);
546 if (rcnt
== -1 || wcnt
!= rcnt
) {
547 uss_procs_PrintErr(line
, "read/write error to %s\n", a_to
);
554 uss_procs_PrintErr(line
, "Failed to close '%s' %s\n", a_to
,
558 if ((rc
= close(fd2
)))
559 uss_procs_PrintErr(line
, "Warning: Failed to close '%s': %s\n",
560 a_from
, strerror(errno
));
565 /*-----------------------------------------------------------------------
569 * Writes a string into a file and sets its mode.
572 * a_s : String to write.
573 * a_f : Filename to write to.
574 * a_mode : New Unix mode to set.
577 * 0 if everything went well,
578 * if there was a problem.
581 * Nothing interesting.
585 *------------------------------------------------------------------------*/
588 Echo(char *a_s
, char *a_f
, int a_mode
)
594 fd
= open(a_f
, O_EXCL
| O_CREAT
| O_WRONLY
, a_mode
);
596 if (errno
== EEXIST
) {
598 * The file exists. Since we can only be called when
599 * overwriting has been enabled, we back off and open the
600 * file normally (not supplying the O_EXCL), then continue
601 * normally. Notice that we must truncate the file, since
602 * if the original file is longer than the stuff we're about
603 * to put in, all the old data past the current write will
606 fd
= open(a_f
, O_TRUNC
| O_WRONLY
, a_mode
);
608 uss_procs_PrintErr(line
,
609 "%s: Failed to open '%s' for overwrite: %s.\n",
610 uss_whoami
, a_f
, strerror(errno
));
614 uss_procs_PrintErr(line
, "%s: Failed to open '%s': %s. \n",
615 uss_whoami
, a_f
, strerror(errno
));
619 if (write(fd
, a_s
, strlen(a_s
)) != strlen(a_s
) ||
620 write(fd
, "\n", 1) != 1) {
621 uss_procs_PrintErr(line
, "Short write to '%s'\n", a_f
);
626 uss_procs_PrintErr(line
, "Failed to close '%s': %s\n", a_f
,
634 /*-----------------------------------------------------------------------
635 * static uss_procs_PickADir
638 * Tries to replace $AUTO by a subdir. Subdirs are given by means
639 * of "G" in the configuration file. Each of the directories is
640 * examined, and the one with the inimum number of entries is
648 * 0 if everything went well,
649 * -1 if there was a problem.
652 * Called with THREE parameters from lex.c!
656 *------------------------------------------------------------------------*/
659 uss_procs_PickADir(char *path
, char *cp
)
660 { /*uss_procs_PickADir */
662 char cd
[300]; /*Current directory for search */
664 int i
, count
, MinIndex
= 0, mina
= 10000;
669 if (uss_NumGroups
== 0) {
670 fprintf(stderr
, "%s: No choice yet given to replace $AUTO\n",
672 fprintf(stderr
, "%s: Use the G command before $AUTO in config file\n",
677 if (uss_Auto
[0] != '\0')
678 return (0); /* we have already done this for this user */
680 if (*(cp
- 1) == '/') { /*it's ..../$AUTO */
681 for (i
= 0; &path
[i
] != cp
; i
++)
687 "%s: $AUTO must be used to replace the whole path or the whole name of a subdirectory. Found: %s$AUTO\n",
696 * We now have the current dir (cd). Search all of the given
697 * subdirs (by G in template), count the number of entries in
698 * each and pick the minimum.
700 for (i
= 0; i
< uss_NumGroups
; i
++) {
701 sprintf(dirname
, "%s/%s", cd
, uss_DirPool
[i
]);
702 if ((dirp
= opendir(dirname
)) == NULL
) {
703 if (errno
!= ENOTDIR
)
705 "%s: Warning: Can't open dir '%s' (errno=%d). Skipped.\n",
706 uss_whoami
, dirname
, errno
);
707 continue; /*Skip and continue anyway */
710 for (dp
= readdir(dirp
); dp
!= NULL
; dp
= readdir(dirp
))
711 if (dp
->d_name
[0] != '.')
712 count
++; /* forget about files starting with . */
714 printf("debug: Dir '%s' has %d entries\n", dirname
, count
);
715 #endif /* USS_PROCS_DB */
722 if (mina
== 10000) { /* We found nothing */
723 fprintf(stderr
, "%s: Warning: No valid choice to replace $AUTO\n",
727 strcpy(uss_Auto
, uss_DirPool
[MinIndex
]);
729 printf("Picking dir w/minimum number of entries: '%s'\n",
734 } /*uss_procs_PickADir */
736 /*-----------------------------------------------------------------------
737 * EXPORTED uss_procs_AddToDirPool
740 * Called from the code generated by the uss grammar.
744 *------------------------------------------------------------------------*/
747 uss_procs_AddToDirPool(char *a_dirToAdd
)
749 if (uss_NumGroups
> 99) {
752 strcpy(uss_DirPool
[uss_NumGroups
++], a_dirToAdd
);
756 /*-----------------------------------------------------------------------
757 * EXPORTED uss_procs_FindAndOpen
760 * Nothing interesting.
764 *------------------------------------------------------------------------*/
767 uss_procs_FindAndOpen(char *a_fileToOpen
)
768 { /*uss_procs_FindAndOpen */
770 #define NUM_TPL_PATHS 3
772 FILE *rv
; /*Template file descriptor */
773 int i
; /*Loop counter */
774 char tmp_str
[uss_MAX_SIZE
]; /*Tmp string */
776 TemplatePath
[NUM_TPL_PATHS
][1024]; /*Template directories */
777 int cant_read
; /*Can't read the file? */
780 * If a full pathname was given, just take it as is.
782 if (strchr(a_fileToOpen
, '/')) {
783 strcpy(tmp_str
, a_fileToOpen
);
784 rv
= fopen(a_fileToOpen
, "r");
787 * A relative pathname was given. Try to find the file in each of
788 * the default template directories.
792 sprintf(TemplatePath
[0], "%s", ".");
793 sprintf(TemplatePath
[1], "/afs/%s/common/uss", uss_Cell
);
794 sprintf(TemplatePath
[2], "%s", "/etc");
796 for (i
= 0; i
< NUM_TPL_PATHS
; i
++) {
797 sprintf(tmp_str
, "%s/%s", TemplatePath
[i
], a_fileToOpen
);
798 if ((rv
= fopen(tmp_str
, "r")) != NULL
)
802 * If the file was there but couldn't be opened, we have
805 if (errno
!= ENOENT
) {
809 } /*Look in template directories */
812 * If we found and opened the file, we're happy. Otherwise,
813 * print out what went wrong.
817 fprintf(stderr
, "Using template '%s'\n", tmp_str
);
821 * Check to see if we specifically found the file but
825 fprintf(stderr
, "%s: Can't open template '%s': %s\n",
826 uss_whoami
, tmp_str
, strerror(errno
));
828 fprintf(stderr
, "%s: Can't find template '%s' in searchlist",
829 uss_whoami
, a_fileToOpen
);
830 for (i
= 0; i
< NUM_TPL_PATHS
; i
++)
831 fprintf(stderr
, " '%s'", TemplatePath
[i
]);
832 fprintf(stderr
, "\n");
833 } /*Can't find template */
835 } /*Relative pathname given */
838 * Whatever happened, return what we got.
842 } /*uss_procs_FindAndOpen */
845 /*-----------------------------------------------------------------------
846 * EXPORTED uss_procs_PrintErr
849 * Nothing interesting.
853 *------------------------------------------------------------------------*/
856 uss_procs_PrintErr(int a_lineNum
, char *a_fmt
, ... )
857 { /*uss_procs_PrintErr */
862 fprintf(stderr
, "%s: Template file, line %d: ", uss_whoami
, a_lineNum
);
863 vfprintf(stderr
, a_fmt
, ap
);
865 } /*uss_procs_PrintErr */