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