Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / libpam / libpam / pam_misc.c
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 $
5  * $DragonFly: src/contrib/libpam/libpam/Attic/pam_misc.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
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.. */
47 int _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
59 char *_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
120 char *_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
146 int _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
209 void _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
223 void _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
243 void _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
331 parse_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 }