merge the version.h autogeneration stuff from 3.0
[jelmer/samba4-debian.git] / source / lib / popt_common.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Common popt routines
4
5    Copyright (C) Tim Potter 2001,2002
6    Copyright (C) Jelmer Vernooij 2002,2003
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /* Handle command line options:
26  *              -d,--debuglevel 
27  *              -s,--configfile 
28  *              -O,--socket-options 
29  *              -V,--version
30  *              -l,--log-base
31  *              -n,--netbios-name
32  *              -W,--workgroup
33  *              -i,--scope
34  */
35
36 extern pstring user_socket_options;
37 extern BOOL AllowDebugChange;
38
39 struct user_auth_info cmdline_auth_info;
40
41 static void popt_common_callback(poptContext con, 
42                            enum poptCallbackReason reason,
43                            const struct poptOption *opt,
44                            const char *arg, const void *data)
45 {
46         pstring logfile;
47         const char *pname;
48         
49         /* Find out basename of current program */
50         pname = strrchr_m(poptGetInvocationName(con),'/');
51
52         if (!pname)
53                 pname = poptGetInvocationName(con);
54         else 
55                 pname++;
56
57         if (reason == POPT_CALLBACK_REASON_PRE) {
58                 pstr_sprintf(logfile, "%s/log.%s", dyn_LOGFILEBASE, pname);
59                 lp_set_cmdline("log file", logfile);
60                 return;
61         }
62
63         switch(opt->val) {
64         case 'd':
65                 lp_set_cmdline("log level", arg);
66                 break;
67
68         case 'V':
69                 printf( "Version %s\n", SAMBA_VERSION_STRING );
70                 exit(0);
71                 break;
72
73         case 's':
74                 if (arg) {
75                         pstrcpy(dyn_CONFIGFILE, arg);
76                 }
77                 break;
78
79         case 'l':
80                 if (arg) {
81                         pstr_sprintf(logfile, "%s/log.%s", arg, pname);
82                         lp_set_cmdline("log file", logfile);
83                 }
84                 break;
85                 
86         case 'W':
87                 lp_set_cmdline("workgroup", arg);
88                 break;
89                 
90         case 'n':
91                 lp_set_cmdline("netbios name", arg);
92                 break;
93                 
94         case 'i':
95                 lp_set_cmdline("netbios scope", arg);
96                 break;
97
98         case 'm':
99                 lp_set_cmdline("max protocol", arg);
100                 break;
101         }
102 }
103
104 struct poptOption popt_common_connection[] = {
105         { NULL, 0, POPT_ARG_CALLBACK, popt_common_callback },
106         { "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use",
107           "SOCKETOPTIONS" },
108         { "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" },
109         { "workgroup", 'W', POPT_ARG_STRING, NULL, 'W', "Set the workgroup name", "WORKGROUP" },
110         { "scope", 'i', POPT_ARG_STRING, NULL, 'i', "Use this Netbios scope", "SCOPE" },
111         { "maxprotocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set max protocol level", "MAXPROTOCOL" },
112         POPT_TABLEEND
113 };
114
115 struct poptOption popt_common_samba[] = {
116         { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_callback },
117         { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
118         { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternative configuration file", "CONFIGFILE" },
119         { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Basename for log/debug files", "LOGFILEBASE" },
120         { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
121         POPT_TABLEEND
122 };
123
124 struct poptOption popt_common_version[] = {
125         { NULL, 0, POPT_ARG_CALLBACK, popt_common_callback },
126         { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
127         POPT_TABLEEND
128 };
129
130
131
132 /****************************************************************************
133  * get a password from a a file or file descriptor
134  * exit on failure
135  * ****************************************************************************/
136 static void get_password_file(struct user_auth_info *a)
137 {
138         int fd = -1;
139         char *p;
140         BOOL close_it = False;
141         pstring spec;
142         char pass[128];
143
144         if ((p = getenv("PASSWD_FD")) != NULL) {
145                 pstrcpy(spec, "descriptor ");
146                 pstrcat(spec, p);
147                 sscanf(p, "%d", &fd);
148                 close_it = False;
149         } else if ((p = getenv("PASSWD_FILE")) != NULL) {
150                 fd = sys_open(p, O_RDONLY, 0);
151                 pstrcpy(spec, p);
152                 if (fd < 0) {
153                         fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
154                                         spec, strerror(errno));
155                         exit(1);
156                 }
157                 close_it = True;
158         }
159
160         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
161                 p && p - pass < sizeof(pass);) {
162                 switch (read(fd, p, 1)) {
163                 case 1:
164                         if (*p != '\n' && *p != '\0') {
165                                 *++p = '\0'; /* advance p, and null-terminate pass */
166                                 break;
167                         }
168                 case 0:
169                         if (p - pass) {
170                                 *p = '\0'; /* null-terminate it, just in case... */
171                                 p = NULL; /* then force the loop condition to become false */
172                                 break;
173                         } else {
174                                 fprintf(stderr, "Error reading password from file %s: %s\n",
175                                                 spec, "empty password\n");
176                                 exit(1);
177                         }
178
179                 default:
180                         fprintf(stderr, "Error reading password from file %s: %s\n",
181                                         spec, strerror(errno));
182                         exit(1);
183                 }
184         }
185         pstrcpy(a->password, pass);
186         if (close_it)
187                 close(fd);
188 }
189
190 static void get_credentials_file(const char *file, struct user_auth_info *info) 
191 {
192         XFILE *auth;
193         fstring buf;
194         uint16 len = 0;
195         char *ptr, *val, *param;
196
197         if ((auth=x_fopen(file, O_RDONLY, 0)) == NULL)
198         {
199                 /* fail if we can't open the credentials file */
200                 d_printf("ERROR: Unable to open credentials file!\n");
201                 exit(-1);
202         }
203
204         while (!x_feof(auth))
205         {
206                 /* get a line from the file */
207                 if (!x_fgets(buf, sizeof(buf), auth))
208                         continue;
209                 len = strlen(buf);
210
211                 if ((len) && (buf[len-1]=='\n'))
212                 {
213                         buf[len-1] = '\0';
214                         len--;
215                 }
216                 if (len == 0)
217                         continue;
218
219                 /* break up the line into parameter & value.
220                  * will need to eat a little whitespace possibly */
221                 param = buf;
222                 if (!(ptr = strchr_m (buf, '=')))
223                         continue;
224
225                 val = ptr+1;
226                 *ptr = '\0';
227
228                 /* eat leading white space */
229                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
230                         val++;
231
232                 if (strwicmp("password", param) == 0)
233                 {
234                         pstrcpy(info->password, val);
235                         info->got_pass = True;
236                 }
237                 else if (strwicmp("username", param) == 0)
238                         pstrcpy(info->username, val);
239 #if 0
240                 else if (strwicmp("domain", param) == 0)
241                         set_global_myworkgroup(val);
242 #endif
243                 memset(buf, 0, sizeof(buf));
244         }
245         x_fclose(auth);
246 }
247
248 /* Handle command line options:
249  *              -U,--user
250  *              -A,--authentication-file
251  *              -k,--use-kerberos
252  *              -N,--no-pass
253  */
254
255
256 static void popt_common_credentials_callback(poptContext con, 
257                                                                                          enum poptCallbackReason reason,
258                                                                                          const struct poptOption *opt,
259                                                                                          const char *arg, const void *data)
260 {
261         char *p;
262
263         if (reason == POPT_CALLBACK_REASON_PRE) {
264                 cmdline_auth_info.use_kerberos = False;
265                 cmdline_auth_info.got_pass = False;
266                 pstrcpy(cmdline_auth_info.username, "GUEST");   
267
268                 if (getenv("LOGNAME"))pstrcpy(cmdline_auth_info.username,getenv("LOGNAME"));
269
270                 if (getenv("USER")) {
271                         pstrcpy(cmdline_auth_info.username,getenv("USER"));
272
273                         if ((p = strchr_m(cmdline_auth_info.username,'%'))) {
274                                 *p = 0;
275                                 pstrcpy(cmdline_auth_info.password,p+1);
276                                 cmdline_auth_info.got_pass = True;
277                                 memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(cmdline_auth_info.password));
278                         }
279                 }
280
281                 if (getenv("PASSWD")) {
282                         pstrcpy(cmdline_auth_info.password,getenv("PASSWD"));
283                         cmdline_auth_info.got_pass = True;
284                 }
285
286                 if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
287                         get_password_file(&cmdline_auth_info);
288                         cmdline_auth_info.got_pass = True;
289                 }
290
291                 return;
292         }
293
294         switch(opt->val) {
295         case 'U':
296                 {
297                         char *lp;
298
299                         pstrcpy(cmdline_auth_info.username,arg);
300                         if ((lp=strchr_m(cmdline_auth_info.username,'%'))) {
301                                 *lp = 0;
302                                 pstrcpy(cmdline_auth_info.password,lp+1);
303                                 cmdline_auth_info.got_pass = True;
304                                 memset(strchr_m(arg,'%')+1,'X',strlen(cmdline_auth_info.password));
305                         }
306                 }
307                 break;
308
309         case 'A':
310                 get_credentials_file(arg, &cmdline_auth_info);
311                 break;
312
313         case 'k':
314 #ifndef HAVE_KRB5
315                 d_printf("No kerberos support compiled in\n");
316                 exit(1);
317 #else
318                 cmdline_auth_info.use_kerberos = True;
319                 cmdline_auth_info.got_pass = True;
320 #endif
321                 break;
322         }
323 }
324
325
326
327 struct poptOption popt_common_credentials[] = {
328         { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_credentials_callback },
329         { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" },
330         { "no-pass", 'N', POPT_ARG_NONE, &cmdline_auth_info.got_pass, True, "Don't ask for a password" },
331         { "kerberos", 'k', POPT_ARG_NONE, &cmdline_auth_info.use_kerberos, True, "Use kerberos (active directory) authentication" },
332         { "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
333         POPT_TABLEEND
334 };