1 /*
2 * $Id$
3 *
4 * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org>
5 *
6 * pamc_start and pamc_end
7 */
8
9 #include "libpamc.h"
10 #include "pam_inline.h"
11
12 /*
13 * liberate path list
14 */
15
16 static void __pamc_delete_path_list(pamc_handle_t pch)
17 {
18 int i;
19
20 for (i=0; pch->agent_paths[i]; ++i) {
21 free(pch->agent_paths[i]);
22 pch->agent_paths[i] = NULL;
23 }
24
25 free(pch->agent_paths);
26 pch->agent_paths = NULL;
27 }
28
29 /*
30 * open the pamc library
31 */
32
33 pamc_handle_t pamc_start(void)
34 {
35 int i, count, last, this;
36 const char *default_path;
37 pamc_handle_t pch;
38
39 pch = calloc(1, sizeof(struct pamc_handle_s));
40 if (pch == NULL) {
41 D(("no memory for *pch"));
42 return NULL;
43 }
44
45 pch->highest_fd_to_close = _PAMC_DEFAULT_TOP_FD;
46
47 default_path = getenv("PAMC_AGENT_PATH");
48 if (default_path == NULL) {
49 default_path = PAMC_SYSTEM_AGENT_PATH;
50 }
51
52 /* number of individual paths */
53 for (count=1, i=0; default_path[i]; ++i) {
54 if (default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR) {
55 ++count;
56 }
57 }
58
59 pch->agent_paths = calloc(count+1, sizeof(char *));
60 if (pch->agent_paths == NULL) {
61 D(("no memory for path list"));
62 goto drop_pch;
63 }
64
65 this = last = i = 0;
66 while ( default_path[i] || (i != last) ) {
67 if ( default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR
68 || !default_path[i] ) {
69 int length;
70
71 pch->agent_paths[this] = malloc(length = 1+i-last);
72
73 if (pch->agent_paths[this] == NULL) {
74 D(("no memory for next path"));
75 goto drop_list;
76 }
77
78 memcpy(pch->agent_paths[this], default_path + last, i-last);
79 pch->agent_paths[this][i-last] = '\0';
80 if (length > pch->max_path) {
81 pch->max_path = length;
82 }
83
84 if (++this == count) {
85 break;
86 }
87
88 last = ++i;
89 } else {
90 ++i;
91 }
92 }
93
94 return pch;
95
96 drop_list:
97 __pamc_delete_path_list(pch);
98
99 drop_pch:
100 free(pch);
101
102 return NULL;
103 }
104
105 /*
106 * shutdown each of the loaded agents and
107 */
108
109 static int __pamc_shutdown_agents(pamc_handle_t pch)
110 {
111 int retval = PAM_BPC_TRUE;
112
113 D(("called"));
114
115 while (pch->chain) {
116 pid_t pid;
117 int status;
118 pamc_agent_t *this;
119
120 this = pch->chain;
121 D(("cleaning up agent %p", this));
122 pch->chain = pch->chain->next;
123 this->next = NULL;
124 D(("cleaning up agent: %s", this->id));
125
126 /* close off contact with agent and wait for it to shutdown */
127
128 close(this->writer);
129 this->writer = -1;
130 close(this->reader);
131 this->reader = -1;
132
133 pid = waitpid(this->pid, &status, 0);
134 if (pid == this->pid) {
135
136 D(("is exit:%d, exit val:%d",
137 WIFEXITED(status), WEXITSTATUS(status)));
138
139 if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
140 retval = PAM_BPC_FALSE;
141 }
142 } else {
143 D(("problem shutting down agent (%s): pid(%d) != waitpid(%d)!?",
144 this->id, this->pid, pid));
145 retval = PAM_BPC_FALSE;
146 }
147 pid = this->pid = 0;
148
149 pam_overwrite_n(this->id, this->id_length);
150 free(this->id);
151 this->id = NULL;
152 this->id_length = 0;
153
154 free(this);
155 this = NULL;
156 }
157
158 return retval;
159 }
160
161 /*
162 * close the pamc library
163 */
164
165 int pamc_end(pamc_handle_t *pch_p)
166 {
167 int retval;
168
169 if (pch_p == NULL) {
170 D(("called with no pch_p"));
171 return PAM_BPC_FALSE;
172 }
173
174 if (*pch_p == NULL) {
175 D(("called with no *pch_p"));
176 return PAM_BPC_FALSE;
177 }
178
179 D(("removing path_list"));
180 __pamc_delete_path_list(*pch_p);
181
182 D(("shutting down agents"));
183 retval = __pamc_shutdown_agents(*pch_p);
184
185 D(("freeing *pch_p"));
186 free(*pch_p);
187 *pch_p = NULL;
188
189 return retval;
190 }