Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / libpam / libpam / pam_misc.c
CommitLineData
984263bc
MD
1/* pam_misc.c -- This is random stuff */
2
3/* $Id: pam_misc.c,v 1.9 1997/04/05 06:56:19 morgan Exp $
4 * $FreeBSD: src/contrib/libpam/libpam/pam_misc.c,v 1.1.1.1.6.3 2001/09/13 08:24:14 roam Exp $
1de703da 5 * $DragonFly: src/contrib/libpam/libpam/Attic/pam_misc.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
984263bc
MD
6 *
7 * $Log: pam_misc.c,v $
8 * Revision 1.9 1997/04/05 06:56:19 morgan
9 * enforce AUTHTOK restrictions
10 *
11 * Revision 1.8 1997/02/15 15:59:46 morgan
12 * modified ..strCMP comment
13 *
14 * Revision 1.7 1996/12/01 03:14:13 morgan
15 * use _pam_macros.h
16 *
17 * Revision 1.6 1996/11/10 20:05:52 morgan
18 * name convention _pam_ enforced. Also modified _pam_strdup()
19 *
20 * Revision 1.5 1996/07/07 23:57:14 morgan
21 * deleted debuggin function and replaced it with a static function
22 * defined in pam_private.h
23 *
24 * Revision 1.4 1996/06/02 08:00:56 morgan
25 * added StrTok function
26 *
27 * Revision 1.3 1996/05/21 04:36:58 morgan
28 * added debugging information
29 * replaced the _pam_log need for a local buffer with a call to vsyslog()
30 * [Al Longyear had some segfaulting problems related to this]
31 *
32 * Revision 1.2 1996/03/16 21:55:13 morgan
33 * changed pam_mkargv to _pam_mkargv
34 *
35 */
36
37#include <stdarg.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41#include <syslog.h>
42#include <ctype.h>
43
44#include "pam_private.h"
45
46/* caseless string comparison: POSIX does not define this.. */
47int _pam_strCMP(const char *s, const char *t)
48{
49 int cf;
50
51 do {
52 cf = tolower(*s) - tolower(*t);
53 ++t;
54 } while (!cf && *s++);
55
56 return cf;
57}
58
59char *_pam_StrTok(char *from, const char *format, char **next)
60/*
61 * this function is a variant of the standard strtok, it differs in that
62 * it takes an additional argument and doesn't nul terminate tokens until
63 * they are actually reached.
64 */
65{
66 char table[256], *end;
67 int i;
68
69 if (from == NULL && (from = *next) == NULL)
70 return from;
71
72 /* initialize table */
73 for (i=1; i<256; table[i++] = '\0');
74 for (i=0; format[i] ; table[(int)format[i++]] = 'y');
75
76 /* look for first non-blank char */
77 while (*from && table[(int)*from]) {
78 ++from;
79 }
80
81 if (*from == '[') {
82 /*
83 * special case, "[...]" is considered to be a single
84 * object. Note, however, if one of the format[] chars is
85 * '[' this single string will not be read correctly.
86 */
87 for (end=++from; *end && *end != ']'; ++end) {
88 if (*end == '\\' && end[1] == ']')
89 ++end;
90 }
91 /* note, this string is stripped of its edges: "..." is what
92 remains */
93 } else if (*from) {
94 /* simply look for next blank char */
95 for (end=from; *end && !table[(int)*end]; ++end);
96 } else {
97 return (*next = NULL); /* no tokens left */
98 }
99
100 /* now terminate what we have */
101 if (*end)
102 *end++ = '\0';
103
104 /* indicate what it left */
105 if (*end) {
106 *next = end;
107 } else {
108 *next = NULL; /* have found last token */
109 }
110
111 /* return what we have */
112 return from;
113}
114
115/*
116 * Safe duplication of character strings. "Paranoid"; don't leave
117 * evidence of old token around for later stack analysis.
118 */
119
120char *_pam_strdup(const char *x)
121{
122 register char *new=NULL;
123
124 if (x != NULL) {
125 register int i;
126
127 for (i=0; x[i]; ++i); /* length of string */
128 if ((new = malloc(++i)) == NULL) {
129 i = 0;
130 pam_system_log(NULL, NULL, LOG_CRIT,
131 "_pam_strdup: failed to get memory");
132 } else {
133 while (i-- > 0) {
134 new[i] = x[i];
135 }
136 }
137 x = NULL;
138 }
139
140 return new; /* return the duplicate or NULL on error */
141}
142
143/* Generate argv, argc from s */
144/* caller must free(argv) */
145
146int _pam_mkargv(char *s, char ***argv, int *argc)
147{
148 int l;
149 int argvlen = 0;
150 char *sbuf, *sbuf_start;
151 char **our_argv = NULL;
152 char **argvbuf;
153 char *argvbufp;
154#ifdef DEBUG
155 int count=0;
156#endif
157
158 D(("_pam_mkargv called: %s",s));
159
160 *argc = 0;
161
162 l = strlen(s);
163 if (l) {
164 if ((sbuf = sbuf_start = _pam_strdup(s)) == NULL) {
165 pam_system_log(NULL, NULL, LOG_CRIT,
166 "pam_mkargv: null returned by _pam_strdup");
167 D(("arg NULL"));
168 } else {
169 /* Overkill on the malloc, but not large */
170 argvlen = (l + 1) * ((sizeof(char)) + sizeof(char *));
171 if ((our_argv = argvbuf = malloc(argvlen)) == NULL) {
172 pam_system_log(NULL, NULL, LOG_CRIT,
173 "pam_mkargv: null returned by malloc");
174 } else {
175 char *tmp=NULL;
176
177 argvbufp = (char *) argvbuf + (l * sizeof(char *));
178 D(("[%s]",sbuf));
179 while ((sbuf = _pam_StrTok(sbuf, " \n\t", &tmp))) {
180 D(("arg #%d",++count));
181 D(("->[%s]",sbuf));
182 strcpy(argvbufp, sbuf);
183 D(("copied token"));
184 *argvbuf = argvbufp;
185 argvbufp += strlen(argvbufp) + 1;
186 D(("stepped in argvbufp"));
187 (*argc)++;
188 argvbuf++;
189 sbuf = NULL;
190 D(("loop again?"));
191 }
192 _pam_drop(sbuf_start);
193 }
194 }
195 }
196
197 *argv = our_argv;
198
199 D(("_pam_mkargv returned"));
200
201 return(argvlen);
202}
203
204/*
205 * this function is used to protect the modules from accidental or
206 * semi-mallicious harm that an application may do to confuse the API.
207 */
208
209void _pam_sanitize(pam_handle_t *pamh)
210{
211 /*
212 * this is for security. We reset the auth-tokens here.
213 */
214 pam_set_item(pamh,PAM_AUTHTOK,NULL);
215 pam_set_item(pamh,PAM_OLDAUTHTOK,NULL);
216}
217
218/*
219 * This function scans the array and replaces the _PAM_ACTION_UNDEF
220 * entries with the default action.
221 */
222
223void _pam_set_default_control(int *control_array, int default_action)
224{
225 int i;
226
227 for (i=0; i<_PAM_RETURN_VALUES; ++i) {
228 if (control_array[i] == _PAM_ACTION_UNDEF) {
229 control_array[i] = default_action;
230 }
231 }
232}
233
234/*
235 * This function is used to parse a control string. This string is a
236 * series of tokens of the following form:
237 *
238 * "[ ]*return_code[ ]*=[ ]*action/[ ]".
239 */
240
241#include "pam_tokens.h"
242
243void _pam_parse_control(int *control_array, char *tok)
244{
245 const char *error;
246 int ret;
247
248 while (*tok) {
249 int act, len;
250
251 /* skip leading space */
252 while (isspace(*tok) && *++tok);
253 if (!*tok)
254 break;
255
256 /* identify return code */
257 for (ret=0; ret<=_PAM_RETURN_VALUES; ++ret) {
258 len = strlen(_pam_token_returns[ret]);
259 if (!strncmp(_pam_token_returns[ret], tok, len)) {
260 break;
261 }
262 }
263 if (ret > _PAM_RETURN_VALUES || !*(tok += len)) {
264 error = "expecting return value";
265 goto parse_error;
266 }
267
268 /* observe '=' */
269 while (isspace(*tok) && *++tok);
270 if (!*tok || *tok++ != '=') {
271 error = "expecting '='";
272 goto parse_error;
273 }
274
275 /* skip leading space */
276 while (isspace(*tok) && *++tok);
277 if (!*tok) {
278 error = "expecting action";
279 goto parse_error;
280 }
281
282 /* observe action type */
283 for (act=0; act < (-(_PAM_ACTION_UNDEF)); ++act) {
284 len = strlen(_pam_token_actions[act]);
285 if (!strncmp(_pam_token_actions[act], tok, len)) {
286 act *= -1;
287 tok += len;
288 break;
289 }
290 }
291 if (act > 0) {
292 /*
293 * Either we have a number or we have hit an error. In
294 * principle, there is nothing to stop us accepting
295 * negative offsets. (Although we would have to think of
296 * another way of encoding the tokens.) However, I really
297 * think this would be both hard to administer and easily
298 * cause looping problems. So, for now, we will just
299 * allow forward jumps. (AGM 1998/1/7)
300 */
301 if (!isdigit(*tok)) {
302 error = "expecting jump number";
303 goto parse_error;
304 }
305 /* parse a number */
306 act = 0;
307 do {
308 act *= 10;
309 act += *tok - '0'; /* XXX - this assumes ascii behavior */
310 } while (*++tok && isdigit(*tok));
311 if (! act) {
312 /* we do not allow 0 jumps. There is a token ('ignore')
313 for that */
314 error = "expecting non-zero";
315 goto parse_error;
316 }
317 }
318
319 /* set control_array element */
320 if (ret != _PAM_RETURN_VALUES) {
321 control_array[ret] = act;
322 } else {
323 /* set the default to 'act' */
324 _pam_set_default_control(control_array, act);
325 }
326 }
327
328 /* that was a success */
329 return;
330
331parse_error:
332 /* treat everything as bad */
333 pam_system_log(NULL, NULL, LOG_ERR, "pam_parse: %s; [...%s]", error, tok);
334 for (ret=0; ret<_PAM_RETURN_VALUES; control_array[ret++]=_PAM_ACTION_BAD);
335
336}